UnityShader实例08:溶解消融(Dissolve)材质

溶解消融(Dissolve)材质

在不少3D游戏中,角色死亡后会有一个溶解消融的特效,这个除了粒子特效以外还需要shader的配合。下面就是本例实现的一个效果,当然没有例子配合看起来是搓搓的,不过效果基本上已经出来了

UnityShader实例08:溶解消融(Dissolve)材质_第1张图片


shader实现原理


消融效果需要用到的CG函数Clip(),这个函数的定义是如果输入向量的任何一个元素小于0,则抛弃当前像素;所以要实现上图逐渐消融的效果,我们需要一个变化值和一张噪波图(如下图)比较,根据差值变化来抛弃像素。

UnityShader实例08:溶解消融(Dissolve)材质_第2张图片


shader代码实现


首先需要在属性里面声明几个控制参数:

_DissolveTex ("DissolveTex (RGB)", 2D) = "white" 	//噪波图,
_Tile("DissolveTile", Range (0.1, 1)) = 1   		//噪波图的平铺系数,平铺倍数与之成反比
	
_Amount ("DissAmount", Range (0, 1)) = 0.5     		//溶解值,低于这个值,像素将被抛弃       
_DissSize("DissSize", Range (0, 1)) = 0.1 		//预溶解范围大小
    
_DissColor ("DissColor", Color) = (1,0,0,1)		//预溶解范围渐变颜色,与_AddColor配合形成渐变色
_AddColor ("AddColor", Color) = (1,1,0,1)


接下来的工作主要是在Frag函数里面处理,关键代码如下:

//对主纹理采样
fixed4 col = tex2D(_MainTex, i.texcoord);
//对噪波贴图进行采样,取R值
float ClipTex = tex2D (_DissolveTex, i.texcoord/_Tile).r;
//获取裁剪量
float ClipAmount = ClipTex - _Amount; 
if(_Amount > 0)
{
	//噪波图中R通道颜色值低于外部量_Amount,则被裁剪	
	if(ClipAmount < 0)
	{
		clip(-0.1);
	}
	//然后处理没被裁剪的值
	else{
		if(ClipAmount < _DissSize) 
		{
			//针对没被裁剪的点,如果裁剪量小于预溶解范围则使用lerp函数做渐变处理
			float4 finalColor=lerp(_DissColor,_AddColor,ClipAmount/_DissSize)*2;
			//将获得的渐变颜色与主颜色叠加融合
			col = col * finalColor;
		}
	}
}

VF版本代码01:

// - no lighting
// - no lightmap support
// - no per-material color

Shader "PengLu/Unlit/DissolveVF" {
Properties {
	_MainTex ("Base (RGB)", 2D) = "white" {}
	_DissolveTex ("DissolveTex (RGB)", 2D) = "white" {}
	_Tile("DissolveTile", Range (0.1, 1)) = 1
	
	_Amount ("DissAmount", Range (0, 1)) = 0.5                     
    _DissSize("DissSize", Range (0, 1)) = 0.1 
    
	_DissColor ("DissColor", Color) = (1,0,0,1)
	_AddColor ("AddColor", Color) = (1,1,0,1)
}

SubShader {
	Tags { "RenderType"="Opaque" }
	LOD 100
	
	Pass {  
		CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma multi_compile_fog
			
			#include "UnityCG.cginc"

			sampler2D _MainTex,_DissolveTex;  
        	fixed4 _MainTex_ST,_DissolveTex_ST;                      
        	half _Tile,_Amount,_DissSize;           	          
        	half4 _DissColor,_AddColor;         
        	
        	          
			struct appdata_t {
				float4 vertex : POSITION;
				float2 texcoord : TEXCOORD0;		
			};

			struct v2f {
				float4 vertex : SV_POSITION;
				half2 texcoord : TEXCOORD0;
				UNITY_FOG_COORDS(1)
			};
			
			v2f vert (appdata_t v)
			{
				v2f o;
				o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
				o.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
				UNITY_TRANSFER_FOG(o,o.vertex);
				return o;
			}
			
			fixed4 frag (v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.texcoord);
				float ClipTex = tex2D (_DissolveTex, i.texcoord/_Tile).r;
				float ClipAmount = ClipTex - _Amount; 
				if(_Amount > 0)
				{
					if(ClipAmount < 0)
					{
						clip(-0.1);
					}
					else{
						if(ClipAmount < _DissSize) 
						{
							float4 finalColor=lerp(_DissColor,_AddColor,ClipAmount/_DissSize)*2;
							col = col * finalColor;
						}
					}
				}
				UNITY_APPLY_FOG(i.fogCoord, col);
				UNITY_OPAQUE_ALPHA(col.a);
				return col;
			}
		ENDCG
	}
}

}





你可能感兴趣的:(unity3D,shader实例笔记)