矩阵:行主序、列主序、行向量、列向量 - 知乎 (zhihu.com)
看龙书的时候发现一个矩阵在传入Shader之前都要转置一下,很好奇为什么要有一步这样的操作。
![](https://pic2.zhimg.com/80/v2-1969d83bf43b46c7fa22d0bea6bbfe69_720w.png)
行主序和列主序
行主序指矩阵在内存中逐行存储,列主序指矩阵在内存中逐列存储。
行主序矩阵内存布局:
![](https://pic2.zhimg.com/80/v2-3d5cde0c897498f9a4bb0e71a060fb7d_720w.png)
列主序矩阵内存布局:
![](https://pic4.zhimg.com/80/v2-dc246d86c64f578189814522096201d3_720w.png)
行向量和列向量
行向量指的是把向量当成一个一行n列的矩阵,列向量指的是把向量当成一个n行一列的矩阵。
左乘和右乘
矩阵“左乘”:矩阵和向量相乘时放在左边。
矩阵“右乘”:矩阵和向量相乘时放在右边。
对于同一个矩阵和同一个向量,“左乘”和“右乘”的结果是不一样的,这是因为矩阵不满足交换律。
总结
HLSL中默认是使用列主序存储矩阵的,也就是矩阵的每一列存储在一个常量寄存器中,此时使用矩阵“右乘”效率更高,因为一个float4和一个4x4的矩阵相乘只需要四个点乘就能计算出结果:
![](https://pic3.zhimg.com/80/v2-7b62a6da30b7e08a64d11203a93170aa_720w.jpg)
如果使用“左乘”,结果就是:
![](https://pic3.zhimg.com/80/v2-beb78b1db6eab9911950d83782c17dd6_720w.jpg)
HLSL中可以通过 #pragmapack_matrix指令或者row_major、column_major keyword来修改矩阵的存储方式。在Shader执行之前会加载矩阵的数据,行主序还是列主序的设置只会影响Shader读取输入的矩阵数据,矩阵读取到Shader后矩阵是行主序还是列主序就不会有其他影响(只会影响计算的效率),比如通过代码获取某个元素的值,我们要获取第一行第三列的值,都是通过_m02来获取。
但是为了使效率最高,对于列主序存储的矩阵我们要“右乘”,对于行主序存储的矩阵我们要“左乘”。
因为DirectXMath中使用行主序矩阵,向量和矩阵相乘使用“左乘”,要想在Shader中读取正确的矩阵,我们就要转置一下,比如一个平移变换,在DirectXMath中是这样:
![](https://pic3.zhimg.com/80/v2-7ef3579035acc4f9ff27ef4deef053d2_720w.png)
矩阵“左乘”表示平移变换:
![](https://pic4.zhimg.com/80/v2-fda70ae530a4162bbd81cb1491a249ab_720w.jpg)
那在HLSL中使用的是列主序矩阵,为了效率我们使用“右乘”,要表示相同的平移变换,就要传入上面矩阵的转置矩阵:
![](https://pic3.zhimg.com/80/v2-77673e50dc8d0dc100388d33cc25091e_720w.jpg)
所以在把DirectXMath的矩阵传入HLSL时需要传入原矩阵的转置。
Reference: