.this is fixed in the latest version of screen3d!!!
this is cause we used renderstepped instead of bindtorenderstep and that had a bunch of weird side effects
edit: nevermind
.this is fixed in the latest version of screen3d!!!
this is cause we used renderstepped instead of bindtorenderstep and that had a bunch of weird side effects
edit: nevermind
The issue is caused inside the pivotAroundPoint
method in Component3D. Even when the rotation from self.offset
is a blank CFrame, it returns incorrect results when it should have returned the original point. All of the frames experience the glitch, but it adds up and becomes visible around 8 frames in.
Continue to consider using BindToRenderstep
though. Iām surprised it doesnāt stutter when you turn your camera without this, but thatās not important right now.
grrr the new version switched to BindToRenderstep!!!
iāll fix the pivotAroundPoint
method eventually
Cool, but would this actually fix the issue? It wouldnāt make sense to me if it did.
update: seems to be a floating point precision issue
Itās more complicated than it seems. There are floating point issues that get scaled dramatically, to the point where thereās shaking caused by minute changes in how the CPU does math on small numbers over time. Using Quaternions may or may not fix the issue, but it may be too imperformant.
Anyways, if this is not possible to fix, itās not a huge deal. I doubt anybody needs that many frames nested for their UI. Iām trying to refine this module and add more features that it missed, like accounting for frame.Visible
.
These are actually used in the VR UI apparently.
Where were you finding that these were supposedly beta features at one point?
Hello, I canāt wait to start using this resource in my games! The module was quite messy though, so I felt the need to improve it first. Iām sharing my improved version here!
CHANGES:
screen:BindToRenderStep
component.ZOffsetBehavior
[0]component.Offset.Position
behavior change [1]You may now choose how the ZOffset is calculated. When set to Ancestory
, it determines the offset based on the hierarchy. When set to Position
, the ZOffset is 0, leaving the UIās 3D position to determine the rendering order.
offset.X
and offset.Y
are scales to the componentās part stud size. offset.Z
is a scale to the display distance. This ensures that the 3D UI looks the same at all distances, making it more intuitive to use.
local time = 0
screen:BindToRenderStep(function(dt)
for i, v in screen.Components do
if i == 1 then continue end
v.Offset = CFrame.new(math.sin(time) / 2, 0, 0)
end
time += dt
end)
The previous ZOffset
calculation was correct, but it didnāt account for the depth of each surfacePart. When one part had a higher offset than another, it would render above it. However, if it was further back, it will render behind it. The ZOffset is in studs, not a ZIndex. These values are now multiplied by a high number to undo this behavior.
Hereās the original example using this version.
local Replicated = game:GetService("ReplicatedStorage")
--\\ Modules
local Screen3D = require(Replicated:WaitForChild("Screen3D"))
--\\ Private Fields
local screen = Screen3D.new(script.Parent,5)
--\\ Connections
for _, component in screen.Components do
component:Enable()
end
screen:BindToRenderStep(function()
local angle = -(math.sin(tick() * 2) * 0.5 + 0.5) * 0.1
for _, component in screen.Components do
component.Offset = CFrame.Angles(angle, angle, angle)
end
end)
The floating-point issue is not fixed here. Donāt nest too many components and you wonāt see it! :3
that is a REALLY cool improved version
it be perfect if it had the 2.0 screen3dās features like support for 2D UI modifiers (this is toggleable on my version since it comes with the tradeoff of the descendant tree looking a little weird) and fov independence for component.Offset.Rotation
, kinda like what you did with the component.Offset.Position
behavior change
May you explain these with a bit more detail? I wouldnāt mind adding anything since I want to use this module for my own game!
Added a RotationBehavior
enum to this module! The videos below show the different behaviors on the button.
for _, component in screen.Components do
if component.Object:IsA("TextButton") then
component.RotationBehavior = Screen3D.RotationBehavior.Screen
end
component:Enable()
end
(edit 4/16/2025): Hereās another version with a small change.
It adds ZOffsetBehavior.ZIndex
to predictably fix layering issues without needing to restructure your hierarchy. Could have sworn I added this before, but that change must have gotten lost when I was trying and failing to do the rotation behaviorā¦! The SurfaceGuiās ZOffset will be the objectās ZIndex. Who knew!
On the original screen3d you can enable UI elements in ācompatibility modeā:
When a 2d element gets turned 3d using :EnableCompatibility(), screen3d creates a new frame in the place of that old 2d element to keep stuff like UIListLayout and UIPadding from completely falling apart
This workflow isnāt intuitive to me. Canāt you just nest the 3D component with a frame yourself? It would be much more predictable this way, and it doesnāt change the UI hierarchy further. You would have to manually code to get AutomaticSize behavior this way, but thatās not a big deal.