323 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			323 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								import {
							 | 
						||
| 
								 | 
							
									MathUtils,
							 | 
						||
| 
								 | 
							
									Mesh
							 | 
						||
| 
								 | 
							
								} from 'three';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class MorphBlendMesh extends Mesh {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									constructor( geometry, material ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										super( geometry, material );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.animationsMap = {};
							 | 
						||
| 
								 | 
							
										this.animationsList = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// prepare default animation
							 | 
						||
| 
								 | 
							
										// (all frames played together in 1 second)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const numFrames = Object.keys( this.morphTargetDictionary ).length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const name = '__default';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const startFrame = 0;
							 | 
						||
| 
								 | 
							
										const endFrame = numFrames - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const fps = numFrames / 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.createAnimation( name, startFrame, endFrame, fps );
							 | 
						||
| 
								 | 
							
										this.setAnimationWeight( name, 1 );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									createAnimation( name, start, end, fps ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											start: start,
							 | 
						||
| 
								 | 
							
											end: end,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											length: end - start + 1,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											fps: fps,
							 | 
						||
| 
								 | 
							
											duration: ( end - start ) / fps,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											lastFrame: 0,
							 | 
						||
| 
								 | 
							
											currentFrame: 0,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											active: false,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											time: 0,
							 | 
						||
| 
								 | 
							
											direction: 1,
							 | 
						||
| 
								 | 
							
											weight: 1,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											directionBackwards: false,
							 | 
						||
| 
								 | 
							
											mirroredLoop: false
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.animationsMap[ name ] = animation;
							 | 
						||
| 
								 | 
							
										this.animationsList.push( animation );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									autoCreateAnimations( fps ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const pattern = /([a-z]+)_?(\d+)/i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let firstAnimation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const frameRanges = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let i = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( const key in this.morphTargetDictionary ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const chunks = key.match( pattern );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( chunks && chunks.length > 1 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const name = chunks[ 1 ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: - Infinity };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const range = frameRanges[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( i < range.start ) range.start = i;
							 | 
						||
| 
								 | 
							
												if ( i > range.end ) range.end = i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( ! firstAnimation ) firstAnimation = name;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											i ++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( const name in frameRanges ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const range = frameRanges[ name ];
							 | 
						||
| 
								 | 
							
											this.createAnimation( name, range.start, range.end, fps );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.firstAnimation = firstAnimation;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationDirectionForward( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.direction = 1;
							 | 
						||
| 
								 | 
							
											animation.directionBackwards = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationDirectionBackward( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.direction = - 1;
							 | 
						||
| 
								 | 
							
											animation.directionBackwards = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationFPS( name, fps ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.fps = fps;
							 | 
						||
| 
								 | 
							
											animation.duration = ( animation.end - animation.start ) / animation.fps;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationDuration( name, duration ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.duration = duration;
							 | 
						||
| 
								 | 
							
											animation.fps = ( animation.end - animation.start ) / animation.duration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationWeight( name, weight ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.weight = weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									setAnimationTime( name, time ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.time = time;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getAnimationTime( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let time = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											time = animation.time;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return time;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									getAnimationDuration( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										let duration = - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											duration = animation.duration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return duration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									playAnimation( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.time = 0;
							 | 
						||
| 
								 | 
							
											animation.active = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											console.warn( 'THREE.MorphBlendMesh: animation[' + name + '] undefined in .playAnimation()' );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									stopAnimation( name ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const animation = this.animationsMap[ name ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ( animation ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.active = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									update( delta ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for ( let i = 0, il = this.animationsList.length; i < il; i ++ ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const animation = this.animationsList[ i ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( ! animation.active ) continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const frameTime = animation.duration / animation.length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											animation.time += animation.direction * delta;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( animation.mirroredLoop ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( animation.time > animation.duration || animation.time < 0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													animation.direction *= - 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( animation.time > animation.duration ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														animation.time = animation.duration;
							 | 
						||
| 
								 | 
							
														animation.directionBackwards = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if ( animation.time < 0 ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														animation.time = 0;
							 | 
						||
| 
								 | 
							
														animation.directionBackwards = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												animation.time = animation.time % animation.duration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ( animation.time < 0 ) animation.time += animation.duration;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											const keyframe = animation.start + MathUtils.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 );
							 | 
						||
| 
								 | 
							
											const weight = animation.weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( keyframe !== animation.currentFrame ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ animation.lastFrame ] = 0;
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ keyframe ] = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												animation.lastFrame = animation.currentFrame;
							 | 
						||
| 
								 | 
							
												animation.currentFrame = keyframe;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											let mix = ( animation.time % frameTime ) / frameTime;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( animation.directionBackwards ) mix = 1 - mix;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ( animation.currentFrame !== animation.lastFrame ) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ animation.currentFrame ] = mix * weight;
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												this.morphTargetInfluences[ animation.currentFrame ] = weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								export { MorphBlendMesh };
							 |