Search code examples
aframewebvrgltf

gltf material override stops animation mixer


I'm very stuck with an issue with a gltf model. If I try to override the gltf's material, the animation stops. I think it has something to do with the update function of the override and the tick function of the animation mixer colliding somehow, but I haven't managed to solve it on my own.

I hope someone can point me to the direction of why this is happening. Here's a live example: http://motiondolphins.com/app_onlyFefo/index.html

Immense thanks in advance. Here's the code itself. The commented section is the override of the material. If I uncomment it, the new material loads but the animation stops:

        AFRAME.registerComponent("fefo", {
            init: function() {

                var texture = new THREE.TextureLoader().load( 'models/static.png' );
                texture.wrapS = THREE.RepeatWrapping;
                texture.wrapT = THREE.RepeatWrapping;
                texture.repeat.set( 20, 20 );


                this.material  = new THREE.MeshToonMaterial({
                    bumpMap:texture,
                    bumpScale:0.03,

                    color : 0xffffff
            });

            this.el.addEventListener('model-loaded', () => this.update());


            var el = this.el;
            setTimeout(()=>{
                var model = el.getObject3D('mesh')       
                this.mixer = new THREE.AnimationMixer(model);
                var clips = model.animations || (model.geometry || {}).animations || 
                [];
                console.log(this.mixer)
                console.log(el)
                console.log(clips[0])
                const action = this.mixer.clipAction(clips[0], model);
                action.setDuration(10).setLoop(THREE.LoopRepeat).play();
                console.log(action)
            }, 3000)
            },

            /////////////////HERE I TRY TO OVERRIDE THE MATERIAL, BUT IF I DO, ANIMATION STOPS

            update: function () {

            //      object = this.el.getObject3D('mesh');

            //     if (!object) return;
            //     object.traverse((node) => {

            //     if (node.isMesh) node.material = this.material;
            // }); 

        },
            tick: function (t, dt) {

                if (this.mixer && !isNaN(dt)) this.mixer.update(dt / 1000);

            }
        })

Solution

  • It's important to keep in mind that a Material in three.js actually represents a WebGL shader program, not just the visual "look" of an object. MeshToonMaterial extends MeshPhongMaterial, and inherits several properties related to animation which need to be preserved in order for animation to work:

    newMaterial.skinning = oldMaterial.skinning;
    newMaterial.morphTargets = oldMaterial.morphTargets;
    newMaterial.morphNormals = oldMaterial.morphNormals;
    

    In this case I think it's just the .skinning property that is important, because the model uses a skeleton.