赞
踩
- // 方法一, 使用transpose 函数对UNITY_MATRIX_IT_MV 进行转置,
- // 得到UNITY_MATRIX_MV 的逆矩阵,然后进行列矩阵乘法,
- // 把观察空间中的点或方向矢量变换到模型空间中
- float4 modelPos = mul(transpose(UNITY_MATRIX_ IT_MV), viewPos);
-
- // 方法二, 不直接使用转置函数transpose ,而是交换mul 参数的位置,使用行矩阵乘法
- // 本质和方法一是完全一样的
- float4 modelPos = mul(viewPos, UNITY_MATRIX_IT_MV);
关于mul 函数参数位置导致的不同,在4.9.2 节中我们会继续讲到。
- float4 a = float4(1.0, 2.0, 3.0 4.0);
- float4 b = float4(1.0, 2.0, 3.0,4.0);
- //对两个矢量进行点积操作
- float result= dot(a, b);
但在进行矩阵乘法时,参数的位置将决定是按列矩阵还是行矩阵进行乘法。在CG 中,矩阵乘法是通过mul 函数实现的。例如:
- float4 v = float4(1 O, 2.0, 3.0 , 4.0);
- float4x4 M = float4x4(1.0, 0.0, 0.0, 0.0 ,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 1.0);
- // 把v当成列矩阵和矩阵M 进行右乘
- float4 column_mul_result = mul(M, v);
- // 把v当成行矩阵和短阵M 进行左乘
- float4 row_mul_result = mul(v, M);
- // 注意· column_mul_result 不等于row_mul_result ,而是.
- // mul(M,v) == mul(v, tranpose(M))
- // mul(v,M) == mul(tranpose(M), v)
因此,参数的位置会直接影响结果值。通常在变换顶点时,我们都是使用右乘的方式来按列矩阵进行乘法。这是因为, Unity 提供的内置矩阵(如 UNITY_MATRIX_MVP 等)都是按列存储的。但有时,我们也会使用左乘的方式,这是因为可以省去对矩阵转置的操作。
- //按行优先的方式初始化矩阵M
- float3x3 M = float3x3(1.0, 2.0, 3.0,
- 4.0, 5.0, 6.0,
- 7.0, 8.0, 9.0);
- // 得到 M 的第一行,即( 1.0, 2.0, 3.0)
- float3 row= M[O];
- // 得到M 的第2 行第1 列的元素,即 4.0
- float ele = M[l][0];
之所以Unity Shader 中的矩阵类型满足上述规则,是因为使用的是CG 语言。换句话说,上面的特性都是CG 的规定。
- fixed4 frag(float4 sp : VPOS) : SV_Target
- {
- // 用屏幕坐标除以屏幕分辨率 _ScreenParams.xy,得到视口空间中的坐标
- return fixed4(sp.xy/_ScreenParams.xy, 0.0, l.0);
- }
得到的效果如图4.49 所示。
- struct vertOut {
- float4 pos : SV_POSITION;
- float4 scrPos : TEXCOOROO;
- }
-
- vertOut vert(appdata_base v) {
- vertOut o;
- o.pos = mul(UNITY MATRIX_MVP, v.vertex);
- //第一步:把ComputeScreenPos 的结果保存到scrPos 中
- o.scrPos = ComputeScreenPos(o.pos);
- return o;
- }
-
- fixed4 frag(vertOut i) : SV_Target {
- //第二步: 用scrPos.xy 除以scrPos.w 得到视口空间中的坐标
- float2 wcoord = (i.scrPos.xy/i.scrPos.w);
- return fixed4(wcoord, 0.0, 1.0);
- }
上面代码的实现效果和图4.49 中的一样。我们现在来看一下这种方式的实现细节。这种方法实际上是手动实现了屏幕映射的过程,而且它得到的坐标直接就是视口空间中的坐标。我们在3.6.8 节中已经看到了如何将裁剪坐标空间中的点映射到屏幕坐标中。据此,我们可以得到视口空间中的坐标,公式如下:
- inline float4 ComputeScreenPos (float4 pos) {
- float4 o = pos * O.5f;
- #if defined(UNITY_HALF_TEXEL_OFFSET)
- o.xy = float2(o.x, o.y* _ProjectionParams.x) + o.w * ScreenParams.zw;
- #else
- o.xy = float2(o.x, o.y* _ProjectionParams.x) + o.w;
- #endif
-
- o.zw = pos.zw;
- return o;
- }
ComputeScreenPos 的输入参数pos 是经过MVP 矩阵变换后在裁剪空间中的顶点坐标。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。