【Unity Shader】 消融效果的實現

1.前言

參加騰訊2018遊戲崗校招結果出師未捷身先死,連面試機會都沒有(-_-||),想想筆試自己三道編程題0個ac也就釋懷了233,忙着實習實在沒精力複習算法題,精力有限啊...

吐槽完畢迴歸主題

咱最近在玩wy的神都夜行錄,這款手遊畫面還是挺不錯的,就是肝疼(萬惡的wy策劃)。

刷本的時候看見了如下圖這個消融效果,就想着怎麼用unity shader來實現,畢竟消融效果在遊戲中是非常常見的。

 

2.實現思路

1.使用clip函數對片元進行裁剪來實現模型的消融

clip(value):當value值小於0時,裁減掉該片元,否則保留。

2.使用下面的噪聲圖來實現僞隨機消融,這樣能使效果看起來更加自然。關於什麼是噪聲,可以去看樂樂大師姐(在下小迷弟一枚)寫的關於噪聲的博文-【圖形學】談談噪聲

3.關於顏色侵蝕過渡的實現

從上面的效果圖中可以看見模型在消融時,有明顯的色彩侵蝕過程,這種色彩變化爲消融提供了很好的過渡效果,爲了實現這種效果,我們可以設置一個侵蝕顏色的閾值,根據這個閾值來判斷和返回侵蝕過程中的色彩變化。

//控制侵蝕程度
float _Erode;
//控制侵蝕的顏色閾值
float _ErodeThreshold;

4.光照

直接使用Lambert光照模型,光照的衰減交給unity內置宏來處理

5.關於展示用的模型

手殘黨的福音,給大家推薦一款小巧的免費體素建模軟件-MagicaVoxel, 上手簡單,不好用不要錢~

來給大家展示一下我的作品:

怎麼樣,是不是神還原,哈哈哈哈

3.代碼

下面是完整的shader代碼,關鍵部分加了註釋:

Shader "Unlit/Melt"
{
	Properties{
		_MainTex("Base(rgb)", 2D) = "white"{}
		_NoiseMap("NoiseMap", 2D) = "white"{}
		_StartColor("StarColor", Color) = (0,0,0,0)
		_EndColor("EndColor", Color) = (0,0,0,0)
		_MeltThreshold("MeltThreshold", Range(0, 1)) = 0
		_Erode("Erode", Range(0.0, 1.0)) = 0.98
		_ErodeThreshold("ErodeThreshold", Range(0.0, 1.0)) = 0.71
	}


	SubShader{

		CGINCLUDE

			#include "Lighting.cginc"
			#include "UnityCG.cginc"
			#include "AutoLight.cginc"

			sampler2D _MainTex;
			float4 _MainTex_ST;
			sampler2D _NoiseMap;
			//消融邊緣起始顏色
			fixed4 _StartColor;
			//最終顏色
			fixed4 _EndColor;
			//消融閾值
			float _MeltThreshold;
			//控制侵蝕程度
			float _Erode;
            //控制侵蝕顏色閾值
			float _ErodeThreshold;

			struct a2v{
				float4 vertex : POSITION;
    			float3 normal : NORMAL;
    			float4 texcoord : TEXCOORD0;
			};

			struct v2f{
				float4 pos : SV_POSITION;
				float3 worldNormal : TEXCOORD0;
				float3 worldPos : TEXCOORD1;
				float2 uv : TEXCOORD2;
				SHADOW_COORDS(3)
			};

			v2f vert(a2v v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.worldNormal = UnityObjectToWorldNormal(v.normal);
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				TRANSFER_SHADOW(o);
				return o;
			}

			fixed4 frag(v2f i) : SV_Target{

				//使用噪聲圖採樣
				fixed3 melt = tex2D(_NoiseMap, i.uv).rgb;

				//採樣閾值與設定閾值比較,小於設定的閾值就裁剪掉該片元
				clip(melt.r - _MeltThreshold);

				//光照計算部分,使用蘭伯特漫反射光照模型

				//紋理採樣得到反射率
				fixed3 albedo = tex2D(_MainTex, i.uv).rgb;
				//世界法線
				fixed3 worldNormal = normalize(i.worldNormal);
				//入射光
				fixed3 worldLightDir = normalize(UnityWorldSpaceLightDir(i.worldPos));
				UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);
				//計算環境光
				fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz * albedo;
				//漫反射
				fixed3 diffuse = _LightColor0.rgb * albedo * max(0, dot(worldNormal, -worldLightDir));
				//最終光照
				fixed3 lightColor = diffuse * atten + ambient;
				//侵蝕計算部分
				float result = _MeltThreshold / melt.r;

				if(result > _Erode){
					//如果結果大於消融顏色的閾值,則返回消融結束部分的顏色,否則返回初始顏色
					if(result > _ErodeThreshold) {
						return _EndColor;
					}
					
					return _StartColor;

				}
				//直接返回光照後顏色
				return fixed4(lightColor, 1);
			}

		ENDCG


		Pass{

			Tags{ "RenderType" = "Opaque"}
			Cull off
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag

			ENDCG
		}
	}

	FallBack Off
}

 

爲了看見整個模型的消融過程,我選擇關閉了剔除

Cull Off  //關閉遮擋剔除

創建一個腳本來控制消融的程度,實現自動播放的效果

  Melt.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Melts : MonoBehaviour {

	public Material material;

	[Range(0.01f, 1.0f)]
	public float meltSpeed = 0.2f;

	private float meltThreshold = 0.0f;

	void Start(){
		material.SetFloat("_MeltThreshold", 0);
	}

	void Update(){
		//使用時間控制消融閾值
		meltThreshold = Mathf.Repeat(Time.time * meltSpeed, 6.0f);
		material.SetFloat("_MeltThreshold", meltThreshold);

	}

}

4.實現效果

來看看實現效果:

emmm,好像顏色有什麼地方不對勁....

截圖與遊戲效果圖對比看看

通過對比可以發現,遊戲截圖中的色彩明顯亮於我所使用的顏色。

這五毛錢特效可沒臉拿出去見人啊 QAQ

5.修改後的效果

想起從樂樂學姐那裏偷師學來的bloom效果,翻出之前寫的代碼加上去試試看效果咋樣

!!! 瞬間感覺高大上了,並且有一種金屬感,效果的還原度也很高

關於bloom效果

bloom效果屬於圖像處理的一種,這種圖像處理技術在渲染中常被稱爲後處理,由腳本和shader共同實現。

bloom的原理簡單的來說就是對圖像中亮度較高的區域進行高斯模糊處理,由於篇幅的原因我這裏不貼出具體代碼,對bloom感興趣的可以看看我的github,我把該效果的源碼放在了GitHub上。

鏈接:我的GitHub

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章