Morphtarget on GLTF

Hello,
I am quite new to ThreeJs and Javascript. Normally I develop in C++ and C#.

Anyway, I have a gltf file with an animation and a morphtarget. The animation game and now I want to dazzle the morphtarget.

I don’t understand how to access the morph target in the gltf file. Tried to take it from the examples but got stuck at the last end of this code that doesn’t work:

Btw, in which IDE are you developing? I’m using visual code which is really hard to use for debugging.

<script>
    if (!Detector.webgl) Detector.addGetWebGLMessage();

    var container, controls;
    var camera, scene, renderer, light, mixer;
    var clock = new THREE.Clock();
    var mesh;

    init();
    animate();

    function init() {
        container = document.createElement('div');
        document.body.appendChild(container);

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.25, 20);
        camera.position.set(-1.8, 0.9, 2.7);

        controls = new THREE.OrbitControls(camera);
        controls.target.set(0, -0.2, -0.2);
        controls.update();

        scene = new THREE.Scene();
        scene.background = new THREE.Color(0xa0a0a0);

        light = new THREE.HemisphereLight(0xffffff, 0x444444);
        light.position.set(0, 200, 0);
        scene.add(light);

        light = new THREE.DirectionalLight(0xffffff);
        light.position.set(0, 200, 100);
        light.castShadow = true;
        light.shadow.camera.top = 180;
        light.shadow.camera.bottom = -100;
        light.shadow.camera.left = -120;
        light.shadow.camera.right = 120;
        scene.add(light);

        // slider
        var params = {
            morphTarget: 0,
        };

        var gui = new dat.GUI();

        var folder = gui.addFolder('Morph Targets');
        folder.add(params, 'morphTarget', 0, 1).step(0.01).onChange(function (value) { mesh.morphTargetInfluences[0] = value });
        folder.open();

        // grid
        var grid = new THREE.GridHelper(20, 20, 0x000000, 0x000000);
        grid.material.opacity = 0.2;
        grid.material.transparent = true;
        scene.add(grid);

        // model
        var loader = new THREE.GLTFLoader();
        var filepath = "models/gltf/Test8/test.gltf";

        alert("Trying to load model from " + filepath);

        loader.load(filepath, function (gltf) {

            gltf.scene.traverse(function (node) {
                if (node.isMesh) mesh = node;
            });

            mesh.material.morphTarget = true;

            scene.add(mesh);

            var pointsMaterial = new THREE.PointsMaterial({
                size: 10,
                sizeAttenuation: false,
                alphaTest: 0.5,
                morphTargets: true
            });

            var points = new THREE.Points(mesh.geometry, pointsMaterial);
            points.morphTargetInfluences = mesh.morphTargetInfluences;
            points.morphTargetDictionary = mesh.morphTargetDictionary;
            mesh.add(points);


            alert("Found and Loaded model!");


            if (gltf.animations.length > 0) {

                alert("Model has animations " + gltf.animations.length);

                var animationIndexToPlay = 0;

                alert("Want to play animation " + gltf.animations[animationIndexToPlay].name);

                var animations = gltf.animations;
                if (animations && animations.length) {
                    mixer = new THREE.AnimationMixer(gltf.scene);
                    var animation = animations[animationIndexToPlay];
                    var action = mixer.clipAction(animation);
                    action.play();
                }

                alert("Playing");

            }
            else {
                alert("Model has NO animations");
            }

            gltf.scene.traverse(function (child) {
                if (child.isMesh) {
                    // handle child objects
                }
            });
        });

        // render
        renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.gammaOutput = true;
        container.appendChild(renderer.domElement);
        window.addEventListener('resize', onWindowResize, false);
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        if (mixer) mixer.update(clock.getDelta());
        renderer.render(scene, camera);
    }

</script>

Thank you :slight_smile:

^I think you mean mesh.material.morphTargets, and this should already be true when the mesh comes out of the loader if it has morph targets. Otherwise your code looks OK, can you create a demo? I’m not sure why this might not work without seeing the model.

I use Chrome Developer Tools for debugging.

^I think you mean mesh.material.morphTargets, and this should already be true when the mesh comes out of the loader if it has morph targets. Otherwise your code looks OK, can you create a demo? I’m not sure why this might not work without seeing the model.

Hi and thank you for your reply. I got it working now. I just created a new cube with a morphtarget and exported it from blender using the blender-gltf exporter. Now I have a looped animation and a morphtarget that I can blend in.

However that block of code here was useless :slight_smile:

var pointsMaterial = new THREE.PointsMaterial({
size: 10,
sizeAttenuation: false,
alphaTest: 0.5,
morphTargets: true
});

var points = new THREE.Points(mesh.geometry, pointsMaterial);
points.morphTargetInfluences = mesh.morphTargetInfluences;
points.morphTargetDictionary = mesh.morphTargetDictionary;
mesh.add(points);

The loader already knows about the morphtargets when the model is loaded, that’s great :slight_smile:

Thank you!