首先,准备一个Shader,用来显示霓虹几何体。它使用两个不同的贴图,一个用于白色霓虹中心,另一个用于围绕着它的发光。

Shader代码如下:

 

[AppleScript] 纯文本查看 复制代码

  fixed4 frag_mult(v2f_vct i) : COLOR
  {
  fixed4 result = tex2D(_MainTex, i.texcoord) * i.color;
  return result;
  }

效果如下图:

 
  垂直偏移

 

  简单的加上垂直偏移——修改查找位置

  代码如下:

[AppleScript] 纯文本查看 复制代码
  float2 displacedTexCoord = i.texcoord + float2(0, .05);
  fixed4 result = tex2D(_MainTex, displacedTexCoord) * i.color;
  return result;

  效果如下:

  效果并不佳,但至少有助于理解它是如何在垂直方向发生偏移的。瓷砖地图的瓷砖贴图来自精灵表单(Spritesheet)中不同的精灵(Sprite)。

 

  垂直移动

 

  现在我们来给它添加一些移动,实现这一点最简便的方法是使用Unity提供给Shader的_Time组件:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(0, cos(_Time.x * 50))/20;

  我们有两个值可以进行调整。50影响循环将怎样进行,而20跟摆动宽度有关。

  以下是使用float2(0, cos(_Time.x * 25))/20形成的缓慢移动的示例。

  以下是使用float2(0, cos(_Time.x * 50))/40形成的不那么宽幅移动的示例。

 

  全移动

 

  在X轴也添加一些移动:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord +
  float2(sin(_Time.x * 50), cos(_Time.x * 50))/40;

 

  静态随机性

 
  现在, 我们来引入一些随机性。因为在Shader代码中添加随机数很麻烦,所以最简单的方法是使用噪声贴图。

  Perlin noise(柏林噪声)算法图像很容易找到。把它添加到Shader的一个属性,进行设置,然后就可以使用了。过程中可能会遇到的问题就是这些奇怪的截断线,是由于使用非无缝柏林噪音贴图造成的。寻找一张无缝的贴图,一切就会接合得很好。

  开始没有移动:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(tex2D(_NoiseTex, i.texcoord).xy)/20;

  末尾的20控制偏移大小。使用40就会像下面这样。

  请注意它的锯齿没有那么大。

 
 
  动画化的随机性
 
  是不是觉得还是很无趣,我们添加点随机动画。

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(
  tex2D(_NoiseTex, i.texcoord + float2(_SinTime.w, _CosTime.w)/10).xy)/25;

  效果如下图:

    然而,如果仔细看,你会发现动画的方向在循环变换:垂直的墙在上下变化,而水平的墙在左右变化。我们在后面再来解决这个问题。这里还隐藏了一个问题,你看不到它是因为使用的值。

  如果仔细看这张图,你就会看到它是如何重复的。同样地,仔细看瓷砖的边缘,每过一会儿你都会看到凸出的小点。

  
  无缝随机性
 
  所有在噪声贴图中的查找都是基于原始贴图中的位置。这意味着两个相邻而且一样的瓷砖将会有完全一样的噪声。要解决这个问题,我们需要基于它的绝对位置来建立查找。

  这必须要先设置好,像这样:o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); 这一行进入到vertex方法,而不是fragment方法。

  理解以上内容之后,我们就可以这样做:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(

  tex2D(_NoiseTex, i.vertex.xy/300 + float2(_SinTime.w, _CosTime.w)/10).xy)/20;

  注意i.vertex.xy——它将确保output中相邻的像素会从噪声贴图中抓取相邻的位置。这就解决了“平铺”的问题,但却使循环移动的问题更加突出了。

 
  无缝无方向的随机性
 
  为了解决这个方向性问题,我们做一个直线偏移:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord +
  float2(tex2D(_NoiseTex, i.vertex.xy/300 + float2((_Time.w%50)/50, (_Time.w%50)/50)).xy)/20;

  注意:现在一直是正确的方向了,它一直走向左上角。(_Time.w%50)/50这样的技巧是为了将_Time.w(这是一个持续增加的值)约束在0-1的范围内。
 
  准确定位问题
 
  为了准确解释这个解决方案,我们尝试更多的步骤,首先去掉x轴的偏移:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(
  0,
  tex2D(_NoiseTex, i.vertex.xy/300 + float2((_Time.w%50)/50, (_Time.w%50)/50)).z
  )/20;

  注意我如何在x上做0偏移,而对.z分量用的是在噪声贴图上按y轴的查找(选择.z是为了少些混乱,实际上我们所做的一切是从刚刚查找的噪声像素上选择一个颜色通道)。

  现在效果如下(垂直方向是静止的):

  试着用一个类比来描述这个问题。

  I假设有一个信箱口,非常宽但一点也不高(比方说1英尺宽,0.1英尺高)。同时 你 正在通过这个口观察,而另一边挂着一件扎染T恤(随机图案)正在移动。现在假设T恤是自左向右移动, 你 将马上看到它的方向性,因为之前看到的画面框架还有一部分在视觉中做参考。如果T恤是上下移动,所有东西看起来就是随机的。

  下面是运行中的画面。全移动:

  同样的图像通过一个很小的视口观察的效果:

  明白为何左图的侧向移动有明显规则,而右图的垂直运动看起来却是随机的?

 
  解决
 
  现在回到我们的问题,需要做的是马上移动贴图。像在x轴移动一样简单:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(
  0,
  tex2D(_NoiseTex, i.vertex.xy/300 + float2(0, (_Time.w%50)/50)).z
  )/20;

  要让它垂直方向也有波动,我们使用与x轴相同的原则。把它们放在一起看起来是这样:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(
  tex2D(_NoiseTex, i.vertex.xy/300 + float2((_Time.w%50)/50, 0)).z,
  tex2D(_NoiseTex, i.vertex.xy/300 + float2(0, (_Time.w%50)/50)).z
  )/20;

 

  一个小修正

 

  另一个我们需要修正的问题是让偏移对称。现在,由于它是使用.z分量(上面说过,它是蓝色通道),它的值应该是处于0~1之间。减去0.5将使它变成-0.5~0.5,这样一切就很好地居中了:

[AppleScript] 纯文本查看 复制代码

  float2 displacedTexCoord = i.texcoord + float2(
  tex2D(_NoiseTex, i.vertex.xy/300 + float2((_Time.w%50)/50, 0)).z - .5,
  tex2D(_NoiseTex, i.vertex.xy/300 + float2(0, (_Time.w%50)/50)).z - .5
  )/20;

  结合文章开头提到的霓虹整个效果就完整了,效果如下:

 

  最终结果

 

  再做一些刚才提到过的数字调节(很细微的东西),添加一些背景(使用同一个Shader的修改版本),这样大功告成了。

文章来源于腾讯gad游戏开发平台。