Rotation relative to surface normal

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.

okay, so this is the problem i’m having.
when on a part with a rotation on one axis, all is well. But if on two or more axes rotated it doesn’t work anymore
Animation
i haven’t tested this yet for your code. hold on

I don’t think my code will help, this is more-so what I was trying to clarify when I was asking the question.

Plus I think the primary caveat to trying to do what you are trying is when you add a mesh or abnormal surface like a sphere (not cylinder) it’ll be very weird. My initial thought to completing this is to compare the orientation of the object which the raycast result returned and see the difference in the yAxis so then you can orientate the object by that amount; I haven’t done this myself yet so I don’t know how it’ll look.

That’s no problem. I’m going to have things in place for that. I don’t know how to do you suggestion

That’s alright, I haven’t done it before so I’m running through some tests before I let you know precisely how it could be done (not saying it will be pretty or good).

1 Like

Alright, so this is a bit wonky and it could definitely been done better but hopefully this satisfies what you’ll use it for.

totally not copy pasting some of code I sent here

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

-- // As far as I know, this might not look pretty with mesh parts
-- // Also checking because I think result.Instance could be terrain
-- // I do not apologize for my use of ternaries
if (result.Instance and result.Instance:IsA("BasePart")) then
    local result_cframe = result.Instance.CFrame
    relative_vector = result_cframe.UpVector ~= result.Normal and result_cframe.UpVector or result_cframe.RightVector
end

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 should be the result of that: https://gyazo.com/f11d43db1e5d5fae51d6f219e32291b4.mp4

2 Likes

Where does this variable come from

Oh my, when I wrote this I accidentally deleted the if statement and the local variable to turn it into a ternary; It’s local result_cframe = result.Instance.CFrame

Oh my god. You actually f#@^$ng did it
Okay, it works, but could you please tell me what
result_cframe.UpVector ~= result.Normal and result_cframe.UpVector or result_cframe.RightVector
means? I have never seen a CFrame operated on by boolean operations. how does that work?

OKAY SO Good question, this operation here is a ternary, in short it’s an if-statement but in one line.

This is what that one line is doing

-- This is 
relative_vector = result_cframe.UpVector ~= result.Normal and result_cframe.UpVector or result_cframe.RightVector

-- the same as this
if (result_cframe.UpVector ~= result.Normal) then
    relative_vector = result_cframe.UpVector
else
    relative_vector = result_cframe.RightVector
end

-- and this
relative_vector = if result_cframe.UpVector ~= result.Normal then result_cframe.UpVector else result_cframe.RightVector

They’re pretty neat to learn, but don’t over use them, will make things complicated, that’s why I said “I do not apologize for my use of ternaries”.

I found a problem, one second


Solved it :smile:

			local absUpVector = Vector3.new(math.abs(target.CFrame.UpVector.X), math.abs(target.CFrame.UpVector.Y), math.abs(target.CFrame.UpVector.Z))
			local absNormal = Vector3.new(math.abs(normal.X), math.abs(normal.Y), math.abs(normal.Z))
			if not absUpVector:FuzzyEq(absNormal, 0.001) then
				relative_vector = target.CFrame.UpVector
			else
				relative_vector = target.CFrame.RightVector
			end

BTW here’s the place file, I used my own algorithm to make a box draggable on every type of surface :smiley:
That is not a smile it is A face of Pure Agony
Untitled-Game.rbxl (854.6 KB)

I kind of figured it was going to be related to the normal being equal to the relative up vector, that skipped my mind because with the tool/plugin I was demonstrating with I checked if the normal equals the relative up vector before I got to the mathy stuff of relative object orientation.

if it isn’t too much to ask, what is the plugin you’re making?

Ironic you ask, it’s pretty much exactly what you’re doing but for studio. I’ll eventually merge a few other plugins with it for arbitrary rotation ETC (Similar to blender randomizer)… but the primary idea is so you can quickly place objects (Because I am lazy and don’t like building things all that much so I built this).

https://gyazo.com/6b101125d0993d0641bb71b03919a972.mp4

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.