[CFrame] Figuring out how to rotate from another parts Z-Axis

  1. What do you want to achieve?

I’d like to figure out how to rotate the camera around a part’s zAxis, relative to the part

  1. What is the issue?

Well, math is hard. Here are a couple of images to try and represent the problem I’m having. Lets say the Arrow is the part, and the red circle is the part’s Axis on its relative z-plane, and we want to rotate by 90 degrees around this axis. We can assume that when the camera rotates it is always orbiting the part - no need to worry about position maths, just the angles here.

Lets say the camera is directly behind the part. This would be simple to figure out - just rotate the camera 90 degrees on the zAxis.

Now, lets say the Camera is looking at the part from the random angle at the side

Now, this is essentially asking to rotate the camera mostly by the xAxis, and probably a bit on the other axis’s too.

  1. What solutions have you tried so far?

I’ve looked around a bit on the dev forums, and the most I’ve found are the commands CFrame:ToWorldSpace, and CFrame:ToObjectSpace. I figure these are commands that are going to be useful here, but I haven’t really been able to find a good explanation of how they work, let alone figure out if they are what I need, here. I figure this is going to be a solution related to figuring out the right way to combine CFrames.

I could use a pointer in the right direction if anyone has anything to share!

Can you tell us your use case so we can better understand?

You are on the right track that’s how you will find the parts zAxis relative to the part.

However, to do the actual rotation you might want to use CFrame.fromAxisAngle to create the rotations you need as you can specify which axis you want the CFrame to rotate on.

I believe your scenario is similar to my experiences of trying to rotate a limb using the direction of the previous limb as a reference axis, however, if not then you can probably use the following as a guide on how CFrame.fromAxisAngle works and how you can use it for CFrame’s in the future.


Here is an example script is taken from my open-source inverse kinematics module detailing the usage of CFrame.fromAxisAngle and it’s advantages of easily finding an axis to rotate around.

This is what the script does in action:

And here is the diagram I drew of the CFrame.fromAxisAngle Manipulation.

It rotates the limb based on where the previous limb was relative to the previous limb’s CFrame using vector to world space like so below. This is illustrated by the pink arrow going from the pink brick to the black brick.

        local limbVectorRelativeToOriginal = previousLimbCF:VectorToWorldSpace(originalVectorLimb)

The red arrow going from the pink brick to the red brick is the goal, where I want the limb to be which I generated using the FABRIK algorithm.

To achieve the rotation from the pink arrow to the red arrow I will first find the angle rotation needed to be represented by the green theta symbol from the pink arrow to the red arrow.

This is done by this piece of code, using the dot product formula with a clamp in order to avoid floating point errors for some reason.

        local dotProductAngle = limbVectorRelativeToOriginal.Unit:Dot(currentVectorLimb.Unit)
        local safetyClamp = math.clamp(dotProductAngle, -1, 1)
        local limbRotationAngle = math.acos(safetyClamp)

Then in order to define where the rotation will happen, I obtained the blue dotted arrow through the cross product as to rotate around this axis like so:

        local limbRotationAxis = limbVectorRelativeToOriginal:Cross(currentVectorLimb) -- obtain the rotation axis

Once the angle and the axis are found we have found the additional rotation CFrame we need to add on to the initial CFrame in order to apply the rotation.

local addRotationCframe = CFrame.fromAxisAngle(limbRotationAxis,limbRotationAngle)

However, due to the CFrame order of operations and how it’s not commutative especially with how the rotation I got only applied relative to the world and not relative to the motor joint C0 things got complex and I ended up with this for some reason.

        --Obtain the CFrame operations needed to rotate the limb to the goal
        local undoPreviousLimbCF = previousLimbCF:Inverse()*CFrame.new(motorPosition)
        local rotateLimbCF =CFrame.fromAxisAngle(limbRotationAxis,limbRotationAngle)*CFrame.fromMatrix(Vector3.new(),previousLimbCF.RightVector,previousLimbCF.UpVector)
        
        local goalCF = undoPreviousLimbCF*rotateLimbCF

The overall code of the CFrame orientation system for my project:

Overall meat of the code
        --Obtains the CFrame of the part0 limb of the motor6d
        local previousLimbPart = self.Motor6DTable[i].Part0
        local previousLimbCF = previousLimbPart.CFrame

        -- Obtains the CFrame rotation calculation for CFrame.fromAxis
        local limbVectorRelativeToOriginal = previousLimbCF:VectorToWorldSpace(originalVectorLimb)
        local dotProductAngle = limbVectorRelativeToOriginal.Unit:Dot(currentVectorLimb.Unit)
        local safetyClamp = math.clamp(dotProductAngle, -1, 1)
        local limbRotationAngle = math.acos(safetyClamp)
        local limbRotationAxis = limbVectorRelativeToOriginal:Cross(currentVectorLimb) -- obtain the rotation axis


        --Obtain the CFrame operations needed to rotate the limb to the goal
        local undoPreviousLimbCF = previousLimbCF:Inverse()*CFrame.new(motorPosition)
        local rotateLimbCF =CFrame.fromAxisAngle(limbRotationAxis,limbRotationAngle)*CFrame.fromMatrix(Vector3.new(),previousLimbCF.RightVector,previousLimbCF.UpVector)
        
        local goalCF = undoPreviousLimbCF*rotateLimbCF

Hope this helps for obtaining a new useful tool that is CFrame.fromAxisAngle you can use to do CFrame math with hopefully for your goals with the camera.

My personal advice is to use Roblox Studio to the diagrams for you like the part debugging I did in my idea since I can’t draw well.

I’m pretty sure @CJ_Oyer will agree with the usefulness of CFrame.fromAxisAngle as he has used it in his own Inverse Kinematics project.

3 Likes

Yep! The function fromAxisAngle is super helpful for defining euler angles, to be honest I’d recommend it over the typical euler angles cframe functions for most stuff. Since they both work the same on the backend, and fromAxisAngle just is easier to debug / visualize.

Speaking of debug I definitely recommend setting aside the time to make debug tools. In your specific case maybe instead of a camera for testing, start by just moving a part instead of a camera. That way you can see how it moves with a stationary camera.

Also in terms of getting a CF rotated by 90 degrees along a z axis, here’s my best shot. I haven’t tested this so it might not work, but I think it will.

local focusPartCF --set this as the focus part's CF
local focusCFZAxis = focusPartCFrame.LookVector --may need to make negative if facing the wrong way
local rotation = math.rad(90) --convert the 90 degrees to radian, flip 90 to -90 if this goes the wrong way
local finalCFrame =  focusPartCF * CFrame.fromAxisAngle(focusCFZAxis, rotation) --creates the new cf and applies it to the original cf
local offsetCamCF = finalCFrame * CFrame(0,0,-10) --moves the camera 10 units back from the pivot axis, feel free to remove if you want it to be in the same place as the part's axis

Hope this helps! Good luck!

2 Likes

Thanks so much for the detailed responses!! Really great info to have. I think I may well be able to use CFrame.fromAxisAngle, Doing some testing now ^.^

3 Likes