Roblox guide: 3d GUI!

my first guide! yay!
so today im gonna teach about creating 3d GUI for your games, what is 3d GUI and why should i use it you may ask

first this is a 3d GUI:
image

a 3D Gui isnt really that different from a normal GUI, but it does look better, more “natural” in some way and allows for funkier animations

to make it, you will need some knowledge about these topics, atleast if you do it the same way i did:
CFrame manipulation
Loops and IPairs

  1. first things first, lets create: The frame!

the frame is the invisible part which holds it all together, it has to be big as if a UI on the surface GUI we add later go to a area the frame dont cover, it dont show up

first, lets get the player GUI, its as easy as just typing

local plr = game.Players.LocalPlayer
local playerGui = plr.PlayerGui

after that, we create the frame, remember! make it big!
dont forget to make it not query, not collide, not touch, and invisible!

local frame = Instance.new("Part")
frame.Size = Vector3.new(100, 10, 0.5)
frame.CanCollide = false
frame.CanQuery = false
frame.CanTouch = false
frame.CastShadow = false
frame.Massless = true
frame.Transparency = 1
frame.Name = "3d ui frame"
frame.Parent = workspace

ok, now we go to step 2
2. Creating Surface GUI

creating the surface gui is also extremely simple, but some parts might give you headaches
surface Gui dont really like button UIs, among(us) other things

but worry not! it can be simple for now
here is how i did it

local uiPixelPerStuds = 512
local surface = Instance.new("SurfaceGui")
	surface.Adornee = frame --connect it to the frame we just made
	surface.Face = Enum.NormalId.Back --set its side to Back
	surface.PixelsPerStud = uiPixelPerStuds --set the PPS, can be anything but i recomment 512
	surface.ClipsDescendants = false
	surface.AlwaysOnTop = true --make it always visible
	surface.SizingMode = Enum.SurfaceGuiSizingMode.PixelsPerStud
	surface.Parent = playerGui --and finally, make it parented to playerGui

here you go! second to last step made

3.RunServicing
here is the longest step, it requires some math in which im not sure is the most optimal, if it isnt, can someone please correct me?

first, get the camera and its ratios

local camera = workspace.CurrentCamera
	local xRatio = camera.ViewportSize.X/camera.ViewportSize.Y
	local yRatio = camera.ViewportSize.Y/camera.ViewportSize.X

then, using that, create a new Vector3, multiplying position by the ratio
example:

local offset = Vector3.new(
1.8, --horizontal scale
-5, --how far down or up it is
9 --depth
)

