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 ?
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:
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>