Happy Memorial Day to everyone! Always remember to honor those who served in the army to defend their own country.
Anyways, I’ve seen that the news of
CFrame.new(position, lookAt) (only the one with the Look At) being deprecated has not spread very far. Many people still use this version, which works absolutely fine, but you shouldn’t use deprecated constructors in your code, should you?
The new version is
CFrame.fromMatrix() which is a little more complicated than the deprecated version. Plus, the DevHub doesn’t clearly explain it yet. It’s more like an understand-it-yourself situation. As a result, I’ve seen a nasty stew of confusion cooking in places like the #help-and-feedback:scripting-support. But don’t worry, I’m here! I’ll show you the recipe for the tastier stew! For that, I recommend you read through this tutorial if you want to understand the concept yourself and not copy code aimlessly.
You must know a little bit about vectors and the general definition of the cross product. If you don’t know check out these resources:
You may already know that the cross product returns an orthogonal (perpendicular) vector to the two given ones. But, there are two possible vectors that are perpendicular, both pointing in opposite directions. The cross product is not commutative, and therefore, it matters in which order you cross two vectors.
Luckily, something called the [color=#3296fa]Right-Hand Rule[/color] exists. For that, you’ll need your right hand (didn’t expect that did you?).
Basically, you point your [color=#2323ff]index[/color] finger in the direction of the [color=#2323ff]first[/color] vector and point your [color=#e12828]middle[/color] finger in the direction of the [color=#e12828]second[/color] vector. Point your [color=#963c96]thumb[/color] up and it will be the direction of the [color=#963c96]resulting[/color] vector from the cross product (index finger * middle finger).
View the image below for a visual explanation:
[color=#2828ff]a[/color] is the [color=#2828ff]index[/color] finger and [color=#e02626]b[/color] is the [color=#e02626]middle[/color] finger.
Note: The first two vectors don’t necessarily have to be perpendicular themselves to obtain another vector perpendicular to both of them. The angle in between can be acute or obtuse and the cross product would still return an orthogonal vector.
This is the abstract definition of the Right-Hand Rule, but we’ll be using it in action rightaway!
This is the API for this constructor:
Explanation of each component:
Pos: The position of the object, pretty straightforward.
vX: The direction of the right vector of a CFrame.
vY: The direction of the up vector.
vZ: [OPTIONAL] The direction of the forward/look vector.
In Roblox Studio, have the view selector open (which displays the 3 axes).
- Select the right (or left) face of a part, which is in the direction of the X axis.
- We all know that the Y-axis is the up direction in Roblox. But still, select the top (or bottom) face of a part and you’ll see that it’s in the direction of the Y axis.
- Select the front (or back) face of a part, it’s in the direction of the Z axis.
You can remember this as the phrase “right up front” in the order of X, Y, and Z.
Also, make sure you know how these three vectors are related:
If you imagine the look vector pointing in the direction you’re facing, then the right vector is to the right and the up vector is pointing up.
Well, since all faces in traditional rectangular parts’ faces are facing in the direction of vectors that are orthogonal to each other, we only need two vectors really. Roblox automatically takes the first two vectors and crosses them to find the third, so we don’t need to include that.
Now that we know about our new little friend, we can now use it in action! Since you may be used to the old
CFrame.new(pos, lookAt) constructor, we’ll create a function to simulate that.
CFrame.new() Simulator! << oh goodness no, don’t that let that be a thing!
For that, we’ll create a function that will take the position and the direction to face and construct a CFrame using
CFrame.fromMatrix(). And then, we’ll return that!
local function getCFrame(position, lookAt) end
Great, now we have a function going. What do we do first? Well, using
lookAt, we can find the LookVector simply by subtracting the two Vector3s:
local lookVector = (position - lookAt).Unit --points from the position to be at to the position to face
Why make it a unit vector? Well, magnitude really doesn’t matter in this new constructor, we only need the direction component. So, making everything a magnitude of 1 will keep things consistent.
Now, before we start crossing
roads vectors, we need two of them to begin with! Remember how I mentioned that the angle between the original two vectors doesn’t matter? Well, we can put that to action by creating a model vector that points straight up.
local modelUpVector = Vector3.new(0, 1, 0) --again, unit vectors!
We can now start crossing. We have the look vector and we have the model up vector, so next, we need to find the right vector.
Let’s get the order right before crossing. But we need to rotate the forward-up-right vectors slightly:
So, we know that the forward vector is the first to come in the cross product followed by the up vector:
local rightVector = lookVector:Cross(modelUpVector) --[[ Yes, the magnitude of the resulting vector is dependent on the area of the parallelogram of the first two, but again, we only care about the direction, not magnitude! ]]
Now all we need is the real up vector that’s perpendicular to the look vector. The model one we made is not orthogonal to the look vector, but we can cross the look and right vectors to find that out!
Use the right-hand rule:
So, the first vector is the right vector and the second vector is the forward vector.
local upVector = rightVector:Cross(lookVector)
And we’re almost done, just need to return the CFrame!
--remember it's X, Y, Z (since Z is optional we don't need to use the look vector) return CFrame.fromMatrix(position, rightVector, upVector)
Now we can actually use this:
taylor.CFrame = getCFrame(taylor.Position, swift.Position) --turn taylor to face swift!
Here is the entire code (uncommented):
local function getCFrame(position, lookAt) local lookVector = (position - lookAt).Unit local modelUpVector = Vector3.new(0, 1, 0) local rightVector = lookVector:Cross(modelUpVector) local upVector = rightVector:Cross(lookVector) return CFrame.fromMatrix(position, rightVector, upVector) end taylor.CFrame = getCFrame(taylor.Position, swift.Position)
Hopefully, after reading this, there isn’t much confusion going on in the #help-and-feedback:scripting-support category (or anywhere else) on this topic. You should now be able to cook up the tastier stew! But I still want to evaluate myself:
So, roll in them polls!
Rate this tutorial.
After reading this tutorial, how strong is your understanding of this concept?
Did you learn anything new?
Thank you for your reading and for leaving your feedback,
Enjoy your delicious stew!
Also, feel free to check out the later parts of the tutorial: