# 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.

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