소스 검색

Examples: Added MDDLoader.

Mugen87 5 년 전
부모
커밋
5b35d8bfee
5개의 변경된 파일230개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      examples/files.js
  2. 20 0
      examples/jsm/loaders/MDDLoader.d.ts
  3. 106 0
      examples/jsm/loaders/MDDLoader.js
  4. BIN
      examples/models/mdd/cube.mdd
  5. 103 0
      examples/webgl_loader_mdd.html

+ 1 - 0
examples/files.js

@@ -98,6 +98,7 @@ var files = {
 		"webgl_loader_lwo",
 		"webgl_loader_md2",
 		"webgl_loader_md2_control",
+		"webgl_loader_mdd",
 		"webgl_loader_mmd",
 		"webgl_loader_mmd_pose",
 		"webgl_loader_mmd_audio",

+ 20 - 0
examples/jsm/loaders/MDDLoader.d.ts

@@ -0,0 +1,20 @@
+import {
+	AnimationClip,
+	BufferAttribute,
+	Loader,
+	LoadingManager
+} from '../../../src/Three';
+
+export interface MDD {
+	morphTargets: BufferAttribute[];
+	clip: AnimationClip;
+}
+
+export class MDDLoader extends Loader {
+
+	constructor( manager?: LoadingManager );
+
+	load( url: string, onLoad: ( result: MDD ) => void, onProgress?: ( event: ProgressEvent ) => void, onError?: ( event: ErrorEvent ) => void ) : void;
+	parse( data: ArrayBuffer ) : MDD;
+
+}

+ 106 - 0
examples/jsm/loaders/MDDLoader.js

@@ -0,0 +1,106 @@
+/**
+ * @author Mugen87 / https://github.com/Mugen87
+ *
+ * MDD is a special format that stores a position for every vertex in a model for every frame in an animation.
+ * Similar to BVH, it can be used to transfer animation data between different 3D applications or engines.
+ *
+ * MDD stores its data in binary format (big endian) in the following way:
+ *
+ * number of frames (a single uint32)
+ * number of vertices (a single uint32)
+ * time values for each frame (sequence of float32)
+ * vertex data for each frame (sequence of float32)
+ */
+
+import {
+	AnimationClip,
+	BufferAttribute,
+	FileLoader,
+	Loader,
+	NumberKeyframeTrack
+} from "../../../build/three.module.js";
+
+var MDDLoader = function ( manager ) {
+
+	Loader.call( this, manager );
+
+};
+
+MDDLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
+
+	constructor: MDDLoader,
+
+	load: function ( url, onLoad, onProgress, onError ) {
+
+		var scope = this;
+
+		var loader = new FileLoader( this.manager );
+		loader.setPath( this.path );
+		loader.setResponseType( 'arraybuffer' );
+		loader.load( url, function ( data ) {
+
+			onLoad( scope.parse( data ) );
+
+		}, onProgress, onError );
+
+	},
+
+	parse: function ( data ) {
+
+		var view = new DataView( data );
+
+		var totalFrames = view.getUint32( 0 );
+		var totalPoints = view.getUint32( 4 );
+
+		var offset = 8;
+
+		// animation clip
+
+		var times = new Float32Array( totalFrames );
+		var values = new Float32Array( totalFrames * totalFrames ).fill( 0 );
+
+		for ( var i = 0; i < totalFrames; i ++ ) {
+
+			times[ i ] = view.getFloat32( offset ); offset += 4;
+			values[ ( totalFrames * i ) + i ] = 1;
+
+		}
+
+		var track = new NumberKeyframeTrack( '.morphTargetInfluences', times, values );
+		var clip = new AnimationClip( 'default', times[ times.length - 1 ], [ track ] );
+
+		// morph targets
+
+		var morphTargets = [];
+
+		for ( var i = 0; i < totalFrames; i ++ ) {
+
+			var morphTarget = new Float32Array( totalPoints * 3 );
+
+			for ( var j = 0; j < totalPoints; j ++ ) {
+
+				var stride = ( j * 3 );
+
+				morphTarget[ stride + 0 ] = view.getFloat32( offset ); offset += 4; // x
+				morphTarget[ stride + 1 ] = view.getFloat32( offset ); offset += 4; // y
+				morphTarget[ stride + 2 ] = view.getFloat32( offset ); offset += 4; // z
+
+			}
+
+			var attribute = new BufferAttribute( morphTarget, 3 );
+			attribute.name = 'morph_' + i;
+
+			morphTargets.push( attribute );
+
+		}
+
+		return {
+			morphTargets: morphTargets,
+			clip: clip
+		};
+
+	}
+
+} );
+
+export { MDDLoader };

BIN
examples/models/mdd/cube.mdd


+ 103 - 0
examples/webgl_loader_mdd.html

@@ -0,0 +1,103 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js WebGL - MDDLoader</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">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - MDDLoader
+		</div>
+
+		<script type="module">
+
+			import * as THREE from '../build/three.module.js';
+
+			import { MDDLoader } from './jsm/loaders/MDDLoader.js';
+
+			var camera, scene, renderer, mixer, clock;
+
+			init();
+
+			function init() {
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.1, 100 );
+				camera.position.set( 10, 10, 10 );
+				camera.lookAt( scene.position );
+
+				clock = new THREE.Clock();
+
+				//
+
+				var hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 );
+				hemiLight.position.set( 0, 20, 0 );
+				scene.add( hemiLight );
+
+				var dirLight = new THREE.DirectionalLight( 0xffffff );
+				dirLight.position.set( - 3, 10, - 10 );
+				scene.add( dirLight );
+
+				//
+
+				var loader = new MDDLoader();
+				loader.load( 'models/mdd/cube.mdd', function ( result ) {
+
+					const morphTargets = result.morphTargets;
+					const clip = result.clip;
+					// clip.optimize(); // optional
+
+					var geometry = new THREE.BoxBufferGeometry();
+					geometry.morphAttributes.position = morphTargets; // apply morph targets
+
+					var material = new THREE.MeshPhongMaterial( { morphTargets: true } );
+
+					var mesh = new THREE.Mesh( geometry, material );
+					scene.add( mesh );
+
+					mixer = new THREE.AnimationMixer( mesh );
+					mixer.clipAction( clip ).play(); // use clip
+
+					animate();
+
+				} );
+
+				//
+
+				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, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				var delta = clock.getDelta();
+
+				if ( mixer ) mixer.update( delta );
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>