Placing GUI Elements in World Space

Hey Guys,
I’ll keep this short because I am using a workaround right now and feel like worrying to much, but:
Essentially I want to have some labels/text placed in the world for projection but that’s about it. Other than that (I move them like particles), I could use all the gui features like: Scaling independent from Distance (created a Control for that), Rendering on top of everything (set the Bucket to Transparency and disabled Depth Test and Write).

Now I am torn between that way and having like dummy nodes in 3d and just move objects in the guiNode by using camera.projectToScreen (or how it is called), because essentially all my workarounds are because I don’t place gui elements where they belong: The guiNode.

I guess I’ll run into problems because the depthTest leads to labels not properly overlaying each other anyway? And Using the Transparent Bucket could lead to problems when there are real transparent elements, because then something Transparent could be rendered before the text, overdrawing it?

1 Like

if you want labels for objects like characters, then why not just put Text in rootNode(object node) instead of guiNode, where it could scale if something is far or close. not sure what do you ask about exactly, if transparency issues, then idk if there will be some too.

I guess your spatials are your game objects? (If so then that’s the underlying issue, really.)

Or do you have separate game objects that are simply viewed by spatials? In which case I would wonder how this is an issue requiring “dummy Spatials”… when you could just create the view in a different way to use the game object’s positions to project GUI points with projectToScreen().

In the end, what is the effect you are going for?

Sorry for the late answer, I was quite busy so far.
I should form a collection of paul’s quotes so I have a checklist of potential mistakes^^
Indeed the problem can be that I mix spatials and gameObjects:

The use case is a “damage text” which pops up where the damage has been done (+ random offset) and then is a move around and messed with it’s color/alpha.

For this, I throw in Labels and use Lemur’s Animation Tooling. That way I get the nice 3D Look but the Damage Text should not be occluded by Geometry and also shouldn’t get smaller if it’s far away, so actually I am abusing the rootNode just to do the perspective transformation (actually what @grizeldi did manually in his LD code).

The question is if something which shouldn’t be a game object (as it’s actually visual only) should be represented by a gameobject for this? Or if there is another easy workaround

If this were an ES-based game, I’d have a system that watched for damage and popped up the damage indicators based on the objects’ locations projected into 2D space, etc. Essentially independent of the models in 3D space.

That way if tomorrow I decided to switch to just showing a health bar, I could.

If this is not an ES-based game, then… something similar to that. To be honest, I struggle a bit to think non-ES anymore.

That’s what I actually do, I have a system watching the damage but I don’t store the text’s location as a component. I mean precisely what I do is placing the text on a half sphere around the actual model and then move it up and right and scale it up for a short moment to have it pop up and then move it down and downscale (like gravity). Problem is however e.g. when the camera changes, the projection also changes (e.g. when there is much damage going on you could even see the text form a half sphere).

Probably I’d need to implement some “DamageTextUIComponent” which has a 3d location and then transforms a label on the guiNode every frame, but I wanted to avoid entities for basically view only things. Maybe that’s just the wrong way to think about it and I should only mark the component as transient

Can’t you just do entities for the damage, with damage position, orientation, velocity and font (font and size) ?

Then it could both be 3d text, but also 2d text (depending on the system that consumes them)

But why?

Calculate the random position offsets in 2D relative to the objects’ locations in 2D space.

There may be something I don’t understand here.

I can, but it felt like “wasting”/spamming my entity system. I thought of it like: What if someone was playing the game from the terminal, would they need that information? if not, it’s not an entity (usually)

I didn’t give this approach much thought but if someone is moving from “infront” of the enemy/damage position, to “right” of him, the position on screen would have to change dramatically (just like the offset)

Then the terminal should just not receive those entities.

Probably I’d need to implement some “DamageTextUIComponent” which has a 3d location and then transforms a label on the guiNode every frame, but I wanted to avoid entities for basically view only things. Maybe that’s just the wrong way to think about it and I should only mark the component as transient

These are not view only entities. Some system on the backend needs to collect all damage in every loop, sum them together, apply buffs/debuffs, create a decrease health entity (perhaps an area of attack), keep track of statistics etc. So it’s hardly view only - the view is just a small part of the underlying data

There is something I don’t understand about what you are doing.

Well I want the labels to appear as placed within the world nevertheless, just without occlussion and with a constant scaling, actually I am thinking if it’s not worth to copy the Opaque Bucket and make it render after the GuiBucket?

So in your example: Given I only have the screen space 2d vectors which would represent the vertices of a cube in relation to the center/origin of the cube. Then I could not rotate the cube (or orbit around the cube) without these vectors becoming invalid.

That’s in my EntitySystem, yes, but I don’t store where the “damage text label” is currently in world space

So, then your system works just like I described except in 3D instead of 2D… keep the coordinates in 3D for your damage text ‘views’… then project then into 2D to place the visuals (the Spatials) in the guiNode.

That being said, creating another 3D viewport isn’t that hard either but then you still end up unscaling, etc. to get the same effect as the guiNode.

That’s what I initially meant with “dummy nodes”, the 3d text view would be the dummy node animated by lemur (I guess I don’t even need to add those nodes to the rootNode as animation works based on the app state?)

Would you recommend that approach (but not a real viewport, only a render pass/bucket thing?) over the manual approach? The good thing is that i could just ditch my “distance based scaling” control, which is actually a hack, so I would not have a problem with unscaling, I want them to be uniform scaled.
I tried to think about other usescases where I might profit from that approach (maybe world space effects which should overlay the GUI), however in most cases I’d just use a post processing filter (e.g. for outline effects)

What you are referring to as “dummy nodes” I was thinking of as “Vector3f”.

In my EntityContainers, I generally have some kind of View object that is associated with the entity. These would hold the Label and the 3D position used to calculate the position of the label.

The fact that you want to create dummy nodes just to reuse some animation code that is easily/trivially rewritten locally to work with Vector3f is up to you.

Am I missing something here? My labels use the 3d cords of the entity translated to 2d cords and placed on the gui node. Damage is a components of the ship entity with it’s own system on the client that positions the visuals on the gui node. I also check the distance of the camera relative to the 3d entity to determine when I will cull the labels if you are too far from the 3d entity. This way labels and progress bars stay the same size regardless of camera distance and they are always on top of the scene.