Animating canvas billboard in Three.js
Asked Answered
E

2

10

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:

<body>
  <script src="http://mrdoob.github.com/three.js/build/three.min.js"></script>
  <script>
    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?

Englebert answered 16/9, 2012 at 21:3 Comment(0)
A
9

Place this right before your render() call:

sign.material.map.needsUpdate = true;
Anaconda answered 16/9, 2012 at 21:24 Comment(0)
N
3

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.

Nyberg answered 22/11, 2017 at 23:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.