UnityShader 中级篇(三)
纹理动画
往往会使用纹理动画来代替复杂的粒子系统等模拟各种动画效果
序列帧动画
只需制作一张序列帧纹理,它的优点在于灵活性很强,不需要进行任何物理计算就可以得到非常细腻的动画效果。而缺点也很明显,由于序列帧中每张关键帧图像都不一样,因此,要制作一张出色的序列帧纹理所需的美术工程量也比较大。
- 声明多个属性,设置该序列帧动画的相关参数:
- 序列帧图像通常是透明纹理,需设置Pass的相关状态
- 顶点着色器
- 片元着色器是重头戏
- 最后把Fallback设置为内置的Transparent/VertexLit(也可选择关闭Fallback)
最终效果
滚动的背景
使用的纹理资源均来自OpenGameArt
- 声明新的属性:
- 顶点着色器
- 片元着色器
- Fallback设置为内置的VertexLit(也可选择关闭Fallback):
最终效果
顶点动画
学习两种常见的顶点动画的应用——流动的河流以及广告牌技术。
流动的河流
需要模拟多层水流效果,还创建了WaterMat1和WaterMat2 材质。场景中创建多个Water模型,调整它们的位置、大小和方向,然后拖拽材质给它们。
- 声明了一些新的属性:
- 为透明效果设置合适的SubShader标签:
- 一些SubShader在使用Unity的批处理功能时会出现问题,这时可通过该标签来直接指明是否对该SubShader使用批处理。而这些需要特殊处理的Shader通常是指包含了模型空间的顶点动画的Shader。这是因为,批处理会合并所有相关的模型,而这些模型各自的模型空间就会丢失。在本例中,需要在物体的模型空间下对顶点位置进行偏移。因此,在这里需要取消对Shader的批处理操作。
- 设置了Pass的渲染状态:
- 在顶点着色器中进行了相关的顶点动画:
- 片元着色器,只需对纹理采样再添加颜色控制即可:
- 最后把Fallback设置为内置的Transparent/VertexLit(也可选择关闭Fallback)
最终效果
广告牌
另一种常见的顶点动画是广告牌技术(Billboarding)。广告牌技术会根据视角方向来旋转一个被纹理着色的多边形(通常就是简单的四边形,该多边形就是广告牌),使得多边形看起来好像总是面对着摄像机。
广告牌技术的本质就是构建旋转矩阵,而知道一个变换矩阵需要3个基向量。广告牌技术使用的基向量通常就是表面法线(normal)、指向上的方向(up)以及指向右的方向(right)。除此之外,还需要指定一个锚点(anchor location),这个锚点在旋转过程中是固定不变的,以此来确定多边形在空间中的位置。
广告牌技术的难点在于,如何根据需求来构建3个相互正交的基向量。计算过程通常是,先会通过初始计算得到目标的表面法线和指向上的方向,而两者往往是不垂直的。但两者其中之一是固定的,例如当模拟草丛时,希望广告牌的指向上的方向永远是(0,1,0),而法线方向应该随视角变化;而当模拟粒子效果时,希望广告牌的法线方向是固定的,即总是指向视角方向,指向上的方向则可以发生变化。假设法线方向是固定的,首先,根据初始的表面法线和指向上的方向来计算处目标方向的指向右的方向(通常叉积操作):
right = up x normal
对其归一化,再由法线方向和指向右的方向计算出正交的指向上的方向即可:
up = normal x right
至此,可得到用于旋转的3个正交基了。如图,如果指向上的方向是固定的,计算过程也是类似的。
创建多个四边形(Quad),调整它们的位置和大小,然后新建的材质拖曳给它们。这些四边形就是用于广告牌技术的广告牌。
- 首先声明了几个新的变量:
- 设置Pass的渲染状态
- 顶点着色器是核心,所有的计算都在模型空间下进行
- 片元着色器
- 最后把Fallback设置为内置的Transparent/VertexLit(也可选择关闭Fallback)
最终效果
注意事项
在模型空间下进行了一些顶点动画,那么批处理往往会破坏这种动画效果。这时,可通过 SubShader 的 DisableBatching 标签来强制取消对该Shader的批处理。然后,取消批处理会带来一定的性能下降,增加了Draw Call,因此尽量避免使用模型空间下的一些绝对位置和方向来进行计算。在广告牌的例子中,为了避免显示使用模型空间的中心来作为锚点,可利用顶点颜色来存储每个顶点到锚点的距离值。
Unity的阴影绘制需要调用一个ShadowCaster Pass,而如果直接使用这些内置的ShadowCaster Pass,这个 Pass 中并没有进行相关的顶点动画,因此Unity会仍然按照原来的顶点位置来计算阴影,这并不是希望看到的。
模拟一个波动的水流,同时,开启了场景中平行光的阴影效果,并添加了一个平面来接收来自"水流"的阴影。还把这个Unity Shader 的 Fallback 设置为了内置的VertexLit,根据 Fallback 最终找到 VertexLit 中的ShadowCaster Pass 来渲染阴影。
- ShadowCaster Pass,相关代码如下:
最终效果