What is this topic and why it exists?
Recently i found the urge to learn how to precisely use CFrames in a project i’m working on.
This topic is meant to be a place to share your knowladge and learn new things about CFrames!
Everything that I learn will be summed up and explained here in topics, with the intention of serving as a guide for new developers (like me) or developers that want to expand their knowladge!
Replies that add knowladge about CFrames will be added here too! After all, this is a community centered space! Feel free to leave questions and help others to learn ;]
Any concept written [like This] can be found explained inside the Concept Library.
Concept Library
- Here you can learn about fundamental concepts used in various CFrame’s functions.
Radians
Radians are units used to describe circunferences and arcs.
A Radian measure the same amount as the circle’s Radius.
It is used together with π (Pi) to determine an arc’s lenght and degrees between points on a circunference.The entire circle’s circunference measures 2π * rad (2π rad for short). This means that 2π rad is equal to 360º.
It can be easily conversible using the formula:deg = (360 / 2π) * radorrad = (deg / 360) * 2π. Or by usingmath.rad( )andmath.deg( )
Rotation Matrix
A Rotation Matrix is a 3x3 Matrix used to manipulate Position Vector3 values with [Trigonometric Functions] to represent Rotation changes.
There are three basic Matrices used to rotate a Vector3 value around a specified axis (Take θ as the angle in with the axis will be rotated)
X Matrix
1 0 0 0 cos(θ) -sin(θ) 0 sin(θ) cos(θ) Y Matrix
cos(θ) 0 sin(θ) 0 1 0 -sin(θ) 0 cos(θ) Z Matrix
cos(θ) -sin(θ) 0 sin(θ) cos(θ) 0 0 0 1
How to Apply Matrices?
To apply Matrices to Vector3 values, we need to transform it into a 1x3 Matrix.
Vector3 X Y Z With this new Matrix, we Multiply it by the Rotation Matrix in the following way.
(Taking the X Rotation Matrix as an example)
Vector3 X Y Z * * * X = 1 + 0 + 0 Y = 0 + cos(θ) + -sin(θ) Z = 0 + sin(θ) + cos(θ) Let’s break it down by grouping the multiplication results.
X = X Y = cos(θ) * Y + -sin(θ) * Z Z = sin(θ) * Y + cos(θ) * Z Now lets take the following Vector3
(1, 2, 3)to represent X, Y, and Z, replace these values and multiply them, then we have:
X = 1 Y = cos(θ) * 2 - sin(θ) * 3 Z = -sin(θ) * 2 + cos(θ) * 3 There we have it! This also aplies to the other Rotation Matrices.
Y
X = cos(θ) * X + sin(θ) * Z Y = Y Z = -sin(θ) * X + cos(θ) * Z Z
X = cos(θ) * X - sin(θ) * Y Y = sin(θ) * X cos(θ) * Y Z = Z
Remember that these values are Positional values, they DO NOT affect rotation, but instead, represent rotation around
(0, 0, 0).
This videos show a point at (0, 3, 0) being multiplied by the X Rotation Matrix
To make these changes represent the rotation, we need to apply these matrices to all of the vertices of an object.
This video demonstrates a cube being multiplied by the X and Y Rotation Matrices
Code being used
local n = 0 local function Rotate (XYZ, Initial, theta) local Rotated = Vector3.zero local theta = math.rad(theta) local tCos = math.cos(theta) local tSin = math.sin(theta) local Matrix = { X = function () Rotated = Vector3.new( Initial.X, Initial.Y * tCos - Initial.Z * tSin, Initial.Y * tSin + Initial.Z * tCos) end, Y = function () Rotated = Vector3.new( Initial.X * tCos + Initial.Z * tSin, Initial.Y, -Initial.X * tSin + Initial.Z * tCos) end, Z = function () Rotated = Vector3.new( Initial.X * tCos - Initial.Y * tSin, Initial.X * tSin + Initial.Y * tCos, Initial.Z) end, } Matrix[XYZ]() return Rotated end local vertexes = {} for _, i in workspace.Cube:GetChildren() do vertexes[i] = i.PrimaryPart.Position end while true do n += 1 for vertex, position in vertexes do vertex:PivotTo(CFrame.new(0,0,0) * CFrame.new(Rotate("X", CFrame.new(Rotate("Y", position, n)), n))) print(vertex) end task.wait(0.05) end
Credits: Wikipedia
Roll, Pitch and Yaw
Roll, Pitch and Yaw are Directions in which an object rotates around the X, Y and Z axis respectively.
The following Images display the CFrame’s axis ([Right, Up and LookVector] directions), and the Roll Pitch and Yaw Rotations.
(Red Block with no rotation for reference)
Roll rotates the object towards the Z axis Direction, taking the top face as reference.
Pitch rotates the object towards the X axis Direction, taking the face pointing at the Z axis as reference.
Yaw rotates the object towards the Y axis Direction, taking the face pointing at the X axis as reference.
Right, Up and Look Vectors
Right Up and Look Vectors are Vector3 values used by CFrames to represent it’s X, Y, and Z direction axis (respectivly) in global axis X, Y and Z. What does it mean?
The following red cube was rotated by 45º around the X axis. It’s Components (Right, Up and LookVector) are
(1, 0, 0),(0, 0.707, -0.707),(0, 0.707, 0.707). Each one of these values represent the global directions for each of the cube’s Axis (Think of this as the Right, Up and Front directions from the cube’s perspective).
So, if we get the position at the Vector(0, 10, 0)from the red cube (using CFrames), it’s global position will be calculated using the CFrame’s Components in the following way:
Positon.X = (Vector.X * Right.X) + (Vector.X * Right..Y) + (Vector.X * Right..Z)
Position.Y = (Vector.Y * Up.X) + (Vector.Y * Up.Y) + (Vector.Y * Up..Z)
Position.Z = (Vector.Z * Look..X) + (Vector.Z * Look.Y) + (Vector.Z * Look.Z)
Think of the Right, Up and Look Vectors as wheights that are responsible for manipulating the Vector’s X, Y and Z respectively (Right is responsible for X, Up for Y and Look to Z), dictating the direction in which each of them will be applied.
For example, since the Right Vector is
(1, 0, 0), if we offset and object by(10, 0, 0), the 10 would be distributed entirely into X as(X = 10 * 1, Y = 10 * 0, Z = 10 * 0), since Right Vector’s X = 1 and Y, Z = 0.Now for a Vector
(0, 10, 0), since Up Vector(0, 0.707, -0.707)is responsible for the Y, the 10 would be distributed as(X = 10 * 0, Y = 10 * 0.707, Z = 10 * -0.707), resulting in(0, 7.07, -7.07), representing(0, 10, 0)from the cube’s perspective.(Global axis can be seen with the View Selector (Cube at the top right of the screen))
Now why does the values turn to 0.707?
This happens because these components use [Rotation Matrices], which uses [Trigonometric Functions] to represent it’s rotation.
To understand it better, please read those concepts! ;]
Trigonometric Functions and Euler Angles Coming Soon.
CFrame Fundamentals
What’s a CFrame?
CFrame is short for Coordinates Frame, a value that stores data about position and rotation, used to manipulate objects in 3D space.
An Intance’s CFrame and Position work similary, but are different.
The Position value uses a Vector3 value to determine the… well.. position of the object in 3D space (mindblowing, i know!!
). It does not store rotation data.
The Orientation value is responsible to store that part.
Both the Position and Orientation values exist inside the intance’s CFrame
The CFrame value on the other hand, stores both Position and Orientation in… yeah i’ll stop saying in 3D space from now on.
The CFrame’s Position and Orientation values can be read, but cannot be individualy changed.
(e.g. you can read the position usingCFrame.Position, but usingCFrame.Position = Vector3.new(0, 1, 2)will throw an error).To Change a CFrame you need to create a new one and replace the original, or add values to it, but things can start to get confusing thanks to the CFrame’s Rotation!
For more information about this go check the “CFrame Arithmetics” session!
CFrame Rotation
A CFrame is composed by a total of 12 components, which compose 4 Vector3 values:
Position Vector, [Right Vector, Up Vector and Look Vector].The [Right, Up and Look Vectors] represent the Rotation and the X, Y and Z directions respectivly in the Instance’s perspective. This means that an instance’s X, Y and Z directions change according with it’s rotation, and every operation i’ll take these directions as the X, Y and Z directions.
This is incredibly useful, since it can be used to offset instances from eachother!
In the following image, for example, the Red Block is rotated by CFrame.Angles(45, 45, 0) (given in radians).
The Blue Block’s CFrame is set toRedBlock.CFrame * CFrame.new(0, 4, 0)(4 studs above the Red Block).
A CFrame’s can be changed using certain constructors that alter the [Right, Up and Look Vectors].
These Vectors are set to(1, 0, 0),(0, 1, 0)and(0, 0, 1)by default, representing the default directions of X, Y and Z respectively. Constructors Change these values by using [Rotation Matrices].
Extra Knowladge!
The Rotation is made by using [Rotation Matrices], and since it uses [Trigonometric Functions] to manipulate the Vectors, the sum of the squares of each Vector will always be equal to one.
For example, let’s rotate the cube by 45º in the Y axis:
- The Right Vector will be
(0.707, 0, 0.707)- The Up Vector will stay the same
(0, 1, 0)- The Look Vector will be
(-0.707, 0, 0.707)If we take the Right Vector, and add it’s squares together
0.707² + 0.707²The result will be one.
0.707² = 0.5
0.5 + 0.5 = 1Pretty neat huh?! I love maths ;]
For more information about
- How to apply the [Rotation Matrices].
- What does the [Right, Up and Look Vectors] values mean.
Please check the Concept Library!
Now that we know how CFrames work, we can explore how they behave!
CFrame Arithmetics
Just like any other value type, CFrames can also be manipulated trough arithmetic operations like addition, subtraction, multiplication and division but there are some rules to be followed.
Addition and Subtraction
A CFrame can only have a Vector3 value added or subtracted to it. Trying to add or subtract Numbers or other CFrames will throw an error.
Adding a Vector3 value to a CFrame will not change it’s Rotation, and the Position value will be added according to the World Axis, ignoring the CFrame Rotation. (Read CFrame Rotation at CFrame Fundamentals to understand what this means)
Example
In the following image, the Red Block is positioned at
(0, 0, 0,)and rotated by CFrame.Angles(45, 45, 0) (given in [Radians])
The result of the operationRedBlock.CFrame + Vector3.new(2, 5, -3)will be a CFrame Positioned at(2, 5, -3)with the same Rotation as the Red Block’s CFrame.
(The Axis Displayed are the Red Block’s Axis, But the Blue Block is Positioned in the World Axis)
Multiplication and Division
A CFrame can be multiplied by another CFrame or Vector3. Trying to multiply it by a Number will throw an error.
(e.g. the result of the operationCFrame.new(10, 5, 4) * 2will not work. To do this you should useCFrame.new(Vector3.new(10, 5, 4) * 2)).
We use Multiplication to Rotate CFrames, which is the most useful part about them!
To Rotate a CFrame we Multiply thier rotation components by a [Rotation Matrix]. Those are created by using CFrame’s Constructors like CFrame.Angles(X, Y, Z). (We’ll talk about them in the following session ;])*.
- If a CFrame with no Rotation is multiplied by another CFrame with no Rotation, their values will just be added.
(e.g.CFrame.new(1, 2, 3) * CFrame.new(2, 3, 4)* will be a CFrame Positioned at(3, 5, 7)).
- If a CFrame with no Rotation is multiplyed by a Rotated CFrame, their Position values get added and the CFrame is Rotated.
(e.g.CFrame.new(1, 2, 3) * CFrame.new(2, 3, 4) * CFrame.Angles(math.rad(45), math.rad(90), math.rad(0))will be a CFrame Positioned at(3, 5, 7)with the [Roll, Pitch, and Yaw](45º, 90º, 0º).
Until now it was simple, just like good’ol Vector3 operations. But Smart things happen when you multiply a Rotated CFrame!!
Since a Rotated CFrame has altered [Right, Up and Look Vectors], Every Addition to it’s position is made in these new X Y and Z Directions.
If a CFrame is multiplied by a Vector3, a new Vector3 is returned, representing the CFrame’s Position with the Vector3 value added to it’s Rotated Axis. In this Process, the Rotation is lost.
*(e.g. The Red Block is Positioned at(0, 0, 0)and Rotated byCFrame.Angles(math.rad(45), math.rad(45), math.rad(0)). The Blue Block’s CFrame will be set toCFrame.new(RedBlock.CFrame * Vector3.new(0, 5, 0)).
If a Rotated CFrame is multiplied by another CFrame, Rotated or not, it returns a new CFrame, offset by the 2º CFrame’s Position Rotated by the 1º CFrame’s Components, and Rotated by the 2º CFrame Rotation taking the 1º CFrame’s Axis as a basis.
(e.g. The following image displays the RedBlock positioned at(0, 0, 0)and Rotated byCFrame.Angles(math.rad(45), math.rad(45), math.rad(0)). The Blue Block's CFrame is equal toRedBlock.CFrame * CFrame.new(2, 5, 0)`).
(e.g. 2 The following image displays the RedBlock positioned at
(0, 0, 0)and Rotated byCFrame.Angles(math.rad(45), math.rad(45), math.rad(0)). The Blue Block's CFrame is equal toRedBlock.CFrame * CFrame.new(2, 5, 0) * CFrame.Angles(math.rad(45), math.rad(0), math.rad(45))`).
A CFrame cannot be Powered, but can be Multiplied by itself manually.
A CFrame cannot be Divided!
*Credits: @TopBagon*
CFrame Functions / Constructors
Here well cover about all of the CFrame’s Functions / Constructors (Or i I think that’s how we call them…)
These are use to create and manipulate CFrames in many ways!
CFrame.new( )
CFrame.new is used to create a new CFrame from a group of values. It can use the following formats:
CFrame.new(Pos: Vector3)
This format creates a CFrame with the position of the Vector3 value and no rotation.
CFrame.new(Pos: Vector3, LookAt: Vector3)
This format takes the Position of the first parameter and creates a rotation value that points the instance’s front face towards the LookAt Vector3.
CFrame.new(X: Number, Y: Number, Z: Number)
This works exaclty like the first format, but here a new Vector3 value is created with the X Y and Z values with no rotation.
CFrame.new(X: Number, Y: Number, Z: Number, qX: Number, qY: Number, qZ: Number, qw: Number)
Here this start to get intressing!
This format creates the Position’s Vector with the X Y and Z values just like the last one, but it uses [Quaternions] to represent the Rotation
What are Quaternions
With Euler angles we use values to descrive rotation around 3 axis, X, Y and Z.
Quaternions represent rotations in a different way.
Insted of describing in which axis to turn, a quaternion points to a direction (normally called the W axis) and rotate around that axis.
How to use Quaternions?
¯_(ツ)_/¯ Coming… Some Time…
Rotation Constructors
The following constructos use [Euler Angles] to return a Rotated CFrame with it’s Position value at
(0, 0, 0), that can be used to manipulate a CFrame’s Orientation.
All of them work in the same way, using [Radians] to effectuate rotations trough a [Rotation Matrix] , but in Different Orders, changing the final result.Read CFrame Rotation at the CFrame Fundamentals session for more information on how this rotation happens
All of the following constructors take:
X as [Roll]
Y as [Pitch]
Z as [Yaw]Note that all of the parameters can be set to negative for the opposite effect!
CFrame.Angles(X, Y, Z)
This Constructor creates a CFrame Rotated by the parameters X, Y, Z in this exact order.
CFrame.fromOrientation(X, Y, Z)
This Constructor creates a CFrame Rotated by the parameters Y, X, Z in this exact order.
CFrame.fromEulerAngles Constructors
CFrame.fromEulerAngles(X, Y, Z, Order: Enum.RotationOrder)
This Constructor creates a CFrame Rotated by the parameters X, Y, Z, but this one is special because you can chosse in which order the axis will be rotated by using the
Orderparameter, that is set as XYZ by Default.
(e.g. using the orderEnum.RotationOrder.ZXY, will return a CFrame Rotated by Z, Y and X respectivly)
CFrame.fromEulerAnglesXYZ(X, Y, Z)
This Constructor creates a CFrame Rotated by the parameters X, Y, Z in this exact order.
CFrame.fromEulerAnglesYXZ(X, Y, Z)
This Constructor creates a CFrame Rotated by the parameters Y, X, Z in this exact order.
CFrame.fromAxisAngles(Vector3, r)
This Constructor return a CFrame Rotated by the parameter r (given in [radians]) around the given Vector3 Axis.
The Vector3 value is used as a Unit / Normalized value, since it just need to represent a direction.
In the following videos, W, represented by the color pink, will represent the given Vector3 value.
- In this video, the given axis (Vector3) is equal to
(0, 1, 0), same as the Y Vector.
- in the following video, the given axis is equal to
(1, 1, 1). The camera starts at the direction(0, 0, 1), then moves to the direction(1, 1, 1).
Credits: @MaddyRing.
Cool Uses
Here in this section we’ll talk about cool things you can make using CFrames!
Outlines
When messing with a CFrame’s Right, Up and Look Vectors, i found out that by setting their values to negative, it creates a cool Front Face Culling effect!
(Video for better demonstration)
By cloning a part, making it a little bigger, and making it’s material Neon, we can create an outline of any color we want!
But it gets wierd in some cases. ;[
By flipping these axis, you actualy flip the whole part too, making it mirrored in every axis.
Take this Wedge Corner as an example:
Flipping it’s axis will lead to this:
To make this outline work, it’s needed to rotate this specific part with
CFrame.fromAxisAngle(Vector3.new(1, 0, 1), math.rad(180))to make it match the part’s position and orientation. Then we can scale it up to make the outline. But there’s a problem. The outline doesn’t fit correctly, leaving a side with no outline.Forgot to take a print sry ;[
To fix this we need to move around the outline to make it fit correctly
That’s a lot of work! And the worst part: It doesn’t even work if the part is not simetrical, because it is mirrored!!
It also does not work with models, Because scaling them will dislocate the outline.
(Sword model made by my friend Niko)
To make it work you’ll need to scale each individual part.
(I’ll be working on a function to make this easier ;])
I don’t know any way to make it work with meshes.
In some cases, it just stops working, and once you update the Part’s CFrame, the Outline one will become normal again, so you’ll need to multiply it’s CFrame by
CFrame.new(0, 0, 0, -1, 0, 0, 0 -1, 0, 0, 0, -1)every time it moves.
This problem can be solved by group both into a Model and only pivoting the model usingModel:PivotTo( )
*Edit: This behaviour stopped happening, but i'll keep it here in case it happens again*
Here’s a simple module function that creates an outline for the given BasePart
Code
local Outlines = {}
local magicalCFrame = CFrame.new(0,0,0,-1,0,0,0,-1,0,0,0,-1) --If Roblox fix this i'm DEAD
function Outlines.CreateOutline(part: Part, size: number, color: Color3?, material: Enum.Material?)
local outline = Instance.new("Part")
outline.Parent = part
outline.Size = part.Size + Vector3.new(size, size, size)
outline.Color = color or part.Color
outline.Material = material or Enum.Material.Neon
outline.CFrame = part.CFrame * magicalCFrame
outline.Shape = part.Shape
outline.Name = "Outline"
local weld = Instance.new("WeldConstraint")
weld.Part0 = part
weld.Part1 = outline
weld.Parent = outline
return outline
end
return Outlines
Please Note that this topic is a WIP, and will slowly expand until every aspect about CFrames is covered here!
Also, if you note wrong information or any misspealing please alert me! (My English isn’t 100% but im working on it ;] ).
Credits
- xXSanrioSlayer99’s CFrame Guide For sharing CFrame Basics !
- @MaddyRing For sharing cool info about Rotation, Radians and constructors! (fromEulerAngles contructors)
- @TopBagon For correcting wrong information about multiplication between CFrames and Vector3s!
- @HeroicPolonaiste For suggesting new Constructor covering! (CFrame.FromAxisAngles)
- Wikipedia:





















