HOW to get 3D Objective Resolution for HUD?

I have doing 3D health bar. The problem is: I’ve stucked on finding objective resolution - so after it I’ll be able to precisely put all 3D elements in the HUD.
What I mean under “objective resolution” is ratio between user’s screen size and actual view size in parallel to eye position.



quint_HUD_hBar_mat = Material("phoenix_storms/pack2/redlight")
quint_HUD_hBar_width = 80
quint_HUD_hBar_thickness = 20
hook.Add("HUDPaint", "quint_HUD", function()
	local healthCoeff = math.Clamp(LocalPlayer():Health() / LocalPlayer():GetMaxHealth(), 0, 1)
	if healthCoeff > 0 && LocalPlayer():Team() != TEAM_SPECTATOR then
		render.OverrideDepthEnable(true, true)
		render.SetLightingMode(1)
		cam.Start3D()
			render.SetMaterial(quint_HUD_hBar_mat)
			local EyeVector_LR = EyeAngles():Right() -- From left to right HUD vector
			EyeVector_LR:Normalize()
			local EyeVector_TB = -EyeAngles():Up() -- From top to bottom HUD vector
			EyeVector_TB:Normalize()
			render.DrawBox(EyePos() + EyeVector() * 256 + EyeVector_LR * -ScrW() / 3.4 + EyeVector_TB * ScrH() / 3.4, EyeAngles(), -Vector(quint_HUD_hBar_thickness, 0, quint_HUD_hBar_thickness), -Vector(0, quint_HUD_hBar_width * healthCoeff, 0), COLOR_WHITE, true)
		cam.End3D()
		render.OverrideDepthEnable(false, false)
		render.SetLightingMode(0)
	end
end)


I have calculated completely inaccurate ratio “3.4”. My perfectionistic feelings are broken now:

Do you want your HUD to react to where to or from the player looking? Like real life? Because that’s impossible without 3rd party binary modules.

If not, rephrase your question.

I want to naturally calculate ratio so nobody will feel it’s wrong.
HUD moves like a sharm with help of EyeVector_LR/TB axis (check please), but I want to rightly put all the elements in workaround in future pixel-by-pixel.
I tested on larger resolution than 800x600 and health bar went out of screen.

I see. Calculate all positions and sizes as a fraction of ScrH() and ScrW(). Do not even use static positions for elements which are supposed to be on the bottom OR on the right of the screen.

[editline]25th February 2015[/editline]

As for a “ratio”, ScrW() / ScrH() or ScrH() / ScrW() will give you players game resolution ratio.

No, it’s not what I mean. I need ratio between screen width and actual view width in parallel to eye position - and in such way with height.

I have no other idea to normalize view area now than dividing on (approximately) 3.4, but it will work only on 800x600 resolution (not so precisely as you see in first screenshot). I ought to use non-static method, I realize.

[editline]25th February 2015[/editline]

Some dumb calculations:
800x600 . . . . . ~= 3.4
1024x768 . . . . = 4.33
800 / 3.4 ~= 1024 / 4.33 ~= 235 (static value :tinfoil:)
800 * 0.29375 = 235 (it’s 3D offset in 800x)
1024 * 0.29375 = 300.8 (same as 1024 / 3.4… no way, IT MUST BE NON-LINEAR?)

Explain. What eye position? What is “actual view width”?

Real view width of camera view relative to EyePos() - in front of camera. I need actual view width to put health bar (and any other 3D HUD element) exactly in given screen position. The reason why I use ratio is that screen resolution is more than actual view size 3.4 times (in first case when resolution is 800x600).
I have tried using constant offset (on both axis) but when resolution is larger offset looks small.

It causes me to use nonlinear dependence. But which dipendence will be better?

Добавь меня в стим я помогу.

[editline]25th February 2015[/editline]

Basically he wants to get the 0, ScrH() pixel and transfer it to world coords, so he can place it infront of the player at the left-bottom.

I suggested this:

[lua]

local vec = gui.ScreenToVector(0,ScrH())

local tr = util.QuickTrace(vec,EyePos())

