Smooth 3d interface?

Recently I’ve been looking into 3d interfaces that are made with SurfaceGuis, but cant seem to get them moving in the way I want them to, while also making them smooth.

Right now I have this code in each part that the SurfaceGui is contained in:

local UIS = game:GetService('UserInputService')
local RuS = game:GetService("RunService")
local TS = game:GetService('TweenService')

RuS.RenderStepped:Connect(function()
	local delta = UIS:GetMouseDelta()

	local cframe = workspace.CurrentCamera.CFrame * CFrame.new(-7,-3,-5) * CFrame.Angles(0,math.rad(delta.X),0)

	workspace.TiltUI.CFrame = cframe
end)

Which in turn does this:

Obviously this is very jittery and not smooth at all, so I would like to get it as smooth as it can be.

I’ve tried TweenService and lerping the cframe of the parts, but those either resulted in the effect being too extreme, or ruining the illusion altogether. (delayed y axis movement, going too far behind the camera, etc.)

If anyone knows what a good way to solve both these issues or just has any advice, let me know!

1 Like
local UIS = game:GetService('UserInputService')
local RuS = game:GetService("RunService")

local Camera = workspace.CurrentCamera
RuS.RenderStepped:Connect(function(dt)
	local delta = UIS:GetMouseDelta()
	local Rotation = Camera.CFrame - Camera.CFrame.Position
	local NextRotationPoint = Rotation * CFrame.Angles(0,math.rad(delta.X),0)
	local cframe = CFrame.new(Camera.CFrame.Position) * CFrame.new(-7,-3,-5) * Rotation:Lerp(NextRotationPoint, dt)

	workspace.TiltUI.CFrame = cframe
end)

Let me know how this looks.

Edit:

local cframe = CFrame.new(Camera.CFrame.Position) * CFrame.new(-7,-3,-5) * Rotation:Lerp(NextRotationPoint, dt)

Should actually be

local cframe = CFrame.new(Camera.CFrame.Position) * Rotation:Lerp(NextRotationPoint, dt) * CFrame.new(-7,-3,-5)


First off, the effect is not nearly as strong as it needs to be.
And even if you scale up the rotation so the effect is stronger, there’s still no smooth transition between two positions, which might be a result of instantly setting the CFrame instead of lerping or tweening it since thats what I noticed in both scripts I’ve tried so far.

Any idea why?

Oh sorry about that. Ill revise it to include a slight margin of position smoothing. Yes immedialty setting the position did cause that. The solution would be to set the position and have a unit vector that we lerp and then just add that onto the position. This way you’re offsetting the position rather then lerping the position. If we did lerp the position and if we move/rotate to fast, it would actually lerp through the character or lag behind. Hopefully that makes sense.

Sorry for the late reply but I still dont understand what you mean by ‘adding’ the unit vector. Could you give me a rough idea on what it means?

(Ill try some ideas in the meantime)

EDIT: I’ve found out that every time i’ve tried to use unit, the y position of the part ends up being some ridiculously low number

Unit vector represents the direction of the interface. Meaning you are removing distance from the vector. So instead of lerping the entire position of the UI, you are lerping the direction of it, then applying the distance to it. This should allow you to get the effect you are looking for.

Unit vector would be this. The position of my part is at (0, 8, 0), we simply take the magnitude/scalar distance of the part and divide it by the vector. You get (0, 1, 0), which is the direction of the part relative to the origin.

local origin = player.Position
local uiPosition = (uiPosition-origin).Unit
-- // This gives me the direction of the uiPosition relative to the player.
-- Lets say this next part is contained within a loop.
local UIDistance = 4 -- Global scope, not the local scope
local LastDirection = Vector3.zero
-- Local scope of the loop
local Rotation = Camera.CFrame - Camera.CFrame.Position
local LerpedDirection = LastDirection:Lerp(Camera.CFrame.LookVector, 0.5)
local PositionCFrame = CFrame.new(LerpedDirection * UIDistance) * Rotation
LastDirection = LerpedDirection
// New position is PositionCFrame