三维空间旋转和Three.JS中的实现

三维空间中主要有两种几何变换,一种是位置的变换,位置变换和二维空间的是同样的。假设一点P(X1,Y1,Z1) 移动到Q(X2,Y2,Z2)只要简单的让P点的坐标值加上偏移值就能够了。可是三维空间的旋转变换就不能简单的使用二维空间的变换了。下面详细介绍一下三维空间的旋转。html

三维空间的旋转:

     二维空间的旋转能够看做是围绕点的旋转,只有一个自由度。而三维空间的旋转是围绕一条线旋转的。当旋转的轴是Z轴时,旋转能够看做是在二维平面XY平面的旋转,旋转的中心点是P(x=0,y=0)。按照右手法则,让拇指指向Z轴的正方向,四指指向为旋转的正方向。按照Y轴和X轴的旋转也相似。按照不一样的轴的旋转能够进行组合。好比,先按照Z轴旋转45度,再按照Y轴旋转45度。可是每个朝向均可以当作是物体在原始位置处围绕某一个轴转动了一个角度造成的。java

                                                                            

      三维空间的旋转有多种方式,如旋转矩阵,欧拉角,四元数:api

1 .欧拉角(Euler Angle)

      欧拉角这种旋转方式是最直观的,由于这种方式是将旋转表示为物体按坐标系的三个轴X(1,0,0) ,Y(0,1,0),Z(0,0,1)的旋转组合成的。这里首先要明确两个概念,1参考系:相似于物理中的参考系,是静止不动的,好比北极星,无论在那里,那就是北。2坐标系:坐标系是固定于物体的,随着物体的转动而发生变化,最简单的例子就是左右,人所说的左边一直是根据人所面对的方向来决定的。在下图中蓝色为参考系的三个轴,而红色是物体的坐标系的三个轴。虽说欧拉角表示的旋转是有多个沿坐标轴的旋转组合而成的。可是旋转的顺序不一样旋转就不一样,因此,欧拉角中旋转的顺序要注明。这里的三个角是zxz顺规的欧拉角。物体先绕Z轴旋转了α°,而后物体坐标系的x轴的位置变化到了图中N的位置,而后绕这个N轴(X轴)旋转β°,最后再沿Z轴旋转γ°。svg

                                                                      

      欧拉角的旋转虽然是最直观的,可是却存在一个很是致命的问题--万向节锁,大体是指。按某一个旋转了90°的时候会使另外两个轴重合,从而丧失一个自由度。没法很好的追踪物体。具体的能够看一下这个视频万向节锁。讲得很是清楚,这里也就再也不赘述了。this

      欧拉角旋转应用于不少第一人称3D游戏中,虽然万向节锁是没法避免的,但能够将触发的几率减至最小。只有当人物视线彻底朝上或者朝下的时候才会触发万向节锁。atom

 

2 .旋转矩阵(Rotation Matrix)

      三维空间的旋转使用旋转矩阵的方式表示比较容易,旋转矩阵是一个3x3的矩阵。能够看做物体沿空间中的某一个轴(x,y,z)旋转了θ°。三维的旋转矩阵能够表示为:spa

      

其中:c=cos(θ) , s=sin(θ),t=1-cos(θ).net

假设物体在初始位置的旋转矩阵为A ,通过旋转以后的旋转矩阵为A` ,那么A,A`以及R之间的关系能够表示为 A` = AR。设计

3 .四元数(Quaternion

      四元数是一种高阶复数,四元数q表示为:=(x,,,w)=xi+j+k+w  能够将四元数写成一个向量和一个实数的组合。=(v  ⃗    +w)=((x,,),w)  ,四元数也可用矩阵表示。3d

 

能够证实这个矩阵和旋转矩阵是一个矩阵。

在数学上四元数来表示的旋转要好一些,可是在程序设计里,旋转矩阵更方便。在Three.js中使用四元数的方式也是将四元数换成了旋转矩阵使用的。

 

Three.JS中的旋转实现

      three.js支持上面所说的三种旋转方式。

1.欧拉角

     three.js中场景里的物体都属于Object3D这个类。这个类中有表示物体朝向的一个属性–rotation,这是一个欧拉类型的值,有三个轴旋转的角度,单位是π,还有一个旋转的顺序组成。要使物体旋转能够改动这个rotation的值。好比让物体按Y轴正方向旋转45°能够写成 object3D.rotation.y+=0.25*Math.PI。这里的旋转顺序默认使用的是‘XYZ’顺序。另外Object3D 还提供了几个方法来进行旋转,rotateX(angle),rotateY(angle),rotateZ(angle),分别是按照X,Y,Z轴的正反向旋转一个角度。但具体使用的时候和 object3D.rotation.y+=0.25*Math.PI 这种方式仍是有一些区别的。另外还有一个方法是rotateOnAxis(axis,angle) 能够指定旋转的轴,这里的axis是一个Vector3类型的值。

2.矩阵

    three.js里的矩阵和以前介绍的不太同样,由于three.js里的矩阵式一个4x4的复合的矩阵(Transform Matrix),将位置信息放在了矩阵的最后一行。能够很容易的从这个矩阵里分解出旋转矩阵(Rotation Matrix),和位置矩阵(Translation Matrix)。Matrix4的主要方法有:

   mutiply():矩阵的乘法。

   transpose() :矩阵转置。

   getInverse(m) :求逆矩阵。

   makeRotationFromEuler(euler) :经过一个欧拉类型的值来设置矩阵的值。

   makeRotationFromQuaternion(q):经过一个四元数类型的值来设置矩阵。

   makeRotationonAxis(axis,theta):按一个轴旋转θ°,而后设置矩阵的值。

   makeRotationonAxis(axis,theta) 的源码为:

makeRotationAxis: function ( axis, angle ) {
 
         var c = Math.cos( angle );
 
         var s = Math.sin( angle );
 
         var t =  1  - c;
 
         var x = axis.x, y = axis.y, z = axis.z;
 
         var tx = t * x, ty = t * y;
 
         this .set(
 
             tx * x + c, tx * y - s * z, tx * z + s * y,  0 ,
 
             tx * y + s * z, ty * y + c, ty * z - s * x,  0 ,
 
             tx * z - s * y, ty * z + s * x, t * z * z + c,  0 ,
 
             0 0 0 1
 
         );
 
          return  this ;
 
     }

    经过源码,能够看出,调用这个方法就能够获得一个旋转矩阵了。而后,让物体的矩阵乘旋转矩阵就能够获得物体转动后的矩阵了。

    下面是一段我使用旋转矩阵来旋转物体的代码。

var rotWorldMatrix;
  function rotateAroundWorldAxis(object, axis, radians) {
                         rotWorldMatrix =  new  THREE.Matrix4();
                         rotWorldMatrix.makeRotationAxis(axis.normalize(), radians);
                         rotWorldMatrix.multiply(object.matrix);                 // pre-multiply
                         object.matrix = rotWorldMatrix;
                         object.rotation.setFromRotationMatrix(object.matrix);
                         }

经过这样的方法,就可让物体沿参考系中的肯定的一个轴进行旋转了。

3.四元数

      没有使用四元数,因此没有研究,在object3D中设置rotation能够经过Matrix ,也能够经过Quaternion ,不过setFromRotationQuaternion的内部也是用的Matrix。

参考资料

https://www.fastgraph.com/makegames/3drotation/

http://www.essentialmath.com/GDC2012/GDC2012_JMV_Rotations.pdf

http://www.gamedev.net/page/resources/_/technical/math-and-physics/do-we-really-need-quaternions-r1199

https://threejs.org/docs/

相关文章
相关标签/搜索