Rotation relative to surface normal

Here’s the gif (as you can see, the top side with the image on it is completely normal. On the bottom side it looks like the part is inverted, and that makes sense, because the normal itself is also inverted. on the other sides it doesn’t work at all, since the normal is parallel to one of the other vectors)
Animation

Oh lol, thanks man btw! I’m really sure though CFrame.fromMatrix works in these situations

I see what is happening. So maybe we gotta check like the normal is Y Vector, Z or X. But I’m not sure how can we do that. Hold on I’ll do some more research rq

1 Like

Okay but I want you to know that we can’t explicitly check for the surfaces! If we were to did that, the method i’m doing right now would completely fall apart on spheres and other shapes that arent boxes. Basically the only lead we have is the normal. I was thinking of making the target CFRAME relative to the normal, but now thinking about it, that wouldn’t work i think.

1 Like

I see, I’m doing more research for this and will get back to you in a moment!

1 Like

Ok, so it seems like we’re going right, but we need to do this maybe -
CFrame.fromMatrix(part.Position, normal.XVector, normal.YVector, normal.ZVector)

I saw some posts which states that a normal is a proper Vector3, so based on that I wrote this code.

That’s the point I got stuck on! CFrame.fromMatrix(part.Position, normal.XVector, normal.YVector, normal.ZVector) is basically exactly like setting the CFrame to CFrame.lookAt(hitPosition, hitPosition + normal). Let me make a gif of how that looks like.

1 Like

As you can see, the rotation is relative to the surface. Except for on axis, which is driving me crazy. And that also makes sense, since the normal is a unit vector. If the normal was a rotation instead of a unit vector one axis would go unused (the roll, imagine the plane was the surface normal). I think that’s the axis that’s not aligned to the part. But I don’t know what that axis is or how to change it
Animation

1 Like

So what I observe is the first code I sent manupulating only the Y vector was correct for top and botton faces. The latest code ruined that too. So we don’t need all the vectors. Now I don’t know how is it suppose to happen and I ain’t even on my pc rn so I could test myself. I’m still doing some research and I’m sorry for not being able to still provide a solution.

1 Like

no problem, could you tell me when you get home?

okay, now the farthest point i got to is this
Animation
basically i figured out how to rotate around that weird axis (but i don’t know where to rotate it to to make it finally relative! )


	local normalCFrame = CFrame.lookAt(hitPosition, hitPosition + normal)
		
	local _rotation: CFrame = rotation
	if relativeRotation then
		local rotationRelativeToTarget: CFrame = CFrame.fromAxisAngle(normal, math.rad(abc)) * normalCFrame
		_rotation = (rotationRelativeToTarget - rotationRelativeToTarget.Position)
	end
local rotation = CFrame.Angles(math.atan2(-normal.Y, normal.X), math.asin(normal.Z), 0)
local translation = CFrame.new(position) -- position is the part's position you want to make it relative to

part.CFrame = translation * rotation

So I ain’t even that good at trigo but I think it should work.

Basically it’s 12:30am here so I can’t open my pc.

1 Like

It didn’t work
But I think i may have found something hold on

1 Like

Isn’t this basically what you asked for? This seems pretty much like what you see in the video. (excluding grid snapping)

I don’t think so because each time you want to place a part on the surface exactly aligned with the part you’re placing it on you have to get real finnicky and exactly get the rotation right

And I think that for my game that’s going to be a big no-no

I think this post has the info. But I think this post has some cases which is only applicable to character like RightVector of the HumanoidRootPart is always perpendicular to SurfaceNormal.

1 Like

Hey, this is almost working! Like i explained earlier, but now on two sides it doesn’t work because then the normal is parallel to the rightvector of the part. Have a look at the code. And the rotation was relative!

	if relativeRotation then
		-- makes it so the RightVector and UpVector run parellel to the surface and LookVector = surface normal
		--local EXTRASPIN = CFrame.fromEulerAnglesXYZ(math.pi/2, 0, 0)
		--local EXTRASPIN = CFrame.fromEulerAnglesXYZ(math.pi/2, 0, 0)
		--_rotation = --getRotationBetween(Vector3.new(0, 1, 0), normal	, Vector3.new(0,0, 1)) * EXTRASPIN
		_rotation = CFrame.fromMatrix(
			Vector3.new(), -- POSITION OF THE OBJECT
			-normal:Cross(target.CFrame.RightVector), -- LOOKVECTOR
			target.CFrame.RightVector, --RIGHTVECTOR
			normal --UPVECTOR
		)
	end
1 Like

So you mean this code almost works but for some sides it’s parallel right?

I think there’s a lot of methods you can do this, so I’m just trying to understand the specific scenario. The method I personally use for getting an object to be aligned upward given the vector normal is:

local result : RaycastResult
local normal : Vector3
local relative_vector = Vector3.yAxis -- This makes it so it's similar to a user's camera

local right_vector = normal:Cross(relative_vector)
local look_vector = right_vector:Cross(normal)

local object_size : Vector3

local cframe = CFrame.fromMatrix(
    result.Position + (normal * object_size.Y * 0.5),
    right_vector,
    normal,
    -look_vector
)

This is what it looks like: https://gyazo.com/8408de856cb7f2e838ce7fcafa38eedc

2 Likes

What does local look_vector = right_vector:Cross(look_vector) mean? Where is the first look_vector coming from?

My bad, I meant to put normal there.