For finding the world-oriented CFrame from a surface and normal from a raycast, if the surface was facing up and already world-oriented

For finding the world-oriented CFrame from a surface and normal from a raycast, if the surface was facing up and already world-oriented, how do I make its result have a lookvector facing (0,0,-1) instead of (-1,0,0)
Result:


image
on a world-axis oriented baseplate (the slate floor)
Expected:


image
on a non world-axis oriented part (the plastic floor)


What I expect is that on all top-facing surfaces, the world-oriented CFrame from this function

local function GetWorldOrientedSurface(part, normalId)
	local cf = part.CFrame
	local rot = cf - cf.Position
	
	local nObject = Vector3.fromNormalId(normalId)
	local nWorld = rot * nObject
	
	-- get orthogonal vector by utilizing the order of NormalId enums
	-- i.e. Front.Value is 5 -> (5+1)%6 = 0 -> Right.Value
	local xWorld = rot * Vector3.fromNormalId((normalId.Value + 1) % 6)
	
	-- get other orthogonal vector
	local zWorld = nWorld:Cross(xWorld)
	
	-- make them both point "generally down"
	if xWorld.Y > 0 then
		print('gas')
		xWorld = -xWorld
	end
	if zWorld.Y > 0 then
		print('gass')
		zWorld = -zWorld
	end
	
	-- choose the one pointing "more down" one as the z axis for the surface
	if xWorld.Y < zWorld.Y then
		print('gasss')
		zWorld = xWorld
	end
	
	-- redefine x axis based on that
	xWorld = nWorld:Cross(zWorld)
	
	local surfaceRot = CFrame.fromMatrix(Vector3.new(), xWorld, nWorld, zWorld)

	-- get width of part in direction of x and y
	local sizeInWorldSpace = rot * part.Size
	local sizeInSurfaceSpace = surfaceRot:Inverse() * sizeInWorldSpace
	
	-- get position on surface
	local surfaceCFrame = surfaceRot + cf.Position + nWorld * math.abs(sizeInSurfaceSpace.Y) / 2

	return surfaceCFrame, Vector2.new(math.abs(sizeInSurfaceSpace.X), math.abs(sizeInSurfaceSpace.Z))
end

Should return a CFrame that has the lookvector of (0,0,-1), such that it always faces the negative Z direction.


IMPORTANT:
On the plastic platform, that’s what I want for the slate baseplate. The plastic platform is NOT rotated by any degree on its Y axis, and it is only rotated by its X axis by 90 degrees.
If it were rotated by any degree on its Y axis, the rotation of the part that follows my mouse would change as well.
The same goes for the slate baseplate. It’s NOT rotated AT ALL.

@nicemike40 A post was requested for me to make for this problem. Here it is.

Sorry, I’m having trouble understanding this. I don’t think this is quite the same problem that the other post solved.

You want the placing part to always have the same rotation as the plastic baseplate? Why not just do something like this:

local rot = plasticBaseplate.CFrame - plasticBaseplate.CFrame.Position
local placedCFrame = rot + mouse.Hit.Position

You’re asking a few different things, and if you could distill it to a sentence or two it might help. For example, these things seem contradictory:

So you want want the LookVector (of the part you’re placing) to always be facing -Z, or do you want the part you’re placing to follow the rotation of the plastic baseplate?

I don’t want

the LookVector (of the part you’re placing) to always be facing -Z

or

the part you’re placing to follow the rotation of the plastic baseplate?

I want the lookvector of the cframe that is returned by your function to always face -Z, instead of -X, IF and only if the surface of the part is facing the top,
Watch my video. See what I said. The plastic platform is rotated (90,0,0) and sized (50,30,2). The slate baseplate is rotated (0,0,0) and sized (2048,50,2048). Because the top surface of the baseplate is already world oriented, Instead of the problem that you had with your earlier script

it returns a cframe that has an upvector of (0,1,0) and a lookvector of (-1,0,0).
I don’t know what you did to fix the previous problem, but what you did made it have a lookvector of (-1,0,0), but I want it to be (0,0,-1)

Oh. Try replacing

local xWorld = rot * Vector3.fromNormalId((normalId.Value + 1) % 6)

With

local xWorld = rot * Vector3.fromNormalId((normalId.Value - 1) % 6)

Right, I forgot (0,0,1) is what I needed instead of (0,0,-1)

Try

local xWorld = rot * -Vector3.fromNormalId((normalId.Value - 1) % 6)

then

Just be aware that if there’s even a tiny bit of tilt to the surface, the function will ignore this and just align it to face generally upwards like normal.

You can add a tolerance to only do the “flipping vectors and choosing the lower one” thing only if the normal vector is off the vertical by a certain amount.

Edit:

You might also need to change this line:

local zWorld = nWorld:Cross(xWorld)

to

local zWorld = xWorld:Cross(nWorld)