Add Vector3.Slerp

As a Roblox developer, it is currently hard to interpolate between directional vectors. Adding in spherical interpolation would solve this. Sure, we can write our own Lua implementation, but having a built-in function to do this would be great.

Other game engines (e.g. Unity, Unreal, Godot) include this function as part of their Vector3 implementations.

local dir0 = Vector3.xAxis
local dir1 = Vector3.zAxis
local dir2 = dir0:Slerp(dir1, 0.5)
132 Likes

Yes!! This would very useful in many ways.

5 Likes

I think Roblox not only needs Slerp, but it needs to be brought up to parity with the math functions that every other engine is provided.
For every project I make these days, I need to pull in modules to do basic vector and cframe operations that other engines provide with the types themselves.
Things like Vector plane projection and calculating angles, slerp, cframe from to rotation… all that really should be in the engine as is.

15 Likes

You can just use the formula for Slerp (i think that is the one if I remember correctly)

math.sin((1 - t) * angle) / math.sin(angle) * p0 + math.sin(t * angle) / math.sin(angle) * p1

image
Edit: I forgot you need Quaternion

7 Likes

Yeah, not having added this one yet is definitely a miss, thanks for pointing it out.

We’ve been filling out some more math methods recently, FuzzyEq for CFrames was enabled just today which was another annoying thing to implement yourself.

51 Likes

I’d like to just pitch that I like many of the vector methods that Unity has and would be cool to have them here, similar to what @ckdevver was saying!

9 Likes

+1 to both of these, I have often found myself looking at and reimplementing methods available in UE, U3D and Godot

3 Likes

That’s great and all, but I will not be able to remember this. I will remember Vector3:Slerp!

Much needed!

2 Likes

How about an optional disambigution direction? A direction the slerp will pass through if the directions are opposite and collinear?

local dir0 = -Vector3.zAxis
local dir1 = Vector3.zAxis
local disambiguationDir = Vector3.xAxis
local dir2 = dir0:Slerp(dir1, 0.5, disambiguationDir)
print(dir2)
--> 1, 0, 0

Otherwise if no disambiguation vector is given or if the disambiguation vector is colinear with the inputs, should probably return dir0 when t < 1/2 and dir1 otherwise.

5 Likes

I understand what you’re asking for, and internally a Slerp could be used to get the result, but it should definitely not be in the API as Vector3.Slerp() for a number of reasons, which include Slerp not being defined for two arbitrary position vectors, and unit direction vectors not fully defining 3D orientations. There are proper formalisms for 3D rotations that are 3-value vectors for which Slerp makes much more sense, like Euler/Rodrigues rotation vectors / exponential map, where a Vector3 encodes a rotation axis scaled by angle. Roblox also uses Vector3 in some places to store triples of Euler angles, like for Part.Orientation. Developers might try to do PartA.Orientation:Slerp(PartB.Orientation, t) and would not get a sensible result because these Orientations are neither directional vectors nor rotation vectors.

It’s probably best to have a helper function for your case, with a name that clearly indicates what’s going on, like Vector3:InterpolateDirectionAndLength(), or some clever shortening of this name (Dlerp? Derp? :laughing: ). Just not Slerp.

3 Likes

What is your opinion on other engines implementing Vector3.Slerp? It seems like Unity has it, but I couldn’t find UE or Godot references so they might agree with you. Does unity have a better use case?

Unity and Godot both have it, and it both cases it works on any arbitrary vectors, interpolating both direction (angle) and length. If both vectors are the same length, it is a geometric slerp. But when they are different length, the resulting path is an ellipse, so not spherical interpolation any more. I don’t object to the function existing, I just wish they had come up with a new name for it.

1 Like

What if slerp just implements it the usual way with geometric algebra. (This ends up homomorphic to the quaterions)

dir1 * (dir1^-1 * dir2)^t

And you can implement it like so, though this would need a bit of work. (tested and appears to work)

