Thumbstick relative to camera?


I’m making custom thumbsticks for mobile users. In this case it’s a thumbstick for aiming attacks and this is how it looks. However, when the camera is rotated the thumbstick’s direction is off. I can’t figure out the proper way to transform the thumbstick’s direction to be relative to the camera.

local position = rootPart.Position
local lookAt = position +, 0, thumbstickVector.Y)
bodyGyro.CFrame =, lookAt)

In the second hyperlink the camera is offseted by a, 16, 16). That means the thumbstick’s direction is off by 45 degrees. So I can fix it like this:

local position = rootPart.Position
local lookAt = position +, 0, thumbstickVector.Y)
bodyGyro.CFrame =, lookAt) * CFrame.Angles(0, math.pi/4, 0)

However, I would like to know how to make it actually relative to the camera and more universal.



I similarly had a situation in which I had to figure out how to solve this problem, and it becomes quite simple, really. Assuming your the Vector3 of your thumbstick is accurate, here’s how to solve this problem:

First, you want to get the lookVector of the camera and ignore its Y value, and then get the unit of that. This is to remove any vertical rotation which might alter the direction of the camera.

Then, you want to solve for the angle between the cameraLookXZ vector and the thumbstick vector in 2d space. This can be done as follows:

Then, you want to convert the angle into a new unit vector.

After doing all of this, I got a function that looks as follows:

local function staticUnitToObjectSpace(staticV3, objectV3)
	-- Remove vertical rotation of vectors
	local objectUnitXZ = (objectV3 *,0,1)).unit
	local staticUnitXZ = (staticV3 *,0,1)).unit
	-- Calculate angle between vectors in 2D space
	local theta = math.atan2(-staticV3.Z, -staticV3.X) - math.atan2(-objectUnitXZ.Z, -objectUnitXZ.X)
	-- Convert angle to new unit vector
	local newVector =, 0, math.cos(theta)).unit
	-- Return new unit vector
	return newVector

You can use this function to get a directional vector with no y rotation. This can be done, for your case, as follows:

local convertedUnit = staticUnitToObjectSpace(, 0, thumbstickY), camera.CFrame.LookVector)

This will effectively give you a vector which will always be in the direction of the joystick. It could also be converted into a directional CFrame value by solving for an upVector and a rightVector which should be relatively simple, and then creating a CFrame by using the 9 values associated with those vectors. You could also (probably) use other toObjectSpace methods available. Additionally, you could definitely simplify this further to your use case, this was just a general method I created.

If you need more help utilizing this in your code, let me know.