Cframe.FromMatrix() question

placing system : Creating A Furniture Placement System

i have been pondering about this for the past week and have yet to find an answer to it.

in Egomooses placing system tutorial he has made a cframe using cframe from matrix,

function Placement:CalcCanvas()
	local canvasSize = self.CanvasPart.Size

	-- want to create CFrame such that cf.lookVector == self.CanvasPart.CFrame.upVector
	-- do this by using object space and build the CFrame
	local back = Vector3.new(0, -1, 0)
	local top = Vector3.new(0, 0, -1)
	local right = Vector3.new(-1, 0, 0)

	-- convert to world space
	local cf = self.CanvasPart.CFrame * CFrame.fromMatrix(-back*canvasSize/2, right, top, back)
	-- use object space vectors to find the width and height
	local size = Vector2.new((canvasSize * right).magnitude, (canvasSize * top).magnitude)

	return cf, size
end

he says that will result in this :

https://gyazo.com/ce9d7915d15fa25e697c9ae5852c6f79
but you can clearly see the x,y,z axis are not in the proper place.

my understanding of it is this:
https://gyazo.com/78fc78a41fc40fdc7c14df17759aa654

can anyone confirm it?

1 Like

No clue about advanced CFrame functions cause I tend not to mess with it.

Are you sure it’s not because

local back = Vector3.new(0, 0, -1)
local top  = Vector3.new(0, -1, 0)

Instead of

local back = Vector3.new(0, -1, 0)
local top  = Vector3.new(0, 0, -1)

Because what I’m looking at is
x, z, y

CFrame page;
CFrame.fromMatrix(Vector3, vX, vY, vZ)

Just throwing crap on the wall because my math sucks.

1 Like

you can replace right top and back with x y and z respectively
hence CFrame.fromMatrix(Vector3pos, vX, vY, vZ)

1 Like

This line, despite all the math that goes into it, does nothing more than rotate the CFrame onto its back so that you get a CFrame that faces up relative to the original CanvasPart CFrame and move it up to the surface. EgoMoose does it in a more complex way, but it’s equivalent to this:

local cf = self.CanvasPart.CFrame * CFrame.Angles(math.rad(-90), math.rad(180), 0) * CFrame.new(0, 0, -canvasSize.Y/2)

The explanation

Let’s take a look at what EgoMoose is doing with his math to see how I arrived at my conclusion.

To start, remember what the different axes mean on a CFrame; the x-axis is the right axis, the y-axis is the up axis, and the z-axis is the back axis.

Notice that EgoMoose defines mathematical constants back, top, and right to aid in his math. Do you notice something strange about them? He sets back to the down direction, top to the forward direction, and right to the left direction. Imagine turning a cube on its back so that its backside points down and turning it so that all these other transformations apply. That’s basically what EgoMoose is doing. This is why I say he’s simply rotating the CFrame.

Now let’s look at how he does it using CFrame.fromMatrix(). Let’s take a look at the CFrame he constructed using the fromMatrix() constructor:

EgoMoose multiplies this CFrame by the original CFrame. Keep in mind that his goal is a CFrame facing directly upwards sitting on the surface of the CanvasPart. Also remember that multiplying two CFrames together positions a CFrame by another CFrame. The CFrame constructed here is created in to be in the original CFrame’s local space. It’s meant to be the offset from the original CFrame to the surface CFrame which is the goal. By multiplying by the original CFrame, you have the surface CFrame in global space.

The first argument is the position; that’s the easiest part. The CanvasPart’s CFrame is in the middle of the part, so to get it on the surface, you simply get the distance to the surface, which the height of the canvasPart divided by 2, since you’re bringing it up (in local space) to the surface. It looks unnecessarily complex because EgoMoose just took advantage of the mathematical constant he created, back, to get the height:

