Jump to content

Label above the mesh


Recommended Posts

Hi all,

When you play a multiplayer game you often can see players name above them. How can I do the same with a BJS ? I've tried a GUI module to create a TextBlock() , it even has a margin parameter, however the result depends on how far the mesh is from you. If it's next to you - the label will be in front of the mesh, if it's far away - the label will look like it's somewhere in the sky.


What is the best way to create a label, which will always be faced to my camera, and which is for example 30 pixels above the mesh independently of the distance?


I understand that BJS takes mesh's center and puts a label on it, margin is also a distance from center. Maybe it's possible to use another point instead of the center? Like a pivot point in Blender. Then it would be possible to leave the default value for margin.



Link to comment
Share on other sites

I don't know what the best way is, but I did it by manually setting the TextBlock top and left each frame:

To get the screen position of something on screen:

function worldToScreen(worldVec: BABYLON.Vector3, engine: BABYLON.Engine, scene: BABYLON.Scene) {
let identity = BABYLON.Matrix.Identity();
let viewport = scene.activeCamera!.viewport.toGlobal(engine.getRenderWidth(), engine.getRenderHeight());
let transform = scene.getTransformMatrix();
return BABYLON.Vector3.Project(worldVec, identity, transform, viewport);

Then I set the top and left, like this (note the 30 px):

let pos = worldToScreen(node.position, engine, scene);
textBlock.left = pos.x - this.canvas.width / 2;
textBlock.top = pos.y - this.canvas.height / 2 - 30;
Link to comment
Share on other sites

Hi guys.  I was working on a playground in another thread... and it will work just fine to illustrate the issue, here.


Up/Down cursoring the camera in/out... causes the labels to move to front-of mesh, or go far-above.

See the linkOffsetY setting in lines 103 and 133? 

Perhaps... hmm... continuously adjust THOSE values (and maybe button height, width, and fontSize too)... per the distance from camera to mesh.

var dist = BABYLON.Vector3.Distance(camera.position, mesh.position)... something like that?  I dunno.  Let's keep thinking.  :)

Link to comment
Share on other sites

Hi, @Wingnut, thanks for confirmation and a PG.

There was an idea above to do the similar calculations on every frame. However I believe this is too heavy, especially when there are many meshes with labels and the scene is changing often enough.


What do you think about adding new GUI option to set the mesh's point where to put the label? Or an image, or another elements. Currently the object's center only is being chosen. There could be 2 new options like:

label.position.x = 0;  // center on X axis
label.position.y = 3;  // 3 units above the center

(0, 0) by default. In this way you could place the label wherever you wish. Or it can be not parented at all and still be positioned somewhere. For example, if the mesh's height is 2 units - we could set label.position.y = 2; and the label will always be 1 unit above the mesh.

Link to comment
Share on other sites

Origin point, pivot point, and GUI point.  :)  (I didn't understand Arte's comment... until just now.) 

Yeah, fool the GUI into thinking mesh origin is much higher, or tell the GUI linkWithMesh system to use our new mesh.guiPoint.  Actually, the GUI must use mesh.origin.add(mesh.guiPoint).

Yep, I've been down this trail before.  It's full of skeeters and ticks.  :)



Lines 1194-1198... a renderLoop contortion for the 7th line's target circle, and using .moveToVector3.  erf

Not applicable for LOTS of labels.

Generally, I wanted linkOffset to be in world units, and not pixels.

DK replied... http://www.html5gamedevs.com/topic/2571-the-wingnut-chronicles/?do=findComment&comment=201739

Invisible dummy mesh.  I had the same concern as Alexoy... too many labels for that extra load.

SO, I got no solutions.  Sorry. 

@Deltakosh may be reluctant to ever add mesh.guiPoint to core... and consider it in GUI.linkWithMesh ops.  In my experience, if DK is reluctant, there's good reason for it... but not necessarily a reason that I could understand the explanation-for.  :)

Even if we DID add BABYLON.AbstractMesh.guiPoint  [vec3 localspace offset from mesh.origin]... we would need to tell BJS GUI links to use THAT for tracking target... instead of mesh origin.  Again, GUI would actually use mesh.origin.add(mesh.guiPoint) as target.

