Screen3D - A 3D UI framework that just works

	RunService.RenderStepped:Connect(function(DeltaTime)

		local RootPartAssemblyLinearVelocity = Knit.Player.Character.HumanoidRootPart.AssemblyLinearVelocity

		if RootPartAssemblyLinearVelocity == 0 then
			return
		end

		local RelativeVelocity = Camera.CFrame.Rotation:ToObjectSpace(CFrame.new(RootPartAssemblyLinearVelocity * Sensitivity)).Position
		local LerpAlpha = math.min(DeltaTime * LerpSpeed, 1)

		if RelativeVelocity.Magnitude ~= 0 then
			RelativeVelocity = math.min(MaxVelocity, RelativeVelocity.Magnitude  ) * RelativeVelocity.Unit
		end

		ThreeDStaminaBarGUI.rootOffset = ThreeDStaminaBarGUI.rootOffset:Lerp(CFrame.new(RelativeVelocity), LerpAlpha)

	end)

This is pretty good, anyway to increase performance?

Doesn’t work :pensive:

Supposed to look like:

Ingame (entropy meter completely disappears…)

Code:
image
Honestly I really wanna use this module but right now it just kinda doesn’t work :slightly_frowning_face:

Any help from anyone who knows what might be happening would be appreicated, happy to give any additional info regarding htis :heart:

Noticed a bug ( I think).

The “3D” element disappears if you respawn.

Code:

--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

--//Local Variables
local Camera = workspace.CurrentCamera

--//Modules
local Modules = ReplicatedStorage.Modules

local Screen3D = require(Modules.UI.Components.Screen3D)

local Information = require(ReplicatedStorage.Shared.Information)
local UserData = require(ReplicatedStorage.Shared.UserData)

--//Information
local MovesetInformation = Information.Movesets
local ChihiroInformation = MovesetInformation.Chihiro
local KunishigeInformation = MovesetInformation.Kunishige

local GlobalData = UserData.Global

--//Main 
local Knit = require(ReplicatedStorage.Packages.Knit)

--//UI
local PlayerGui: PlayerGui = Knit.Player.PlayerGui

local HotbarGUI: GuiBase = PlayerGui:WaitForChild("Hotbar")

local HotbarFrame: Frame = HotbarGUI:WaitForChild("Hotbar")
local TipCanvas: CanvasGroup = HotbarFrame:WaitForChild("Tip")

local SkillSlots = HotbarFrame:WaitForChild("SkillSlots")

local SkillSlot1: TextButton = SkillSlots:WaitForChild("1")
local SkillSlot2: TextButton = SkillSlots:WaitForChild("2")
local SkillSlot3: TextButton = SkillSlots:WaitForChild("3")
local SkillSlot4: TextButton = SkillSlots:WaitForChild("4")

local SkillSlotText1: TextLabel = SkillSlot1:WaitForChild("ButtonText")
local SkillSlotText2: TextLabel = SkillSlot2:WaitForChild("ButtonText")
local SkillSlotText3: TextLabel = SkillSlot3:WaitForChild("ButtonText")
local SkillSlotText4: TextLabel = SkillSlot4:WaitForChild("ButtonText")

--//3D UI
local ThreeDHotbarGUI = Screen3D.new(HotbarGUI, 5)

local ThreeDHotbarFrame = ThreeDHotbarGUI:GetComponent3D(HotbarFrame)
local ThreeDTipCanvas = ThreeDHotbarGUI:GetComponent3D(TipCanvas)

local ThreeDSkillSlots = ThreeDHotbarGUI:GetComponent3D(SkillSlots)

local ThreeDSkillSlot1 = ThreeDHotbarGUI:GetComponent3D(SkillSlot1)
local ThreeDSkillSlot2 = ThreeDHotbarGUI:GetComponent3D(SkillSlot2)
local ThreeDSkillSlot3 = ThreeDHotbarGUI:GetComponent3D(SkillSlot3)
local ThreeDSkillSlot4 = ThreeDHotbarGUI:GetComponent3D(SkillSlot4)

local ThreeDSkillSlotText1 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText1)
local ThreeDSkillSlotText2 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText2)
local ThreeDSkillSlotText3 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText3)
local ThreeDSkillSlotText4 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText4)

