3D数学之-向量矩阵欧拉角和四元数

本文探讨了3D空间中的几何变换,包括点与向量的关系、向量运算和矩阵的应用。讨论了矩阵如何表示坐标系变换,并深入研究了矩阵、欧拉角和四元数各自的优缺点以及它们之间的转换方法。
摘要由CSDN通过智能技术生成

摘要:

1.基本的空间数学概念
向量运算和点乘和叉乘很重要
求多个单位向量的平均向量,是将这些向量求和然后单位化。非单位向量之间很难求平均,因为向量除了大小还有方向。
向量齐次化为:(x,y,z,w)其中w用来进行平移,w一般是1,如果不唯一那么转换后需要变换为1例如透视投影钟,向量齐次化可以代表空间点和向量,当w= 0时候是向量,w非0是代表空间点,因为空间点有大小方向和位置。

矩阵本质行是新坐标系相对于上一个坐标系的基向量用于对一个点在原来各个轴方向的分解,列是对一个点在原来各个轴的汇总,所以矩阵在空间几何上的解释是新的相对于原来坐标系的新的坐标轴,也就是对空间中的点进行重新分解和组合从而实现对点的变换,矩阵就是一个变换。矩阵插值会产生蠕变。

欧拉角,是对物体的坐标轴进行变换,但是还是用旧的坐标轴来衡量的,所以物体变换取反,和变换轴一样的顺序但相反的量变换物体即可,欧拉角有万向锁和二义性问题,用限制欧拉角可以解决,但是欧拉角插值不平滑。欧拉角物体变换到惯性,和惯性变换到物体才是相反的顺序相反的量进行变换,因为他们之间是相互逆变换。
例如:
欧拉角惯性到物体变换为head pitch back:旋转角度为:h p b,那么物体旋转方位计算为:M(-h) * M(-p) * M(-b), 如果是欧拉角那么直接用旋转向量标记,如果是四元数那么用四元数方式进行变换。
若从惯性到物体变换来计算物体到惯性的逆变换,那么变换为:M(-b)^-1 M(-p)^-1 M(-h)^-1, 也就是roll pitch yaw变换,yaw相对于当前物体坐标系的z轴,head是惯性坐标系的y轴 。

四元数中的旋转四元数,将旋转角度和旋转轴放入到了四元数中,但是旋转角度是半角因为另一半的角放置到了该四元数的 逆(共轭)四元数中,四元数变换一个顶点在标准乘法时候[w1,v1]*[w2,v2) = (w1*w2 - v1.v2 w1*V2 + w2*V1 + V1xV2),用q四元数变换向量p公式是:p' = qpq-1。
本引擎定义的乘法的四元数乘法为[w1,v1]*[w2,v2) = (w1*w2 - v1.v2 w1*V2 + w2*V1 + V2xV1)用q四元数变换向量p公式是:p' = q-1pq连续进行a,b四元数变换得到:(ab)-1p(ab),等价于标准乘法定义下的(ba)p(ba)-1,所以如果需要连续四元数变换那么改变四元数标准乘法规则更好使用四元数连续a,接着b变换,在标准乘法下先进行ba乘法(反正a,b都是已知,如OGRE中直接即可)记录整个变换,真正实施变换时候才对向量进行ba * p * (ba)-1变换,或者将ba转换为矩阵M(矩阵包含了ba,(ba)-1信息)包含了所有变换信息,向量进行p*M变换即可;如果是非标准本引擎乘法那么进行ab乘法记录整个变换OGRE中用了标准乘法,但是父节点变换a和子节点变换b?他们之间的连续变换依然是用a*b进行的,每次子节点渲染时候,需要递归到根节点进行变换刚好是从根节点向下连续变换
因为右手坐标系中顺时针四元数变换为:a-1pa,连续变换为: (ab)-1 p(ab),所以是父节点乘以子节点刚好实现连续四元数旋转变换。
记得右手坐标系顺时针变换,因为相对于左手坐标系的顺时针变换apa-1,因为左右手变换了乘法规则还是不变,a和a-1刚好是互逆的,所以到右手中就变成了a-1pa。
且在左手坐标系中逆时针旋转也是a-1pa,在右手坐标系中逆时针为:apa-1,所以对于四元数变换在标准乘法下在右手坐标系中顺时针下刚好是可以按照先后连续变换的(ab)-1p(ab)。
左手坐标系下顺时针变换如果用标准四元数连续乘法就要变为(ba) p(ba)-1。如果左手坐标系下想要获得按照先后乘法顺序就要改变标准乘法,例如:
[w1,v1]*[w2,v2) = (w1*w2 - v1.v2 w1*V2 + w2*V1 + V2xV1) 才能用(ab)-1p(ab)实现连续变换。

四元数变换向量,一定要小心求逆,四元数的求逆都是唯一的(w, -x, -y, -z)无论是在变换旋转方向,还是变换轴下。


2.物体变换等价于相反的量变换坐标系(如果都是用旧坐标系表达,则用相反量,相同的顺序得到变换物体矩阵)
3.坐标系间转换(如果是不同坐标系表达),例如物惯到惯物,那么需要相反的顺序,相同的量求逆执行变换。

4.连续变换,都是基于上一个变换的,因为变换是相对的,所以变换不满足交换律,但是满足结合律。

5.不同坐标系统间的变换,一个需要注意轴的方向和点的模型位置一致对轴变化所有顶点需要进行这样的变化,二个是点积方向发生改变所以网格法向量需要改变(三角网格的索引缓存和顶点法向量,三角形法向量具体改变计算),三是绕序绕序改变旋转改变三角网格的正面也改变,四个是坐标系位置改变了那么观察坐标系中观察点也要做调整否则观察到的情况会发生变化。

矩阵:

每个变换都可以解释为一个矩阵,也就是一个新的坐标系,如果新坐标系是用旧坐标系描述的那么是物体变换,如果对这个变换求逆那么是坐标变换。
连续变换就是连续的建立坐标系,且都是基于上一个坐标系的,所以变换的顺序不同得到的结果完全不同。至于相对任意轴不在原点的变换,先平移到原点再进行放缩旋转变换,在平移回去(平移矩阵求逆);这时只是得到相对于该任意轴的变换,对于具体的变换还需要先平移到物体所在的坐标系(物体每个点都是基于物体坐标系的情况下),然后再对物体进行变换。


1)同坐标系描述,直接变换物体(参考坐标系用旧坐标系表达):
一定要搞清楚前提条件(例如过原点的仿射变换和不过原点的差别巨大的); 也要搞清楚是一个变换,和多个变换的连续变换(例如非过原点的仿射平移是轴或者平面的,R = P_1 * R * P), 然后T是平移的是独立的,那么最终M = T * R); 也要弄清楚DX或者OPENGL变换函数的含义,有些情形下是不支持的或者通过恰当转化后改变了前提条件,那么才是可以使用的。

矩阵是代表物体的变换(虽然也可以代表坐标系变换但是最终还是要作用在物体上),该变换是用物体变换,假设变换到新的用旧坐标系表示的新的坐标系。那么物体进行该变换(缩放旋转平移)就相当于是到了物体变换到了这个参考坐标系,只是这个参考坐标系是用旧坐标系来表达的,但是从旧坐标系来看确实是变换了物体得到想要的效果。
矩阵的行向量是新坐标系的基向量,是用原坐标系轴假设变换(旋转或平移)到一个新的位置后在各个原轴上面分解的向量之和
矩阵的列向量是新坐标系各个基向量在某一个原轴上分解出来的向量的汇总,用于对物体向量的某分量在新坐标系下面重新组合计算位置
例子:
// 如果在同一个坐标系中直接变换就是了,但是每一个变换都是基于上一个解释的变换的(具有层级关系的不仅是欧拉角中),所以变换顺序很重要
// 将在原点位置描述的茶壶(茶壶网格顶点是相对于原点位置的)平移到这个地方,进行绘制
// 这里也可以看做是物体坐标系,到世界坐标系的变换
   D3DXMATRIX W;
    // 将茶壶平移到这个位置
    D3DXMatrixTranslation(&W,
        TeapotPosition.x,
        TeapotPosition.y,
        TeapotPosition.z);

    Device->SetTransform(D3DTS_WORLD, &W);
    Teapot->DrawSubset(0);


