Pitch rotation based on angle and a reference normal

Hello,
I’m trying to calculate the angle offset of two vectors that will create a plane rotated on a pitch-rotation axis.

I’m aware that using the dot product is one way to go about this, but I couldn’t get far after finding my angle, and not knowing how to continue solving to reach my solution.

I did my best to project my problem on this diagram
c381f854-1b38-4569-ab5b-e4b896a5e953
The pitch angle gets calculated (orange theta) using the world up normal (in green), to the mouse hit direction (in red), and should align to the the surface plane (in purple), and returns the new plane normal.

The new rotated normal should be aligned to the part’s surface normal (in purple) and rotated by the theta angle (in orange) on the pitch axis rotation

The function i'm using to calculate the closest normal to the mouse point:
local function GetSurfaceNormal(cf, point, plane)
	local Up	= cf.UpVector
	local Right	= cf.RightVector
	local Look	= cf.LookVector
	
	local Difference	= (point - cf.p)
	local plane			= plane or Difference.Unit
	local upAngle		= math.abs(Up:Dot(plane))
	local rightAngle	= math.abs(Right:Dot(plane))
	local lookAngle		= math.abs(Look:Dot(plane))
	
	local data	= {
		{rightAngle, Right, "X"},
		{upAngle, Up, "Y"},
		{lookAngle, Look, "Z"}
	}
	table.sort(data, function(next, now)
		return next[1] > now[1]
	end)
	
	local direction	= data[1][2]:Dot(Difference) > 0 and 1 or -1
	return direction * data[1][2], direction
end
1 Like

I got close to what i was aiming for, but for certain cases, the rotation isn’t negated when it should be.

local Origin = CFrame.new() -- a part's cframe
local Plane = CFrame.new() -- a rotated plane

		local surfaceNormal, surfaceDirection = GetSurfaceNormal(Origin, Plane.p, PlaneToOrigin.Unit)
		local difference	= Plane:VectorToObjectSpace(surfaceNormal)
		difference			= CFrame.new(Vector3.new(), difference):VectorToObjectSpace(Vector3.new(0,1,0))
		local angle			= math.atan2(difference.Y, -difference.Z) -- math.pi/2
		print(math.deg(angle))
		
		local cutPlane		= CFrame.new(Plane.p, Plane.p + surfaceNormal) * CFrame.Angles(surfaceDirection * (math.pi/2 - angle), 0, 0)

The “GetSurfaceNormal” function can be found right above this post.

I can’t really understand what you’re trying to do? Maybe explain the purpose you intend to use this function for and we can help better.

So, on this image i was able to snapshot one of the current mathematical errors:
The purple part is the reference part.

The yellow part is the “Plane” cframe.

The blue part represents the new calculated plane cframe, which is incorrect as it should’ve aligned with the yellow part’s rotation.


I’m trying to calculate the pitch rotation of the yellow plane, adjusted to the closest surface normal of a part which should be perfectly aligned in the Yaw and Roll axis of that closest surface normal.

1 Like

Im still a bit confused what you are trying to achieve, but if I’m understanding correctly you want a cframe that aligns with a surface given you provide it’s normal?

I’d recommend looking at these two posts as they can help you with that.

They aren’t exact duplicates of your problem, but you should be able to distill the information you need from them.

1 Like