3D2D Above a Player's Head

So, I have the following code:

local Head = ply:LookupBone("ValveBiped.Bip01_Head1")
local Pos = Head + Vector(0, 0, 30)
local Ang = ply:EyeAngles()

hook.Add("PostDrawOpaqueRenderables", "3D2DName", function()
	cam.Start3D2D(Pos, Ang, 1)
		draw.DrawText("Hello World!", "Default", 0, 0, Color(0, 0, 0, 255), TEXT_ALIGN_CENTER)

There’s no error when the code is ran.

I’m trying to make “Hello World!” appear in 3D2D-style above the player’s head.

Why is this not working? I mean I figured everything is right, correct? Please help! I’d also like an explanation, as I’m really only doing this to learn about gLua, thanks guys :slight_smile:

I think you need to rotate the angles a little bit so they always face the player - I forgot what to rotate them to though…

[editline]19th March 2016[/editline]

Try playing around with

Angle:RotateAroundAxis until you can actually see the text

Okay, so now I’m getting an error. I changed nothing.

[ERROR] addons/nameaddon/lua/autorun/client/3d2d.lua:1: attempt to index global 'ply' (a nil value)
  1. unknown - addons/nameaddon/lua/autorun/client/3d2d.lua:1

I tried changing “ply” to “LocalPlayer()”, I figured it wouldn’t work and I was right.

[ERROR] addons/nameaddon/lua/autorun/client/3d2d.lua:1: Tried to use a NULL entity!
  1. LookupBone - [C]:-1
   2. unknown - addons/nameaddon/lua/autorun/client/3d2d.lua:1

What the actual fuck?

Set your variables in the hook, LocalPlayer doesn’t exist until after InitPostEntity is called on the client

Now this is just spammed in my console:

[ERROR] addons/nameaddon/lua/autorun/client/3d2d.lua:2: attempt to index global 'ply' (a nil value)
  1. v - addons/nameaddon/lua/autorun/client/3d2d.lua:2
   2. unknown - lua/includes/modules/hook.lua:84

here is my code now:

hook.Add(“PostDrawOpaqueRenderables”, “3D2DName”, function()
local Head = ply:LookupBone(“ValveBiped.Bip01_Head1”)
local Pos = Head + Vector(0, 0, 30)
local Ang = ply:EyeAngles()

cam.Start3D2D(Pos, Ang, 1)
	draw.DrawText("Hello World!", "Default", 0, 0, Color(0, 0, 0, 255), TEXT_ALIGN_CENTER)


Sorry, I’m pretty new to GLua and Lua in general.

“ply” was never defined, either replace with “LocalPlayer()” or declare “ply” as “LocalPlayer()”

local ply = LocalPlayer()

Also, LookupBone returns an index, not a position, what you want to call is:

local Bone = Player:LookupBone( "..." )
local Position, Angles = Player:GetBonePosition( Bone )

The rest seems like it would work.

I thought ply was already defined in client-side scripts? Or is that server-side? I’m confused…

Also, how does the Position, Angles variable work? Is it just two different names for the same variable? Or what?

Other than those questions thanks bro :slight_smile:

Positions are 3D vectors while angles represent rotation in Euler form. They may have the same number of variables, and both use numbers, but they do not function the same way.

I don’t think that’s what he’s asking:

The function GetBonePosition returns two variables and that’s just a way you can get the value of both those variables and use both of them in one line of code.

You can set variables as you’re doing in the example for any function, like this for example:

function SomeFunction()
   return 'three', 'different', 'strings'

local var1, var2, var3 = SomeFunction() -- var1 is 'three', var2 is 'different', var3 is 'strings'

I see, thanks a lot!

So LocalPlayer() is the Client-Side ‘version’ of the player correct? And ply is the Server-Side ‘version’?

[editline]19th March 2016[/editline]

Also, I really appreciate your reply… But how would I use that?

I mean I don’t understand the Vector axis argument.

I tried putting X as the first argument, and 90 as the second argument, as I expected, I got errors. Please help!

ply doesn’t mean anything serverside…that wouldn’t really make sense if it did

Also, that RotateAroundAxis thing is pretty annoying to work with - you need to do something like Ang:Right(), Ang:Forward(), or Ang:Up() for the first argument - I’ll try playing around with it until it faces the player

[editline]20th March 2016[/editline]

I tried some stuff, and this seems to work:

hook.Add("PostDrawOpaqueRenderables", "3D2DName", function()

	local ply = LocalPlayer()

	local HeadPos, HeadAng = ply:GetBonePosition( ply:LookupBone("ValveBiped.Bip01_Head1") )
	local Pos = HeadPos + Vector(0, 0, 30)

	local Ang = EyeAngles()
	Ang:RotateAroundAxis( Ang:Right(), 90 )
	Ang:RotateAroundAxis( Ang:Up(), -90 )

	cam.Start3D2D(Pos, Ang, 1)
		draw.DrawText("Hello World!", "Default", 0, 0, Color(0, 0, 0, 255), TEXT_ALIGN_CENTER)


Useful visual aid when dealing with axis rotation.

Pitch = Right
Roll = Forward
Yaw = Up

So everything’s working. Thank you both, both posts were VERY helpful!

However, it looks really ugly(The text):

Every font I try(default fonts) has a low quality look… Why is it like this, and what could I do to fix it? The font is DermaDefault in the picture, however, I’ve tried a number of different default fonts.

Increase the resolution of the cam by using numbers lower than 1. If you use 1, that means 1 pixel is equal to one source unit. Using something like 0.05 means 20 pixels are equal to 1 source unit. The only limiting factor is that fonts can only get so big.


You need to resize the fonts as well, so doing something like this is ideal:

local SCALE = 10

-- When creating the font, multiply the size by SCALE

hook.Add ... function

    cam.Start3D2D ..., ..., 1 / SCALE



You must also multiply everything in the 3D2D context by the scale.

I see, thanks so much! Thank you for explaining in detail how it works :slight_smile:

That’s cause 3D2D doesn’t smooth anything - it just makes it scaled as if you were making it bigger in Photoshop or something - try using

surface.CreateFont to make a new font with a larger size, then change your 3D2D scale

[editline]20th March 2016[/editline]