使用Unity3D實(shí)現(xiàn)選中物體消融特效的方法詳解
1 消融特效原理
消融特效中基于 Shader Graph 實(shí)現(xiàn)了消融特效,本文將基于 Shader 實(shí)現(xiàn)消融特效。
當(dāng)前實(shí)現(xiàn)消融特效的方法主要有 Alpha 測(cè)試消融、clip(或 discard)消融,它們的本質(zhì)都是隨機(jī)丟棄一些片元,以實(shí)現(xiàn)消融效果。
1)噪聲紋理
為模擬隨機(jī)效果,可以通過(guò)對(duì)噪聲紋理進(jìn)行采樣實(shí)現(xiàn),如下是一些常用的噪聲紋理。

這些噪聲紋理有一個(gè)共同特點(diǎn):在較小的鄰域范圍內(nèi),灰度是漸變的,使得模擬的消融效果更加和諧。
2)Alpha 測(cè)試消融原理
將片元的 alpha 通道設(shè)置為隨機(jī)值,通過(guò) AlphaTest 剔除 alpha 值小于閾值的片元,以實(shí)現(xiàn)消融效果,代碼如下。由于改變了 alpha 通道值,該方案會(huì)影響半透明物體的混合效果。
AlphaTest Greater [_AlphaThreshold]
...
fixed4 frag(v2f i) : SV_Target {
fixed noise = tex2D(_NoiseTex, i.uvNoiseTex).r; // 噪聲采樣
...
return fixed4(r, g, b, noise);
}3)clip(或 discard)消融原理
對(duì)噪聲紋理進(jìn)行采樣,使得每個(gè)片元都對(duì)應(yīng)一個(gè)噪聲值,通過(guò) clip(或 discard)函數(shù)剔除噪聲值小于閾值的片元,代碼如下。
fixed4 frag(v2f i) : SV_Target {
fixed noise = tex2D(_NoiseTex, i.uvNoiseTex).r; // 噪聲采樣
float factor = noise - _BurnAmount;
clip(factor); // 剔除factor小于0的片元, 即: if(factor < 0) discard;
...
}2 消融特效實(shí)現(xiàn)
DieController.cs
using UnityEngine;
public class DieController : MonoBehaviour {
private RaycastHit hit; // 碰撞信息
private void Start() {
hit = new RaycastHit();
}
private void Update() {
if (Input.GetMouseButtonUp(0)) {
GameObject hitObj = GetHitObj();
if (hitObj != null) {
GameObject rootObj = GetRootObj(hitObj);
rootObj.AddComponent<DissolveEffect>();
}
}
}
private GameObject GetHitObj() { // 獲取屏幕射線碰撞的物體
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit)) {
return hit.collider.gameObject;
}
return null;
}
private GameObject GetRootObj(GameObject obj) { // 獲取根對(duì)象
while (obj.transform.parent != null && obj.layer == obj.transform.parent.gameObject.layer) {
obj = obj.transform.parent.gameObject;
}
return obj;
}
}說(shuō)明:DieController 腳本組件掛在相機(jī)上。
DissolveEffect.cs
using UnityEngine;
[DisallowMultipleComponent] // 不允許在同一對(duì)象上掛載多個(gè)該組件
public class DissolveEffect : MonoBehaviour {
private Renderer[] renderers; // 渲染器
private Material dissolveMat; // 消融材質(zhì)
private float burnSpeed = 0.25f; // 燃燒速度
private float burnAmount = 0; // 燃燒量, 值越大模型鏤空的越多
private void Awake() {
dissolveMat = Resources.Load<Material>("DissolveMat");
renderers = GetComponentsInChildren<Renderer>();
}
private void OnEnable() {
foreach (Renderer renderer in renderers) {
Material[] materials = renderer.sharedMaterials;
Material[] dissolveMaterials = new Material[materials.Length];
for (int i = 0; i < materials.Length; i++) {
Material newMaterial = new Material(dissolveMat);
SetTexture(materials[i], newMaterial);
SetColor(materials[i], newMaterial);
newMaterial.SetFloat("_BurnAmount", 0);
dissolveMaterials[i] = newMaterial;
}
renderer.sharedMaterials = dissolveMaterials;
}
}
private void Update() {
burnAmount += Time.deltaTime * burnSpeed;
foreach (Renderer renderer in renderers) {
Material[] materials = renderer.sharedMaterials;
foreach (Material material in materials) {
material.SetFloat("_BurnAmount", burnAmount);
}
}
if (burnAmount >= 1f) {
Destroy(gameObject);
}
}
private void SetTexture(Material oldMaterial, Material newMaterial) { // 設(shè)置材質(zhì)
if (oldMaterial.HasTexture("_MainTex")) {
Texture texture = oldMaterial.GetTexture("_MainTex");
newMaterial.SetTexture("_MainTex", texture);
}
}
private void SetColor(Material oldMaterial, Material newMaterial) { // 設(shè)置顏色
Color color = Color.white;
if (oldMaterial.HasColor("_Color")) {
color = oldMaterial.GetColor("_Color");
}
newMaterial.SetColor("_Color", color);
}
}DissolveEffect.shader
Shader "MyShader/DissolveEffect" {
Properties {
_MainTex("Main Tex", 2D) = "white" {} // 主紋理
_Color("Color", Color) = (1, 1, 1, 1) // 模型顏色
_NoiseTex("Noise Tex", 2D) = "white"{} // 噪聲紋理
_BurnAmount("Burn Amount", Range(0, 1)) = 0 // 燃燒量, 值越大模型鏤空的越多
_LineWidth("Burn Line Width", Range(0, 0.2)) = 0.1 // 燃燒的線條寬度
_BurnOuterColor("Burn Outer Color", Color) = (1, 0, 0, 1) // 燃燒線條的外側(cè)顏色
_BurnInnerColor("Burn Inner Color", Color) = (1, 0, 0, 1) // 燃燒線條的內(nèi)側(cè)顏色
}
SubShader {
Tags { "RenderType"="Opaque" "Queue"="Geometry"}
Pass {
Tags { "LightMode"="ForwardBase" }
Cull Off // 關(guān)閉剔除, 正反面都渲染, 因?yàn)橄跁?huì)裸漏模型內(nèi)部結(jié)構(gòu)
CGPROGRAM
#include "Lighting.cginc"
#pragma vertex vert
#pragma fragment frag
sampler2D _MainTex; // 主紋理
fixed4 _Color; // 模型顏色
sampler2D _NoiseTex; // 噪聲紋理
fixed _BurnAmount; // 燃燒量, 值越大模型鏤空的越多
fixed _LineWidth; // 燃燒的線條寬度
fixed4 _BurnOuterColor; // 燃燒線條的外側(cè)顏色
fixed4 _BurnInnerColor; // 燃燒線條的內(nèi)側(cè)顏色
float4 _MainTex_ST; // _MainTex的縮放和偏移
float4 _NoiseTex_ST; // _NoiseTex的縮放和偏移
struct a2v {
float4 vertex : POSITION; // 模型空間頂點(diǎn)坐標(biāo)
float3 normal : NORMAL; // 模型空間頂點(diǎn)法線向量
float4 texcoord : TEXCOORD0; // 頂點(diǎn)紋理坐標(biāo)
};
struct v2f {
float4 pos : SV_POSITION; // 裁剪空間頂點(diǎn)坐標(biāo)
float3 normal : Normal; // 世界空間頂點(diǎn)法線向量
half2 uvMainTex : TEXCOORD0; // 主紋理的紋理坐標(biāo)
half2 uvNoiseTex : TEXCOORD1; // 噪聲紋理的紋理坐標(biāo)
float3 worldPos : TEXCOORD2; // 世界空間頂點(diǎn)坐標(biāo)
};
v2f vert(a2v v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex); // 模型空間頂點(diǎn)坐標(biāo)變換到裁剪空間, 等價(jià)于: mul(UNITY_MATRIX_MVP, v.vertex)
o.normal = UnityObjectToWorldNormal(v.normal); // 將模型空間法線向量變換到世界空間(已歸一化)
o.uvMainTex = TRANSFORM_TEX(v.texcoord, _MainTex); // 主紋理坐標(biāo)縮放和偏移
o.uvNoiseTex = TRANSFORM_TEX(v.texcoord, _NoiseTex); // 噪聲紋理坐標(biāo)縮放和偏移
o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; // 將模型空間頂點(diǎn)坐標(biāo)變換到世界空間
return o;
}
fixed4 frag(v2f i) : SV_Target {
fixed noise = tex2D(_NoiseTex, i.uvNoiseTex).r; // 噪聲采樣
float factor = noise - _BurnAmount;
clip(factor); // 剔除factor小于0的片元, 即: if(factor < 0) discard;
fixed3 lightDir = normalize(UnityWorldSpaceLightDir(i.worldPos)); // 世界空間燈光向量
fixed4 albedo = tex2D(_MainTex, i.uvMainTex) * _Color; // 模型顏色
fixed4 ambient = UNITY_LIGHTMODEL_AMBIENT * albedo; // 環(huán)境光顏色
fixed4 diffuse = _LightColor0 * albedo * max(0, dot(i.normal, lightDir)); // 漫反射光顏色
fixed t = smoothstep(0, _LineWidth, factor);
fixed4 burnColor = lerp(_BurnOuterColor, _BurnInnerColor, t);
fixed4 finalColor = lerp(burnColor, ambient + diffuse, t);
return fixed4(finalColor.xyz, 1);
}
ENDCG
}
}
FallBack "Diffuse"
}說(shuō)明:在 Assets 目錄下面新建 Resources 目錄,接著在 Resources 目錄下面創(chuàng)建材質(zhì),重命名為 DissolveMat,將 DissolveEffect.shader 與 DissolveMat 材質(zhì)綁定,并將噪聲紋理拖拽到 DissolveMat 的 Noise Tex 中。
3 運(yùn)行效果


