1

I'm trying to have text sprites in the 3d scene with constant size (regardless of camera distance) using a PerspectiveCamera. In order to get non-sprites to have constant size, I make them children of a special "scaled" object which adjusts its scale as the camera distance to origin changes (see the code below). This works well to keep a general object roughly the same visual size, but when I add a sprite to the scaled object, the sprite seems to ignore its parent's scale (so it gets smaller and bigger as you zoom out and in).

Interestingly, when we switch to an orthographic camera (uncomment the appropriate line below), this special scaled object doesn't seem to affect children anymore (i.e., children don't stay a constant size). However, since we have an orthographic camera, sprites no longer scale as the camera distance changes (so they maintain a constant size), but this is independent of the scaled object.

I notice a few other similar questions and answers, including adjust the scale of the sprites themselves (it seems much easier to add all my sprites to a single scaling object), use an orthographic camera overlay to draw sprites (see also this) (but I want my sprites to be inside the 3d perspective scene).

So, my questions are: why do sprites not use scale according to their parent's scale when using a PerspectiveCamera? Also, why does my scaled object not work with the orthographic camera? Are these bugs or features of the cameras?

Thanks!

http://jsfiddle.net/LLbcs/8/

var camera, scene, renderer, geometry, material, mesh, text, controls;

init();
animate();
function init() {
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000); var scenescale=1;
    //camera = new THREE.OrthographicCamera( -7,7,7,-7, 1, 20 );

    camera.position.z = 10;
    scene.add(camera); 

    scaled=new THREE.Object3D();
    scene.add(scaled);

    var textmaterial = new THREE.SpriteMaterial( {color: 'red', useScreenCoordinates: true, map: texttexture("hi")});
    text = new THREE.Sprite( textmaterial );
    text.position.set( 1, 1, 0);
    scaled.add(text);

    var geometry = new THREE.BoxGeometry( 1, 1,1 );
    var material = new THREE.MeshLambertMaterial( { color: 0xffffff } );
    mesh = new THREE.Mesh( geometry, material );
    mesh.position.set(0,3,0);
    scaled.add(mesh);

    var light = new THREE.PointLight('green');
    light.position.set(10,15,10);
    camera.add(light);
    light = new THREE.PointLight(0x333333);
    light.position.set(-10,-15,-8);
    camera.add(light);

    renderer = new THREE.WebGLRenderer();
    controls = new THREE.OrbitControls( camera, renderer.domElement );
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
}

function animate() {
    requestAnimationFrame(animate);
    var scale = camera.position.length()/10;
    scaled.scale.set(scale,scale,scale);
    render();
}

function render() {
    renderer.render(scene, camera);
}
function texttexture(string) {

    var fontFace = "Arial"
    var size = "50";
    var color = "white"
    var squareTexture = true;

    var canvas = document.createElement("canvas");
    var context = canvas.getContext("2d");

    canvas.height = size;
    var font = "Normal " + size + "px " + fontFace;
    context.font = font;

    var metrics = context.measureText(string);
    var textWidth = metrics.width;
    canvas.width = textWidth;

    if (squareTexture) {
        canvas.height = canvas.width;
    }

    var aspect = canvas.width / canvas.height;

    context.textAlign = "center";
    context.textBaseline = "middle";
    context.fillStyle = color;
    // Must set the font again for the fillText call
    context.font = font;
    context.fillText(string, canvas.width / 2, canvas.height / 2);

    var t = new THREE.Texture(canvas);
    t.needsUpdate = true;
    return t;
}
Community
  • 1
  • 1
Jason Grout
  • 631
  • 6
  • 10

1 Answers1

0

If you want text to appear over a 3D scene and you don't care if it is static, why not try layering a div over the scene instead?

This will allow you to save graphics bandwidth and memory, improving performance of your scene and give you much better flexibility over what you display. It's also much easier to do and to maintain.

Alex
  • 4,844
  • 7
  • 44
  • 58
  • I do want to be able to change the text, and I want it to move around (be occluded, etc.) in the 3d scene. – Jason Grout Oct 03 '14 at 16:17
  • Because scale is governed by the .geometry object, it will act independently of a parent mesh. You'll have to adjust the scale of the text mesh itself. – Alex Oct 07 '14 at 10:35
  • As in the above example, the Box scale *is* affected by the parent mesh. My question is why it is working for the Box, but not for the Sprite. – Jason Grout Oct 14 '14 at 14:58
  • (I guess I should clarify) the scale numbers themselves are not changed, obviously, but the effective scale in the image should be multiplied by the transformation matrices of parents. This seems to happen for the box, but not for the sprite. – Jason Grout Oct 21 '14 at 14:17