首页 > 解决方案 > 在 ThreeJS 中使用 GLTFExporter 导出动画场景?

问题描述

我正在尝试使用 GLTFExporter 在 ThreeJS 中导出动画场景,但动画没有被导出。一切都正确导出,形状,颜色......这个项目正在使用示例导出:https ://threejs.org/examples/#misc_exporter_gltf ,以及动画示例:https ://threejs.org/examples /#misc_animation_keys,但它们不能一起工作。任何想法?

如果我使用https://gltf-viewer.donmccurdy.com/打开文件,我会看到一个错误: 在此处输入图像描述

但是如果我在导出时记录导出选项,我可以看到动画在那里: 在此处输入图像描述

这是代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>three.js webgl - exporter - gltf</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link type="text/css" rel="stylesheet" href="main.css">
</head>

<body>
    <div id="info">
        <button id="export_scene">Export Scene</button>
    </div>

    <script type="module">

        import * as THREE from '../../build/three.module.js';
        import { GLTFExporter } from './jsm/exporters/GLTFExporter.js';

        function exportGLTF(input, animationClip) {
            const gltfExporter = new GLTFExporter();

            const options = {
                binary: true,
                maxTextureSize: 4096,
                animations: [animationClip],
                includeCustomExtensions: true
            };

            console.log(options);
            gltfExporter.parse(input, function (result) {

                if (result instanceof ArrayBuffer) {

                    saveArrayBuffer(result, 'scene.glb');

                } else {

                    const output = JSON.stringify(result, null, 2);
                    console.log(output);
                    saveString(output, 'scene.gltf');

                }

            }, options);

        }

        document.getElementById('export_scene').addEventListener('click', function () {
            exportGLTF(scene, clip);
        });

        const link = document.createElement('a');
        link.style.display = 'none';
        document.body.appendChild(link); // Firefox workaround, see #6594

        function save(blob, filename) {
            link.href = URL.createObjectURL(blob);
            link.download = filename;
            link.click();
        }

        function saveString(text, filename) {
            save(new Blob([text], { type: 'text/plain' }), filename);
        }

        function saveArrayBuffer(buffer, filename) {
            save(new Blob([buffer], { type: 'application/octet-stream' }), filename);
        }

        let clock;
        let camera, geometry, scene, renderer, mixer, clip;
        let gridHelper, sphere, smallSphere;

        init();
        animate();

        function init() {
            scene = new THREE.Scene();
            scene.name = 'scene';

            // Perspective Camera
            camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 2000);
            camera.position.set(10, 300, 0);

            camera.name = "PerspectiveCamera";
            scene.add(camera);

            // Ambient light
            const ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
            ambientLight.name = 'AmbientLight';
            scene.add(ambientLight);

            // DirectLight
            const dirLight = new THREE.DirectionalLight(0xffffff, 1);
            dirLight.target.position.set(0, 0, - 1);
            dirLight.add(dirLight.target);
            dirLight.lookAt(- 1, - 1, 0);
            dirLight.name = 'DirectionalLight';
            scene.add(dirLight);

            //Axes 
            /*
            const axes = new THREE.AxesHelper(500);
            axes.name = "AxesHelper";
            scene.add(axes);*/

            // Sphere

            const material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true });
            sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 10, 10), material);
            sphere.position.set(0, 0, 0);
            sphere.name = "Sphere";
            scene.add(sphere);

            // Small sphere
            smallSphere = new THREE.Mesh(new THREE.SphereGeometry(20, 10, 10), material);
            smallSphere.position.set(80, 0, 0);
            smallSphere.name = "SmallSphere";
            scene.add(smallSphere);

            // POSITION
            const positionKF = new THREE.VectorKeyframeTrack('.position', [0, 1, 2], [0, 90, 60, 30, 0, 60, 70, 40, 50]);

            // SCALE
            const scaleKF = new THREE.VectorKeyframeTrack('.scale', [0, 1, 2], [1, 1, 1, 2, 2, 2, 1, 1, 1]);

            // ROTATION
            // Rotation should be performed using quaternions, using a THREE.QuaternionKeyframeTrack
            // Interpolating Euler angles (.rotation property) can be problematic and is currently not supported

            // set up rotation about x axis
            const xAxis = new THREE.Vector3(1, 0, 0);

            const qInitial = new THREE.Quaternion().setFromAxisAngle(xAxis, 0);
            const qFinal = new THREE.Quaternion().setFromAxisAngle(xAxis, Math.PI);
            const quaternionKF = new THREE.QuaternionKeyframeTrack('.quaternion', [0, 1, 2], [qInitial.x, qInitial.y, qInitial.z, qInitial.w, qFinal.x, qFinal.y, qFinal.z, qFinal.w, qInitial.x, qInitial.y, qInitial.z, qInitial.w]);

            // COLOR
            const colorKF = new THREE.ColorKeyframeTrack('.material.color', [0, 1, 2], [1, 0, 0, 0, 1, 0, 0, 0, 1], THREE.InterpolateDiscrete);

            // OPACITY
            const opacityKF = new THREE.NumberKeyframeTrack('.material.opacity', [0, 1, 2], [1, 0, 1]);

            // Clip
            clip = new THREE.AnimationClip('Action', 3, [scaleKF, positionKF, quaternionKF, colorKF, opacityKF]);

            // Mixer
            mixer = new THREE.AnimationMixer(smallSphere);
            const clipAction = mixer.clipAction(clip);
            clipAction.play();

            // Clock
            clock = new THREE.Clock();

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

            window.addEventListener('resize', onWindowResize);
        }

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

        function animate() {
            requestAnimationFrame(animate);
            render();
        }

        function render() {
            const timer = Date.now() * 0.0001;

            const delta = clock.getDelta();

            if (mixer) {
                mixer.update(delta);
            }

            camera.position.x = Math.cos(timer) * 400;
            camera.position.z = Math.sin(timer) * 400;

            camera.lookAt(scene.position);
            renderer.render(scene, camera);
        }

    </script>

</body>

</html>

任何想法?

标签: three.jsgltf

解决方案


正如 Don McCurdy 在评论中解释的那样,存在两个问题:

  • 无法导出材质属性(不透明度和颜色)的动画。
  • 我必须在每个指针之前指定对象名称:<object-name>.position.

谢谢唐·麦柯迪。


推荐阅读