9
votes

Everyone,

I'm trying to animate a Canvas-based texture that is mapped onto a plane, like a billboard. I've made a point of including material.needsUpdate & texture.needsUpdate, but I'm still unable to get the texture to come to life. I've also included a rotating cube just so I know the animation routine is functioning on some level.

Here is the code:


    
      
      
        if ( window.innerWidth === 0 ) { window.innerWidth = parent.innerWidth; window.innerHeight = parent.innerHeight; }

            var camera, scene, renderer;
            var mesh, geometry, material;
            var light, sign, animTex;
            var canvas, context;

            init();
            animate();

            function init() {

                camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1200 );
                camera.position.z = 700;

                scene = new THREE.Scene();

                material = new THREE.MeshLambertMaterial(
                    { color: 0x885522
                    , wireframe: false
                     , overdraw: false
                    } );
                geometry = new THREE.CubeGeometry( 80, 120, 100, 1,1,1);
                mesh = new THREE.Mesh( geometry, material );

                sign = createSign();

                light = new THREE.DirectionalLight(0xFFFFFF, 3.0);
                light.position = new THREE.Vector3(5,10,7);
                light.target = new THREE.Vector3(0,0,0);

                scene.add( mesh );
                scene.add( sign );
                scene.add( light );

                renderer = new THREE.CanvasRenderer();
                renderer.setSize( window.innerWidth, window.innerHeight );
                document.body.appendChild( renderer.domElement );

            }
            function createSign() {
                canvas = document.createElement("canvas");
                context = canvas.getContext("2d");
                canvas.width = 200;
                canvas.height = 200;
                context = canvas.getContext("2d");              
                var texture = new THREE.Texture(canvas);
                texture.needsUpdate = true;
                var material = new THREE.MeshBasicMaterial({ map : texture, overdraw: true });
                material.needsUpdate = true;
                var mesh = new THREE.Mesh(new THREE.PlaneGeometry(200, 200), material);
                mesh.doubleSided = true;
                return mesh;
            }

            function animate() {

                var time = Date.now()*0.01;
                var sinTime = Math.sin ( time * 0.05 ) * 100;
                var cosTime = Math.cos ( time * 0.05 ) * 100;

                mesh.rotation.y = sinTime*0.01;

                requestAnimationFrame( animate );
                context.fillStyle="black";
                context.fillRect(0,0,canvas.width,canvas.height);
                context.fillStyle="white";
                context.fillRect ( (canvas.width/2) + sinTime, (canvas.height/2) + cosTime, 20, 20 )
                renderer.render( scene, camera );
            }

This runs, but I can't seem to get the Canvas texture material to update. What have I overlooked? Thanks very much for any pointers!

2

2 Answers

8
votes

Place this right before your render() call:

sign.material.map.needsUpdate = true;

Fiddle: http://jsfiddle.net/pPKVa/

3
votes

The needsUpdate flag is reset (to false) every time the texture is used (every render loop), so it needs to be set to true in the render loop (before the render call, or it'll be a frame off). So in your example, put sign.material.map.needsUpdate = true before renderer.render( scene, camera ). texture.needsUpdate = true and material.needsUpdate = true are not needed.

Also, you only need to set the needsUpdate flag on the texture, as the material properties are not changing.