Looking for advice on how best to animate a mesh

Firstly, some screenshots to illustrate my current setup:

This is a mesh from video game Unreal Tournament '99. The mesh has 148 frames which make up a total of 16 different animation sequences.

One of these sequences is a “Grab” animation which consists of 20 frames; here are the first three:



As you can see, I’ve managed to draw each frame as an individual scene; I would like, however, to input all 20 frames into one scene and have Three animate them.

The root of my problem is that I am reading the mesh data manually from the game file at the byte level, as opposed to a file exported from Blender, for example.

Obviously this means I cannot use the model loaders provided by Three and thus have to manually create the animation myself.

After reading the documentation and looking at many examples, it sounds like using keyframe tracks to move between morphTargets would be the most suitable approach; however, I’m finding it frustratingly difficult to find a clear example of how this can be done manually.

The mesh data I have looks like the following:

const frames = [
	// Frame 0
	[
		new THREE.Vector3(vertex1.x, vertex1.z, vertex1.y),
		new THREE.Vector3(vertex2.x, vertex2.z, vertex2.y),
		new THREE.Vector3(vertex3.x, vertex3.z, vertex3.y),
		// etc.
	],

	// Frame 2
	[
		new THREE.Vector3(vertex1.x, vertex1.z, vertex1.y),
		new THREE.Vector3(vertex2.x, vertex2.z, vertex2.y),
		new THREE.Vector3(vertex3.x, vertex3.z, vertex3.y),
		// etc.
	],

	// etc.
];

Can anyone advise on the best way to create an animation clip from this data structure?

Thank you.

2 Likes

Maybe the following fiddle helps: three.js dev template - module - JSFiddle - Code Playground

The idea is to add data to BufferGeometry.morphAttributes. First, you define what attribute you want to animate e.g. the vertices:

geometry.morphAttributes.position = [];

In the next step you add morph targets to this array. Each morph target is represented as a buffer attribute that requires the same count and item size like the actual position attribute. In the fiddle the code just clones the existing position attribute and applies a random transformation to it:

for ( var i = 2; i <= 8; i ++ ) {

	var morphTarget = positionAttribute.clone();
	morphTarget.name = 'target_' + i;
	
	// generate some random morph data
	
	s.set( 1, 1, 1 ).multiplyScalar( Math.random() );
	morphTarget.applyMatrix4( m.identity().scale( s ) );
	
	// add it to the geometry
	
	geometry.morphAttributes.position.push( morphTarget );

}

You can then generate an animation clip from the defined morph targets:

var clip = THREE.AnimationClip.CreateFromMorphTargetSequence( 'clip', geometry.morphAttributes.position, 4 );

The second step of this workflow (the generation of morph targets) is application specific it will look different in your code.

4 Likes

/cc

Thank you very much for your detailed reply; it looks very promising. I’m still very new to Three so it will take me a while to digest, but I’ll be sure to post back if/when I have a complete solution.