How to find rotation difference between 2 CFrames

Hello!

I’m working on the enemies system for my game and there’s one problem which completely destroyed me. Basically what I want to do is I want to make smooth rotation of enemy when he rotates by 180 degress and goes backwards, and to make this I want to make smooth enemy rotation based on DeltaTime value.

local function SetEnemyCFrame(EnemyObject, DeltaTime, NewCFrame: CFrame)
    --local RotSpeed = DeltaTime * EnemyObject.Speed
    local X, Y, Z = EnemyObject.CFrame:ToObjectSpace(NewCFrame):ToOrientation()
    -- X, Y, Z should be multiplied by RotSpeed, so they rotate smoothly
    -- on all devices and this is based on enemy speed
    print(math.deg(X), math.deg(Y), math.deg(Z))
    EnemyObject.CFrame = CFrame.new(NewCFrame.Position) * CFrame.Angles(X, Y, Z)
end

I found this solution while searching a TON of topics but it still work incorrectly for me. Here’s what’s going on in the actual game: https://youtu.be/ltsb3SOi-qc

CFrame of new enemy position is calculated perfectly (with rotation) and there are no problems with it, but the problem is that rotating difference between current enemy CFrame and new enemy CFrame which I am trying to calculate turns out to be incorrect every 2nd time it calculates. So I cannot make smooth rotation because I cannot calculate difference between 2 CFrames rotations to then multiply it by RotSpeed value.

And yes, I looked through 10 pages on Google, trillion devforum topics, tried to open websites with advanced mathematics, spent a whole day solving this problem and still didn’t understand what is going wrong with the calculation. So I would appreciate any help!

2 Likes

I think you got a weird formula.

Checkout my turret CFrame module to do it and constant speed im pretty busy cant help out much further.

Also CFrame.Angles is not orientation read the documentation.

1 Like

I would try using the dot product between the two CFrame’s LookVectors. Combining that with inverse cosine would give you the angle in radians.

-- replace with your own cframes being used
local angularDifference = math.acos(cframe1.LookVector:Dot(cframe2.LookVector))

Reference if needed:
Dot product - extreme oversimplification: gives a number that indicates how similar two vectors are
Sine/cosine - trigonometry functions, using their inverses can help find angles

Also the turret controller linked in the above post is probably helpful for this situation, I personally have used it for a different purpose before.

2 Likes

I’m really sorry for late response. Thank you for your help, that’s exactly what I was needed and you saved a ton of my time, but I’ve got 1 question.

This is a code snippet of your TurretController module:

local adjustedLerpAlpha
if step and self.ConstantSpeed then
	local angularDistance = VectorUtil.AngleBetween(currentRotation.LookVector,goalRotationCFrame.LookVector)
	local estimatedTime = self.AngularSpeed/angularDistance
	adjustedLerpAlpha = math.min(step*estimatedTime,1)
elseif step then
	adjustedLerpAlpha = step
end

local newRotationCF = currentRotation:lerp(goalRotationCFrame, adjustedLerpAlpha or self.LerpAlpha)

self.JointMotor6D.C0 = CFrame.new(originalC0Position)*newRotationCF

You find estimatedTime by dividing self.AngularSpeed by angularDistance but usually time is distance divided by speed, so why is it necessary to do the opposite in this case? I tried to divide angularDistance by self.AngularSpeed but it didn’t seem like a very good idea.

2 Likes

Good question.

The answer is my variable naming is probably incorrect or doesnt make sense.

The formula can be rearranged like this.

(AngularSpeed / distance)*step

Step*(AngularSpeed / Distance )

It finds the distance traveled in a frame speed * time then divides it by the total travel distance to get lerp alpha as lerp alpha is a fraction of distance.

In the end the units will cancel out the above is distance / distanceToGoal, with my naming convention its time/timeToReachGoal

I didnt really understand this formula before got it off a devforum post.

use beziers for smooth path walking, it’s 5 more points and pretty much best solution for you

So in this case self.AngularSpeed means how much was travelled like speed * time, then it finds alpha using distance (which is self.AngularSpeed) / whole distance (which is angularDistance) and then it calculates new alpha by multiplying it all by step (which is deltaTime)?

So final result is value between 0 and 1 which represents lerping time, right?

It’s a little confusing because of the variables names, but makes sense.

I didn’t know that you can lerp between 2 orientation CFrames and get such behaviour. It’s quite simple but really smart.

1 Like

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