three Quaternion 源码解读

//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 ) {
      

     // 设置由旋转轴和角度指定的旋转四元数。从这里的方法改编。假定轴被标准化,

         // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm

        // 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 () {}

} ) ;
发布了31 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_38694034/article/details/79269608