2)同坐标系描述,变换坐标系来变换物体(参考坐标系用旧坐标系表达)
不是用新坐标系描述,而是假设变换坐标系,那么物体就往相反的方向来变换,其实就是在变换物体,所以每一步只需要相反的量(相反量和 逆变换是完全不同的),不需要相反的顺序来变换。
其实这里的变换坐标系只是变换物体。

例如欧拉角变换转换为矩阵变换中,因为欧拉角描述的是坐标系变换,所以需要转换为物体变换(相反的量即可),因为每次都是坐标系的变换转换为每次物体的变换,得到的都是物体的变换,所以变换只用相反的量,不需要相反的顺序进行。得到的矩阵就是在旧坐标系中变换物体的矩阵。
M = M(-y) M(-x)M(-z), 相同的顺序,相反的量进行变换( 不是相反的顺序,因为变换中的坐标系都是相对于同一个坐标系的,每一步坐标系变换和物体变换相反,欧拉角本身就是如此定义的hpb都是局部坐标系的变换并非物体变换,至于进一步的证明还需要更多的积累和研究开源引擎? )
欧拉角中的,惯性到物体是M = M(-y) M(-x)M(-z),物体到惯性是:M = M(-z) ^-1M(-x)^-1M(-y)^-1,这里是不包括平移的,包括平移则和新坐标系描述变换一样的方式进行。因为欧拉角描述的是物体的变换,但是变换的内部小步骤又是通过变换坐标系方式来讲述的(整个感觉描述得比较模糊),所以根据head pitch row得到的是物体坐标系中描述的物体,如果需要渲染转换到世界坐标系,还是需要进行物惯转换和平移来做的。

3)新坐标系描述,变换物体来变换坐标系(参考坐标系用新坐标系表达)
用新的坐标系来描述物体,那么需要先将物体某个向量从旧坐标系变换到该新坐标系中,得到变换矩阵然后对变换求逆即得物体用新坐标系描述的变换。将需要变换到新坐标系中的物体乘以该矩阵就得到了物体在新坐标系中的位置,且不需要旋转观察视角就是正确的结果因为新坐标系默认也是x向右,y向上,z向内的。具体应用中所谓有时候变换物体,有时候变换坐标系来达到转换到同一个坐标系中以便计算碰撞检测相对运动等中的有时变换坐标系更方便就是这个意思
所以变换坐标系是变换物体严格相反的顺序,相反的量来进行变换。

例如惯物变换之间,世界坐标系变换到观察坐标系之间,因为是用新坐标系来描述,且是变换物体,所以变换物体不能用相反的量(因为坐标系改变了),而是用相同的量变换物体然后求逆(逆并不同于相反的量,因为相反的量是反向的变换,而逆是变换的撤销),要求相同的量相反的变换,得到坐标系的变换。
M =(PM)^-1 = M^-1P^-1,相反的顺序,相同的量求逆进行变换
坐标系间的转换:
物体到世界坐标系,通常是先缩放 -> 旋转 -> 平移; 世界到物体就要先平移->旋转->缩放,这是因为矩阵乘法不满足交换律导致的,深层次的原因是变换之间是层层嵌套的,每一个前提条件都代表了基于不同的基向量坐标系,所以变换次序是非常重要的。
例子:物体坐标系到世界坐标系:缩放旋转到惯性坐标系,进行相对于世界坐标系的平移,设置这样的变换坐标系,所有接下来渲染的物体都会进行这样的变换,其实物体本身是不清楚的,它把每一个变换作为一个新的坐标系,只不过这个新的相对的坐标系是世界坐标系而已。同样要得到相对于物体坐标系的变换,那么对物体到世界坐标系的变换矩阵求逆即可,求逆也就是相反的顺序相反的变换矩阵进行相乘,就会得到世界坐标系描述物体到物体坐标系(复杂模型或摄像机)描述物体的变换。