–tr.HitPos are the coords, however I am not sure about it…
[/lua]

OK, I’ll try to compute some coordinates with gui.ScreenToVector, as arcaneex suggested me, and compare with trace to EyePos(). If all will go normal, I’ll make a formula.

This may have been answered or suggested but…

I’d suggest creating the elements you want to create on the flat panel that is your screen. Create everything needed, even scaled up work work great. Next, when everything is done, use your Cam 2D3D to allow them to be moved in 3D space, made smaller, etc…

Doing things like this will simplify the logic and math. You can then create things based on x, y, w, h, and be done…

Here are some HUD Tuts I have although nothing I have covers the 3d portion yet but I’ll be expanding my hud section soon.

https://dl.dropboxusercontent.com/u/26074909/tutoring/hud/proper_hud_creation.lua.html

https://dl.dropboxusercontent.com/u/26074909/tutoring/hud/understanding_hardcoding_of_screensizes.lua.html

https://dl.dropboxusercontent.com/u/26074909/tutoring/hud/basic_healthbar.lua.html

Poly… Create the table once, then draw many times: https://dl.dropboxusercontent.com/u/26074909/tutoring/poly/creating_shapes_using_poly.lua.html

https://dl.dropboxusercontent.com/u/26074909/tutoring/poly/simplified_circles_with_poly.lua.html

https://dl.dropboxusercontent.com/u/26074909/tutoring/poly/tilted_rectangle_poly_as_health_meter.lua.html

Hopefully these help as much as any of the previous responses. Remove .html to view .lua…

Yeah, thanks, but it seems not supported with 3D.

Nice, I have forgotten that I need to specify development screen size.

Anything I do will be relatived some way. I mean why not to place these elements on imaginary panel, but not to lock them on (so I’ll be able to move them far or near player, as I want). OK, it will be not so easy.

There’s fallback:
Need to create clientside 3D “panel” that is parralel to user’s view. This “panel” must be collideable or something else to do (clientside) traces to find needed point. Butt… is there possibility to create clientside collision shapes? (Anyway I think it must be there, cause nobody want to fight with maths in a futile attempts to simulate these collision shapes…)

IntersectRayWithPlane might help (without clientside panels). I’ll try.

Yeah, IntersectRayWithPlane works like a sharm! Now I know how to get an edge of screen in objective view coordinates.



quint_HUD_hBar_mat = Material("phoenix_storms/pack2/redlight")
quint_HUD_hBar_width = 80
quint_HUD_hBar_thickness = 20
hook.Add("HUDPaint", "quint_HUD", function()
    local healthCoeff = math.Clamp(LocalPlayer():Health() / LocalPlayer():GetMaxHealth(), 0, 1)
    if healthCoeff > 0 && LocalPlayer():Team() != TEAM_SPECTATOR then
        render.OverrideDepthEnable(true, true)
        render.SetLightingMode(1)
        cam.Start3D()
            render.SetMaterial(quint_HUD_hBar_mat)
            local hb_x = 75
            local hb_y = ScrH() - 75 - quint_HUD_hBar_thickness
            render.DrawBox(util.IntersectRayWithPlane(EyePos(), gui.ScreenToVector(hb_x, hb_y), EyePos() + EyeVector() * LocalPlayer():GetFOV() * 5.9, EyeVector():GetNormalized()), EyeAngles(), -Vector(quint_HUD_hBar_thickness, 0, quint_HUD_hBar_thickness), -Vector(0, quint_HUD_hBar_width * healthCoeff, 0), COLOR_WHITE, true)
        cam.End3D()
        render.OverrideDepthEnable(false, false)
        render.SetLightingMode(0)
    end
end)


LocalPlayer():GetFOV() * 5.9 gives a distance to put elements in absolute coordinates ratio. So if I have putted width of 80 for health bar, I will get 80 pixels on 3D - and so for 20.
I do not understand why 5.9, I’ve just got it increasing from 512 to 531 and dividing on my FOV, 90. It might not work on other resolutions than 1024x768. Let’s check!

Later…
:dance: YES! It works nice! Thanks to all who participated in discussion!