Why is CFrame.new(1,1,1) * CFrame.new(2,2,2) equal to CFrame.new(3,3,3)?
A short CFrame question. Can someone explain this?
1 answer
I'm going to back-up and first answer a related question:
Why is Vector3.new(1, 2, 3) + Vector3.new(4, 5, 6) equal to Vector3.new(5, 7, 9)?
What are vectors -- in general
Vector3s represent two kinds of values:
- positions in the world (called absolute coordinates)
- translations between points in the world -- the relationship between two points in space (how far, close, in what direction they are) (called relative coordinates)
In general, the .x and .y and .z of absolute coordinates don't really mean much. How "big" they are just means how far they are from (0, 0, 0) -- and you probably build your games not really caring where (0, 0, 0) is anyway. Their sign gives you an idea of which "direction" they are from the origin, but again, who cares about the origin?
The .x and .y and .z of relative coordinates means everything. "one stud below" is Vector3.new(0, -1, 0) -- you probably have relative coordinates like this all throughout your code.
What do you mean by 'relative coordinate'?
Adding to absolute
Let's say we want to spawn a light 10 studs above a player's head. What does the code for that look like?
local p = Instance.new("Part", workspace)
p.Position = head.Position + Vector3.new(0, 10, 0)
Instance.new("PointLight", p)
When we say "10 studs above", we are describing a position (p.Position) relative to another position (head.Position).
That relative Vector3 is Vector3.new(0, 10, 0).
If we do + , we get another absolute vector.
Adding relative
If you have two relative positions, e.g., 10 steps forward Vector3.new(0, 0, -10) and 10 steps to the right Vector3.new(10, 0, 0), you could take that like this:
person.Position = foo
person.Position = person.Position + Vector3.new(0, 0, -10)
person.Position = person.Position + Vector3.new(10, 0, 0)
This is really just doing
person.Position = foo + Vector3.new(0, 0, -10) + Vector3.new(10, 0, 0)
You can combine the two relative vectors into a single relative vector instead:
motion = Vector3.new(0, 0, -10) + Vector3.new(10, 0, 0) -- equal to Vector3.new(10, 0, -10)
person.Position = foo + motion
Subtracting
Algebra tells us that if p = h + r, then we should be able to do p - h = r.
In fact, we can print
print(p.Position - head.Position) --> 0, 10, 0
In general, you can get the relative displacement between two absolute positions by subtracting them. This is useful for, e.g., getting the distance to a target:
local displacement = zombie.Position - victim.Position
if displacement.magnitude < 10 then
-- the relative difference in position
-- between `victim` and `zombie`
-- is less than 10 in magnitude
-- i.e., they're nearby
end
Vectors
Vectors are in general defined by the behavior of + and - to behave as they do here.
Actually, vectors are defined in terms of addition + and inverse -. When you write a - b, really what that means is a + -b. This is significant in the analogy CFrames.
CFrames
CFrames are similar, with a few wrinkles.
CFrames can be relative or absolute;
part.CFrame is an absolute CFrame; CFrame.new(0, 1, 0) is a relative CFrame describing "up" one stud.
You can "apply" a relative CFrame by using * instead of +:
part.CFrame = part.CFrame * CFrame.new(0, 1, 0)
Just like with Vector3s, you can "combine" two relative CFrames into another relative CFrame, by using *:
part.CFrame = part.CFrame * CFrame.new(10, 0, 0)
part.CFrame = part.CFrame * CFrame.new(0, 0, -10)
-- same thing as
local motion = CFrame.new(10, 0, 0) * CFrame.new(0, 0, -10)
part.CFrame = part.CFrame * motion
Minus CFrames
Because of how CFrames are constructed, CFrame.new(a, b, c) is the same thing as CFrame.new(Vector3.new(a, b, c)) -- we know how Vectors get combined (add the components), so the corresponding Vector3 + happens when you * the CFrames constructed in that way.
Note that CFrames are a bit different; with vectors, u + v is the same as v + u. That's not the case with CFrames; x * y is NOT[^1] the same as y * x (and that's why CFrames don't also use +).
[^1]: In general, they're different, but they can be the same. For CFrame.new(x, y, z)'s, they behave just like vectors -- a * b and b * a will be the same in that case. Try using CFrame.Angles as an example where they're different
However, there isn't a corresponding - for *. In mathematics, we write x^-1, but that's not an acceptable notation in code. CFrames have an :inverse() method which makes the relative CFrame that "undoes" a CFrame. Thus
part.CFrame * blah * blah:inverse()
-- same thing as
part.CFrame
4 comments
Whoa
But I just tried print(a * b) print(b * a), where a and b are both CFrames, and I got the same result each time.
@Perci1 in general it's not true, but for some CFrames (e.g., just translations) it is. Added footnote
Much thanks. This was extremely helpful. I already knew everything you explained at the top. I've been told that part.CFrame * CFrame * CFrame:Inverse() is the same as part.CFrame but never understood why until now. Thank you very much.
This discussion is preserved as it was. New answers, comments, and votes are closed.

2 comments
It has to do with confusing matrix math mumbo jumbo
Just imagine * is a "plus".