//Quaternion 执行一个四元数。这是用来旋转的东西, 而不会遇到可怕的 万向节锁问题等优点。
function Quaternion( x, y, z, w ) { // 设置 _x,_y,_z,w四个轴的值和默认值
this._x = x || 0;
this._y = y || 0;
this._z = z || 0;
this._w = ( w !== undefined ) ? w : 1;
}
Object.assign( Quaternion, {
// slerp 线性插值 , qa,qb,qm为 Quaternion 对象 ,t为线性插值的系数
slerp: function ( qa, qb, qm, t ) {
// qm复制 qa的值 ,然后执行 原型链中的slerp方法
return qm.copy( qa ).slerp( qb, t );
},
slerpFlat: function ( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
// fuzz-free, array-based Quaternion SLERP operation
var x0 = src0[ srcOffset0 + 0 ],
y0 = src0[ srcOffset0 + 1 ],
z0 = src0[ srcOffset0 + 2 ],
w0 = src0[ srcOffset0 + 3 ],
x1 = src1[ srcOffset1 + 0 ],
y1 = src1[ srcOffset1 + 1 ],
z1 = src1[ srcOffset1 + 2 ],
w1 = src1[ srcOffset1 + 3 ];
if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
var s = 1 - t,
cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
dir = ( cos >= 0 ? 1 : - 1 ),
sqrSin = 1 - cos * cos;
// Skip the Slerp for tiny steps to avoid numeric problems: 该Number.EPSILON
属性表示1与大于1的最小浮点数之间的差值.js中的最小误差,具体可参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON if ( sqrSin > Number.EPSILON ) {
var sin = Math.sqrt( sqrSin ),
len = Math.atan2( sin, cos * dir );
s = Math.sin( s * len ) / sin;
t = Math.sin( t * len ) / sin;
}
var tDir = t * dir;
x0 = x0 * s + x1 * tDir;
y0 = y0 * s + y1 * tDir;
z0 = z0 * s + z1 * tDir;
w0 = w0 * s + w1 * tDir;
// Normalize in case we just did a lerp:
if ( s === 1 - t ) {
var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
x0 *= f;
y0 *= f;
z0 *= f;
w0 *= f;
}
}
dst[ dstOffset ] = x0;
dst[ dstOffset + 1 ] = y0;
dst[ dstOffset + 2 ] = z0;
dst[ dstOffset + 3 ] = w0;
}
} );
Object.defineProperties( Quaternion.prototype, {
// 设定 x,y,z,w的值
x: {
get: function () {
return this._x;
},
set: function ( value ) {
this._x = value;
this.onChangeCallback();
}
},
y: {
get: function () {
return this._y;
},
set: function ( value ) {
this._y = value;
this.onChangeCallback();
}
},
z: {
get: function () {
return this._z;
},
set: function ( value ) {
this._z = value;
this.onChangeCallback();
}
},
w: {
get: function () {
return this._w;
},
set: function ( value ) {
this._w = value;
this.onChangeCallback();
}
}
} );
Object.assign( Quaternion.prototype, {
// set方法设置值
set: function ( x, y, z, w ) {
this._x = x;
this._y = y;
this._z = z;
this._w = w;
this.onChangeCallback();
return this;
},
// 克隆一个与现在对象相同值的对象
clone: function () {
return new this.constructor( this._x, this._y, this._z, this._w );
},
// 把现在的对象赋值给新的quaternion 对象
copy: function ( quaternion ) {
this._x = quaternion.x;
this._y = quaternion.y;
this._z = quaternion.z;
this._w = quaternion.w;
this.onChangeCallback();
return this;
},
setFromEuler: function ( euler, update ) {
// euler 判断如果不是(euler)欧拉对象,抛出错误
if ( ! ( euler && euler.isEuler ) ) {
throw new Error( 'THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.' );
}
// 里面的逻辑暂时不是很明白,,为什么这样计算,返回这个四元素
var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
// content/SpinCalc.m
var cos = Math.cos;
var sin = Math.sin;
var c1 = cos( x / 2 );
var c2 = cos( y / 2 );
var c3 = cos( z / 2 );
var s1 = sin( x / 2 );
var s2 = sin( y / 2 );
var s3 = sin( z / 2 );
if ( order === 'XYZ' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'YXZ' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
} else if ( order === 'ZXY' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'ZYX' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
} else if ( order === 'YZX' ) {
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
} else if ( order === 'XZY' ) {
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
}
if ( update !== false ) this.onChangeCallback();
return this;
},
setFromAxisAngle: function ( axis, angle ) {
// 设置由旋转轴和角度指定的旋转四元数。从这里的方法改编。假定轴被标准化,
// assumes axis is normalized
var halfAngle = angle / 2 , s = Math. sin ( halfAngle ) ;
this . _x = axis.x * s ;
this . _y = axis.y * s ;
this . _z = axis.z * s ;
this . _w = Math. cos ( halfAngle ) ;
this . onChangeCallback () ;
return this ;
} ,
// 传入一个 4 *4的矩阵,前面3*3的矩阵,必须是旋转矩阵
setFromRotationMatrix : function ( m ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var te = m. elements ,
m11 = te[ 0 ] , m12 = te[ 4 ] , m13 = te[ 8 ] ,
m21 = te[ 1 ] , m22 = te[ 5 ] , m23 = te[ 9 ] ,
m31 = te[ 2 ] , m32 = te[ 6 ] , m33 = te[ 10 ] ,
trace = m11 + m22 + m33 ,
s ;
if ( trace > 0 ) {
// Math.sqrt 求平方根
s = 0.5 / Math. sqrt ( trace + 1.0 ) ;
this . _w = 0.25 / s ;
this . _x = ( m32 - m23 ) * s ;
this . _y = ( m13 - m31 ) * s ;
this . _z = ( m21 - m12 ) * s ;
} else if ( m11 > m22 && m11 > m33 ) {
s = 2.0 * Math. sqrt ( 1.0 + m11 - m22 - m33 ) ;
this . _w = ( m32 - m23 ) / s ;
this . _x = 0.25 * s ;
this . _y = ( m12 + m21 ) / s ;
this . _z = ( m13 + m31 ) / s ;
} else if ( m22 > m33 ) {
s = 2.0 * Math. sqrt ( 1.0 + m22 - m11 - m33 ) ;
this . _w = ( m13 - m31 ) / s ;
this . _x = ( m12 + m21 ) / s ;
this . _y = 0.25 * s ;
this . _z = ( m23 + m32 ) / s ;
} else {
s = 2.0 * Math. sqrt ( 1.0 + m33 - m11 - m22 ) ;
this . _w = ( m21 - m12 ) / s ;
this . _x = ( m13 + m31 ) / s ;
this . _y = ( m23 + m32 ) / s ;
this . _z = 0.25 * s ;
}
this . onChangeCallback () ;
return this ;
} ,
setFromUnitVectors : function () {
// assumes direction vectors vFrom and vTo are normalized
var v1 = new Vector3 () ;
var r ;
var EPS = 0.000001 ;
return function setFromUnitVectors( vFrom , vTo ) {
if ( v1 === undefined ) v1 = new Vector3 () ;
// vFrom.dot( vTo ) 两个向量的点乘结果 ,即 a.dot(b) ====》 |a| * |b| * cos @ (@为两向量的夹角)
r = vFrom. dot ( vTo ) + 1 ;
if ( r < EPS ) {
r = 0 ;
if ( Math. abs ( vFrom.x ) > Math. abs ( vFrom.z ) ) {
v1.set( - vFrom.y , vFrom.x , 0 ) ;
} else {
v1.set( 0 , - vFrom.z , vFrom.y ) ;
}
} else {
// v1 为向量 vFrom 和 vTo的叉乘的结果
v1. crossVectors ( vFrom , vTo ) ;
}
this . _x = v1. x ;
this . _y = v1. y ;
this . _z = v1. z ;
this . _w = r ;
return this . normalize () ;
} ;
}() ,
// 返回标准的相反的四元数
inverse : function () {
return this . conjugate (). normalize () ;
} ,
// 返回相反的四元数
conjugate : function () {
this . _x *= - 1 ;
this . _y *= - 1 ;
this . _z *= - 1 ;
this . onChangeCallback () ;
return this ;
} ,
// 两个四元数的点乘
dot : function ( v ) {
return this ._x * v._x + this ._y * v._y + this ._z * v._z + this ._w * v._w ;
} ,
// 四元数长度的平方
lengthSq : function () {
return this ._x * this ._x + this ._y * this ._y + this ._z * this ._z + this ._w * this ._w ;
} ,
// 四元素的长度
length : function () {
return Math. sqrt ( this ._x * this ._x + this ._y * this ._y + this ._z * this ._z + this ._w * this ._w ) ;
} ,
// 将四元数进行归一化
normalize : function () {
var l = this . length () ;
if ( l === 0 ) {
this . _x = 0 ;
this . _y = 0 ;
this . _z = 0 ;
this . _w = 1 ;
} else {
l = 1 / l ;
this . _x = this . _x * l ;
this . _y = this . _y * l ;
this . _z = this . _z * l ;
this . _w = this . _w * l ;
}
this . onChangeCallback () ;
return this ;
} ,
multiply : function ( q , p ) {
// 如果传两个参
if ( p !== undefined ) {
// 警告:multiply 现在仅接受一个参数,use multiplyQuaternions ,代替,可能是后期API变更引起的
console . warn ( 'THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ) ; // 返回 multiplyQuaternions 函数执行的结果
return this . multiplyQuaternions ( q , p ) ;
}
// 否则 返回 当前的 Quaternions 与 q这个 Quaternions 的结果
return this . multiplyQuaternions ( this , q ) ;
} ,
// 前乘矩阵 ,矩阵不满足交换律,所以前乘和后乘是不一样的
premultiply : function ( q ) {
return this . multiplyQuaternions ( q , this ) ;
} ,
// 将 a和b两个Quaternions ,相乘,并且将结果给了,现在的Quaternions
multiplyQuaternions : function ( a , b ) {
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
var qax = a._x , qay = a._y , qaz = a._z , qaw = a._w ;
var qbx = b._x , qby = b._y , qbz = b._z , qbw = b._w ;
this . _x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby ;
this . _y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz ;
this . _z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx ;
this . _w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz ;
this . onChangeCallback () ;
return this ;
} ,
// 不是很理解算法, 下面是官网网站的解释:v 代表 qb , t 待变alpha v - Vector3 向内插。
alpha 在闭区间[0,1]中的α - 插值因子。
在这个向量和qb 之间进行线性插值,其中alpha是沿线的距离 - alpha = 0将是这个向量,alpha = 1将是 v 。
slerp : function ( qb , t ) {
if ( t === 0 ) return this ;
if ( t === 1 ) return this . copy ( qb ) ;
var x = this . _x , y = this . _y , z = this . _z , w = this . _w ;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z ;
if ( cosHalfTheta < 0 ) {
this . _w = - qb._w ;
this . _x = - qb._x ;
this . _y = - qb._y ;
this . _z = - qb._z ;
cosHalfTheta = - cosHalfTheta ;
} else {
this . copy ( qb ) ;
}
if ( cosHalfTheta >= 1.0 ) {
this . _w = w ;
this . _x = x ;
this . _y = y ;
this . _z = z ;
return this ;
}
var sinHalfTheta = Math. sqrt ( 1.0 - cosHalfTheta * cosHalfTheta ) ;
if ( Math. abs ( sinHalfTheta ) < 0.001 ) {
this . _w = 0.5 * ( w + this . _w ) ;
this . _x = 0.5 * ( x + this . _x ) ;
this . _y = 0.5 * ( y + this . _y ) ;
this . _z = 0.5 * ( z + this . _z ) ;
return this ;
}
// Math.atan2 ,求弧度 参数 Math.atan2(y,x),
var halfTheta = Math. atan2 ( sinHalfTheta , cosHalfTheta ) ;
var ratioA = Math. sin ( ( 1 - t ) * halfTheta ) / sinHalfTheta ,
ratioB = Math. sin ( t * halfTheta ) / sinHalfTheta ;
this . _w = ( w * ratioA + this . _w * ratioB ) ;
this . _x = ( x * ratioA + this . _x * ratioB ) ;
this . _y = ( y * ratioA + this . _y * ratioB ) ;
this . _z = ( z * ratioA + this . _z * ratioB ) ;
this . onChangeCallback () ;
return this ;
} ,
// 判断两个quaternion ,是否完全相等
equals : function ( quaternion ) {
return ( quaternion._x === this ._x ) && ( quaternion._y === this ._y ) && ( quaternion._z === this ._z ) && ( quaternion._w === this ._w ) ;
} ,
// 将数组的值赋值给quaternion
fromArray : function ( array , offset ) {
if ( offset === undefined ) offset = 0 ;
this . _x = array[ offset ] ;
this . _y = array[ offset + 1 ] ;
this . _z = array[ offset + 2 ] ;
this . _w = array[ offset + 3 ] ;
this . onChangeCallback () ;
return this ;
} ,
// 将 quaternion 的值赋值给数组
toArray : function ( array , offset ) {
if ( array === undefined ) array = [] ;
if ( offset === undefined ) offset = 0 ;
array[ offset ] = this ._x ;
array[ offset + 1 ] = this ._y ;
array[ offset + 2 ] = this ._z ;
array[ offset + 3 ] = this ._w ;
return array ;
} ,
// 指定onChangeCallback 函数的值
onChange : function ( callback ) {
this . onChangeCallback = callback ;
return this ;
} ,
onChangeCallback : function () {}
} ) ;