效果展示:
Shader功能:影象變白+根據頂點的y值作透明裁剪;
才是可操作屬性:
IsDead: 控制畫素變白,片元著色階段IsDead小於0將顏色改為白色;
Percent: 透明剔除分界線,也是圖片展示百分比;在頂點計算階段,記錄Percent - vertex.y值,傳入片元著色器,直接裁剪;
Revert:反轉percent結果;(粒子顯示效果和圖片遮擋效果正好相反)
調整shader中Percent得到如下結果:
使用該shader建立兩個材質,spriterenderer和ParticalSystemRenderer分別使用,ParticalSystem勾選Revert;
完整shader:
Shader "PixelDisappear"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_IsDead("IsDead",float) = 1
_Percent("Percent",Range(-8,10))=0
_Revert("Revert",float) = 1
}
SubShader
{
Tags { "RenderType"="Opaque" }
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float3 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _Percent;
float _IsDead;
float _Revert;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex);
if(_Revert > 0)
o.uv.z = _Percent - v.vertex.y;
else
o.uv.z = -_Percent + v.vertex.y;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
clip(i.uv.z);
fixed4 col;
if(_IsDead < 0)
col = float4(1,1,1,1);
else
col = tex2D(_MainTex, i.uv);
return col;
}
ENDCG
}
}
}
基礎屬性設定:
maxparticle控制最大粒子數量;
stopaction決定粒子非loop結束後是disable還是銷燬;
gravitymodifier新增一點重力,負值向上移動粒子;
粒子新增shape元件;
選擇SpriteRender,需要晶格化的gameobject賦值給Sprite;
Clip裁剪透明通道;
Emisson元件,選擇隨時間,或者Burst都可;
粒子數量不能高於MaxParicles的設定(高了也沒用);
Noise元件設定固定捲動速度;
Quality選2D;
Renderer元件中,新增上面寫好的shader材質;
size設定粒子大小;
使用時,程式碼控制兩個材質的percent屬性;
public class Test : MonoBehaviour
{
public SpriteRenderer SP;
public ParticleSystem PS;
private bool isDead;
private float curTime;
private float offset;
private float speed = 6.5f;
Material matPS;
[SerializeField]private float startVal = 10;
private void Start()
{
matPS = PS.GetComponent<Renderer>().sharedMaterial;
matPS.SetFloat("_Percent", startVal );
SP.sharedMaterial.SetFloat("_Percent", startVal );
SP.sharedMaterial.SetFloat("_IsDead",1);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.P))
{
isDead = true;
matPS.SetFloat("_Percent", startVal );
SP.sharedMaterial.SetFloat("_Percent", startVal );
matPS.SetFloat("_IsDead",-1);
var mainModule = PS.main;
mainModule.loop = true;
PS.gameObject.SetActive(true);
offset = 0;
}
if (isDead)
{
offset += Time.deltaTime * speed;
matPS.SetFloat("_Percent", startVal - offset);
SP.sharedMaterial.SetFloat("_Percent", startVal - offset);
if (matPS.GetFloat("_Percent") < -10)
{
isDead = false;
var mainModule = PS.main;
mainModule.loop = false;
}
}
}
}