Animating Canvas Billboard in THREE.js

2019-02-13 16:03发布

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条回答
forever°为你锁心
2楼-- · 2019-02-13 16:26

Place this right before your render() call:

sign.material.map.needsUpdate = true;

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

查看更多
霸刀☆藐视天下
3楼-- · 2019-02-13 16:35

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.

查看更多
登录 后发表回答