查看: 5112|回复: 3
打印 上一主题 下一主题

[Shaders] Shader中矩阵的一些用法(转载)

[复制链接]

2722

主题

42

听众

3万

积分

资深设计师

Rank: 7Rank: 7Rank: 7

纳金币
38266
精华
111

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2014-6-30 19:26:48 |只看该作者 |倒序浏览
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
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

hyui    

1

主题

2

听众

6671

积分

高级设计师

Rank: 6Rank: 6

纳金币
2715
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2014-6-30 21:51:50 |只看该作者
感谢分享!
回复

使用道具 举报

wucnj    

1

主题

1

听众

3160

积分

中级设计师

Rank: 5Rank: 5

纳金币
1065
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

板凳
发表于 2014-7-1 09:44:57 |只看该作者
感谢分享!!!
回复

使用道具 举报

0

主题

1

听众

461

积分

设计实习生

Rank: 2

纳金币
10
精华
0

最佳新人

地板
发表于 2014-8-1 13:41:20 |只看该作者
好深啊,表示很难学
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

关闭

站长推荐上一条 /1 下一条

手机版|纳金网 ( 闽ICP备08008928号

GMT+8, 2024-5-5 21:44 , Processed in 0.088734 second(s), 32 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部