--//Settings
local LerpSpeed = 2
local Sensitivity = .02

local MaxVelocity : number = 1 --or anything


--//Module
local HotBarController = Knit.CreateController  {
	Name = "HotBarController",
	
	CurrentMoveset = nil,
}

--//Start
function HotBarController:KnitStart()
	
	--//Initial
	self:Create3DHotbar()
	
	Knit.Player.CharacterAdded:Connect(function(Character)
		self:Create3DHotbar()
	end)

end

--//Methods
function HotBarController:Create3DHotbar()
	
	--//Enable
	ThreeDHotbarFrame:Enable()
	ThreeDTipCanvas:Enable()

	ThreeDSkillSlots:Enable()

	ThreeDSkillSlot1:Enable()
	ThreeDSkillSlot2:Enable()
	ThreeDSkillSlot3:Enable()
	ThreeDSkillSlot4:Enable()

	ThreeDSkillSlotText1:Enable()
	ThreeDSkillSlotText2:Enable()
	ThreeDSkillSlotText3:Enable()
	ThreeDSkillSlotText4:Enable()

	--//Inital Offset
	ThreeDHotbarFrame.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDTipCanvas.offset = CFrame.Angles(0,math.rad(10),0) 

	ThreeDSkillSlots.offset = CFrame.Angles(0,math.rad(10),0) 

	ThreeDSkillSlot1.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlot2.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlot3.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlot4.offset = CFrame.Angles(0,math.rad(10),0) 

	ThreeDSkillSlotText1.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlotText2.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlotText3.offset = CFrame.Angles(0,math.rad(10),0) 
	ThreeDSkillSlotText4.offset = CFrame.Angles(0,math.rad(10),0) 
	
	task.spawn(function()
		
		local Connection = RunService.RenderStepped:Connect(function(DeltaTime)

			local RootPartAssemblyLinearVelocity = Knit.Player.Character.HumanoidRootPart.AssemblyLinearVelocity

			if RootPartAssemblyLinearVelocity == 0 then
				return
			end

			local RelativeVelocity = Camera.CFrame.Rotation:ToObjectSpace(CFrame.new(RootPartAssemblyLinearVelocity * Sensitivity)).Position
			local LerpAlpha = math.min(DeltaTime * LerpSpeed, 1)

			if RelativeVelocity.Magnitude ~= 0 then
				RelativeVelocity = math.min(MaxVelocity, RelativeVelocity.Magnitude  ) * RelativeVelocity.Unit
			end

			ThreeDHotbarGUI.rootOffset = ThreeDHotbarGUI.rootOffset:Lerp(CFrame.new(RelativeVelocity), LerpAlpha)

		end)
		
	end)
	
end

	
function HotBarController:SetHotbarEnabled(Boolean: boolean)

	for _,SurfaceGui: SurfaceGui in HotbarGUI:GetDescendants() do

		if SurfaceGui:IsA("SurfaceGui") then
			SurfaceGui.Enabled = Boolean
		end

	end

end

function HotBarController:SetSkillTexts(CharacterName: string)
	
	if CharacterName == "Chihiro" then

		self.CurrentMoveset = "Chihiro"

		SkillSlotText1.Text = ChihiroInformation.Skills.One
		SkillSlotText2.Text = ChihiroInformation.Skills.Two
		SkillSlotText3.Text = ChihiroInformation.Skills.Three
		SkillSlotText4.Text = ChihiroInformation.Skills.Four


	elseif CharacterName == "Kunishige" then

		self.CurrentMoveset = "Kunishige"

		SkillSlotText1.Text = KunishigeInformation.Skills.One
		SkillSlotText2.Text = KunishigeInformation.Skills.Two
		SkillSlotText3.Text = KunishigeInformation.Skills.Three
		SkillSlotText4.Text = KunishigeInformation.Skills.Four

	end
	
end



return HotBarController

Disable the ResetOnSpawn property of your base gui if you dont want the 3d ui to refresh when the player respawns

its an intentional choice i made when designing the ui framework to make sure it acts as closely as possible to its 2d counterpart

1 Like

Ahhh, I sort of just assumed ResetOnSpawn wouldn’t affect it for some reason…

But honestly, great thinking!

