Skip to content

HUD Spaces

Zach Hembree edited this page Sep 16, 2021 · 11 revisions

Every UI element in the framework is drawn using textured quads located in the game's world-space, each element associated with a HUD Space Node. These nodes, in turn, define 2D planes embedded in world-space that their children are rendered to using their Plane-To-World (PTW) matrix transforms.

By default, UI elements will use the Pixel-To-World transform supplied by HudMain, and as the name suggests, that transform is used to draw elements in screen space, with units in pixels and the origin at the center of the screen. Technically, nothing rendered by this framework draws in screen-space, but for the sake of brevity and clarity, that's the terminology I'll be sticking with.

At the time of writing this, there are three types of HUD Space Node: ScaledSpaceNode, CustomSpaceNode and CamSpaceNode. ScaledSpaceNode is dead-simple. All it does is let you rescale the XY plane of the parent space node. If the next space node above it in the tree is HudMain.Root, then it will rescale that. CamSpaceNode and CustomSpaceNode are a bit more complicated; if you're not interested in drawing UI elements in world space or creating your own draw matrices, then ignore them.

If you're uncomfortable with matrix transforms or any of the other concepts discussed here, then you might want to do a little extra research. Personally, I think LearnOpenGL is a great resource for this kind of stuff.

Custom HUD Spaces:

Each of these nodes are responsible not only for updating their PTW matrices but for calculating the position of the cursor over their planes as well as their distances from the screen at that point. This allows UI elements attached to that node to determine when they're moused over and whether or not they're occluded by other elements at that point, allowing the cursor to function regardless of the local coordinate system of that node. By default, this is handled automatically in HudSpaceNodeBase using the inverse PTW matrix.

CustomSpaceNode is the most open-ended and allows you to update the PTW matrix using a delegate. CamSpaceNode, on the other hand, is more specialized and is designed to allow you to more easily create custom screen spaces by allowing you to specify custom scaling, rotation, and offset with respect to the camera. This node type also serves as a fairly decent example of how to manipulate draw matrices for this framework. You can try out the CamSpaceNode in real-time in the Rich HUD Terminal by enabling debugging with the "/rhd toggleDebug" chat command and opening the Demo page.

Depth Sorting:

As mentioned previously, UI elements in this framework are rendered using textured quads, semitransparent textured quads, to be specific. I mention this because of the way 3D renderers handle semitransparent geometry. Where opaque geometry occludes, semitransparent fragments have to be blended with the fragments behind them and in the correct order. Otherwise, you'd end up with pieces of semitransparent geometry that appear to be in front of an object when they're actually behind it, and not necessarily with any consistency.

Typically, this is corrected by sorting per-object s.t. semitransparent objects furthest are drawn first and those closest are drawn last, but in this framework, it's done per HUD Space, with the origin/translation of that space being used to calculate distance from the camera.