以上就是使用Unity3D實(shí)現(xiàn)選中物體消融特效的方法詳解的詳細(xì)內(nèi)容,更多關(guān)于Unity3D選中物體消融特效的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C# 當(dāng)前系統(tǒng)時(shí)間獲取及時(shí)間格式詳解
這篇文章主要介紹了C# 當(dāng)前系統(tǒng)時(shí)間獲取及時(shí)間格式詳解的相關(guān)資料,這里提供代碼實(shí)例,幫助大家學(xué)習(xí)參考,需要的朋友可以參考下2016-12-12
使用C#實(shí)現(xiàn)將Excel轉(zhuǎn)換為Markdown表格
Markdown 表格廣泛應(yīng)用于技術(shù)文檔,README 文件以及各類靜態(tài)站點(diǎn)生成器中,本文將介紹如何使用 C# 將 Excel 文件轉(zhuǎn)換為 Markdown 表格,感興趣的小伙伴可以了解下2026-01-01
C#高效比較兩個(gè)DataTable數(shù)據(jù)差異化的方法實(shí)現(xiàn)
本文主要介紹了C#高效比較兩個(gè)DataTable數(shù)據(jù)差異化的方法實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-05-05
c#訪問(wèn)this關(guān)鍵字和base關(guān)鍵字示例
this關(guān)鍵字引用類的當(dāng)前實(shí)例。靜態(tài)成員方法中不能使用this關(guān)鍵字,this關(guān)鍵字只能在實(shí)例構(gòu)造函數(shù)、實(shí)例方法或?qū)嵗L問(wèn)器中使用。base關(guān)鍵字用于從派生類中訪問(wèn)基類的成員。下面學(xué)習(xí)一下這二個(gè)關(guān)鍵字的使用方法2014-01-01
WPF利用TextBlock實(shí)現(xiàn)查找結(jié)果高亮顯示效果
在應(yīng)用開(kāi)發(fā)過(guò)程中,經(jīng)常遇到這樣的需求:通過(guò)關(guān)鍵字查找數(shù)據(jù),把帶有關(guān)鍵字的數(shù)據(jù)顯示出來(lái),同時(shí)在結(jié)果中高亮顯示關(guān)鍵字,所以本文就來(lái)和大家介紹一下如何利用TextBlock實(shí)現(xiàn)查找結(jié)果高亮顯示效果吧2023-08-08