4)连续变换:每个都是基于上一个观察坐标系不管该坐标系是用旧坐标还是新坐标来表达的变换,而不是基于原坐标系的变换(除了第一个变换)。 如果物体的连续变换(一般物体到世界是先缩放旋转平移,世界到物体是平移旋转缩放变换,都是不能改变变换顺序的,因为连续变换符合结合律不符合交换律,都是基于前一个坐标系的) ,是矩阵直接连乘即可;如果是坐标系变换,先转换为物体的连续变换,然后求逆得到坐标系的连续变换结果。所以欧拉角中的连续旋转变换,是符合物体连续变换的直接变换即可。

一定要搞清楚前提条件(例如过原点的仿射变换和不过原点的差别巨大的); 也要搞清楚是一个变换,和多个变换的连续变换(例如非过原点的仿射平移是轴或者平面的,R = P_1 * R * P), 然后T是平移的是独立的,那么最终M = T * R); 也要弄清楚DX或者OPENGL变换函数的含义,有些情形下是不支持的或者通过恰当转化后改变了前提条件,那么才是可以使用的。

例子:
// 直接变换和连续变换问题
1.前提条件问题,如果是不包含平移的放射变换,那么缩放还是旋转的轴都是过原点的,否则需要先平移到原点然后进行仿射变换再平移回去才会得到正确的结果;两者该直接仿射变换时候就直接变换,该平移回来仿射变换再平移回去是不能混淆使用的。
2.空间变换思维方式,矩阵行向量就是变换后的新坐标系的位置,用简单例子情景分析即可。
3.非经过原点的,若用D3DX的进行变换,因为它变换默认是认为绕过原点的轴进行变换,且变换一刀切(缩放旋转部分和平移部分都直接用仿射公式进行变换),所以这种情况下是不能直接用DX仿射变换函数进行变换的。这个时候有两种方法:
1)通过改变变换轴或者平面,去掉平移部分,让其是过原点的轴和平面,令其为P2;然后将平移部分抽取为P,求逆回原点平移_P;用DX仿射变换基于P2条件求得变换矩阵R; 则最终变换为W = _P * R * P。
2)自定义过原点的仿射变换矩阵R,直接对不过原点的轴或者平面取得平移部分P,求逆得到_P,那么最终变换为:W = _P * R * P。
最后如果还有其他的连续变换,比如仿射变换前需要平移先,那么变换为:M = T * W;如果先仿射变换后再平移,那么为:M = W * T。
继续不断实践各种各样的变换,和研究开源引擎,看还有没有更好的方法和结论。
例子:
// 非过原点的镜面反射变换实现,position reflection
 D3DXMATRIX T;
 // 镜像平面定义,平面为ax + by + cz + dw = 0. n法向量为(a,b,c), dw为平面到原点的距离
 D3DXPLANE plane(0.0f, 0.0f, 1.0f, 1.0f); // xy plane
 // 平移到茶壶所在的坐标系,因为茶壶用本地坐标系描述
 D3DXVECTOR3 TeapotPosition(0.0f, 3.0f, -7.5f);
 
 D3DXMatrixTranslation(&T,
  TeapotPosition.x,
  TeapotPosition.y,
  TeapotPosition.z);
 // 方法1:抽取非过原点轴或者平面的平移部分,且用DX函数求取过原点的仿射变换矩阵
 D3DXMATRIX R,W,M;
 // 抽取非过原点的变换平面的平移部分
 D3DXMATRIX P(1, 0, 0, 0,
  0, 1, 0, 0,
  0, 0, 1, 0,
  0, 0, 1, 1);
 // 对平移部分求反
 D3DXMATRIX _P;
 D3DXMatrixInverse(&_P, NULL, &P);

 // 去掉平移部分的平面(有时候是轴),得到过原点的仿射变换
 D3DXPLANE plane2(0.0f, 0.0f, 1.0f, 0.0f); // xy plane
 D3DXMatrixReflect(&R, &plane2);
