关于矩阵相乘顺序的理解(跟旋转没关)

        开始学习矩阵时,知道旋转、移动都可以由矩阵乘法来实现,想着也是挺简单的。

比如一个点P =(x, y, z),

        第一次绕X轴旋转,设绕X轴旋转矩阵为

        A =\begin{bmatrix} a00 & a01 & a02\\ a10& a11 & a12\\ a20 & a21 & a22 \end{bmatrix},

        这样

       P*A =\begin{bmatrix} x & y & z \end{bmatrix}\begin{bmatrix} a00 & a01 & a02\\ a10& a11 & a12\\ a20 & a21 & a22 \end{bmatrix} = P1,

        得到P点绕X轴旋转后的P1点,这时如果再绕Y轴旋转,可以看做是新的点P1绕Y轴旋转,设绕Y轴旋转的的矩阵为

       B =\begin{bmatrix} b00 & b01 & b02\\ b10& b11 & b12\\ b20 & b21 & b22 \end{bmatrix},

        这样

        P1*B =\begin{bmatrix} x1 & y1 & z1 \end{bmatrix}\begin{bmatrix} b00 & b01 & b02\\ b10& b11 & b12\\ b20 & b21 & b22 \end{bmatrix} = P2

        如果旋转后得到的新点,又要继续绕世界某坐标轴旋转,只需如下

        P^{'}=P*A*B*C*D...

        是不是觉得很简单,因为这种理解方式是很常规理解方式,把每次的旋转都理解成是某个点绕某轴旋转,也就是点直接与旋转矩阵相乘,即(((P)*A)*B)*C,但由于矩阵结合率,只要相乘顺序不变,如A*B*C=A*(B*C),所以

        P^{'}=P*A*B*C*D...=P*(A*B*C*D...)

        上面这个理解,我觉得大多数人都能理解。可是在实际应用中,常常看到的是矩阵乘点,如

        A{}'*P^{T}=\begin{bmatrix} a{}'00 & a{}'01 & a{}'02\\ a{}'10& a{}'11 & a{}'12\\ a{}'20 & a{}'21 & a{}'22 \end{bmatrix} \begin{bmatrix} x\\y\\z \end{bmatrix}= P{}'1,

        为了使P1= P{}'1,即P*A =A{}'*P^{T},发现之前是点P乘A矩阵的列,现在是矩阵 A{}'的行乘以P^{T},可得

        之前点PA矩阵后的点P^{'}的x坐标

        P1.X=P.x * A00 + P.y*A10 + P.z*A20

        现在A^{'}矩阵乘点P后的点P^{'}的x坐标

        P^{'}1.X= A^{'}00 * P.x + A^{'}01 * P.y + A^{'}02* P.z

        很明显要让P1.X=P{'}1.X,需要让A的列成为A{}'的行,所以A{}'=A^{T},即

        A{}'=\begin{bmatrix} a{}'00 & a{}'01 & a{}'02\\ a{}'10& a{}'11 & a{}'12\\ a{}'20 & a{}'21 & a{}'22 \end{bmatrix} = \begin{bmatrix} a00 & a10 & a20\\ a01& a11 & a21\\ a02 & a12 & a22 \end{bmatrix}=A^{T}

        A{}'*P^{T}=\begin{bmatrix} a{}'00 & a{}'01 & a{}'02\\ a{}'10& a{}'11 & a{}'12\\ a{}'20 & a{}'21 & a{}'22 \end{bmatrix} \begin{bmatrix} x\\y\\z \end{bmatrix}= \begin{bmatrix} a00 & a10 & a20\\ a01& a11 & a21\\ a02 & a12 & a22 \end{bmatrix} \begin{bmatrix} x\\y\\z \end{bmatrix}=A^{T}*P^{T}

        即 A{}'*P^{T}=A^{T}*P^{T}=P*A

        这时可得P*A=A^{T}*P^{T},

        到了这,之前我犯了个错,因为P*A=A^{T}P^{T},就以为所有矩阵A*B=B^{T}A^{T},可有天发现教材写的是(AB)^{T}=B^{T}A^{T},当时我就想P*A*B*CC^{T}*B^{T}*A^{T}*P^{T}相等不.

        后来我觉得当P为只有一行或只有一列时,上式P*A*B*CC^{T}*B^{T}*A^{T}*P^{T}相等是成立的,现在简单证明下。

        因为矩阵乘法结合率,只要顺序不变,可以先去求右边的结果,手动计算方式从右往左乘,即

        .B^{T}*A^{T}*P^{T}=B^{T}*(A^{T}*P^{T})

        因为A^{T}P^{T}=P*A=P1,则        

        B^{T}*(A^{T}*P^{T})=B^{T}*(P*A)=B^{T}*(P1)

        因为P1只有一行且在最右端,实际上矩阵乘点时,是把P1作为列相乘,所以B^{T}*(P1) = B^{T}*P1^{T}

        因为根据点乘矩阵,P2=P1*B,然后又根据P1*B=B^{T}P1^{T},所以

        P2=B^{T}*P1^{T}=B^{T}*((P*A)^{T})=B^{T}*(A^{T}*P^{T}),

        从而得到P*A*B*C=C^{T}*B^{T}*A^{T}*P^{T}=P2

        本来点依次乘矩阵,哪怕是点去乘多个矩阵的组合也很好理解,为什么实际使用是用矩阵去乘点呢?

        我想可能是为了矩阵相乘的效率,比如一个节点下面连了很多多层的子节点,如果用点乘矩阵,那么每个子节点的矩阵会从下一直往上乘,到父节点时,父节点无法利用从子节点得到的矩阵乘积,当对父节点进行操作时,父节点会重复向上相乘,一直乘到根节点才能得到完整的矩阵乘积。

        而如果采用矩阵乘点,即矩阵从上往下乘,可以把父节点所得的乘积传给子节点,子节点只需要直接将自身的矩阵乘父矩阵乘积就可以,减少计算消耗。

        还有一个我发现的是在opengl里,因为opengl的矩阵采用的是列优先,那么用点乘矩阵的方式推出来的矩阵,在opengl里用矩阵乘点时,可以直接使用点乘矩阵方式退出来的矩阵,不需要行列互换,即

P*A*B*C(行优先,点乘矩阵)=C^{T}*B^{T}*A^{T}*P^{T}(行优先,矩阵乘点)

        在opengl用列优先存储C^{T}*B^{T}*A^{T}*P^{T}时,可得

((C^{T})^{T})*((B^{T})^{T})*((A^{T})^{T})*((P^{T})^{T})=C*B*A*P,居然在opengl最终使用的还是点乘矩阵方式推导出的矩阵,只不过顺序颠倒而已,我在想这会不会就是opengl为什么采用列优先存储。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值