Shader中矩阵的一些用法

来源:互联网 发布:python shadowsockt 编辑:程序博客网 时间:2024/05/22 03:46
1.从世界的变换矩阵中提取仅带有旋转缩放那部分信息的矩阵:
因为平移信息仅存放在矩阵的m41,m42,m43这些位置上,所以该矩阵中左上方的3*3矩阵既为旋转缩放矩阵。
代码如下:

float4x4 WorldViewXf : WorldView; // 世界*视变换矩阵 
float3x3 modelViewRotXf; // 世界矩阵中的旋转缩放矩阵
modelViewRotXf[0] = WorldViewXf[0].xyz;
modelViewRotXf[1] = WorldViewXf[1].xyz;
modelViewRotXf[2] = WorldViewXf[2].xyz;

注意:Shader中通过"[]"取出的是该矩阵的一列

2.对正交矩阵进行快速的逆变换
我们经常会遇到通过A空间到B空间的矩阵实现从B变换到A的这种情况,一般为了省事就直接从外部传一个A空间到B空间的矩阵的你矩阵就行了。但我前不久看到了一个这样的写法:

float4x4 tbnXf;  // 模型空间->切向空间的变换矩阵
float3 vec_model; // 模型空间的一条向量
float3 vec_tbn; // 切向空间的一条向量
vec_model = mul(tbnXf,vec_tbn); // 变换

你也许还没看出什么特别来,注意mul中两个参数的位置,变换矩阵放在了前面!而向量却在后面!要知道矩阵乘法是不支持交换率的!!如果我们想把vec_tbn变换到模型空间,正常的方法应该是:
vec_model = mul(vec_tbn, tbnXf_INVERT);     // tbnXf_INVERT是tbnXf的逆矩阵
但事实上两个运算的结果完全一致!其实这里的实现方法是用到了正交矩阵的一个特性以及转置矩阵的一个运算定理,其分别是:
-正交矩阵的转置矩阵就是该矩阵的逆矩阵
-() = 
所以mul(tbnXf,vec_tbn)表达的含义是用vec_tbn的转置矩阵乘上tbnXf的逆矩阵,由于对向量转置这个操作貌似HLSL有不错的保护,结果就等同于了mul(vec_tbn, tbnXf_INVERT),这的确是一个非常非常机的方法orz。

3.将几个运算整合到一个矩阵中
由于矩阵乘法是支持结合率的,所以假如我们可以把一组运算写成矩阵的形式,那么我们就能把这些表达运算的矩阵预先乘到一起(甚至可以和变换矩阵乘到一起),这样仅需一次矩阵乘法就可以解决所有的问题,大大缩减了运算量!不过不是所有的算法都可以抽象成矩阵的(反正我是做不到orz),下面这个是我见到的比较典型的。
在实现ShadowMap时,我们需要计算一个模型空间下的3维坐标它所对应的在ShadowMap这张深度图的贴图坐标系下所对应的UV坐标。一般的步骤是:

预先计算的部分:
float g_fTexOffset = 0.5 + ( 0.5 / SHADOW_MAP_SIZE ); // 贴图空间变换到纹理空间需要的偏移量

PixelShader中的片段:
float4 UV = mul( vPos, WorldViewProjXf );         // 变换到投影后的视空间
UV.xy = g_fTexOffset + float2( UV.x * 0.5f, UV.y * -0.5f);  // 变换到纹理空间
float4 color = tex2Dproj( sampler, UV );  // tex2Dproj在取样前会先进行规格化(UV.xyz / UV.w)
// DO SOMETHING

下面我们把变换到纹理空间的这段运算写成矩阵的形式以便预先和WorldViewProjXf矩阵整合到一起:
float4x4 MatTexAdj = {0.5, 0, 0, 0 
                      0, -0.5, 0, 0
                      0, 0, 1, 0
                      g_fTexOffset, g_fTexOffset, 0, 1 }
float4x4 WorldViewProjTexadjXf = WorldViewProjXf * MatTexAdj;

于是在Shader中我们只需要这些运算就足够了
float4 UV = mul( vPos, WorldViewProjTexadjXf ); // 一次完成所有的运算,COOL?
float4 color = tex2Dproj( sampler, UV );
// DO SOMETHING
0 0
原创粉丝点击