【图形学】12 UnityShader语法入门

本文详细介绍了Unity中Shader的语法,包括空间变换名词如模型空间、世界空间、观察空间和屏幕空间,以及变换矩阵的应用。特别讨论了向量矩阵乘法的左右乘选择和屏幕坐标的特异性。还深入讲解了法线变换问题,指出在保持法线垂直性的需求下,如何利用切线和矩阵运算来解决。此外,文中还提到了不同平台屏幕坐标的差异,以及在特定情况下正交矩阵对于法线变换的影响。
摘要由CSDN通过智能技术生成

12 UnityShader语法入门

来源:《UNITY SHADER入门精要》

1、Unity的空间变换名词

模型变换Model Transform
观察变换View Transform
投影变换Projection Transform
屏幕映射Screen Mapping
模型空间(model space)
世界空间(world space)
观察空间(摄像机空间)
裁剪空间(clip sapce)
屏幕空间(screen space)

  最后的一个步骤:将视椎体(view frustum)变换成 立方体。我们进行齐次除法(homogeneous division),实际上就是用齐次坐标系中的 w 分量去除以 x,y,z ,在OpenGL中,我们把这一步得到的坐标叫做归一化的设备坐标(Normalized Device Coordinates,NDC)
  OpenGL中,立方体的 x,y,z 分量的范围是 [-1, 1] ,而 DirectX 中 z 的分量是 [0, 1] 也就是说,有半个立方体。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xGYewqjl-1658670012827)(assets/image-20220614154318768.png)]

  PS:一定要吐槽的是,各个教程和书籍的术语使用都不一样呢,这里的裁剪空间,在标准的术语中叫做投影空间。

2、Unity的变换矩阵

  Unity内置的空间变换和内置变量已经在UnityShaderVariables.cginc文件定义和说明了。这些都是 float4x4 类型的。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5bxifMRa-1658670012828)(assets/image-20220614155940848.png)]

  其中,UNITY_MATRIX_T_MV矩阵是从模型空间到观察空间的矩阵,当只有旋转、平移、缩放 这种线性变换,MV矩阵就是个正交矩阵,也就是说它的逆矩阵是它的转置矩阵。在Unity中可以直接调用。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wfGxAwuE-1658670012828)(assets/image-20220614162850690.png)]

3、Unity中的向量矩阵乘法

  Unity提供的内置矩阵(如UNITY_MATRIX_MVP等)都是按列存储的,所以,我们都是使用右乘的方法来按列存储的。**但有时,我们也会使用左乘的方式,这是因为可以省去对矩阵转置的操作。**所以,看到这种左乘的方式,就不要慌,很有可能就是它不想求逆,所以左乘的。

4、Unity中的屏幕坐标

  在写Shader的过程中,我们有时希望能获得屏幕上像素的位置。
  由于 Unity 有 HLSL/CG 的语义支持。,我们就嫩在片元着色器中声明VPOS(HLSL中对屏幕坐标的语义)或者WPOS(CG中对屏幕坐标的语义),就能获得。例子:

fiexd4 frag(float4 sp : VPOS) : SC_Target{
	return fixed4(sp.xy/_ScreenParams.xy, 0.0, 1.0);
}

  如果屏幕分辨率为 400 × 300 400 \times 300 400×300,那么 x 的范围是 [ 0.5 , 400.5 ] [0.5, 400.5] [0.5,400.5],y 的范围 [ 0.5 , 300.5 ] [0.5, 300.5] [0.5,300.5] 。这里的像素坐标不是整数值,是因为 OpenGL 和 DirectX 10以后的版本认为像素的中心应该是像素中心的浮点值中的0.5。

5、屏幕坐标问题

  在OpenGL中,渲染纹理(Render Texture)的(0, 0)点是在左下角,而在DirectX中,(0, 0)点是在左上角。

