Shader里向量矩阵乘法mul(x,y)函数的使用
R抱着嫦娥烤玉兔R
2022年05月14日 20:02

    写在前面的话:在学完入门精要的shaderlab的着色器编写之后,已经习惯了mul(x,y)函数里,把矩阵写在左边(x的位置),把向量写在右边(y的位置);这样是进行对向量的矩阵变换,因为看3B1B的教程,手写也是这么写的,所以也没想太多。但是当我学习Ben的hlsl”远古“教程的时候,里面却是把向量和矩阵的位置相反着写。这个时候我就意识到,这个函数要研究一下。根据网上找到的资料,总结了以下几点:

---------------------------------------------------------------------------------------------------------------------------

    1    矩阵在编程里是有两种表示方式的,row_major(行主)和cloume_major(列主),简单可以理解为横着写和竖着写。由于存在这两种差异,在不同语言,以及针对不同图形接口中的不同,所以造成当我们使用mul函数的时候的不同。

    2    对于矩阵相乘的基础描述方法:

    向量v和矩阵M,  v * M叫做向量v左乘矩阵M;  M * v 叫做向量v右乘矩阵M。(以前我一直反着叫)两者要满足写在第一个矩阵的列数,等于写在第二个矩阵的行数,即(m行n列)* (n行o列)—— 结果就是M行o列的矩阵。

    ***  向量也可以被写成矩阵形式,也有row_major和cloume_major的区别,且写在mul()中还会自动转置,很繁琐。mul(x,y)函数里,当向量被写在x的位置,就被表示为row_major形式,即行向量左乘矩阵;当向量被写在y的位置,就被表示为cloume_major形式,即列向量右乘矩阵。

    3    调用图形API使用的函数时,不同的使用方式(这里,我们不关心储存方式,我们只关心mul的使用)

    OpenGL(图形接口):  按列存储矩阵(column-major)。调用API形成的矩阵用来和一个列向量相乘,矩阵在左,列向量在右,即mul(M,v)     GLSL(着色器语言):   矩阵的存储方式和OpenGL相同(column-major)

    DirectX(图形接口):    按行存储矩阵(row-major)。调用API形成的矩阵用来和一个行向量相乘,矩阵在右,行向量在左,即mul(v, M)     HLSL(着色器语言): 矩阵存储方式和DirectX相反(column-major)

    *** Unity的Shaderlab里CG片段是按行存储矩阵(row-major), C#和C++按列存储矩阵(column-major)。

    4    在调用图形接口默认从cpu那里拿到的矩阵的时候(管线里的传入MVP相关矩阵),直接按照上面的针对不同图形接口的的使用方法,直接使用就好。但是问题就在,如果要自己写一些矩阵,传进图形接口中;或者自己在shader中构建矩阵。就有很麻烦了,所以就要深刻理解出现这问题的原因,要去深究底层汇编语言的计算方式。由于其优化计算,会对矩阵进行转置操作,以及在hlsl中会由于其矩阵表示方式,和mul里的数据方式,都可能对矩阵进行转置。—— 很明显我是废物,理解的太懵了。

---------------------------------------------------------------------------------------------------------------------------

        我自己的理解:由于我主要写的是shader,所以当你使用的是内置的矩阵的时候,不管你在什么语言里编写,只要你针对的图形接口是这个,就按这个的方式调用mul()函数。例如:在Unity里就用OpenGL的方式,即mul(M,v) ; 在编写max使用的HLSL的时候就用DirectX的方式,即mul(v, M)

*当然这里如果反着写mul的参数的时候,就代表的是,对v进行 行列向量改变,对M矩阵进行转置。

---------------------------------------------------------------------------------------------------------------------------

        这里写个小贴士,在涉及到法线的计算的时候,经常会用到将其由物体空间转换到世界空间,这个时候直接乘MVP中的M矩阵的时候,对进行了不均匀变换的物体来说,法线就会错误,所以这个时候应该乘M矩阵的逆转置(Unity有内置的函数宏来实现这个,原理是一样的)。