local function slerp(a, b, t)
    local magA = a.magnitude
    local magB = b.magnitude

    -- first interpolate the magnitude

    -- these are the degenerate cases
    if magA == 0 and magB == 0 then
        return Vector3.zero
    elseif magA == 0 then
        if t < 1 then
            return Vector3.zero
        elseif t == 1 then
            return b
        else
            return math.huge*b
        end
    elseif magB == 0 then
        if t < 0 then
            return math.huge*a
        elseif t == 0 then
            return a
        else
            return Vector3.zero
        end
    end

    -- the typical path:
    local magC = magA^(1 - t)*magB^t -- final magnitude

    -- now interpolate direction:

    -- get k*cosine and k*sine components of the angle between a and b
    local co = a:Dot(b)
    local si = a:Cross(b).magnitude

    local unitA = a.unit
    local unitB = b.unit

    -- more degenerate cases
    if co < 0 and si < -1e-16*co then -- this test sees, in a stable way, if they are opposite and abs(tan(angle)) < 1e-16
        -- opposite and colinear
        if t%2 < 1/2 or t%2 >= 3/2 then
            return magC*unitA
        else
            return magC*unitB
        end
    elseif co > 0 and si < 1e-16*co then -- this test sees, in a stable way, if they are in the same direction and abs(tan(angle)) < 1e-16
        -- colinear
        -- so we approximate using a unitized lerp
        return magC*((1 - t)*unitA + t*unitB).unit
    end

    -- the typical path:

    -- compute the angle in a numerically stable way
    local ang = math.atan2(si, co)

    -- don't divide by sine(ang), instead just unitize the result for greater accuracy
    local unitC = (math.sin((1 - t)*ang)*unitA + math.sin(t*ang)*unitB).unit

    return magC*unitC
end
2 Likes

I feel like the math library could also use a lerp method. Unity has this, so why doesn’t Roblox have it?

1 Like

The math library comes from generic Luau. As such it only has very general functions, not more focused game development specific ones.

1 Like

Can you also add the methods for multipling cframes and vector3s?

Vector3(1,4,1) * Vector3(1,3,1) -- Vector3(1,12,1)
2 Likes

You can already multiply Vector3s

image

8 Likes

I don’t think this is a good response, given that it’s incorrect.

It can be agreed upon that the math library is built upon the initial implementation from Lua, but what currently exists in Luau includes several additions which aren’t even present up to Lua 5.4, for example; math.clamp, math.round, math.noise (which can be considered very game development centric), any hyperbolic trigonometric function, and etc.

Interpolation is also not a “game development” centric function either, I’m not sure why this was even said?

Either way - Roblox recently has been more attentive to what could be added to its existing libraries to make development quicker/easier - which is how we’ve gotten all these math library additions in the first place.

A built-in interpolation function (that operates on numbers) I believe is essential and I feel the same about a Slerp method for Vector3 as well: these two together would absolutely fill a gap that developers themselves have had to fill in the past with their own implementations.

2 Likes

You’re correct that this is changing. There have been some targeted additions, and you might see stuff like lerp added. You could even be the one to make an RFC proposing adding it! We are responsive to Luau RFCs from outside the company.

But that doesn’t change it being the explanation for why there is no lerp function (the legacy of the math library being a minimal general library for Lua), vs if we were designing a math library from scratch for Roblox specifically there probably would be.

9 Likes

Ah, my apologies then, it came off to me as if you were answering the original question (posed at the end) and then also asserting it as to why it wouldn’t be considered.

I’ve been watching the Luau RFC repository (and prior to that being made, just the Luau repository) intensively for new features to be aware of and pitch support for, there are several things I could make RFCs for that don’t already exist (and haven’t already been denied) but I’ve been waiting until the new type system is finished and stably released to do so. Will do some research on the guidelines for PRing a RFC and what is expected of you once one has been made (or prior to one being made).

Thanks for the quick responses, I appreciate it.

1 Like