I'm trying to export an animation scene in ThreeJS with GLTFExporter, but the animation is not being exported. Everything is correctly exported, the shapes, the color... This project is using the example to export: https://threejs.org/examples/#misc_exporter_gltf, and the example to animate: https://threejs.org/examples/#misc_animation_keys, but they don't work together. Any idea?
If I open the file with https://gltf-viewer.donmccurdy.com/, I see an error:

But if I log the export options when exporting, I can see the animations are there:

Here's the code:
<!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>
Any idea?