Dynamically create 2D text in three.js

anders picture anders · Mar 6, 2013 · Viewed 70.5k times · Source

I have 3D model which I have created in three.js. Based on some data, I want to create a set of arrows which is decorated by a small text label. These labels should be in 2D.

It seems like I have two alternatives: either use a separate canvas element to create a texture which in its turn is used in the 3D model, or use HTML on top the 3D model's canvas element.

I'm wondering how to go about this. Which is the "correct" way to do this? Any suggestions and example code is very welcome!

Answer

kronuus picture kronuus · Mar 6, 2013

If you don't mind that the text will always be on top (e.g. if the object is blocked by something else, its text label will still be visible and on top of everything else), and that the text will not be affected by any rendering like lights/shadow, etc, then HTML is the easiest way to go imho.

Here is some sample code:

var text2 = document.createElement('div');
text2.style.position = 'absolute';
//text2.style.zIndex = 1;    // if you still don't see the label, try uncommenting this
text2.style.width = 100;
text2.style.height = 100;
text2.style.backgroundColor = "blue";
text2.innerHTML = "hi there!";
text2.style.top = 200 + 'px';
text2.style.left = 200 + 'px';
document.body.appendChild(text2);

Substitute 200 in the style.top and style.left variables for the y and x coordinates (respectively) you wish to place the text. They will be positive values where (0,0) is the top left of the canvas. For some guidance on how to project from the 3D point in your canvas to a 2D point in pixels in your browser window, use a code snippet like the following:

function toXYCoords (pos) {
        var vector = projector.projectVector(pos.clone(), camera);
        vector.x = (vector.x + 1)/2 * window.innerWidth;
        vector.y = -(vector.y - 1)/2 * window.innerHeight;
        return vector;
}

Make sure you have called camera.updateMatrixWorld() beforehand.