Exporting an animated GLTF using GLTFExporter

Hi, I’m trying to export an animated scene with GLTFExporter, but the exported file is not working (it does without the animation). I’m following the documentation, and I wonder what I’m doing wrong. This is an example with basic components and animations:

<!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) {
			const gltfExporter = new GLTFExporter();

			const options = {
				binary: true,
				maxTextureSize: 4096,
				animations: [clip],
				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);
		});

		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, [positionKF]);

			// 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>

Added a comment here: three.js - Exporting an animated scene with GLTFExporter in ThreeJS? - Stack Overflow

1 Like

Your comment solved the issue! Thank you so much

1 Like