How do I make a vector normal translate into a rotation?

To make it short, I’m trying to rotate something relative to a raycast hit’s surface, however it doesn’t seem to rotate fully, always seeming to stop at a limit that I’ve never set. I want to try and fix it, unfortunately I do not know how. Is there anything I can do about it?

It’s doing this

(For reference, I want this to face completely up)

3 Likes

One possible solution should be to use EgoMooses advanced CFrame trick to rotate the boards current UpVector or whereever it’s “UpVector” is defined towards the surface normal using this function:

local function getRotationBetween(u, v, axis)
    local dot, uxv = u:Dot(v), u:Cross(v)
    if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
    return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end

Then apply this rotation to the current Board’s CFrame or the boards BodyGyro CFrame if you are using BodyGyro to orient the board to the surface.

1 Like

Ah I see, I guess I should ask that in the case that it uses the LookVector instead, would that also work?
(To explain, I got the boards rotations mixed up and ended up having to use LookVector to make it work)

Yep, any axis works, as long as the vector is relative to part’s current Orientation or current Rotation.

Alright, I’ll try it out and see if this solves the problem!

Actually, before I forget I am a bit confused as to what u and v stand for, I think I know what axis is however which is just the DirectionVector correct?

Hmm, here is an example script that uses the rotation between method to rotate a part to orient with how the part is facing downwards. This should be applicable with your hover board as well try it out:

Edit: This is the newer more correct method the key being the CFrame order of operations, plus it’s smoother with lerping.

local wedge = script.Parent

local randomAxis = Vector3.new(1,0,0)

local DOWN = -Vector3.new(0,500,0)

local function getRotationBetween(u, v, axis)
	local dot, uxv = u:Dot(v), u:Cross(v)
	if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
	return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end


while true do
	local dt = wait()

	local rayResult = workspace:Raycast(wedge.Position,-1000*wedge.CFrame.UpVector)
	if rayResult then
		local rotateToFloorCFrame = getRotationBetween(wedge.CFrame.UpVector,rayResult.Normal,randomAxis)
		local goalCF = rotateToFloorCFrame*wedge.CFrame
		wedge.CFrame = wedge.CFrame:Lerp(goalCF,5*dt).Rotation +wedge.CFrame.Position
	end
end
Old one

https://i.imgur.com/EfGPRob.mp4

Just insert it to any part and it’ll start raycasting downwards relative to how the part is facing:

local wedge = script.Parent

local randomAxis = Vector3.new(1,0,0)

local DOWN = -Vector3.new(0,500,0)

local function getRotationBetween(u, v, axis)
	local dot, uxv = u:Dot(v), u:Cross(v)
	if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
	return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end


while true do
	local rayResult = workspace:Raycast(wedge.Position,-1000*wedge.CFrame.UpVector)
	if rayResult then
		local rotateToFloorCFrame = getRotationBetween(wedge.CFrame.UpVector,rayResult.Normal,randomAxis)
		wedge.CFrame *= rotateToFloorCFrame
	end
	wait()
end
3 Likes

It uhh, seems to have made it slightly worse.
image
That’s a new picture mind you, the old one is here…

I guess I should also say that I’m trying to avoid the Y axis for most of this, since it screws with the whole turning stuff.

Here’s the code I’m using for this…

local ray = game.Workspace:Raycast(char.HumanoidRootPart.Position + char.HumanoidRootPart.CFrame.LookVector * 0 ,-char.HumanoidRootPart.CFrame.UpVector * 11,rayparams)
			local ray2 = game.Workspace:Raycast(char.HumanoidRootPart.Position + char.HumanoidRootPart.CFrame.LookVector * 2 ,-char.HumanoidRootPart.CFrame.UpVector * 11,rayparams)
			local actualpushfactor = 0
			local rot7 = 0
			local rot6 = 0
			local x, y, z = 0,0,0
			local x2, y2, z2 = 0,0,0
			local thelook = CFrame.Angles(0,1,0)
			if ray and ray2 then
				local raypos = ray.Position
				first3.Position = ray2.Position
				local boardpos = char.HumanoidRootPart.CFrame.p + Vector3.new(0,-1,0)
				local check = (boardpos - raypos).Magnitude
				local percentage = math.clamp(math.abs(check / pushfactor),0,1)
				if firstray == false then
					firstray = true
					firstrayresult = ray.Normal
				end
				print(math.abs(percentage))
				if check > wantedheight then
					percentage = percentage
				else
					percentage = percentage
				end
				rot7 = ray2.Normal
				rot6 = ray2.Position
				x, y, z = rot7.X , rot7.Y ,rot7.Z
				x2, y2, z2 = rot7.X , rot7.Y ,rot7.Z
				print(x.." | "..y.." | "..z)
				local reduction = pushfactor * percentage
				thelook = CFrame.new(Vector3.new(char.HumanoidRootPart.Position),Vector3.new(char.HumanoidRootPart.Position) - Vector3.new(x,y,z))
				actualpushfactor = pushfactor - reduction
				thelook = getRotationBetween(char.HumanoidRootPart.CFrame.UpVector,ray2.Normal,Vector3.new(1,0,0))
				print(thelook.LookVector.X .." | ".. thelook.LookVector.y .." | ".. thelook.LookVector.z)
			else
				rot7 = firstrayresult
				x, y, z = rot7.X , rot7.Y ,rot7.Z
				thelook = CFrame.new(Vector3.new(char.HumanoidRootPart.Position),Vector3.new(char.HumanoidRootPart.Position) - Vector3.new(x,y,z))
			end
			
			
			if rotation ~= 0 then
				if ray then
					rot.CFrame = CFrame.new(char.HumanoidRootPart.Position) * CFrame.Angles(thelook.UpVector.Z,0,thelook.UpVector.X ) * CFrame.Angles(math.rad(0),math.rad(-rotation + 180),math.rad(0))
				else	
					rot.CFrame = CFrame.new(char.HumanoidRootPart.Position) * CFrame.Angles(thelook.LookVector.Z,0,thelook.LookVector.X) * CFrame.Angles(0,math.rad(-rotation + 180),0)
				end
			end

Sorry for all of the junk-text in it, I gotta clean it up after all of this…

On a bit more editing, I had to just simply make it a WorldVector for the first input (Vector3.new(0,1,0))
So yeah, it works now!

1 Like