提交 d1aff495 编写于 作者: M Mr.doob

Fixed Quaternion::slerp.

上级 d1e3a9d8
......@@ -48,9 +48,10 @@ this.matrix.n12=this.matrixRotation.n12;this.matrix.n13=this.matrixRotation.n13;
b,c){if(this.visible){this.matrixAutoUpdate&&(b|=this.updateMatrix());if(b||this.matrixNeedsUpdate){a?this.matrixWorld.multiply(a,this.matrix):this.matrixWorld.copy(this.matrix);this.matrixNeedsUpdate=!1;b=!0}var d=this.children.length;for(a=0;a<d;a++)this.children[a].update(this.matrixWorld,b,c)}}};THREE.Object3DCounter={value:0};THREE.Quaternion=function(a,b,c,d){this.set(a||0,b||0,c||0,d!==undefined?d:1)};
THREE.Quaternion.prototype={set:function(a,b,c,d){this.x=a;this.y=b;this.z=c;this.w=d;return this},setFromEuler:function(a){var b=0.5*Math.PI/360,c=a.x*b,d=a.y*b,f=a.z*b;a=Math.cos(d);d=Math.sin(d);b=Math.cos(-f);f=Math.sin(-f);var g=Math.cos(c);c=Math.sin(c);var h=a*b,k=d*f;this.w=h*g-k*c;this.x=h*c+k*g;this.y=d*b*g+a*f*c;this.z=a*f*g-d*b*c;return this},calculateW:function(){this.w=-Math.sqrt(Math.abs(1-this.x*this.x-this.y*this.y-this.z*this.z));return this},inverse:function(){this.x*=-1;this.y*=
-1;this.z*=-1;return this},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)},normalize:function(){var a=Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w);if(a==0)this.w=this.z=this.y=this.x=0;else{a=1/a;this.x*=a;this.y*=a;this.z*=a;this.w*=a}return this},multiplySelf:function(a){var b=this.x,c=this.y,d=this.z,f=this.w,g=a.x,h=a.y,k=a.z;a=a.w;this.x=b*a+f*g+c*k-d*h;this.y=c*a+f*h+d*g-b*k;this.z=d*a+f*k+b*h-c*g;this.w=f*a-b*g-c*h-d*k;return this},
multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,f=a.z,g=this.x,h=this.y,k=this.z,j=this.w,m=j*c+h*f-k*d,n=j*d+k*c-g*f,w=j*f+g*d-h*c;c=-g*c-h*d-k*f;b.x=m*j+c*-g+n*-k-w*-h;b.y=n*j+c*-h+w*-g-m*-k;b.z=w*j+c*-k+m*-h-n*-g;return b},slerp:function(a,b,c,d){var f=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(Math.abs(f)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<0.001){c.w=0.5*(a.w+b.w);c.x=0.5*(a.x+b.x);c.y=0.5*(a.y+b.y);c.z=0.5*(a.z+b.z);return c}f=Math.sin((1-
d)*g)/h;d=Math.sin(d*g)/h;c.w=a.w*f+b.w*d;c.x=a.x*f+b.x*d;c.y=a.y*f+b.y*d;c.z=a.z*f+b.z*d;return c}};THREE.Vertex=function(a,b){this.position=a||new THREE.Vector3;this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.normal=b||new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.normalScreen=new THREE.Vector3;this.tangent=new THREE.Vector4;this.__visible=!0};
THREE.Vertex.prototype={toString:function(){return"THREE.Vertex ( position: "+this.position+", normal: "+this.normal+" )"}};THREE.Face3=function(a,b,c,d,f){this.a=a;this.b=b;this.c=c;this.centroid=new THREE.Vector3;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.materials=f instanceof Array?f:[f]};THREE.Face3.prototype={toString:function(){return"THREE.Face3 ( "+this.a+", "+this.b+", "+this.c+" )"}};
multiplyVector3:function(a,b){b||(b=a);var c=a.x,d=a.y,f=a.z,g=this.x,h=this.y,k=this.z,j=this.w,m=j*c+h*f-k*d,n=j*d+k*c-g*f,w=j*f+g*d-h*c;c=-g*c-h*d-k*f;b.x=m*j+c*-g+n*-k-w*-h;b.y=n*j+c*-h+w*-g-m*-k;b.z=w*j+c*-k+m*-h-n*-g;return b}};
THREE.Quaternion.slerp=function(a,b,c,d){var f=a.w*b.w+a.x*b.x+a.y*b.y+a.z*b.z;if(Math.abs(f)>=1){c.w=a.w;c.x=a.x;c.y=a.y;c.z=a.z;return c}var g=Math.acos(f),h=Math.sqrt(1-f*f);if(Math.abs(h)<0.001){c.w=0.5*(a.w+b.w);c.x=0.5*(a.x+b.x);c.y=0.5*(a.y+b.y);c.z=0.5*(a.z+b.z);return c}f=Math.sin((1-d)*g)/h;d=Math.sin(d*g)/h;c.w=a.w*f+b.w*d;c.x=a.x*f+b.x*d;c.y=a.y*f+b.y*d;c.z=a.z*f+b.z*d;return c};
THREE.Vertex=function(a,b){this.position=a||new THREE.Vector3;this.positionWorld=new THREE.Vector3;this.positionScreen=new THREE.Vector4;this.normal=b||new THREE.Vector3;this.normalWorld=new THREE.Vector3;this.normalScreen=new THREE.Vector3;this.tangent=new THREE.Vector4;this.__visible=!0};THREE.Vertex.prototype={toString:function(){return"THREE.Vertex ( position: "+this.position+", normal: "+this.normal+" )"}};
THREE.Face3=function(a,b,c,d,f){this.a=a;this.b=b;this.c=c;this.centroid=new THREE.Vector3;this.normal=d instanceof THREE.Vector3?d:new THREE.Vector3;this.vertexNormals=d instanceof Array?d:[];this.materials=f instanceof Array?f:[f]};THREE.Face3.prototype={toString:function(){return"THREE.Face3 ( "+this.a+", "+this.b+", "+this.c+" )"}};
THREE.Face4=function(a,b,c,d,f,g){this.a=a;this.b=b;this.c=c;this.d=d;this.centroid=new THREE.Vector3;this.normal=f instanceof THREE.Vector3?f:new THREE.Vector3;this.vertexNormals=f instanceof Array?f:[];this.materials=g instanceof Array?g:[g]};THREE.Face4.prototype={toString:function(){return"THREE.Face4 ( "+this.a+", "+this.b+", "+this.c+" "+this.d+" )"}};THREE.UV=function(a,b){this.set(a||0,b||0)};
THREE.UV.prototype={set:function(a,b){this.u=a;this.v=b;return this},copy:function(a){this.set(a.u,a.v);return this},toString:function(){return"THREE.UV ("+this.u+", "+this.v+")"}};THREE.Geometry=function(){this.id="Geometry"+THREE.GeometryIdCounter++;this.vertices=[];this.faces=[];this.uvs=[];this.uvs2=[];this.colors=[];this.skinWeights=[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.geometryChunks={};this.hasTangents=!1};
THREE.Geometry.prototype={computeCentroids:function(){var a,b,c;a=0;for(b=this.faces.length;a<b;a++){c=this.faces[a];c.centroid.set(0,0,0);if(c instanceof THREE.Face3){c.centroid.addSelf(this.vertices[c.a].position);c.centroid.addSelf(this.vertices[c.b].position);c.centroid.addSelf(this.vertices[c.c].position);c.centroid.divideScalar(3)}else if(c instanceof THREE.Face4){c.centroid.addSelf(this.vertices[c.a].position);c.centroid.addSelf(this.vertices[c.b].position);c.centroid.addSelf(this.vertices[c.c].position);
......
......@@ -3,33 +3,38 @@
*/
THREE.Animation = function( root, data ) {
this.root = root;
this.data = data;
this.root = root;
this.data = data;
this.hierarchy = [];
this.startTime = 0;
this.isPlaying = false;
this.loop = true;
this.offset = 0;
this.loop = true;
this.offset = 0;
// need to initialize data?
if( !this.data.initialized )
if( !this.data.initialized ) {
THREE.AnimationHandler.initData( this.data );
}
// setup hierarchy
if( root instanceof THREE.SkinnedMesh ) {
for( var b = 0; b < this.root.bones.length; b++ )
if ( root instanceof THREE.SkinnedMesh ) {
for( var b = 0; b < this.root.bones.length; b++ ) {
this.hierarchy.push( this.root.bones[ b ] );
}
} else {
// parse hierarchy and match against animation (somehow)
}
......@@ -44,36 +49,35 @@ THREE.Animation = function( root, data ) {
THREE.Animation.prototype.play = function( loop ) {
if( !this.isPlaying ) {
this.isPlaying = true;
this.startTime = new Date().getTime() * 0.001;
// reset key cache
for( var h = 0; h < this.hierarchy.length; h++ ) {
for ( var h = 0; h < this.hierarchy.length; h++ ) {
this.hierarchy[ h ].useQuaternion = true;
this.hierarchy[ h ].matrixAutoUpdate = true;
if( this.hierarchy[ h ].prevKey === undefined ) {
if ( this.hierarchy[ h ].prevKey === undefined ) {
this.hierarchy[ h ].prevKey = { pos: 0, rot: 0, scl: 0 };
this.hierarchy[ h ].nextKey = { pos: 0, rot: 0, scl: 0 };
}
this.hierarchy[ h ].prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ];
this.hierarchy[ h ].prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ];
this.hierarchy[ h ].prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ];
this.hierarchy[ h ].nextKey.pos = this.getNextKeyWith( "pos", h, 1 );
this.hierarchy[ h ].nextKey.rot = this.getNextKeyWith( "rot", h, 1 );
this.hierarchy[ h ].nextKey.scl = this.getNextKeyWith( "scl", h, 1 );
}
}
this.update();
THREE.AnimationHandler.add( this );
}
......@@ -86,9 +90,9 @@ THREE.Animation.prototype.play = function( loop ) {
*/
THREE.Animation.prototype.pause = function() {
THREE.AnimationHandler.remove( this );
// todo
}
......@@ -98,7 +102,7 @@ THREE.Animation.prototype.pause = function() {
*/
THREE.Animation.prototype.stop = function() {
this.isPlaying = false;
THREE.AnimationHandler.remove( this );
}
......@@ -110,15 +114,15 @@ THREE.Animation.prototype.stop = function() {
THREE.Animation.prototype.update = function( time ) {
// todo: add input time
// TODO: add input time
// early out
if( !this.isPlaying ) return;
// vars
var types = [ "pos", "rot", "scl" ];
var scale;
var relative;
......@@ -127,117 +131,116 @@ THREE.Animation.prototype.update = function( time ) {
var object;
var frame;
var JIThierarchy = this.data.JIT.hierarchy;
// update
var currentTime = new Date().getTime() * 0.001 - this.startTime + this.offset;
var unloopedCurrentTime = currentTime;
// looped?
if( currentTime > this.data.length ) {
while( currentTime > this.data.length )
if ( currentTime > this.data.length ) {
while( currentTime > this.data.length ) {
currentTime -= this.data.length;
}
this.startTime = new Date().getTime() * 0.001 - currentTime;
currentTime = new Date().getTime() * 0.001 - this.startTime;
}
frame = Math.min( parseInt( currentTime * this.data.fps ), parseInt( this.data.length * this.data.fps ) );
// update
for( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) {
object = this.hierarchy[ h ];
if( JIThierarchy[ h ][ frame ] !== undefined ) {
object.skinMatrix = JIThierarchy[ h ][ frame ];
object.matrixAutoUpdate = false;
object.matrixNeedsUpdate = false;
if ( JIThierarchy[ h ][ frame ] !== undefined ) {
object.skinMatrix = JIThierarchy[ h ][ frame ];
object.matrixAutoUpdate = false;
object.matrixNeedsUpdate = false;
object.skinMatrix.flattenToArrayOffset( this.root.boneMatrices, h * 16 );
}
else {
for( var t = 0; t < 3; t++ ) {
} else {
for ( var t = 0; t < 3; t++ ) {
// get keys
var type = types[ t ];
var prevKey = object.prevKey[ type ];
var nextKey = object.nextKey[ type ];
// switch keys?
if( nextKey.time < unloopedCurrentTime ) {
if ( nextKey.time < unloopedCurrentTime ) {
// did we loop?
if( currentTime < unloopedCurrentTime ) {
if( this.loop ) {
if ( currentTime < unloopedCurrentTime ) {
if ( this.loop ) {
prevKey = this.data.hierarchy[ h ].keys[ 0 ];
nextKey = this.getNextKeyWith( type, h, 1 );
} else {
this.stop();
return;
}
} else {
do {
prevKey = nextKey;
nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 );
}
while( nextKey.time < currentTime )
} while( nextKey.time < currentTime )
}
object.prevKey[ type ] = prevKey;
object.nextKey[ type ] = nextKey;
}
// interpolate rot (quaternion slerp)
object.matrixAutoUpdate = true;
object.matrixNeedsUpdate = true;
scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
scale = ( currentTime - prevKey.time ) / ( nextKey.time - prevKey.time );
prevXYZ = prevKey[ type ];
nextXYZ = nextKey[ type ];
if( type === "rot" ) {
if( scale < 0 || scale > 1 ) {
if ( type === "rot" ) {
if ( scale < 0 || scale > 1 ) {
console.log( "Scale out of bounds:" + scale );
scale = scale < 0 ? 0 : 1;
}
THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale );
}
// lerp pos/scl
else {
vector = type === "pos" ? object.position : object.scale;
vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale;
vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale;
......@@ -250,59 +253,45 @@ THREE.Animation.prototype.update = function( time ) {
}
}
// update JIT?
if( JIThierarchy[ 0 ][ frame ] === undefined ) {
if ( JIThierarchy[ 0 ][ frame ] === undefined ) {
this.hierarchy[ 0 ].update( undefined, true );
for( var h = 0; h < this.hierarchy.length; h++ )
for ( var h = 0; h < this.hierarchy.length; h++ ) {
JIThierarchy[ h ][ frame ] = this.hierarchy[ h ].skinMatrix.clone();
}
}
};
/*
* Update Object
*/
THREE.Animation.prototype.updateObject = function( h, currentTime, unloopedCurrentTime ) {
}
*/
THREE.Animation.prototype.updateObject = function( h, currentTime, unloopedCurrentTime ) {}
THREE.Animation.prototype.getNextKeyWith = function( type, h, key ) {
var keys = this.data.hierarchy[ h ].keys;
for( ; key < keys.length; key++ ) {
if( keys[ key ][ type ] !== undefined )
return keys[ key ];
}
return this.data.hierarchy[ h ].keys[ 0 ];
}
var keys = this.data.hierarchy[ h ].keys;
for ( ; key < keys.length; key++ ) {
if ( keys[ key ][ type ] !== undefined ) {
return keys[ key ];
}
}
return this.data.hierarchy[ h ].keys[ 0 ];
}
......@@ -139,43 +139,43 @@ THREE.Quaternion.prototype = {
return dest;
},
}
slerp : function ( qa, qb, qm, t ) {
}
var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
THREE.Quaternion.slerp = function ( qa, qb, qm, t ) {
if ( Math.abs( cosHalfTheta ) >= 1.0 ) {
var cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
qm.w = qa.w; qm.x = qa.x; qm.y = qa.y; qm.z = qa.z;
return qm;
if ( Math.abs( cosHalfTheta ) >= 1.0 ) {
}
qm.w = qa.w; qm.x = qa.x; qm.y = qa.y; qm.z = qa.z;
return qm;
var halfTheta = Math.acos( cosHalfTheta ),
sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
}
if ( Math.abs( sinHalfTheta ) < 0.001 ) {
var halfTheta = Math.acos( cosHalfTheta ),
sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta );
qm.w = 0.5 * ( qa.w + qb.w );
qm.x = 0.5 * ( qa.x + qb.x );
qm.y = 0.5 * ( qa.y + qb.y );
qm.z = 0.5 * ( qa.z + qb.z );
if ( Math.abs( sinHalfTheta ) < 0.001 ) {
return qm;
qm.w = 0.5 * ( qa.w + qb.w );
qm.x = 0.5 * ( qa.x + qb.x );
qm.y = 0.5 * ( qa.y + qb.y );
qm.z = 0.5 * ( qa.z + qb.z );
}
return qm;
var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
}
qm.w = ( qa.w * ratioA + qb.w * ratioB );
qm.x = ( qa.x * ratioA + qb.x * ratioB );
qm.y = ( qa.y * ratioA + qb.y * ratioB );
qm.z = ( qa.z * ratioA + qb.z * ratioB );
var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
return qm;
qm.w = ( qa.w * ratioA + qb.w * ratioB );
qm.x = ( qa.x * ratioA + qb.x * ratioB );
qm.y = ( qa.y * ratioA + qb.y * ratioB );
qm.z = ( qa.z * ratioA + qb.z * ratioB );
}
return qm;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册