Search code examples
javascriptaframe

aframe not rendering lottie json texture mapped to canvas but works in three.js


so i'm basically trying to render a json onto a canvas via aframe, u did successfully get it to map onto a canvas in three.js, but when i try to replicate this in aframe, it just show a white frame, it shows that it is there, but no animation is shown.

unable to render in aframe (https://glitch.com/edit/#!/sun-innate-cupboard)

able to render in three.js (https://jsfiddle.net/crays/15cgbvsp)

function init() {

    camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 0.01, 10 );
    camera.position.z = 5;

    scene = new THREE.Scene();
        scene.background = new THREE.Color( 0xffffff );
        
        const canvas = document.createElement( 'canvas' );
        canvas.width = 1024;
        canvas.height = 1024;
        const context = canvas.getContext( '2d' );
        
        const animation = bodymovin.loadAnimation( {
            container: document.getElementById( 'bm' ),
            renderer: 'canvas',
            rendererSettings: {
                context: context
            },
            loop: true,
            autplay: true,
            path: 'https://assets5.lottiefiles.com/packages/lf20_mb9ka7yz.json'
      //animationData: json
        } );

        const texture = new THREE.CanvasTexture( canvas );

    const geometry = new THREE.PlaneGeometry();
    const material = new THREE.MeshBasicMaterial( { map: texture } );

    mesh = new THREE.Mesh( geometry, material );
    scene.add( mesh );

    renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );

}

function animate() {

    requestAnimationFrame( animate );
        
        mesh.material.map.needsUpdate = true;
    

    renderer.render( scene, camera );

}

could it be something that i'm missing ?


Solution

  • Two things, regarding not only lottie animations, but textures in general:

    1. The canvas contains transparent elements

    You need to tell the material that you want it to be transparent, otherwise You will see artifacts like these:

    enter image description here

    Doing so is quite straight-forward:

    <!-- in threejs: material.transparent = true -->
    <!-- in a-frame: -->
    <a-entity material="transparent: true">
    

    2. The canvas is animated

    You need to tell the texture to update on each render loop. Otherwise only the first frame of the animation will be visible (or an empty cavas). You can do it easily with an custom component, in a nutshell:

    // grab the mesh upon initialization
    const mesh = element.getObject3D("mesh");
    // cache it for later use
    texture = mesh.material.map;
    
    // on each renderloop
    texture.needsUpdate = true;
    

    3. Turning theory into practice

    // load the lottie animation
    const canvas = document.getElementById('animation')
    const context = canvas.getContext("2d");
    
    const animation = bodymovin.loadAnimation({
      renderer: "canvas",
      rendererSettings: {
        context: context
      },
      loop: true,
      autplay: true,
      path: "https://assets5.lottiefiles.com/packages/lf20_mb9ka7yz.json"
    });
    <script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.7.3/lottie.min.js"></script>
    <script>
      AFRAME.registerComponent("update-texture", {
        init: function() {
          this.el.addEventListener("loaded", e => {
            const mesh = this.el.getObject3D("mesh");
            this.texture = mesh.material.map
          })
        },
        tick: function() {
          if (this.texture) {
            this.texture.needsUpdate = true;
          }
        }
      })
    </script>
    
    <canvas id="animation" width="1024" height="1024"></canvas>
    <a-scene background="color: #ECECEC">
      <a-plane position="0 1.5 -1" material="shading: flat; transparent: true; src: #animation" update-texture></a-plane>
    </a-scene>