Vector3:Slerp(v2,t unclamped)

As a Roblox developer, it is currently annoying (and slow) to slerp vectors
Right now we have to write our own utility functions to do slerp and I think it discourages its use

So far I’ve only used slerp 3 times in my game, but I think I would have found a lot more use cases for it had I an open mind about slerp (2 of these 3 times have been today when I was working on my hover car)

I know we can implement it with axis angles/pythag(?) but I’ve had it implemented and haven’t used it much
Also I think if Roblox made Vector3:slerp() it would be a lot faster than these implementations:

local axisangle=CFrame.fromAxisAngle
local asin=math.asin
function md.slerp(v0,v1,t0)
	local unit 
	if t0==0 then unit=v0.unit
	elseif t0==1 then unit=v1.unit
	elseif v0.unit==v1.unit then unit=v0.unit
	else
		local cross=v0.unit:Cross(v1.unit)
		local t1=asin(cross.magnitude)*t0
		unit=axisangle(cross.unit,t1)*v0.unit
	end
	assert(unit.X==unit.X,'vecs are opposite')
	return unit--*(v0.magnitude*(1-t0)+v1.magnitude*t0)--uncomment to lerp magnitudes
end
local new=Vector3.new
local acos=math.acos
local cos=math.cos
local sin=math.sin
local sqrt=math.sqrt

function md.slerp(q0,q1,t)--too lazy to rewrite so just took quaternion one; use slerp for directions and lerp for points
	--unclamped
	--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 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
3 Likes

An slerp on a 3d value is just lerp unless you assume that it is a direction vector from the origin, which doesn’t make sense to have as assumption for most use cases where you’d want to smoothly interpolate between two 3d values.

You should use CFrame.Lerp, it actually does slerping despite the name implies. (Source: How would I slerp between 2 CFrames)

local cfr1 = CFrame.new(Vector3.new(), v1)
local cfr2 = CFrame.new(Vector3.new(), v2)

local result = cfr1:Lerp(cfr2, t).LookVector

I don’t know where you use this code, but it might be convenient to entirely work with CFrame values and not touching loose direction vectors at all, then you don’t need to do the CFrame instancing. I’ve never personally had a situation where I didn’t already have CFrame values available when I wanted to slerp, at least.

10 Likes