How to think about CFrames

#CFrames are how ROBLOX represents the 3D position and orientation of objects in the game world.
Understanding how these work can lead to easier to write, easier to read, and overall more efficient CFrame code.

If you’ve ever done something like:

print(CFrame.new())

you know that it gives you 12 numbers. What do these numbers mean?

Well before we start, let’s think about CFrame.lookVector. lookVector is a unit vector (vector with a magnitude of 1) that points in the direction the CFrame is facing. A CFrame actually contains three more of these lookVectors, except instead of pointing in the forward direction, they point to the right, top and back of the CFrame (See picture below).

These vectors, the one positional vector, and the three directional vectors, the Right Vector, Top Vector and Back Vector, can be acquired through CFrame:components().

image

Keep in mind the Right, Top, and Back Vectors are NOT the positions of the centers of the faces on a Part. They are directions. Not positions.
Keep in mind that the three directional vectors are unit length.
Keep in mind that the Position is the same as CFrame.p, and if it’s in a Part, then it is also equal to Part.Position.

The three directional vectors make up something called a rotation matrix. The rotation matrix describes the 3D orientation (not position), of the CFrame.

And example of the numbers you might find in a CFrame are:

5,10,3,
1,0,0,
0,1,0,
0,0,1

A bit of code to get these into a nice format is:

local function DeconstructCFrame(CFrame)
	local px,py,pz,xx,yx,zx,xy,yy,zy,xz,yz,zz=CFrame:components()

	local Position=Vector3.new(px,py,pz)
	local Right=Vector3.new(xx,xy,xz)
	local Top=Vector3.new(yx,yy,yz)
	local Back=Vector3.new(zx,zy,zz)

	return Position,Right,Top,Back
end

local Pos,RightVec,TopVec,BackVec=DeconstructCFrame(CFrame.new())

##What does it mean to say CFrame * Vector3?

A Vector3 is made up of three components, x y and z. These determine where the Vector3 is in the game world coordinate grid, which is how the game world defines positions.

Changing the x component causes the Vector3 to move along the right/left axis of the coordinate grid.
Changing the y component causes the Vector3 to move along the up/down axis of the coordinate grid.
Changing the z component causes the Vector3 to move along the backward/forward axis of the coordinate grid.

If the Vector3 is <0, 0, 0>, then the Vector3 is at the origin of the coordinate grid.

When you say, CFrame * Vector3, you’re telling the Vector3 to take on a coordinate grid defined by the CFrame.
In other words, now that right/left axis is defined as the Right Vector of the CFrame.
The up/down axis is defined as the Top Vector of the CFrame
The backward/forward axis is defined as the Back Vector of the CFrame.
The origin is defined as the Position of the CFrame

CFrame0 * CFrame1 does exactly the same thing, except the orientation part of CFrame1 is also transformed.

You can accomplish this by hand without the use of CFrames with some code like this using the DeconstructCFrame function:

local function CFrameTimesVector3(CFrame,Vector3)
	local Pos,RightVec,TopVec,BackVec=DeconstructCFrame(CFrame)

	local TransformedVector3=Pos+RightVec*Vector3.x+TopVec*Vector3.y+BackVec*Vector3.z

	return TransformedVector3
end

Or, a little more complexly, but waaay more efficiently, like:

local function CFrameTimesVector3(CFrame,Vector)
	local px,py,pz,xx,yx,zx,xy,yy,zy,xz,yz,zz=CFrame:components()
	local vx,vy,vz=Vector.x,Vector.y,Vector.z

	local x=px+xx*vx+yx*vy+zx*vz
	local y=py+xy*vx+yy*vy+zy*vz
	local z=pz+xz*vx+yz*vy+zz*vz

	return Vector3.new(x,y,z)
end

##What does it mean to say CFrame:inverse() * Vector3?

It really just does the opposite of CFrame * Vector3
If we say that CFrame * Vector3 multiplies a Vector3 out of a CFrame, then we can say that CFrame:inverse() * Vector3 divides a Vector3 into a CFrame.

Mathematically,

Vector3B = CFrame * Vector3A
Vector3A = CFrame:inverse() * Vector3B

We can use this formula when we want to get what a Vector3’s coordinates are relative to a coordinate grid defined by a CFrame.

With Vector3 in the game world’s coordinate grid:
The x element tells us how far right the Vector3 goes.
The y element tells us how far up the Vector3 goes.
The z element tells us how far back the Vector3 goes.

If we want to do the opposite of CFrame*Vector3, we need to figure out how far the Vector3 goes along each of the directional vectors of the CFrame.
In order to determine how far a VectorA goes along VectorB, we can make use of Dot Product.

How Far VectorA Goes Along VectorB = (VectorA) dot (Unit(VectorB))

Keep in mind that because the directional vectors of the CFrame are already unit length, we didn’t need to unitize them.

You can accomplish this by hand without the use of CFrames with some code like this using the DeconstructCFrame function:

local function CFrameTimesVector3(CFrame,Vector)
	local Pos,RightVec,TopVec,BackVec=DeconstructCFrame(CFrame)

	local RelativeVector3=Vector-Pos

	local HowFarRight=RelativeVector3:Dot(RightVec)
	local HowFarUp=RelativeVector3:Dot(TopVec)
	local HowFarBack=RelativeVector3:Dot(BackVec)

	local TransformedVector3=Vector3.new(HowFarRight,HowFarUp,HowFarBack)

	return TransformedVector3
end

Or, a little more complexly, but waaay more efficiently, like:

local function CFrameTimesVector3(CFrame,Vector)
	local px,py,pz,xx,yx,zx,xy,yy,zy,xz,yz,zz=CFrame:components()
	local vx,vy,vz=Vector.x,Vector.y,Vector.z

	local rx,ry,rz=vx-px,vy-py,vz-pz--r for Relative

	local HowFarRight=rx*xx+ry*xy+rz*xz
	local HowFarUp=rx*yx+ry*yy+rz*yz
	local HowFarBack=rx*zx+ry*zy+rz*zz

	return Vector3.new(HowFarRight,HowFarUp,HowFarBack)
end

If you understand this, then CFrame0:inverse()*CFrame1 does exactly as you would expect.

I’m sure you guys know what to do with this and what you can replace with this. At least you have a better understanding of what the numbers in the CFrame mean.

####If you want to share this with your non-RBX Dev buddies, I’ve compiled a big PNG of it here: AxisAngle's Guide to CFrames - Imgur

256 Likes

I would love to have more information regarding CFrame. I really liked your ‘article’ so far. Keep it up !

9 Likes

I have a feeling I’m behind the existence of this thread when I asked [b]how to find the “up” face of a part[/b], haha.

4 Likes

You and others.

I feel bad when I see people coming up with really complicated code that’s 10 times harder to understand than it needs to be and is 10 times slower than it should be. I also just get tired of having people tell me that my code is unreadable because they don’t understand CFrame.

6 Likes

Very useful information. Make more.

I love you. :blush:

3 Likes

Thanks for this demonstration, I never properly took time to look into CFrame properly as I’d meant too, but this sums it up pretty well, and now that I know the order of the components it makes a lot more sense.

2 Likes

So right, top and back vectors are just a center position of that side’s face?

No. As I said, they’re like lookVectors. The right, top and back vectors are directions. Not positions. That’s why they’re drawn as arrows and not as points.

Also CFrames don’t have faces. I just put a part there as an example.

If you wanted to find the center position of each side’s face, you could do that pretty simply with the function I put in my original post:

local Pos,RightVec,TopVec,BackVec=DeconstructCFrame(Part.CFrame)
local RightSide=Pos+Part.Size.x/2*RightVector
local LeftSide=Pos-Part.Size.x/2*RightVector
--etc.
5 Likes

This guy needs to be a wiki writer NOW =O

18 Likes

Update. Added CFrame:inverse()*Vector3

2 Likes

O.o Badass.

All my CFrame work just comes from how I can manipulate the normal lookVector to become a TopVector or RightVector using CFrame.angles()

I’ll probably still do that, but this makes me visualize more things more better.

[quote] O.o Badass.

All my CFrame work just comes from how I can manipulate the normal lookVector to become a TopVector or RightVector using CFrame.angles()

I’ll probably still do that, but this makes me visualize more things more better. [/quote]

You won’t once I post my: “How to make reasonably efficient code” Topic.

I can actually write out what math you’re making your computer do when you manipulate the normal lookVector to become TopVector or RightVector, if you want me to. It might make you cry a little bit.

1 Like

This is honestly the most useful resource I have ever seen on this forum. You sir, are amazing :smiley:

Would you like for me to do one on Vectors, stuff like dot and cross product?

5 Likes

Would you like for me to do one on Vectors, stuff like dot and cross product?[/quote]

I would love an article on dot and cross product, with examples of applicable usage for each one.

Would you like for me to do one on Vectors, stuff like dot and cross product?[/quote]

I would love an article on dot and cross product, with examples of applicable usage for each one.[/quote]

The first one, I can do. The second part about applicable usage, I don’t really know.
There’s only one use for cross and dot product, kind of like there’s only one use for multiplication or one use for subtraction. You use multiplication when you need to multiply two numbers together, and you use subtraction when you need to find the difference between two numbers.

You use cross product when you need to find a vector perpendicular to two vectors with a magnitude equal to the area of the parallelogram defined by said two vectors. That’s all of the usage you get out of it.

1 Like

Would you like for me to do one on Vectors, stuff like dot and cross product?[/quote]

I would love an article on dot and cross product, with examples of applicable usage for each one.[/quote]

The first one, I can do. The second part about applicable usage, I don’t really know.
There’s only one use for cross and dot product, kind of like there’s only one use for multiplication or one use for subtraction. You use multiplication when you need to multiply two numbers together, and you use subtraction when you need to find the difference between two numbers.

You use cross product when you need to find a vector perpendicular to two vectors with a magnitude equal to the area of the parallelogram defined by said two vectors. That’s all of the usage you get out of it.[/quote]

Well, that’s pretty general. What I’m looking for are specific use cases, such as when would you need to find a vector perpendicular to two vectors with a magnitude equal to the area of the parallelogram defined by the two vectors? What are some things you could do that involve the usage of the cross and/or dot products of vectors?

Edit:

Like how the Pythagorean theorem is useful for finding the distance between two points by creating a right triangle and finding the hypotenuse. With that information you can, for example, find the distance of a rocket from where it fired. This information has many uses that can determine the fate of the rocket and those near it.

That’s essentially what I meant by applicable usages.

Would you like for me to do one on Vectors, stuff like dot and cross product?[/quote]

I would love an article on dot and cross product, with examples of applicable usage for each one.[/quote]

The first one, I can do. The second part about applicable usage, I don’t really know.
There’s only one use for cross and dot product, kind of like there’s only one use for multiplication or one use for subtraction. You use multiplication when you need to multiply two numbers together, and you use subtraction when you need to find the difference between two numbers.

You use cross product when you need to find a vector perpendicular to two vectors with a magnitude equal to the area of the parallelogram defined by said two vectors. That’s all of the usage you get out of it.[/quote]

Well, that’s pretty general. What I’m looking for are specific use cases, such as when would you need to find a vector perpendicular to two vectors with a magnitude equal to the area of the parallelogram defined by the two vectors? What are some things you could do that involve the usage of the cross and/or dot products of vectors?

Edit:

Like how the Pythagorean theorem is useful for finding the distance between two points by creating a right triangle and finding the hypotenuse. With that information you can, for example, find the distance of a rocket from where it fired. This information has many uses that can determine the fate of the rocket and those near it.

That’s essentially what I meant by applicable usages.[/quote]

Huh. I don’t know. You know, I don’t really have a list of formulas I keep. Every time I do something, I come up with the solution again from scratch. Because of this, when I think about math, all I see are a few basic formulas, and all math is very simple as a result of that.

I don’t even really know the Pythagorean theorem. I just remember that dot product returns a scalar and is multiplication, so if you dot a vector with itself, you get the scalar, vector^2, if you just take the square root of that, you get the scalar of the vector, which has to logically be magnitude.

In my opinion, this very basic understanding of everything is what allows me to do what I do as well as I do it. The purpose of putting up this article was not to tell people how to use CFrame, it was to give them to knowledge to be able to freely create new ways of doing things and to solve problems that they wouldn’t have previously been able to. But I do now understand that it would be good to give a bit of context, I might do so in this article, and definitely will in the dot and cross product article. Thank you for convincing me to.

HOWEVER, the examples will take up the majority of the article.

Should really put this on wiki.

(And I wouldn’t mind putting it up there, but putting it up there without credits, which I think is forbidden…)

1 Like

Could you explain why the z direction is pointing to back, not front? There is right direction, top direction and then one to the back, seems strange to me.

1 Like