1
votes

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;
}
1

1 Answers

0
votes

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.