Lerping a clamped number resulting in spinning

I’m lerping a value that maxes at 360 degrees, and since i’m lerping it when it’s currently at 360 and needs to reach a number below 180, instead of switching to 0 and continuing from there, it will lerp all the way from 360 down to said number. This can cause the value to snap around instead of rotating smoothly to its destination.

This is my current code, which works fine except for the issue stated above.

local targetCFrame = CFrame.new(CAMERA.CFrame.Position, position)
local newRot = Vector3.new(targetCFrame:ToOrientation()) / math.pi * 180
mouseXAngle = lerp(mouseXAngle, newRot.X, Config.CAMERA_SMOOTH)
mouseYAngle = lerp(mouseYAngle, newRot.Y, Config.CAMERA_SMOOTH)

I’m confused, do you mean that the rotation goes the wrong direction, so the lerp goes a lot faster? A video would help to elaborate what you’re saying.

1 Like

Lets say my current angle is 360, and my target angle is 0. Instead of going 360 > 0, it goes backwards. 360 > 180 > 0 because of gimbal lock.

https://gyazo.com/a28dcd4cf0b54d6755dc43f914269f99

I believe the issue is coming from your usage of CFrame:ToOrientation and handling the rotation as a Vector3 Orientation then, not necessarily from the lerp function.

Yeah its a bit confusing as @WovenBreaker said I would suggest to improve the post with the video next time in the beginning of the post.

On the other hand I have had the same experience with a turret system. The issue is that the value caps as you have said.

Using CFrame:Lerp might fix it because CFrame:Lerp is special and it uses slerp so it moves using the shortest path, ex: y orientation in degrees: - 160 → -180 → +180 → + 160, instead of normal number lerp which goes -160 → 0 – > +160.

1 Like

My main issue is that I don’t start with a CFrame, I start with a number, so i can’t use CFrame:Lerp()

If that is the case then the other solution is to uncap your value.

For my y orientation example instead of the target being +160 degrees of y orientation from -160 degrees the goal target should instead be - 200 degrees.

	self._PreviousGoalCFrameRelativeToBase = CFrame.new()
	self._TargetY = 0 --Initial target goal 0 degrees

--Within loop code:
				local yGoalCFOnly = CFrame.fromOrientation(0, yTarget, 0)
		local _, previosYGoalOnly, _ = self._PreviousGoalCFrameRelativeToBase:ToOrientation()

		local differenceCF = CFrame.fromOrientation(0, previosYGoalOnly, 0):Inverse()*yGoalCFOnly

		local _, addedY, _ = differenceCF:ToOrientation()

		self._TargetY += addedY

		self._PreviousGoalCFrameRelativeToBase = relativeToTurretBase

		--Prevents excess rotation towards goal from current position
		local difference = self._TargetY - newY
		if abs(difference) > TAU then
			self._TargetY -= math.sign(self._TargetY)*TAU
		end

		ySpring.Target = self._TargetY

NVM, feels like an XY problem:

Relooking at your GIF you just need to rotate the camera towards a target position, you can just use CFrame from axis angles for that.

local target = workspace.Rig.Head

local function AngleBetween(vectorA, vectorB)
	return math.acos(math.clamp(vectorA:Dot(vectorB), -1, 1))
end

local camera = workspace.CurrentCamera

while true do
	local dt = task.wait()
	local currentLookVector = camera.CFrame.LookVector
	local targetLookVector = (target.Position-camera.CFrame.Position).Unit
	
	local angleTowardsTarget = AngleBetween(currentLookVector, targetLookVector)
	
	local rotationAngleTowardsTarget = math.min(angleTowardsTarget, dt*1) --Rotate 1 radian per second towards target, or the minimum distance to complete goal (prevent overshoot)
	
	local axis = currentLookVector:Cross(targetLookVector)
	camera.CFrame = CFrame.fromAxisAngle(axis, rotationAngleTowardsTarget)*camera.CFrame
end

I’m not actually changing the cameras CFrame, the cameras CFrame is being updated by a MouseX and MouseY variable, which is what im updating to move the camera to my desired position.

The issue i’m having is with gimbal locks, since my variables are numbers and not CFrames I can’t use CFrame Lerp to get past this.

local targetCFrame = CFrame.new(CAMERA.CFrame.Position, position)
local newRot = Vector3.new(targetCFrame:ToOrientation()) / math.pi * 180
mouseXAngle = lerp(mouseXAngle, newRot.X, Config.CAMERA_SMOOTH)
mouseYAngle = lerp(mouseYAngle, newRot.Y, Config.CAMERA_SMOOTH)