Shader实现喷射蜘蛛网特效

本文由RoadLun原创,转载请声明

效果如下:


由于录屏软件的原因,gif看起来一卡一卡的,实际情况并没有卡顿,详情见篇末资源包
图片是由本人绘制,没有alpha通道,Shader没有用透明度混合,所以整个特效看起来有些low,
阅读本文需要一定shader基础,如果阅读困难,可以先阅读 浅墨大神的Shader教程。
蛛网效果主要由三个部分组成:
1.弧形效果   2.剔除  3.蛛网喷射(放大)  4.蛛网抖动   5.消失    

1.先说第一个弧形效果,我刚开始的思路是用一个Plan,获取Plan的中心点,即UV为(0.5,0.5),然后使Plan的所有顶点沿法线方向外拓,外拓距离为当前顶点到中心点的距离,此距离当作一个二次函数的x值,y值即为外拓长度。
(x*a)²*b=y            用a和b来控制曲面的弧度。

理论上,这是一种可行的方法,但是涉及到逐顶点计算并且涉及到较为复杂的数学运算,这对于GPU来说并不是一件好事,所以我用了一个偷懒的方法模拟弧度,用一个Sphere:


如图,但借用Sphere模拟弧度也不是最佳的方法,还是会有多余的网格,对于CPU来说是一种浪费,让美术同学制作一个弧面模型是最完美的解决方案。
2.好,言归正传,现在解决剔除问题,如果没有剔除,将会显示一个球体,而不是蜘蛛网。
通常用来剔除背景的方式是透明度混合,这种特效看起来更虚幻飘渺,本人电脑上并没有安装PS(ps破解三次都没成功,真是头疼),所以我用CDR来绘制贴图,并没有透明度通道,所以我用在片段着色函数里写discorve方法来剔除背景,设置一个剔除值,如果下当前像素的亮度低于剔除值,则剔除当前像素。
此处我的剔除值初始是0.7,所以刚开始贴图的黑色背景就会被剔除。

3. 蛛网喷射效果,此处我用顶点沿法线外拓的方法实现,外拓的值随时间增大而增大,但外拓后顶点的x值偏移量太大,所以对x进行修正。
4.蛛网的抖动,这里通过顶点进行有频率的抖动实现,同样是在顶点着色器里面,


5. 蛛网消失,操作方法在第二步,通过剔除来实现,使剔除值随时间增大而增大,当超过1时,蛛网被完全剔除掉。

ok,思路就是这样。源码附上:
Shader "Custom/1" {

	Properties
	{
		_Diffuse("漫反射",Color)=(1,1,1,1)
		_MainTex("基础贴图",2D)="white"{}
		//控制溶解的参数
		_DissolveMap("噪波贴图",2D)="white"{}
		_DissolveThreshold("溶解阈值",Range(0,1.1))=0
		_FlyThreshold("破灭程度",Range(0,1))=0.1
		_FlyFactor("破灭延迟",Range(0,0.19))=0.1
		//控制曲线的参数
		_K1("K1",Float)=0.1
		_K2("K2",Float)=0.1
		_B1("B1",Float)=1
	}
	CGINCLUDE
	#include "Lighting.cginc"
	uniform fixed4 _Diffuse;
	uniform sampler2D _MainTex;
	uniform float4 _MainTex_ST;    
	uniform sampler2D _DissolveMap;
	uniform float _DissolveThreshold;
	uniform float _FlyThreshold;
	uniform float _FlyFactor;
	uniform float _K1;
	uniform float _K2;
	uniform float _B1;
	struct v2f
	{
		float4 pos :SV_POSITION;  // 
		float3 worldNormal:TEXCOORD0;  //贴图坐标 0
		float2 uv:TEXCOORD1;   //贴图坐标 1
	};

	v2f vert(appdata_base v)
	{
		//法线外拓
		v2f o;
		_FlyFactor=_Time*2;
		v.vertex.xyz += v.normal * _FlyFactor*10; 
		v.vertex.x-=v.normal*_FlyFactor*30;
		//顶点抖动
		v.vertex.y+=1-sin(_Time.y* +v.vertex.x *_K1 * v.vertex.z+_B1)*_K2;
		o.pos=UnityObjectToClipPos(v.vertex);
		o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
		o.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
		return o;
	}

	fixed4 frag(v2f i): SV_Target
	{
		//剔除
		_DissolveThreshold=_Time+0.7;
		fixed4 dissolveVolue =tex2D(_DissolveMap,i.uv);       
		if(dissolveVolue.r<_DissolveThreshold)							  
		{																  
			discard;													  
		}
		//Diffuse+Ambient 光照计算
        fixed3 worldNormal = normalize(i.worldNormal);													 
        fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);  									 
        fixed3 lambert = saturate(dot(worldNormal, worldLightDir));  									 
        fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz;  		 
        fixed3 color = tex2D(_MainTex, i.uv); 
		return fixed4(color,1);
	}
	ENDCG
	SubShader
	{
		Tags{"RenderType"="Opaque"}
		Pass
		{
		Cull off
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma Lambert          
			ENDCG
		}
	}
	Fallback"Diffuse"

}
资源包(百度网盘):https://pan.baidu.com/s/12Br6wh7ikBgI0H73qFhMMg


猜你喜欢

转载自blog.csdn.net/roadlun/article/details/80288900