How to put 2d text in 3d world

Hi,

I would like to display damage numbers above a mesh. How can I put 2d text at a position in a 3rd world?

Thank you!

Use the Babylon.GUI in Texture Mode as in this example https://www.babylonjs-playground.com/#ZI9AK7#1

More information at Use the Babylon GUI - Babylon.js Documentation

2 Likes

Thank you!

I’ve tried this approach, and it does work, but as the number of meshes with attached dynamic textures gets large (greater than 50) the performance really tanks. I don’t need a full GUI, I just need a static text label in 3D space. Any workarounds for that? I’ve tried MeshWriter too, with similar performance issues.

We used html overlays, 2D TXTs over 3D, for the same reason (lots of TXTs). : )

Then the text would just be on top of the 3D world in screen space, right? It’d always have the same orientation and would write over everything.

We used that for speech bubbles… correct.

Maybe this does not work for your static label… maybe it does.

Yeah, it was not working for me with 20 texts at the same time, the FPS would drop to 20, I used this for a damage text over a character (think Diablo, WoW etc).

I had to drop that implementation and instead just have 1 text block that updates.

I’ve been having this same issues and stumbled upon this post 12 months later. Forgive me for resurrecting it. I really do not want to resort to having to go about this in the way suggested above because it seems to cut down optimization and bottleneck the game. So I looked into how to get x and y coordinates of the mesh in the viewport and thought if I can get these two points I could potentially create a div and move it around on statechange and then I came up with this.

The function getMeshScreenPosition is where the magic happens, it returns back the x and y coordinates of your meshes whereabouts on your canvas.

What I then proceed to do was create a div, set the top & left css styles to that of the x and y provided by getMeshScreenPosition and the rest is history (it is wise to note that this code is dumbed down to get an idea of how I went about this. In reality you would want to create the div on load, and then on statechange move it around, and remove the div on update)

let meshPositionOnWindow = getMeshScreenPosition(scene,canvas, yourMesh);
let name = document.createElement(“div”);
name.id = “my_players_name”
name.style.position = “absolute”;
name.style.top = meshPositionOnWindow.y + “px”;
name.style.left = meshPositionOnWindow.x + “px”;
name.innerHTML = “your_players_name”
document.body.appendChild(name);

function getMeshScreenPosition( scene, canvas, mesh) {

        pos = BABYLON.Vector3.Project(mesh.position,
            BABYLON.Matrix.Identity(),
            scene.getTransformMatrix(),
            { 'x': 0, 'y': 0, 'width': canvas.width, 'height': canvas.height }
        );
         return {
            x: (Math.trunc(Math.round(pos.x) * 1) / 1),
            y: (Math.trunc(Math.round(pos.y) * 1) / 1)
   }

}

I’ve tested it and it works! however it is not perfect…
As soon as I move around all the divs start to shift a few pixels towards the direction i’ve moved and when I stop the divs go back into their respective positions. It definitely needs polishing.

I’m leaving this here on the forums in hopes that the community can perfect it or come up with a better way to go about it!