local size = Vector3.new(x, y, z) -- Represents the size of the canvas part
(Vector3.new(0, 1, 0) * size)/2 == Vector3.new(0, y/2, 0) -- Just the offset of the distance required
-- Also remember negative of the back vector is Vector3.new(0, 1, 0)

In reality, -back*canvasSize/2 is just Vector3.new(0, canvasSize.Y/2, 0).

For the other three arguments, EgoMoose plugs in each of the three variables into their corresponding axes to create his rotated CFrame.

Then, multiplying by the original CFrame, cf becomes the surface CFrame in global space, as was shown in the picture.

1 Like

so what he did here is basically this https://gyazo.com/78fc78a41fc40fdc7c14df17759aa654?

but at what point did he manage to rotate the cframe 180 to that of the 3rd figure in that image?
the rest of the part like how he offsets the cframe for it to be the top i understand, but i just dont get how he rotates it back to that 3rd figure

Your diagram is too vague to describe the entire story.

The CFrame is “rotated” in the line I pointed out, when it is multiplied, positioned by the offset CFrame, which not only brings it up to the surface, but switches around the axes such that it is rotated onto its back and facing up relative to the original CFrame. Read my post above for a detailed mathematical analysis.

Especially pay attention to how he assigned the axes when creating back, top, and right and see how EgoMoose constructed a CFrame that was rotated in the way that was equivalent to the way I showed you.

Do you know how to rotate a CFrame by multiplying it by CFrame.Angles()?

CFrame.fromMatrix(-back*canvasSize/2, right, top, back) == CFrame.Angles(math.rad(-90), math.rad(180), 0) * CFrame.new(0, 0, -canvasSize.Y/2)
-- Equivalent!

They both make rotated offset CFrames. Be sure to read my explanation on the exact way he rotated above where the backside points down, the topside points forward, and the right side points left :slight_smile:

It helps to visualize it so try imagining the rotation.

sorry if im being dumb then how did he get this https://gyazo.com/ce9d7915d15fa25e697c9ae5852c6f79

the x is still pointing to the right. even though it should be pointing the other way which is (-1,0,0)?

Clarification: When I use terms such as “right” and “left”, I’m referring to the local space of the original CFrame, not the CFrame of the camera that EgoMoose took the picture at. If EgoMoose flew to the other side of the part before taking the picture, then wouldn’t the x-axis be pointing “left”? :stuck_out_tongue:

The red line, the x-axis, is the x-axis of the surface CFrame (whose axes are visible). It is pointing left relative to the original CanvasPart CFrame, as I explained above when EgoMoose set the offset CFrame’s right axis to the CanvasPart’s “left” axis (it is local to the CanvasPart because it is multiplied by the CanvasPart’s CFrame later to bring the surface CFrame into global space).

my gosh my head hurts,
why cant egomoose just set canvaspart right to cf right when all he wants is canvaspart upvector alredy equals to lookvector

I agree that EgoMoose did jump some unnecessary mathematical acrobatics. That was why I showed you the simpler, more understandable equivalent (provided you’re already familiar with the basics of CFrame math). But look on the bright side; those unnecessarily complicated mathematical acrobatics are something you could learn from :slight_smile:

(about math, if not about practicality)

ok so, i drew a image of my understanding of cframe.frommatrix and labeled it
https://gyazo.com/920ef48e41160f9704a25eda81f59c2b

so
local back = Vector3.new(0, -1, 0)
local top = Vector3.new(0, 0, -1)
local right = Vector3.new(-1, 0, 0)

you can replace the words right,top,back with x,y,z respectively.
and frommatrix takes in (pos,x,y,z)
so this image of egomooses drawn out cframe is wrong
https://gyazo.com/ce9d7915d15fa25e697c9ae5852c6f79

No; it’s perfectly correct. As I said, the CFrame (perspective) of the camera doesn’t matter. I’ve told you all that matters is the CFrame (perspective) of the original CanvasPart. What you drew is how the offset CFrame is created and rotated using CFrame.fromMatrix().