I think the mod to GUI... would go right here in adt.checkUpdate... https://github.com/BabylonJS/Babylon.js/blob/master/gui/src/2D/advancedDynamicTexture.ts#L473

Mod:  var position = mesh.getBoundingInfo().boundingSphere.center.add(mesh.guiPoint);  mesh.guiPoint would be a distance-from-center OFFSET.

Two mods... gets it done.  One mod to BABYLON.AbstractMesh (adding .guiPoint prop), and one mod to BABYLON.GUI.AdvancedDynamicTexture.prototype._checkUpdate().  (utilizing new mesh.guiPoint).  Might work.  Custom mod... your project only.  I don't know if DK would ever go-for core-ifying those mods.  Also, such a mod would/could eliminate the need for linkOffsetX and linkOffsetY.

I'll keep thinking, but, my thinking is not too useful.  :( 

Off-topic note:  Anyone trying more "touring" in the Wingnut Chronicles leg-joints physics tests... don't bother.  Only a few of the playgrounds still work... due to recent changes in Oimo plugin.  I DID manage to get #196... the most modern one... running again... but its red GUI button impulsers are still broken, sending the red femur mesh into outer space somewhere.  #197 and #198 got their physics removed... to make them run (now just GUI demos).  I know better than to do big, long-life projects in webGL... due to evolution.  Backward-compat is really a pipe dream... when the tech changes as fast as webGL does.  It's all ok... there was little/no interest in the physics human-leg-joints experiments, anyway.  Undertandable.  Learning collidesWith/belongsTo physics collision-group crap... and 3-axis hinge joints... is sort of like learning to tolerate physical pain.  It's not the most fun learning to be found.  :)

Link to comment
Share on other sites

If we modify a mesh for that - we won't be able to create independent labels, for example, to put them at different points of the same mesh (zooming will still move some of them from their correct places).

But if we configure the label itself, by setting a "connection point" - there won't be such issues. I think about it like it's a mesh parented to another mesh.

Link to comment
Share on other sites

Hi @Dad72,

Isn't gui3d an almost normal 3D mesh with it's own size, rotation, shadows, etc? I mean label (text on the plane?) will rotate with player's rotation, won't it? And will become smaller when zooming out.

Sure it is useful in other use cases, but users/objects labels are just a plaintext on the screen, with no rotation, connected to some point in a virtual 3D space.


The working solution I see for now is to place an empty/invisible mesh above the player's head and attach the label to it.


But I really feel that an ideal solution would be to "parent" the label to some mesh and set it's position, just like we do with normal mesh-to-mesh :) Like we do now, but without setting the position yet. One label to the mesh's top, one to the bottom.. rotate/zoom the scene whatever you like and everything will be in a correct places

Link to comment
Share on other sites

@leanderr, similar to Wingnut's PG :) But if you zoom in/out - you'll notice, that the label doesn't stay on the same place relative to the mesh. If you go far away from the mesh - label will look like it is far above the mesh. I wish label is "connected" to the top point of the mesh for example, independently of the zoom level

Link to comment
Share on other sites

"The working solution I see for now is to place an empty/invisible mesh above the player's head and attach the label to it."

Yep, put a advanced dynamic texture for text or more GUI stuff and make it the child of your mesh.

If you want it to appear as if it is always on top of the mesh (seen relatively from the camera) you can offset the plane by using the camera's up-vector.

upvector would be 

const viewVector = this.camera.getFrontPosition(1).subtract(this.camera.position);
const right = BABYLON.Vector3.Cross(BABYLON.Axis.Y, viewVector);
const upOrDownOneOfThem = BABYLON.Vector3.Cross(right, viewVector).normalize();

If you want the plate to face the camera use lookat().

Hope it helps :)

Link to comment
Share on other sites



See lines 134-144. Uses two methods suggested above; modifying linkedoffsetY each frame, or using an empty mesh parented to the desired mesh.

On 5/27/2018 at 8:13 AM, alexoy said:

Too heavy :( . GUI module has almost good label, problem is to place it on top of the mesh instead of it's center

What @Gijs suggested is basically what the GUI module is doing internally anyway, so is no heavier than relying on that.

Regarding linkedOffsetY calculation each frame being too heavy, you're going to run into performance issues with projecting positions to screen space each frame long before performance of such a simple calculation is a concern.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...