How to get a CFrame's interpolation value around a fixed point (circular path)

I’m trying to figure out how to get the interpolation value from Point A to Point B with a defined alpha while also following a circular path created from a pivot point.
I can only think of a hacky way, I am curious if anyone has a proper solution.

I currently have my code (example below) lerping the CFrame every RenderStep, creating the actual path if Point B were to move fast enough, but I need a solution to follow the expected path.

game:GetService("RunService").RenderStepped:Connect(function()
    a.CFrame = a.CFrame:Lerp(b.CFrame, 0.1)
end)

lerp goal
This is what it looks like when applied.

Here’s an example of what I’m trying to achieve:

1 Like

You could do something like this:

local radius = 10
local speed = 10
local angleToInterpolateTo = 90

while true do
	local dt = game:GetService("RunService").Heartbeat:Wait() -- Or Renderstep
	local _, Y, _ = workspace.RotationPart.CFrame:ToOrientation()

	if Y < math.rad(angleToInterpolateTo) then
		workspace.RotationPart.CFrame = workspace.Pivot.CFrame * CFrame.Angles(0, (math.rad(speed * dt) + Y) , 0)
		workspace.RotationPart.Position = workspace.Pivot.CFrame:PointToWorldSpace(workspace.RotationPart.CFrame.LookVector * radius)
	else
		break
	end
end

radius Is how much you want it to be away from the pivot. speed Is the interpolation speed, and angleToInterpolateTo is the angle that you want to interpolate to.

EDIT: Also, I’m sure there is a better way to do this, but I’m not that good with CFrame and angle math so I tried my best lol.

1 Like

Sorry, it’s not what I was looking for.
I’m essentially trying to achieve lerping but with a circular path, essentially getting a position with a defined alpha to achieve the effect in the diagram

1 Like

All you need is the vectors. You don’t need CFrame or 3D for this.

local rs: (RunService) = game:GetService("RunService")

local origin_v3: (Vector3) = workspace.origin.Position
local origin: (Vector2) = Vector2.new(origin_v3.X, origin_v3.Z)
local startPoint: (Vector2) = Vector2.new(workspace.s.Position.X, workspace.s.Position.Z) - origin
local endPoint: (Vector2) = Vector2.new(workspace.e.Position.X, workspace.e.Position.Z) - origin
local angleBetween: (number) = math.acos(startPoint.unit:Dot(endPoint.unit))

--[[
* Rotates a Vector2 by theta
]]
local function rotateVector2(v2: (Vector2), theta: (number), alpha: (number)): (Vector2)
	return Vector2.new(
		v2.X * math.cos(theta * alpha) - v2.Y * math.sin(theta * alpha),
		v2.X * math.sin(theta * alpha) + v2.Y * math.cos(theta * alpha)
	)
end

-- Scope variables
local alpha: (number) = 0

while true do
	rs.Heartbeat:Wait()
	local rotatingVector: (Vector2) = rotateVector2(startPoint, -angleBetween, alpha)
	workspace.s.Position = workspace.origin.Position + Vector3.new(rotatingVector.X, 0, rotatingVector.Y)
	alpha += 0.01
	
	if (alpha >= 1) then
		break
	end
end

You can further this using an alpha by supplying the rotateVector2 function with a third argument that is a percentage.

Edit Simplified to use an alpha

1 Like

Does my code not do what you asked for?

1 Like

I appreciate the help, but I’m working with a 3D space.
I essentially want the CFrame value between 2 points in a circular path. Title is a bit misleading, I’ll fix it shortly after this reply goes up.

Just imagine getting the value between 0-1 with an alpha of 0.5 but repeat it a couple of times,

function lerp(a, b, alpha)
    return a + (b - a) * alpha
end

local c
for i = 1, 100 do
    c = lerp(0, 1, 0.5)
    print(c)
end

-- 0.5, 0.75, 0.875, 0.9375, 0.96875, etc.

It is essentially the same logic I use for my camera lerping but it doesn’t follow a circular path which I need.

That doesn’t make any sense. You can’t rotate circularly in a 3D space. There is always a plane between them that is represented by vector u

Between the start and end point exists a 2D plane that will be rotated on.

If this is for a camera track, then you should be using Bezier curves to make spherical movements. Here is an example using a camera track creator plugin I made with Beziers.

Can you give us a better explanation of what you are trying to do?

Sorry, I’m sleep deprived lol. I meant I’m working with CFrames in a 3D environment, I don’t mean 3 rotational axes.

And I’ll go take a look at bezier curves!

Yeah it definitely sounds like that is what you’re aiming for. Beziers make it easier to use 3D space to interpolate in arcs. Shown below.

Crazyman32/sleitnick has a Bezier Curve module script I use to create them.
(1) Bezier Module - Roblox

1 Like

Hopefully this image can clear things up. I’m essentially trying to grab a lerp(?) value using an alpha from the red point to the blue point, just following the curved path.

Edit: Adding on, I essentially want this:

function lerp(pivot, start, end, alpha)
    return -- ?
end
2 Likes

Thank you for the help! I will be looking into this :slight_smile:
I’ve also posted an example above of what I want to achieve if that helps

1 Like

I’m confused how your example is any different from my above solution. There still exists only a 2D plane between those points and my code can just be rotated to fit that plane.

image

There is no “3D” rotation going on in spherical interpolating (called slerping)

On which plane a theta exists between the points that can be rotated in 2D.

image

Which will cause the point to move along the arc of the sphere.

image

1 Like

Yes, which is why I’m looking into your 1st solution right now haha. I don’t mean a 3 axes rotation, I just meant I’m working on a 3D environment and getting the alpha instead of actually moving it. Sorry, brain go boom lol

1 Like

Sorry, I guess I should really be posting your final solution.

You can use :lerp() for this, but you have to apply the principle that all circles have a constant radius. Please see the place file attached to test at your convenience (and for anyone else who wants to slerp a position on a 3D plane).

slerp.rbxl (22.5 KB)

4 Likes