Unrelated but,
Do you mind if I credit you in my game for the 3d framework?

1 Like

I have this weird bug concering shiftlock (Specifically SmoothShiftlock) Which offsets the humanoid.cameraoffset value.

Here is the visual bug:

When you turn on shiftlock, it basically offsets too far and the 3d UI is no longer visible.

Here is the code for the 3d UI:

--//Services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

--//Local Variables
local Camera = workspace.CurrentCamera

--//Modules
local Modules = ReplicatedStorage.Modules

local Screen3D = require(Modules.UI.Components.Screen3D)

local Information = require(ReplicatedStorage.Shared.Information)
local UserData = require(ReplicatedStorage.Shared.UserData)

--//Information
local MovesetInformation = Information.Movesets
local ChihiroInformation = MovesetInformation.Chihiro
local KunishigeInformation = MovesetInformation.Kunishige

local GlobalData = UserData.Global

--//Main 
local Knit = require(ReplicatedStorage.Packages.Knit)

--//UI
local PlayerGui: PlayerGui = Knit.Player.PlayerGui

local HotbarGUI: GuiBase = PlayerGui:WaitForChild("Hotbar")

local HotbarFrame: Frame = HotbarGUI:WaitForChild("Hotbar")
local TipCanvas: CanvasGroup = HotbarFrame:WaitForChild("Tip")

local SkillSlots = HotbarFrame:WaitForChild("SkillSlots")

local SkillSlot1: TextButton = SkillSlots:WaitForChild("1")
local SkillSlot2: TextButton = SkillSlots:WaitForChild("2")
local SkillSlot3: TextButton = SkillSlots:WaitForChild("3")
local SkillSlot4: TextButton = SkillSlots:WaitForChild("4")

local SkillSlotText1: TextLabel = SkillSlot1:WaitForChild("ButtonText")
local SkillSlotText2: TextLabel = SkillSlot2:WaitForChild("ButtonText")
local SkillSlotText3: TextLabel = SkillSlot3:WaitForChild("ButtonText")
local SkillSlotText4: TextLabel = SkillSlot4:WaitForChild("ButtonText")

--//3D UI
local ThreeDHotbarGUI = Screen3D.new(HotbarGUI, 5)

local ThreeDHotbarFrame = ThreeDHotbarGUI:GetComponent3D(HotbarFrame)
local ThreeDTipCanvas = ThreeDHotbarGUI:GetComponent3D(TipCanvas)

local ThreeDSkillSlots = ThreeDHotbarGUI:GetComponent3D(SkillSlots)

local ThreeDSkillSlot1 = ThreeDHotbarGUI:GetComponent3D(SkillSlot1)
local ThreeDSkillSlot2 = ThreeDHotbarGUI:GetComponent3D(SkillSlot2)
local ThreeDSkillSlot3 = ThreeDHotbarGUI:GetComponent3D(SkillSlot3)
local ThreeDSkillSlot4 = ThreeDHotbarGUI:GetComponent3D(SkillSlot4)

local ThreeDSkillSlotText1 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText1)
local ThreeDSkillSlotText2 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText2)
local ThreeDSkillSlotText3 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText3)
local ThreeDSkillSlotText4 = ThreeDHotbarGUI:GetComponent3D(SkillSlotText4)

--//Settings
local LerpSpeed = 2
local Sensitivity = .02

local MaxVelocity : number = 1 --or anything


--//Module
local HotBarController = Knit.CreateController  {
	Name = "HotBarController",
	
	CurrentMoveset = nil,
}

--//Start
function HotBarController:KnitStart()
	
	self:Create3DHotbar()

end

