Unity Shader 入门精要笔记

纹理动画

纹理动画即控制纹理随着时间的变化而变化。

序列帧动画

首先需要一张包含了所有动画帧的主纹理,它有两点要求,它的每行和每列都应该是可以等分的,它是从左到右,从上到下依次排列的。

序列帧动画的关键在于,计算该时刻下应该播放的关键帧的位置,并对该关键帧进行纹理采样。

步骤如下:

  1. 除了声明序列帧图像的纹理_MainTex外,还需要声明序列帧图像纹理上每一行和每一列有多少个关键帧图像。
  2. 序列帧图像通常都是透明纹理,包含了透明通道,所以需要设置Pass的状态,将其当做一个半透明对象,在SubShader中将Tags设置为:Tags { "RenderType"="Transparent" "Queue"="Transparent" "IgnoreProjector"="True" },并且在Pass中关闭深度写入,使用Blend命令开启混合模式。
  3. 在片元着色器中计算关键帧的位置,并对其采样。

    
           float time = floor(_Time.y * _Speed);
             float row = floor(time/_HorizontalAmount);
             float column = time - row * _VerticalAmount;
    
             // half2 uv=float2(i.uv.x/_HorizontalAmount,i.uv.y/_VerticalAmount);
             // uv.x+=column/_HorizontalAmount;
             // uv.y-=row/_VerticalAmount;
             half2 uv = i.uv + half2(column,-row);
             uv.x /= _HorizontalAmount;
             uv.y /= _VerticalAmount;

    前三行计算了关键帧的位置,即对序列帧中第几个关键帧采样。_Time内置变量存储了该场景加载以来经过了多少时间,其y分量上即是具体的时间。用时间time除以水平方向上关键帧的个数,并对结果向下取证,可以得到对应的行索引,然后用除法结果的余数作为列索引。这样我们就知道了需要对第几个关键帧进行采样。然后我们要计算当前纹理坐标映射到子图像(需要采样的关键帧)中的纹理坐标是多少,这可以用当前的纹理坐标除以行数和列数来获得。最后,我们需要计算最后实际要采样的纹理坐标是多少,这就是关键帧的左上角的坐标来加上坐标偏移量。那么关键帧左上角的坐标是多少?我们知道uv坐标的范围是(0,1),并且在纹理属性中将其设置为了Repeat(值超过1的坐标会舍弃整数部分,取小数进行计算)。因此用行索引和列索引来除以行列上的关键帧个数,即得到了关键帧左上角的坐标。如下图:

滚动动画

很多2D游戏使用了不断滚动的背景来模拟角色在场景中的穿梭,用多个层(layers)来模拟视差效果。

滚动动画的关键在于,使用多张纹理图,对这些纹理图进行采样的时候,uv坐标偏移量随时间变化,并且每张纹理图的单位偏移量不同。
比如,我们要使用两张纹理图来模拟滚动背景。

关键步骤如下:

  1. 声明两张纹理图属性和滚动速度属性。
  2. 在顶点着色器中对uv坐标进行变换:

     o.uv.xy = TRANSFORM_TEX(v.texcoord, _MainTex) + frac(float2(_ScrollX,0.0) * _Time.y);
     o.uv.zw = TRANSFORM_TEX(v.texcoord, _DetailTex) + frac(float2(_Scroll2X,0.0) * _Time.y);
     
  3. 在片元着色器中,利用前景图像纹理的透明通道来混合两张纹理:

     fixed4 firstLayer = tex2D(_MainTex,i.uv.xy);
     fixed4 secondLayer = tex2D(_DetailTex,i.uv.zw);
    
     fixed4 c = lerp(firstLayer,secondLayer,secondLayer.a);
     

顶点动画

顶点动画,即利用时间变量在顶点着色器中对顶点坐标进行偏移。因此需要在SubShader中设置DisableBatching = True.

顶点动画需要注意以下几点:

  1. 需要在SubShader中设置DisableBatching = True。避免Unity Shader的批处理(批处理会合并相关模型,导致模型空间丢失),但是这样会降低性能,因此要避免使用模型空间下的绝对位置和方向进行计算。
  2. 对顶点动画的物体添加阴影效果,无法使用Unity自带的阴影Pass,因为内置的阴影Pass没有进行相关的顶点动画。需要自己编写ShadowCaster Pass。
03-05 20:31