// 会先对平面进行单位化,但是也是没有用的

 // 得到非过原点的仿射变换矩阵
 W = _P * R * P;
 // 继续进行平移
 M = T * W;

 // 方法2:抽取非过原点轴或者平面的平移部分,自定义的过原点的仿射变换矩阵
 D3DXMATRIX RF(1-2*plane.a*plane.a, -2*plane.a *plane.b, -2 * plane.a * plane.c, 0,
  -2*plane.b*plane.a, 1-2*plane.b *plane.b, -2 * plane.b* plane.c, 0,
  -2*plane.c*plane.a, -2*plane.c *plane.b, 1 -2 * plane.c * plane.c, 0,
  0/*-2*plane.d*plane.a*/, 0/*-2*plane.d*plane.b*/, 0/*-2*plane.d*plane.c*/, 1);
 
 W = _P * RF * P;
 M = T * W;

 // 设置变换
 Device->SetTransform(D3DTS_WORLD, &M);
 // 绘制出来
 Teapot->DrawSubset(0);


其实一个变换矩阵就是从一个新的观察坐标系来描述物体空间位置。
如果这个新的观察坐标系,也就是矩阵的基向量都是用旧坐标系来表达的,那么物体向量进行该矩阵变换就是相对于旧坐标系的物体变换。
如果这个新的观察坐标系,也就是矩阵是用旧坐标系描述的物体变换(直观简单)的 逆来表达,物体向量进行该矩阵变换,就是坐标系变换。

坐标系间的连续变换,都是基于上一个观察坐标系的变换(不管该坐标系是用旧坐标还是新坐标来表达),所以不能随便交换次序,仿射变换都要先平移到原点,再在原点进行放缩旋转变换,再平移回去。如果是平移和旋转之间却是可以相互变换的,因为他们得到的旋转矩阵都是一样的

欧拉角的连续变换,也都是基于上一个变换进行的变换,虽然说是惯性坐标空间到物体坐标空间进行M=H(-h)P(-p)B(-b)变换,但是这些变换矩阵都是基于旧坐标系的,所以并没有真正转换到物体空间来描述,所以只是一个基于旧坐标空间(惯性坐标空间)的旋转序列变换而已,至于为何用-h、-p、-b那是因为对欧拉角的不同规则的定义,完全是可以M=H(h)P(p)B(b)进行变换的(需要更多的研究开源引擎证明之?)。所谓的从物体坐标系到惯性坐标系的变换,M=B(-b)^-1P(-p)^-1H(-h)^-1也不算是从物体坐标系转换到惯性坐标系,因为不是真正的物体坐标系,而是变换物体的逆向变换(如果用惯性坐标系中物体进行该逆向变换,就是变换了坐标系用新的物体坐标系来表达惯性坐标系中的物体位置,但是这里是用物体坐标系中物体进行该变换,所以是欧拉旋转的逆向变换)。所以欧拉角连续变换就是同坐标系描述,变换坐标系来变换物体的变换,如果一定要强说是惯性坐标系变换到物体坐标系,物体坐标系变换到惯性坐标系也是可以的,只是这个物体坐标系都是用旧坐标系(惯性坐标系)来表达的。

    D3DXMATRIX My;
    D3DXMatrixRotationY(&My, D3DX_PI / 6);
    D3DXMATRIX Mx;
    D3DXMatrixRotationX(&Mx, D3DX_PI / 6);
    D3DXMATRIX Mall = My * Mx;
    D3DXVECTOR3 v(0,0,1);
    D3DXVECTOR3 Q ;
    D3DXVec3TransformCoord(&Q, &v, &Mall);
    // Q为{x=0.49999997 y=-0.43301266 z=0.74999994 }
    // v旋转My后为v'=(0.5, 0, 0.866)
    // v'根据自身的坐标系(x', y, z')旋转Mx后得到的比例是(0, -0.5, 0.866)
    // v'进行Mx变换后为v''=(0.5, 0.866*-0.5, 0.866*0.866)刚好为Q
    // 如果v'根据的不是自身的坐标系基础上而是世界坐标系基础上变换,
    // 那么进行Mx旋转的y方向的比例变化一定小于0.5,z方向的比例也一定小于0.866。
    // 证明:
    // 旋转和平移,平移和旋转之间却是可以相互变换的,因为他们得到的旋转矩阵都是一样的
    // 旋转序列之间都是每个基于上一个得到的参考坐标系来进行变换的,欧拉角其实是描述物体的连续变换,至于用-h-p-b应该是对欧拉角的不同定义
