Is it possible to export animation and morphs from the scene in the GLTF format?

I want to export a model that is in the scene with all animations, textures and morphs.

all code

	import * as THREE from './three/build/three.module.js';
	
	import { OrbitControls } from './three/examples/jsm/controls/OrbitControls.js';
	// Create 3d scene
	
	// Create Scene Camera Renderer
	const scene = new THREE.Scene();
	
	const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
	camera.position.z = 5;
	
	
	
	const renderer = new THREE.WebGLRenderer();
	// set size for render
	renderer.setSize( window.innerWidth, window.innerHeight );
	
	
	document.body.appendChild( renderer.domElement );
	
	
	// Light
	var DiLight = new THREE.DirectionalLight(0xFDFCEB, 0.5) 
	scene.add(DiLight);
	
	
	
	const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
	hemiLight.position.set( 0, 100, 0 );
	scene.add( hemiLight );

	const dirLight = new THREE.DirectionalLight( 0xffffff );
	dirLight.position.set( - 0, 40, 50 );
	dirLight.castShadow = true;
	dirLight.shadow.camera.top = 50;
	dirLight.shadow.camera.bottom = - 25;
	dirLight.shadow.camera.left = - 25;
	dirLight.shadow.camera.right = 25;
	dirLight.shadow.camera.near = 0.1;
	dirLight.shadow.camera.far = 200;
	dirLight.shadow.mapSize.set( 1024, 1024 );
	scene.add( dirLight );
	
	
	
	// CONTROLS
	const controls = new OrbitControls( camera, renderer.domElement );
	
	
	// GLTFLoader
	import { GLTFLoader } from './three/examples/jsm/loaders/GLTFLoader.js';
	
	const mixers = [];
	const loader = new GLTFLoader();
	const clock = new THREE.Clock();
	
	
	let exsp_obj 
	
	loader.load( 'models/gltf/Flamingo.glb', function ( gltf ) {

		const mesh = gltf.scene.children[ 0 ];

		exsp_obj = mesh;

		mesh.castShadow = true;
		mesh.receiveShadow = true;

		scene.add( mesh );

		const mixer = new THREE.AnimationMixer( mesh );
		mixer.clipAction( gltf.animations[ 0 ] ).setDuration( 1 ).play();
		mixers.push( mixer );

	} );



	
	function animated() {
		const delta = clock.getDelta();
		for ( let i = 0; i < mixers.length; i ++ ) {
			mixers[ i ].update( delta );
		}
	}
	
	// Run animate
	const animate = function () {
		controls.update();
		requestAnimationFrame( animate );
		renderer.render( scene, camera );
		animated()
	};

	animate();
	
	
	
	
	
	
	// EXSPORT
	import { GLTFExporter } from './three/examples/jsm/exporters/GLTFExporter.js';
	
	function exportGLTF( input ) {

		const gltfExporter = new GLTFExporter();

		const options = {
			trs: document.getElementById( 'option_trs' ).checked,
			onlyVisible: document.getElementById( 'option_visible' ).checked,
			truncateDrawRange: document.getElementById( 'option_drawrange' ).checked,
			binary: document.getElementById( 'option_binary' ).checked,
			maxTextureSize: Number( document.getElementById( 'option_maxsize' ).value ) || Infinity // To prevent NaN value
		};
		gltfExporter.parse( input, function ( result ) {

			if ( result instanceof ArrayBuffer ) {
				console.log(result)

			} else {

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

			}

		}, options );

	}
	exportGLTF( exsp_obj );

But I do not quite understand how to turn the scene into the GLTF model.
I repeat I want to export all that is possible from the scene in GLTF

GLTFExporter does support all this. Have you tried using the class according to the documentation?

There is also an example that demonstrates the usage of the exporter.

Right now, you have only shared code that shows how you load a glTF. But this code is actually unrelated to your issue. I suggest you give GLTFExporter a try. If you encounter problems, share a live example or GitHub repo that shows what you do.

I used exactly an example from the link three.js webgl - exporter - gltf
But I do not know how to export animation as it is played in animations and is not part of the scene.

	function animated() {
		const delta = clock.getDelta();
		for ( let i = 0; i < mixers.length; i ++ ) {
			mixers[ i ].update( delta );
		}
	}
	
	// Run animate
	const animate = function () {
		controls.update();
		requestAnimationFrame( animate );
		renderer.render( scene, camera );
		animated()
	};

	animate();

You have to add the animation clips as an array to the options object. Something like:

exporter.parse( scene, onComplete, { animations: [ clip1, clip2 ] } );

I’m using this method, but the exported file is not working (it does without the animation). Is there any example exporting an animation?

^Let’s discuss the problem you’re having in Exporting an animated GLTF using GLTFExporter - #2 by donmccurdy.

1 Like

It is work only with Mixer

mixer.clipAction( Export_Animation ).setEffectiveWeight( 1.0 ).play();

// some code ... 

exporter.parse( scene, onComplete, { animations: [ Export_Animation ] } );

But how i can export example Assimp or MD2?

const loader = new AssimpLoader();
loader.load(url, function ( result ) {
	const object = result.object;
	object.position.y = - 100;
	object.rotation.x = Math.PI * 2;
	group.add(object)
	animation = result.animation;
	export_animates = [result.animation]
	console.log(result.animation)
} );


function ani() { 
	if ( animation ) animation.setTime( performance.now() / 1000 );
}

and why i can’t use bvh?
I get error.

THREE.GLTFExporter: Could not export animation track ".bones[hip].position".

The list of available exporters can be found here: examples/jsm/exporters

The error you mentioned appears when GLTFExporter can’t figure out what object is associated with the animation:

You can fix it perhaps by renaming the track to include the name of the SkinnedMesh, like MyCharacter.bones[hip].position.

I think you misunderstood about Assimp.
I can export FBX to GLTFExporter.js
FBXExporter.js is not exists.
But i do not understand how export Assimp to GLTFExporter.js
I try use result.animation
but i get error

AssimpLoader.js:302  Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'name')

And about BVH
Where i need renaming MyCharacter.bones[hip].position.
I have only

loader.load(url, function ( result ) {
	skeletonHelper = new THREE.SkeletonHelper( result.skeleton.bones[ 0 ] );
	skeletonHelper.skeleton = result.skeleton; // allow animation mixer to bind to THREE.SkeletonHelper 
	group.add(skeletonHelper)
	group.add(result.skeleton.bones[ 0 ])
	// play animation
	mixer = new THREE.AnimationMixer( skeletonHelper );
	mixer.clipAction( result.clip ).setEffectiveWeight( 1.0 ).play();
	
	export_animates = [result.clip]
} );

And where is hip in my code?

Below code will download/export animationClip from loaded gltf model in json format.
Here gltfAnimations[0] refers to first animation clip.

let gltfAnimations = gltf.animations;
var fileContent = gltfAnimations[0].toJSON();
var bb = new Blob([JSON.stringify(fileContent)], { type: ‘text/plain’ });
var a = document.createElement(‘a’);
a.download = ‘animation_0.json’;
a.href = window.URL.createObjectURL(bb);
a.click();

1 Like