--//Methods
function HotBarController:Create3DHotbar()
	
	task.spawn(function()
		
		--//Enable
		ThreeDHotbarFrame:Enable()
		ThreeDTipCanvas:Enable()

		ThreeDSkillSlots:Enable()

		ThreeDSkillSlot1:Enable()
		ThreeDSkillSlot2:Enable()
		ThreeDSkillSlot3:Enable()
		ThreeDSkillSlot4:Enable()

		ThreeDSkillSlotText1:Enable()
		ThreeDSkillSlotText2:Enable()
		ThreeDSkillSlotText3:Enable()
		ThreeDSkillSlotText4:Enable()

		--//Inital Offset
		ThreeDHotbarFrame.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDTipCanvas.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlots.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlot1.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot2.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot3.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlot4.offset = CFrame.Angles(0,math.rad(10),0) 

		ThreeDSkillSlotText1.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText2.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText3.offset = CFrame.Angles(0,math.rad(10),0) 
		ThreeDSkillSlotText4.offset = CFrame.Angles(0,math.rad(10),0) 

		local Connection = RunService.RenderStepped:Connect(function(DeltaTime)

			local RootPartAssemblyLinearVelocity = Knit.Player.Character.HumanoidRootPart.AssemblyLinearVelocity

			if RootPartAssemblyLinearVelocity == 0 then
				return
			end

			local RelativeVelocity = Camera.CFrame.Rotation:ToObjectSpace(CFrame.new(RootPartAssemblyLinearVelocity * Sensitivity)).Position
			local LerpAlpha = math.min(DeltaTime * LerpSpeed, 1)

			if RelativeVelocity.Magnitude ~= 0 then
				RelativeVelocity = math.min(MaxVelocity, RelativeVelocity.Magnitude  ) * RelativeVelocity.Unit
			end

			ThreeDHotbarGUI.rootOffset = ThreeDHotbarGUI.rootOffset:Lerp(CFrame.new(RelativeVelocity), LerpAlpha)

		end)
		
	end)
	
end

	
function HotBarController:SetHotbarEnabled(Boolean: boolean)

	for _,SurfaceGui: SurfaceGui in HotbarGUI:GetDescendants() do

		if SurfaceGui:IsA("SurfaceGui") then
			SurfaceGui.Enabled = Boolean
		end

	end

end

function HotBarController:SetSkillTexts(CharacterName: string)
	
	if CharacterName == "Chihiro" then

		self.CurrentMoveset = "Chihiro"

		SkillSlotText1.Text = ChihiroInformation.Skills.One
		SkillSlotText2.Text = ChihiroInformation.Skills.Two
		SkillSlotText3.Text = ChihiroInformation.Skills.Three
		SkillSlotText4.Text = ChihiroInformation.Skills.Four


	elseif CharacterName == "Kunishige" then

		self.CurrentMoveset = "Kunishige"

		SkillSlotText1.Text = KunishigeInformation.Skills.One
		SkillSlotText2.Text = KunishigeInformation.Skills.Two
		SkillSlotText3.Text = KunishigeInformation.Skills.Three
		SkillSlotText4.Text = KunishigeInformation.Skills.Four

	end
	
end



return HotBarController

Any idea how to fix this?

4 Likes

my guess as to what is happening here is that the shiftlock module’s renderstepped is running after the module3d’s renderstepped so module3d doesn’t notice that the camera gets offset to the right every frame

when i get on pc i’ll update module3d to run on BindOnRenderStep so that it always runs last and detects renderstepped camera changes

1 Like

yea thank you for noticing that. It was really detrimental to me lol

1 Like

Have you been able to implement BindOnRenderStep? I can do it for you if you want.

1 Like


doesnt work for me how do i fix, parent is a screen gui

you have to enable the frames/textlabels inside the screengui, not the screengui itself

1 Like

thats silly. add a :EnableDescendants() function :smiley:

Have you been able to update it yet?
Im in desperate need of a fix so ill probably just do it myself atp.

Agreed. Takes alot of extra space just to do something 1 function should do.

Probably will build it tho

1 Like

Can you upload this to the creator marketplace?

1 Like

Hi, Great module but i am having trouble with it. It seems to be duplicating the UI the I created when I enable the 3D Components.

Is there a way to apply it on guis inside ui list layout?
unsure if i did it right (or theres a specific thing i should do)
Expected :


What I got :

sadly none of the ui modifiers work on it 3d ui yet because idk how to properly implement them :sob:

as usual if someone is smart and/or crazy enough to somehow get all the ui modifiers to work flawlessly with screen3d please feel free to send a pull request

the current workaround is just to set all the positions manually

guess who got ui modifier compatibility working??? expect a new version coming out soon once i iron out all the bugs

5 Likes

Cant wait !! Been using it to replace old 3D UI I did using surfaceguis and positioning the camera manually and it works a lot better