local CalculatedOffset = Vector3.new(
offset.X * xRatio,
offset.Y * yRatio,
-offset.Z

now that you have the Position offset, shall we get the rotation offset?

local rotOffset = Vector3.new(0, -20, 0)

local calculatedRot = CFrame.Angles(math.rad(rotOffset.X), math.rad(rotOffset.Y), math.rad(rotOffset.Z))

done!
now for the last part! the cframe manipulating
just get the cameraCframe, multiply it by the posOffset and the rotOffset and insert it into the frame

local newCframe = camera.CFrame * CFrame.new(CalculatedOffset) * calculatedRot
if frame ~= nil then
frame.CFrame = newCframe
end

done! you got a working and set up 3D ui frame, the remaining is up to you! create unique designs and have fun!

61 Likes

Does it have lerping? I think it’d make a great addition so that it feels more “realistic”

1 Like

i mean i believe you can just do

frame.CFrame = frame.CFrame:Lerp(newCFrame, 1/10) -- 1/10 is the alpha factor (the lower it is, the smoother and longer will it be)

(though might be better to make it rigid)

it doesnt work i tried editing it to my case but i get the error

invalid argument #1 (CFrame expected, got Vector3)

please help i cant find any solutions

edit i fixed it

but how do i make it fit all devices???

thats honestly the only thing i dont know, and its the reason i added the

it requires some math in which im not sure is the most optimal, if it isnt, can someone please correct me

part, the ratio calculations should be fine until a certain degree, after that, only equation gods know how to make a more optimal code

btw i fixed it after wanting to eat my desk for 3 hours. it works on like 80 percent of the devices i need it to work on and its pretty simple

local xRatio = camera.ViewportSize.X/camera.ViewportSize.Y
local yRatio = camera.ViewportSize.Y/camera.ViewportSize.X

Frame.Inventory.Position = Frame.Inventory.Position + Vector3.new(-xRatio * 2.75, 0, 0)
Frame.Map.Position = Frame.Map.Position + Vector3.new(xRatio * 2.75, 0, 0)

its not real math that acautlly scales but it looks nice :person_shrugging:

Result

TYfor tutorial i couldn’t find anything else

also rate the gui lol

  • its really really amazing wow
  • its pretty good
  • its alright ig
  • its absolutely disgusting (pls no :cry:)

0 voters

4 Likes

this has alot of errors on my side, its good but i recommended just giving the entire script in one box and checking for errors. Thank you

1 Like

this is amazing :sob: better than everything I ever made

1 Like

Yea😭 they managed to put a minimap on there which I’m just very impressed to be honest.
Probably going to do the same but in a different way.
Debut rays maybe for character hit scan but besides that I’m going to try to get into contact with them for the “working” code because I sadly wasn’t able to get the tutorial parts to work :rage:

1 Like

I dont really have a full, working code right now, but tomorrow if I remember I will send one

thank you the mini map was so annoying it kept breaking. id be happy to help you make the gui work cause when i got it to finally work i was so happy

Can I contact you through discord or Roblox messages? Thank you so much for your time though. I will share some of my secrets in exchange as well lol

1 Like

message me on forum dms

bruh

I tried using this tutorial, uhh yeah the code doesnt works, from stuff like “Math.Rad” and the cool error you get.
image
it would be cool if it worked tho.

Hey could you just drop the file? I know it defeated the purpose of this but I cannot seem to get it to work even after 2 weeks

1 Like

Hey my ui works great but do you know how i could make it work when i change FOV?
this is what happens when i zoom in:

(also rate the ui and gunmodel i made them myself)

  • amazing
  • good
  • meh
  • disgusting

0 voters

I’m pretty sure that what I did is use Camera:ViewportPointToRay() at the top left corner and bottom right, at X studs distance, to get the screen size in studs basically, and then position the parts within the two points. At that point, since you have the screen size in studs, and the bounds, you can position it kind of like normal UI, with some CFrame math

If you want, I can dig up the code tomorrow, the code isn’t very pretty though lol

It also resizes dynamically, depending on the screen size

3 Likes

i forgot about this! im gonna make it right now

ok ok, i fixed it, i did a lot of typos on the script, but its back at its prime, here’s the updated thing:

local plr = game.Players.LocalPlayer
local playerGui = plr.PlayerGui

local frame = Instance.new("Part")
frame.Size = Vector3.new(100, 10, 0.5)
frame.CanCollide = false
frame.CanQuery = false
frame.CanTouch = false
frame.CastShadow = false
frame.Massless = true
frame.Transparency = 1
frame.Name = "3d ui frame"
frame.Parent = workspace

local surface = Instance.new("SurfaceGui")
surface.Adornee = frame --connect it to the frame we just made
surface.Face = Enum.NormalId.Back --set its side to Back
surface.PixelsPerStud = 512 --set the PPS, can be anything but i recomment 512
surface.ClipsDescendants = false
surface.AlwaysOnTop = true --make it always visible
surface.SizingMode = Enum.SurfaceGuiSizingMode.PixelsPerStud
surface.Parent = playerGui --and finally, make it parented to playerGui

game:GetService("RunService").RenderStepped:Connect(function()
	local camera = workspace.CurrentCamera
	local xRatio = camera.ViewportSize.X/camera.ViewportSize.Y
	local yRatio = camera.ViewportSize.Y/camera.ViewportSize.X

	local offset = Vector3.new(
		1.8, --horizontal scale
		-5, --how far down or up it is
		9 --depth
	)

	local CalculatedOffset = Vector3.new(
		offset.X * xRatio,
		offset.Y * yRatio,
		-offset.Z)
	local rotOffset = Vector3.new(0, -20, 0)

	local calculatedRot = CFrame.Angles(math.rad(rotOffset.X), math.rad(rotOffset.Y), math.rad(rotOffset.Z))
	local newCframe = camera.CFrame * CFrame.new(CalculatedOffset) * calculatedRot
	if frame ~= nil then
		frame.CFrame = newCframe
	end
end)

nice man thanks
been waiting for a long time lol