提交 d6f2228b 编写于 作者: M Mugen87

BVHLoader: Clean up

上级 bf4f6cba
/** /**
* @author herzig / http://github.com/herzig * @author herzig / http://github.com/herzig
* * @author Mugen87 / https://github.com/Mugen87
* Description: reads BVH files and outputs a single THREE.Skeleton and an THREE.AnimationClip *
* * Description: reads BVH files and outputs a single THREE.Skeleton and an THREE.AnimationClip
* Currently only supports bvh files containing a single root. *
* * Currently only supports bvh files containing a single root.
*/ *
*/
THREE.BVHLoader = function( manager ) { THREE.BVHLoader = function( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
this.animateBonePositions = true; this.animateBonePositions = true;
this.animateBoneRotations = true; this.animateBoneRotations = true;
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
}; };
THREE.BVHLoader.prototype = { THREE.BVHLoader.prototype = {
...@@ -40,14 +41,15 @@ THREE.BVHLoader.prototype = { ...@@ -40,14 +41,15 @@ THREE.BVHLoader.prototype = {
and outputs a skeleton structure including motion data and outputs a skeleton structure including motion data
returns thee root node: returns thee root node:
{ name: "", channels: [], children: [] } { name: '', channels: [], children: [] }
*/ */
function readBvh( lines ) { function readBvh( lines ) {
// read model structure // read model structure
if ( nextLine( lines ) !== "HIERARCHY" ) {
throw "HIERARCHY expected"; if ( nextLine( lines ) !== 'HIERARCHY' ) {
console.error( 'THREE.BVHLoader: HIERARCHY expected.' );
} }
...@@ -55,35 +57,40 @@ THREE.BVHLoader.prototype = { ...@@ -55,35 +57,40 @@ THREE.BVHLoader.prototype = {
var root = readNode( lines, nextLine( lines ), list ); var root = readNode( lines, nextLine( lines ), list );
// read motion data // read motion data
if ( nextLine( lines ) != "MOTION" ) {
throw "MOTION expected"; if ( nextLine( lines ) !== 'MOTION' ) {
console.error( 'THREE.BVHLoader: MOTION expected.' );
} }
// number of frames // number of frames
var tokens = nextLine( lines ).split( /[\s]+/ ); var tokens = nextLine( lines ).split( /[\s]+/ );
var numFrames = parseInt( tokens[ 1 ] ); var numFrames = parseInt( tokens[ 1 ] );
if ( isNaN( numFrames ) ) { if ( isNaN( numFrames ) ) {
throw "Failed to read number of frames."; console.error( 'THREE.BVHLoader: Failed to read number of frames.' );
} }
// frame time // frame time
tokens = nextLine( lines ).split( /[\s]+/ ); tokens = nextLine( lines ).split( /[\s]+/ );
var frameTime = parseFloat( tokens[ 2 ] ); var frameTime = parseFloat( tokens[ 2 ] );
if ( isNaN( frameTime ) ) { if ( isNaN( frameTime ) ) {
throw "Failed to read frame time."; console.error( 'THREE.BVHLoader: Failed to read frame time.' );
} }
// read frame data line by line // read frame data line by line
for ( var i = 0; i < numFrames; ++ i ) {
tokens = nextLine( lines ).split( /[\s]+/ ); for ( var i = 0; i < numFrames; i ++ ) {
tokens = nextLine( lines ).split( /[\s]+/ );
readFrameData( tokens, i * frameTime, root ); readFrameData( tokens, i * frameTime, root );
} }
...@@ -105,16 +112,14 @@ THREE.BVHLoader.prototype = { ...@@ -105,16 +112,14 @@ THREE.BVHLoader.prototype = {
function readFrameData( data, frameTime, bone ) { function readFrameData( data, frameTime, bone ) {
// end sites have no motion data // end sites have no motion data
if ( bone.type === "ENDSITE" ) {
return; if ( bone.type === 'ENDSITE' ) return;
}
// add keyframe // add keyframe
var keyframe = { var keyframe = {
time: frameTime, time: frameTime,
position: { x: 0, y: 0, z: 0 }, position: new THREE.Vector3(),
rotation: new THREE.Quaternion() rotation: new THREE.Quaternion()
}; };
...@@ -127,40 +132,42 @@ THREE.BVHLoader.prototype = { ...@@ -127,40 +132,42 @@ THREE.BVHLoader.prototype = {
var vz = new THREE.Vector3( 0, 0, 1 ); var vz = new THREE.Vector3( 0, 0, 1 );
// parse values for each channel in node // parse values for each channel in node
for ( var i = 0; i < bone.channels.length; ++ i ) {
for ( var i = 0; i < bone.channels.length; i ++ ) {
switch ( bone.channels[ i ] ) { switch ( bone.channels[ i ] ) {
case "Xposition": case 'Xposition':
keyframe.position.x = parseFloat( data.shift().trim() ); keyframe.position.x = parseFloat( data.shift().trim() );
break; break;
case "Yposition": case 'Yposition':
keyframe.position.y = parseFloat( data.shift().trim() ); keyframe.position.y = parseFloat( data.shift().trim() );
break; break;
case "Zposition": case 'Zposition':
keyframe.position.z = parseFloat( data.shift().trim() ); keyframe.position.z = parseFloat( data.shift().trim() );
break; break;
case "Xrotation": case 'Xrotation':
quat.setFromAxisAngle( vx, parseFloat( data.shift().trim() ) * Math.PI / 180 ); quat.setFromAxisAngle( vx, parseFloat( data.shift().trim() ) * Math.PI / 180 );
keyframe.rotation.multiply( quat ); keyframe.rotation.multiply( quat );
break; break;
case "Yrotation": case 'Yrotation':
quat.setFromAxisAngle( vy, parseFloat( data.shift().trim() ) * Math.PI / 180 ); quat.setFromAxisAngle( vy, parseFloat( data.shift().trim() ) * Math.PI / 180 );
keyframe.rotation.multiply( quat ); keyframe.rotation.multiply( quat );
break; break;
case "Zrotation": case 'Zrotation':
quat.setFromAxisAngle( vz, parseFloat( data.shift().trim() ) * Math.PI / 180 ); quat.setFromAxisAngle( vz, parseFloat( data.shift().trim() ) * Math.PI / 180 );
keyframe.rotation.multiply( quat ); keyframe.rotation.multiply( quat );
break; break;
default: default:
throw "invalid channel type"; console.warn( 'THREE.BVHLoader: Invalid channel type.' );
} }
} }
// parse child nodes // parse child nodes
for ( var i = 0; i < bone.children.length; ++ i ) {
for ( var i = 0; i < bone.children.length; i ++ ) {
readFrameData( data, frameTime, bone.children[ i ] ); readFrameData( data, frameTime, bone.children[ i ] );
...@@ -172,23 +179,24 @@ THREE.BVHLoader.prototype = { ...@@ -172,23 +179,24 @@ THREE.BVHLoader.prototype = {
Recursively parses the HIERACHY section of the BVH file Recursively parses the HIERACHY section of the BVH file
- lines: all lines of the file. lines are consumed as we go along. - lines: all lines of the file. lines are consumed as we go along.
- firstline: line containing the node type and name e.g. "JOINT hip" - firstline: line containing the node type and name e.g. 'JOINT hip'
- list: collects a flat list of nodes - list: collects a flat list of nodes
returns: a BVH node including children returns: a BVH node including children
*/ */
function readNode( lines, firstline, list ) { function readNode( lines, firstline, list ) {
var node = { name: "", type: "", frames: [] }; var node = { name: '', type: '', frames: [] };
list.push( node ); list.push( node );
// parse node type and name. // parse node type and name
var tokens = firstline.split( /[\s]+/ ); var tokens = firstline.split( /[\s]+/ );
if ( tokens[ 0 ].toUpperCase() === "END" && tokens[ 1 ].toUpperCase() === "SITE" ) { if ( tokens[ 0 ].toUpperCase() === 'END' && tokens[ 1 ].toUpperCase() === 'SITE' ) {
node.type = "ENDSITE"; node.type = 'ENDSITE';
node.name = "ENDSITE"; // bvh end sites have no name node.name = 'ENDSITE'; // bvh end sites have no name
} else { } else {
...@@ -197,49 +205,51 @@ THREE.BVHLoader.prototype = { ...@@ -197,49 +205,51 @@ THREE.BVHLoader.prototype = {
} }
if ( nextLine( lines ) != "{" ) { if ( nextLine( lines ) !== '{' ) {
throw "Expected opening { after type & name"; console.error( 'THREE.BVHLoader: Expected opening { after type & name' );
} }
// parse OFFSET // parse OFFSET
tokens = nextLine( lines ).split( /[\s]+/ ); tokens = nextLine( lines ).split( /[\s]+/ );
if ( tokens[ 0 ] !== "OFFSET" ) { if ( tokens[ 0 ] !== 'OFFSET' ) {
throw "Expected OFFSET, but got: " + tokens[ 0 ]; console.error( 'THREE.BVHLoader: Expected OFFSET but got: ' + tokens[ 0 ] );
} }
if ( tokens.length != 4 ) { if ( tokens.length !== 4 ) {
throw "OFFSET: Invalid number of values"; console.error( 'THREE.BVHLoader: Invalid number of values for OFFSET.' );
} }
var offset = { var offset = new THREE.Vector3(
x: parseFloat( tokens[ 1 ] ), parseFloat( tokens[ 1 ] ),
y: parseFloat( tokens[ 2 ] ), parseFloat( tokens[ 2 ] ),
z: parseFloat( tokens[ 3 ] ) parseFloat( tokens[ 3 ] )
}; );
if ( isNaN( offset.x ) || isNaN( offset.y ) || isNaN( offset.z ) ) { if ( isNaN( offset.x ) || isNaN( offset.y ) || isNaN( offset.z ) ) {
throw "OFFSET: Invalid values"; console.error( 'THREE.BVHLoader: Invalid values of OFFSET.' );
} }
node.offset = offset; node.offset = offset;
// parse CHANNELS definitions // parse CHANNELS definitions
if ( node.type != "ENDSITE" ) {
if ( node.type !== 'ENDSITE' ) {
tokens = nextLine( lines ).split( /[\s]+/ ); tokens = nextLine( lines ).split( /[\s]+/ );
if ( tokens[ 0 ] != "CHANNELS" ) { if ( tokens[ 0 ] !== 'CHANNELS' ) {
throw "Expected CHANNELS definition"; console.error( 'THREE.BVHLoader: Expected CHANNELS definition.' );
} }
...@@ -250,11 +260,12 @@ THREE.BVHLoader.prototype = { ...@@ -250,11 +260,12 @@ THREE.BVHLoader.prototype = {
} }
// read children // read children
while ( true ) { while ( true ) {
var line = nextLine( lines ); var line = nextLine( lines );
if ( line === "}" ) { if ( line === '}' ) {
return node; return node;
...@@ -284,9 +295,9 @@ THREE.BVHLoader.prototype = { ...@@ -284,9 +295,9 @@ THREE.BVHLoader.prototype = {
bone.position.add( source.offset ); bone.position.add( source.offset );
bone.name = source.name; bone.name = source.name;
if ( source.type != "ENDSITE" ) { if ( source.type !== 'ENDSITE' ) {
for ( var i = 0; i < source.children.length; ++ i ) { for ( var i = 0; i < source.children.length; i ++ ) {
bone.add( toTHREEBone( source.children[ i ], list ) ); bone.add( toTHREEBone( source.children[ i ], list ) );
...@@ -310,19 +321,21 @@ THREE.BVHLoader.prototype = { ...@@ -310,19 +321,21 @@ THREE.BVHLoader.prototype = {
var tracks = []; var tracks = [];
// create a position and quaternion animation track for each node // create a position and quaternion animation track for each node
for ( var i = 0; i < bones.length; ++ i ) {
for ( var i = 0; i < bones.length; i ++ ) {
var bone = bones[ i ]; var bone = bones[ i ];
if ( bone.type == "ENDSITE" ) if ( bone.type === 'ENDSITE' )
continue; continue;
// track data // track data
var times = []; var times = [];
var positions = []; var positions = [];
var rotations = []; var rotations = [];
for ( var j = 0; j < bone.frames.length; ++ j ) { for ( var j = 0; j < bone.frames.length; j ++ ) {
var frame = bone.frames[ j ]; var frame = bone.frames[ j ];
...@@ -330,6 +343,7 @@ THREE.BVHLoader.prototype = { ...@@ -330,6 +343,7 @@ THREE.BVHLoader.prototype = {
// the animation system animates the position property, // the animation system animates the position property,
// so we have to add the joint offset to all values // so we have to add the joint offset to all values
positions.push( frame.position.x + bone.offset.x ); positions.push( frame.position.x + bone.offset.x );
positions.push( frame.position.y + bone.offset.y ); positions.push( frame.position.y + bone.offset.y );
positions.push( frame.position.z + bone.offset.z ); positions.push( frame.position.z + bone.offset.z );
...@@ -343,21 +357,19 @@ THREE.BVHLoader.prototype = { ...@@ -343,21 +357,19 @@ THREE.BVHLoader.prototype = {
if ( scope.animateBonePositions ) { if ( scope.animateBonePositions ) {
tracks.push( new THREE.VectorKeyframeTrack( tracks.push( new THREE.VectorKeyframeTrack( '.bones[' + bone.name + '].position', times, positions ) );
".bones[" + bone.name + "].position", times, positions ) );
} }
if ( scope.animateBoneRotations ) { if ( scope.animateBoneRotations ) {
tracks.push( new THREE.QuaternionKeyframeTrack( tracks.push( new THREE.QuaternionKeyframeTrack( '.bones[' + bone.name + '].quaternion', times, rotations ) );
".bones[" + bone.name + "].quaternion", times, rotations ) );
} }
} }
return new THREE.AnimationClip( "animation", - 1, tracks ); return new THREE.AnimationClip( 'animation', - 1, tracks );
} }
......
<html> <!DOCTYPE html>
<html lang="en">
<head> <head>
<title>three.js webgl - BVHLoader</title> <title>three.js webgl - loaders - BVHLoader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style> <style>
body { body {
color: #fff; color: #fff;
...@@ -26,7 +29,7 @@ ...@@ -26,7 +29,7 @@
</head> </head>
<body> <body>
<div id="info"> <div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - BVH Loader - <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> - BVH Loader -
animation from <a href="http://mocap.cs.cmu.edu/">http://mocap.cs.cmu.edu/</a> animation from <a href="http://mocap.cs.cmu.edu/">http://mocap.cs.cmu.edu/</a>
</div> </div>
<script src="../build/three.js"></script> <script src="../build/three.js"></script>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册