How would I slerp between 2 CFrames

Now obviously the built in api :lerp already slerps the rotation, but I want to slerp the position as well. Google searches are starting to make my head hurt, send help.

1 Like

It LERPS the position. I want it to SLERP the position.

Why would you want to slerp positions? CFrame:lerp automatically slerps the rotations

2 Likes

So that I get a nice spherical arc between two points.

1 Like

it sounds like you should be rotating an angle and then using math.cos/math.sin or cframe angles * offset…I don’t think you should ever slerp position
Also you can’t slerp magnitudes, so either the vectors have to be unit, or you lerp the magnitudes while you slerp

Heres a vector3 slerp function I have:

function md.slerp(q0,q1,t,noflip)--too lazy to rewrite so just took quaternion one; use slerp for directions and lerp for points
	--unclamped slerp between q0 and q1 at time t [0,1]
	--http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/
	--https://en.wikipedia.org/wiki/Slerp
	q0=q0.unit q1=q1.unit--only unit quaternions are valid Rotations; normalize to avoid undefined behavior
	local xx=q0.x
	local xy=q0.y
	local xz=q0.z
	local px=q1.x
	local py=q1.y
	local pz=q1.z
	local dot=xx*px+xy*py+xz*pz
	if not noflip and dot<0 then dot=-dot px=-px py=-py pz=-pz end--flipping will find the shortset path but sometimes it isn't desired such as with Squad because it will abruptly switch quaternions midway
	if dot>1-1e-4 then
		local t0=1-t
		return new(xx*t0+px*t,xy*t0+py*t,xz*t0+pz*t)
	end
	
	local yx=px-dot*xx
	local yy=py-dot*xy
	local yz=pz-dot*xz
	local a=acos(dot)*t
	local c=cos(a)
	local s=sin(a)/sqrt(yx*yx+yy*yy+yz*yz)
	return new(xx*c+yx*s,xy*c+yy*s,xz*c+yz*s)
end

This won’t lerp the magnitudes, it just slerps unit vectors (and makes the vectors unit if they aren’t already), so you will need to add that functionality if you desire it
Check out the two links too if you want to learn about the implementation details

3 Likes

Here’s a CFrame slerping function.

~~Making a camera transition to a new spot? - #5 by buildthomas

Use CFrame:Lerp instead. This slerps the CFrame’s rotation.

Worse CFrame slerp code.

local function slerp(c0, c1, t)

	t = math.clamp(t,0,1)

	-- Lerp position:
	local position = c0.p:Lerp(c1.p, t)
	
	-- Slerp look-vector:
	local omega = math.acos(c0.lookVector:Dot(c1.lookVector))
	local lookVector
	if omega < 0.0001 then
		-- Difference in rotation is negligible:
		lookVector = c0.lookVector
	else
		-- Slerp formula to interpolate uniformly between the two look-vectors:
		lookVector = math.sin((1 - t)*omega)/math.sin(omega)*c0.lookVector + math.sin(t*omega)/math.sin(omega)*c1.lookVector
	end
	
	-- Construct new cframe from these two components:
	return CFrame.new(position, position + lookVector)
	
end
1 Like

That lerps position and slerps lookvector, but it removes your roll too so you are better off using cframe:lerp

1 Like

You’re right, I didn’t notice that. Like you said, CFrame:Lerp (despite its name…) also slerps rotations.

That’s new, I don’t think it used to do that. Might be worth making a doc request to have it explicitly say so on the hub since the name is “Lerp”.

For the path to have a spherical arc, there needs to be somewhere it pivots around. You can’t really decide where the pivot is with only two points.