经常在影视作品中看到一些电流滋啦啦的效果,看上去特牛逼,就想怎么实现以下。

 
从特效那里获得这个场景的时候发现这个效果真的很有意思,以前的电流效果一般是用贴图动画或是直接用程序控制面片位移来得到这样的效果。看来要多看别人的shader实现,就会有更多的收获。 
但当我打开Electricity_Sh.shader,这个最关键的shader的时候,我感觉蛋蛋悠悠的疼,这NM就是反编译回来的代码。我不知道如何产生这样的代码,如果有人知道那请教教小弟。大家可以打开源文件看看,全都是float4 Mask8=float4(0.0,v.texcoord.y,0.0,0.0);这样不知所云的东西,还是花了一个下午看完了。我不知道如何产生着样的代码略有收获现在就更大家分享一下,希望大家也能受益。 
 
上图就是闪电原来的样子,一条螺旋形的丝带,为什么要是这个样子的,再后边讲解源码的时候我会讲到。先要给大家一个印象。Shader主要改变的只是每个顶点的位置。明白的了大家再往下看。 
 
下面是我改好的vs代码 


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void vert (inout appdata_full v, out Input o) {
    
float4 m_time = frac((_Time + v.color.r + v.color.g + v.color.b)* float4( 0.05));
float4 m_time_global = m_time * float4( 25) * float4(_MotionRateGlobal);
float4 floor0 = floor(m_time_global * float4(1.123));
float4 floor1 = floor(m_time_global * float4(3));
//Z轴的初始偏移量
float4 zoffset = m_time_global + (floor0 + floor1)* float4( 8.93);
o.color = v.color;
float4 zRates = float4(3,0.15,0.15,-0.1051);
float4 zFrequencys = float4(193.1759,8.567,93.15,25.31);
float4 zScales = float4(0.25,5,0.5,1.5);
float4 zSum = float4(0);
for(int i=0;i<4;i++)
{
float4 offset = zoffset * _NoiseMotionRate.xxxx * zRates[i];
offset = float4(0.0,v.texcoord.y,0.0,0.0) + offset;
offset = offset * zFrequencys[i] * _NoiseFrequency.xxxx;
float4 SinOffset = sin(offset);
float4 sum = SinOffset * zScales[i] * _NoiseScale.xxxx;
zSum += sum;
}
//y轴的初始偏移量
float4 yoffset = zoffset + float(2);
float4 yRates = float4(0.256,0.190731,2.705931,-0.107335);
float4 yFrequencys = float4(7.071,79.533,179.5317,23.0917);
float4 yScales = float4(5,0.5,0.25,1.5);
float4 ySum = float4(0);
for(int i=0;i<4;i++)
{
float4 offset = yoffset * _NoiseMotionRate.xxxx * yRates[i];
offset = float4(0.0,v.texcoord.y,0.0,0.0) + offset;
offset = offset * yFrequencys[i] * _NoiseFrequency.xxxx;
float4 SinOffset = sin(offset);
float4 sum = SinOffset * yScales[i] * _NoiseScale.xxxx;
ySum += sum;
}
    
float4 Mask1=float4(0.0,ySum.y,zSum.y,0.0);
    
float4 Add13=float4( -1) + v.texcoord.y * float4( 2);
float4 Abs0=abs(Add13);
float4 Lerp1 = lerp(Mask1,float4( 0.0 ),Abs0);
float4 Add0=Lerp1 + v.vertex;
v.vertex = Add0;
    
o.meshUV.xy = v.texcoord.xy;
o.meshUV.zw = v.texcoord1.xy;
}




这里需要详细的讲解一下。 
 float4 m_time = frac((_Time + v.color.r + v.color.g + v.color.b)* float4( 0.05)); 
 float4 m_time_global = m_time * float4( 25) * float4(_MotionRateGlobal); 
 float4 floor0 = floor(m_time_global * float4(1.123)); 
 float4 floor1 = floor(m_time_global * float4(3)); 
这里主要获得了floor0floor1相当于是让闪电有一个跳动的感觉,floor函数会使floor0floor1有一个较大的值得变化,从而使闪电在形状上有较大的变化。 
需要floor0floor1是为了让跳动看上去不那么规律,大家可以将一个置零,看看效果。 
 
 
 //Z轴的初始偏移量 
 float4 zoffset = m_time_global + (floor0 + floor1)* float4( 8.93); 
 o.color = v.color; 
 
 float4 zRates = float4(3,0.15,0.15,-0.1051); 
 float4 zFrequencys = float4(193.1759,8.567,93.15,25.31); 
 float4 zScales = float4(0.25,5,0.5,1.5); 
 
 float4 zSum = float4(0); 
 
 for(int i=0;i<4;i++) 
 { 
 float4 offset = zoffset * _NoiseMotionRate.xxxx * zRates; 
 offset = float4(0.0,v.texcoord.y,0.0,0.0) + offset; 
 offset = offset * zFrequencys * _NoiseFrequency.xxxx; 
 float4 SinOffset = sin(offset); 
 float4 sum = SinOffset * zScales * _NoiseScale.xxxx; 
 
 zSum += sum; 
 } 
闪电上凹凸不平的效果归功于上面这些代码,主要的功能是结合四个振幅,偏移,速率不同的正玄函数的解,用于z轴上的偏移,为什么会这个样子,只能说 
             float4 zRates = float4(3,0.15,0.15,-0.1051); 
 float4 zFrequencys = float4(193.1759,8.567,93.15,25.31); 
 float4 zScales = float4(0.25,5,0.5,1.5); 
这些参数取得好,相当于简单的傅里叶变化。如果要问我这些参数怎么来,我也不知道,要请知道的大牛指点了。不过,可以用matlabb这样的工具试出来。 
 
   下面一段函数,和上面一样用于y轴上的偏移。 
 
   问题来了 ,x轴上的偏移为什么不用动?其实动了,原因就在前面讲到的模型为什么是螺旋线的,这样的话就省去了x轴上的偏移,大家也可以看到效果非常好。 
 
最后,可以发现电流的顶点和末点都是不动的,原因就在于模型的UV值,其中的v值在01的时候,偏移值就是0。大家可以根据这些代码改出自己想要的效果。希望对大家有所启发。不清楚的地方可以多多提问。