Unity Shader入门精要 第十五章

  1. 1. 使用噪声
  2. 2. 15.1 消融效果
  3. 3. 15.2 水波效果
  4. 4. 15.3 再谈全局雾效

使用噪声


15.1 消融效果

  • 消融(dissolve)效果常见于游戏中的角色死亡、地图烧毁等效果。在这些效果中,消融往往从不同的区域开始,并向看似随机的方向扩张,最后整个物体都将消失不见

消融效果

  • Shader:
  • _BurnAmount用于控制消融程度
  • _LineWidth控制模拟烧焦效果的线宽,值越大,火焰边缘的蔓延范围越广
  • _MainTex和_BumpMap对应漫反射纹理和法线纹理
  • _BurnMap就是噪声纹理

  • 还定义了一个阴影Pass,这是因为如果被剔除的区域仍然向其他物体投射阴影的话,会产生穿帮的效果,为了让阴影也能配合透明度测试产生正确的效果,需要定义一个投射阴影的Pass

15.2 水波效果

  • 在模拟实时水面的过程中,往往也会使用噪声纹理。此时,噪声纹理通常会用作一个高度图。以不断修改水面的法线方向。为了模拟水不断流动的效果,会使用和时间相关的变量来对嗓声纹理进行采样,当得到法线信息后,再进行正常的反射+折射计算,得到最后的水面波动效果
  • Shader:
  • _WaveMap是一个由噪声纹理生成的法线纹理
  • _CubeMap是用于模拟反射的立方体纹理
  • _Distortion用于控制模拟折射时的图像扭曲程度
  • _WaveXSpeed和_WaveYSpeed分别控制法线纹理在x和y方向上的平移速度
  • 把Queue设置成Transparent可以确保改物体渲染时,其他所有的不透明物体已经被渲染到了屏幕上。否则就可能无法正确得到透过水面看到的图像
  • 设置RenderType是为了在使用着色器替换时,该物体可以在需要时被正确的渲染。这通常发生在需要得到摄像机深度和法线纹理时
  • 通过关键词GrabPass来定义一个抓取屏幕图像的Pass,在这个Pass中定义了一个字符串,该字符串内部的名称就决定了抓取得到的屏幕图像会被存储在哪个纹理中,也就是此处的_RefractionTex
  • _RefractionTex_TexelSize可以得到该纹理的像素大小。比如一个大小为256x512的纹理,它的纹素大小就是1/256及1/512。需要对屏幕图像的采样坐标进行偏移时,就使用该变量
  • 使用ComputeGrabScreenPos()函数得到对应被抓取的屏幕图像的采样坐标
  • 之后对两个纹理运用平移和缩放
  • 之后为了在片元着色器中把法线方向从切线空间变换到世界空间下,以便对CubeMap进行采样,因此需要在这里计算该顶点对应的从切线空间到世界空间的变换矩阵,并把该矩阵每一行分别存储在TtoW0、1、2中,其中xyz分量就是变换矩阵的分量,w分量为了不浪费,把世界空间下的顶点坐标放进去了
  • 在片元着色器中做实际的运算
  • 首先将w分量取出来,得到顶点的世界坐标,并用该值得到该片元对应的视角方向
  • 利用_Time.y和WaveSpeed计算法线纹理的偏移量,并利用该值对法线纹理做二次采样
  • 为了模拟两层交叉的水面波动效果,对两次结果相加并归一化后,就得到了切线空间下的法线方向
  • 利用该值和_Discortion属性及_RefractionTex_TexelSize对屏幕图像的采样坐标进行偏移以模拟折射效果,_Discortion值越大,偏移就越大,水面背后的物体看起来变形程度就越大
  • 这里选择使用切线空间下的法线进行偏移,是因为该空间下的法线可以反应顶点局部空间下的法线方向
  • 需要注意的是,把这个偏移量和屏幕坐标的z分量相乘,是为了模拟深度最大,折射程度最大的效果。也可以把屏幕偏移值叠加到屏幕坐标上面
  • 之后对sorPos运用透视除法,再使用该坐标对屏幕抓取的图像进行采样得到模拟的折射颜色
  • 之后把法线从切线空间变换到世界空间下,这里使用到前面获取的变换矩阵,并据此得到视角方向对于法线方向的反射方向,随后使用反射方向对CubeMap进行采样,并把结果和主纹理颜色相乘以得到反射的颜色。同时对主纹理进行这样的纹理动画,以模拟水波的效果
  • 为了去混合折射和反射的颜色,随后计算分量系数,使用之前的公式计算,并据此混合折射反射的颜色,以得到最终的输出颜色

15.3 再谈全局雾效

  • 在前面讲到了如何使用深度纹理来实现一种基于屏幕后处理的全局雾效。我们由深度纹理重建每个像素在世界空间下的位置,再使用一个基于高度的公式来计算雾效的混合系数,最后使用该系致来混合雾的颜色和原屏幕颜色。前面的实现效果是一个基于高度的均匀雾效,即在同一个高度上,雾的浓度是相同的
  • 然而,一些时候我们希望可以模拟一种不均匀的雾效,同时让雾不断飘动,使雾看起来更加飘渺
  • 而这就可以通过使用一张噪声纹理来实现
  • MainCamera上的脚本:
  • 首先获取摄像机的相关参数,这是为了计算摄像机在世界空间下的位置,以及世界空间下该像素对应摄像机的偏移量
  • fogDensity用于控制雾的浓度
  • 使用的雾效模拟函数是基于高度的,因此fogStart用于控制雾的起始高度,fogEnd用于控制雾的终止高度

  • Shader: