How to make a part of a tool face a particular global direction regardless of local orientation

So, I am attempting to create a flag tool that will maintain a global orientation regardless of the local orientation. Since it is a tool, the flag is connected to the flag pole via a Motor6D which I can rotate. My question is, how can I determine the angle I need to multiply the motor6D by. This is hard because the angle has to be a certain number based on the given wind angle and the current angle of the flag. I am fairly familiar with CFrame stuff, but I’m kind of stumped on this

This is code that I wrote:

local angle = math.rad(workspace:GetAttribute('WindDirection')) 
local currentAngleX, currentAngleY, currentAngleZ = (CFrame.Angles(0, angle, 0):ToObjectSpace(info.Handle.CFrame)):ToOrientation()
info.Motor.C0 = info.Motor.C0:Lerp(info.OriginalC0 * CFrame.Angles(0, 0, currentAngleY), 0.1)

It works, except for the fact that it is offset by a certain weird amount, for example when you look forward it should be 0 degrees but its 18 something degrees, and when you look left it should be 90 degrees but its 108 degrees, etc. I tried doing the dot product of Vector3.new(0,0,-1) against the LookVector of the handle of the flag, but that didn’t give me what I needed.
Video demonstrating the issue:
https://streamable.com/yjrwb0

Any help is appreciated, cheers!

Edit: You can see here, the global orientation of the flag should be facing 0 degrees (forward) but it is offsetted by a small angle to the left (18 ish degrees i talked about earlier)
image

1 Like

Oh yea this is a problem I had when writting some code that involved aligning a parts rotation align to the derivative of a graph. You can think of direction as a result of vector3 operations. More specifically if we wanted to express direction from 2 points - and you will see this a lot when working with guns - you get the “tail” of the directional vector, or where it starts in a sense and subtract that by the head, a point on the vector. So with this knowledge what we could do knowing that both of what we describe, the direction and the tools face (a vector) all we need to do now is align it. There is a few ways to do this, and it really depends on what you want. Do you want them to rotate smoothly? You would have to use this cframe trick for that.

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

If you just want it to be instantaneous we can use this trick too

object.CFrame = CFrame.new((head + tail) / 2, head)

Why are they like this? Honestly I really don’t know how they work on a fundamental level.

1 Like

I tried using the getrotationbetween function, and it has the same issue.
Here is my code:

local windVector = Vector3.new(-math.sin(angle), 0, -math.cos(angle))
local rotationalCFrame = getRotationBetween(windVector, info.Handle.CFrame.LookVector, Vector3.new(0, 0, -1))
local x, y, z = rotationalCFrame:ToOrientation()
info.Motor.C0 = info.Motor.C0:Lerp(info.OriginalC0 * CFrame.Angles(0, 0, y), 0.1)

I also tried doing the same thing of comparing the forward vector with the handle look vector, and it also had the same result. (just the angles were switched).
It’s weird, it was returning the exact same angle as my code.
I am not particularly sure what the second code block you sent me, it looks like you’re constructing a CFrame that’s inbetween 2 vectors and facing the first vector, which isn’t what I am looking for.

I think you want the wind matrix to be in Handle*C0 space, not just Handle space?

Try

:ToObjectSpace(info.Handle.CFrame * info.OriginalC0)

Not 100% certain though, will need to experiment a bit :slight_smile:

1 Like

Didn’t do anything, sadly. It just stayed the same.

For what it’s worth, I tried your code. It worked fine for me.

Test code
local tool = script.Parent
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local head = character:WaitForChild("Head")
local handle = tool.Handle
local flag = tool.Flag
local weld = Instance.new("Motor6D")
local c0 = CFrame.new(0, 1.5, 0) * CFrame.Angles(math.pi/2, 0, 0)
local c1 = CFrame.new(-3, 0, 0)
weld.C0 = c0
weld.C1 = c1
weld.Part0 = handle
weld.Part1 = flag
weld.Parent = handle

game:GetService("RunService").Stepped:Connect(function()
	local angle = math.rad(workspace:GetAttribute('WindDirection')) 
	local currentAngleX, currentAngleY, currentAngleZ = (CFrame.Angles(0, angle, 0):ToObjectSpace(handle.CFrame)):ToOrientation()
	weld.C0 = c0 * CFrame.Angles(0, 0, currentAngleY)
end)

image

Where Flag is a wide flat object that I turn on its side with the weld, to try to match your setup.

Results (white arrow is wind direction):

0 degrees:
image

45 degrees:
image

-135 degrees:
image

Sooo… your logic isn’t too bad at least :slight_smile: . If you tell me the grip position/orientation of your tool, OriginalC0, and C1, I can test your setup more accurately.

I think it’s my animation. When I stopped it the issue fixed, so I’m not sure what it could be. The flag is connected to the arm via another motor6D for animating, but idk how that causes that.

I’m just going to hard code subtract 18 degrees from the y angle, because this is a really dumb issue I don’t have time for. Thanks for your help!

Can you elaborate more on the code. I have a similar system I am trying to complete where the flags on the top of boats match the direction that the “Main Flag” is facing. The main flag is anchored somewhere on the map and the flags on the boat are welded via Motor6d. Your code did not seem to work.

Old post but here’s some code using matrices instead of angular space:

local tf = joint.Part0.CFrame
local dirLocal = (tf - tf.Position):Inverse() * direction
local right = baseC0.UpVector:Cross(dirLocal).Unit
joint.C0 = CFrame.fromMatrix(baseC0.Position, right, BaseC0.UpVector)

It needs:

  • a global Vector3 called Direction (normalized on the x, z axis)
  • the joint’s original C0 saved in a variable called baseC0
  • a joint variable for the motor6D

You may need to add a 90, 180 whatever offset to the final CFrame depending on how the joint is rotated.