?更深入研究下开源代码证明之。

欧拉角:

欧拉角变换是变换坐标系而不是变换物体,欧拉角变换是h(惯性y轴)->p(物体x轴)->b(物体z轴)顺序进行,被限制在hb在[-pi,pi]内,p在[-pi/2,pi/2]内。转换为四元数或者矩阵时,注意坐标变换转换为物体变换,对物体进行连续的变换计算即可。
欧拉角本身的别名问题:pitch角度变换为自身的补角,那么head,bank同时正向旋转pi即得到。
当为万向锁别名问题,此时定义规则z轴和y轴同轴且方向一致(万向锁出现前已定义原因是绕z轴的旋转平面和绕y轴的旋转平面重合了,而重合平面不区分正面和反面,都认为是绕z轴的正面和绕y轴的正面重合了,故认为z轴和y轴重合了),bank的旋转全部用head代替即可。

四元数:
旋转四元数q = (w,x,y,z) = ( cos(θ/2), sin(θ/2)nx,  sin(θ/2)ny,  sin(θ/2)nz)对于空间几何最有用, θ为旋转的角度,( nx, ny, nz)为旋转轴。连续四元数变换得到的结果四元数是标准的四元数,即和乘法定义无关,四元数的连续变换并不等价于四元数连续乘法,而是刚好相反。 四元数和矩阵之间转换是纯粹的四元数转换,而该四元数只是一半的方位变换信息,还有一半在四元数的逆中,
但四元数转换为矩阵,已经包含了另外的一半逆四元数的信息。

内容:

1.变换物体等价于相反的顺序相反的量变换坐标系

变换坐标对于所有的点都适用,且可以组合多个变换最终计算一次(不过变换物体也有这些优点,看下面矩阵的理解)。

2.点和向量的关系

点是终点描述的是位置(相对位置),向量描述的是大小和方向,也可以描述相对位置,所以向量可以代替点,点不能代替向量,且有些计算不需要知道原点,用向量来描述3D几何计算更加灵活,3D中的所有于位置、大小、方向、方位等几何数学相关的计算都应该优先考虑用向量来表达。

3.向量的运算

1)模来表示大小,单位化来表示方向。
2)加减法用“三角”法则,分而治之。
3)数乘用于放缩。
4)点乘计算cos   θ , cos θ = (vectorA * vectorB) / (vectorA.Length()  vectorB.Length());
θ = arccos θ;
vectorA和到   vectorN上的投影向量A'// =    vectorA.Length() * cos θ * vectorN.normalize();
vectorA垂直vectorN的向量A'| = vectorA - A'//;
5)叉乘计算法向量,vectorN = vectorA x vectorB; vectorN的方向是vectorA终点平移到vectorB的始点,左手四指绕vectorAvectorB的向量方向,拇指指向的方向就是vectorN的方向。
叉乘  (vectorA x vectorB).Length() =  vectorA.Length()  *  vectorB.Length() * sin θ;
 vectorA x vectorB = (AyBz - AzBy, AzBx - AxBz, AyBz - AzBy)。

4.矩阵

Unfortunately, no one can be told what the Matrix is. You have to see it for yourself.

矩阵在3D几何应用中表示变换,具体是用新的坐标系用旧的坐标系来表达(假设)。目的是对空间物体向量乘以矩阵可实现需要的变换。

矩阵的行向量是新坐标系的基向量,是用原坐标系轴假设变换(旋转或平移)到一个新的位置后在各个原轴上面分解的向量之和
矩阵的列向量是新坐标系各个基向量在某一个原轴上分解出来的向量的汇总,用于对物体向量的某分量在新坐标系下面重新组合计算位置
实际变换中,虽然经常说坐标系变换,但是   图形库实际中无论是物体变换还是坐标系变换都是用变换物体形式得到变换矩阵,也就是当前坐标系假设是不变的,而物体进行旋转平移(或者逆向的平移旋转),   变换矩阵的计算方
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值