6、法线变换问题

  这里讨论的是从 模型空间 到 世界空间 的法线变换问题。一般来说,绝大部分矢量和空间中的点都能通过一个 4x4 或者 3x3 的矩阵 m A → B \boldsymbol{m}_{A\rightarrow B} mAB 能够解决。但是,在变换法线的时候,如果使用同一个换换矩阵,就可能出现无法确保法线的垂直性。

  为此,我们引入切线(tangent)。它也是模型顶点所携带能确认的信息,而且与法线垂直。
  同时,我们通过数学的约束条件来推导出所需要的矩阵,即,切线 T A \boldsymbol{T}_A TA 和法线 N A \boldsymbol{N}_A NA ,必须满足: T A ⋅ N A = 0 \boldsymbol{T}_A \cdot \boldsymbol{N}_A = 0 TANA=0。我们已知 世界变换矩阵 m A → B \boldsymbol{m}_{A\rightarrow B} mAB ,有 T B = m A → B   T A \boldsymbol{T}_B = \boldsymbol{m}_{A\rightarrow B} \, \boldsymbol{T}_A TB=mABTA 。我们现在需要一个矩阵 G \boldsymbol{G} G,来保持垂直的特性。
  为使得变换后,法线任然与切线垂直,有:
T B ⋅ N B = 0 ( M A → B T A ) ⋅ ( G N A ) = 0 ( M A → B T A ) T ( G N A ) = 0 T A T M A → B T    G N A = 0 T A T ( M A → B T    G ) N A = 0 \boldsymbol{T}_B\cdot \boldsymbol{N}_B=0 \\ \left( \boldsymbol{M}_{A\rightarrow B}\boldsymbol{T}_A \right) \cdot \left( \boldsymbol{GN}_A \right) =0 \\ \left( \boldsymbol{M}_{A\rightarrow B}\boldsymbol{T}_A \right) ^T\left( \boldsymbol{GN}_A \right) =0 \\ {\boldsymbol{T}_A}^T{\boldsymbol{M}_{A\rightarrow B}}^T\,\,\boldsymbol{GN}_A=0 \\ {\boldsymbol{T}_A}^T\left( {\boldsymbol{M}_{A\rightarrow B}}^T\,\,\boldsymbol{G} \right) \boldsymbol{N}_A=0 TBNB=0(MABTA)(GNA)=0(MABTA)T(GNA)=0TATMABTGNA=0TAT(MABTG)NA=0
  由于 T A ⋅ N A = 0 \boldsymbol{T}_A \cdot \boldsymbol{N}_A = 0 TANA=0,因此,如果
M A → B T    G = I {\boldsymbol{M}_{A\rightarrow B}}^T\,\,\boldsymbol{G}=\boldsymbol{I} MABTG=I,那么上式成立。
  也就是说:
   G = ( M A → B T ) − 1 = ( M A → B − 1 ) T \,\,\boldsymbol{G}=\left( {\boldsymbol{M}_{A\rightarrow B}}^T \right) ^{-1} \\ =\left( {\boldsymbol{M}_{A\rightarrow B}}^{-1} \right) ^T G=(MABT)1=(MAB1)T
  翻译一下:用原来的变换矩阵的 逆矩阵 转置 一下,就能得到我们想要的矩阵 G \boldsymbol{G} G

  当然,值得注意的是,如果 m A → B \boldsymbol{m}_{A\rightarrow B} mAB 本身就是正交矩阵,按照性质, M A → B T = M A → B − 1 {\boldsymbol{M}_{A\rightarrow B}}^T={\boldsymbol{M}_{A\rightarrow B}}^{-1} MABT=MAB1,那么 ( M A → B T ) − 1 = M A → B \left( {\boldsymbol{M}_{A\rightarrow B}}^T \right) ^{-1}=\boldsymbol{M}_{A\rightarrow B} (MABT)1=MAB
  也就是,这个时候的 法线的世界转换矩阵 就是 普通其它顶点的世界矩阵。
  那什么时候它又是正交矩阵呢,答案:当变换只包含旋转,不包含平移和缩放的时候,它就是正交矩阵。
  而如果当变换只有旋转和统一缩放的时候,我们可以利用统一缩放系数 k 来得到 世界矩阵 的逆转置矩阵 ( M A → B T ) − 1 = 1 k M A → B \left( {\boldsymbol{M}_{A\rightarrow B}}^T \right) ^{-1}=\frac{1}{k}\boldsymbol{M}_{A\rightarrow B} (MABT)1=k1MAB。这样可以避免计算逆矩阵的过程。当然,避无可避的时候,就只能计算它的逆矩阵了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值