使用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() { // 獲取屏幕射線(xiàn)碰撞的物體 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 // 燃燒的線(xiàn)條寬度 _BurnOuterColor("Burn Outer Color", Color) = (1, 0, 0, 1) // 燃燒線(xiàn)條的外側(cè)顏色 _BurnInnerColor("Burn Inner Color", Color) = (1, 0, 0, 1) // 燃燒線(xiàn)條的內(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; // 燃燒的線(xiàn)條寬度 fixed4 _BurnOuterColor; // 燃燒線(xiàn)條的外側(cè)顏色 fixed4 _BurnInnerColor; // 燃燒線(xiàn)條的內(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)法線(xiàn)向量 float4 texcoord : TEXCOORD0; // 頂點(diǎn)紋理坐標(biāo) }; struct v2f { float4 pos : SV_POSITION; // 裁剪空間頂點(diǎn)坐標(biāo) float3 normal : Normal; // 世界空間頂點(diǎn)法線(xià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); // 將模型空間法線(xiàn)向量變換到世界空間(已歸一化) 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#反射實(shí)現(xiàn)插件式開(kāi)發(fā)的過(guò)程詳解
插件式架構(gòu),一種全新的、開(kāi)放性的、高擴(kuò)展性的架構(gòu)體系,插件式架構(gòu)設(shè)計(jì)好處很多,把擴(kuò)展功能從框架中剝離出來(lái),降低了框架的復(fù)雜度,讓框架更容易實(shí)現(xiàn),這篇文章主要介紹了C#反射實(shí)現(xiàn)插件式開(kāi)發(fā),需要的朋友可以參考下2023-09-09Silverlight實(shí)現(xiàn)星星閃爍動(dòng)畫(huà)
這篇文章主要為大家詳細(xì)介紹了Silverlight實(shí)現(xiàn)星星閃爍動(dòng)畫(huà),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07C#實(shí)現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法
這篇文章主要介紹了C#實(shí)現(xiàn)解析百度天氣數(shù)據(jù),Rss解析百度新聞以及根據(jù)IP獲取所在城市的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2014-10-10C#中out參數(shù)、ref參數(shù)與值參數(shù)的用法及區(qū)別
這篇文章主要給大家介紹了關(guān)于C#中out參數(shù)、ref參數(shù)與值參數(shù)的用法及區(qū)別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2018-09-09C#組件系列 你值得擁有的一款Excel處理神器Spire.XLS
又一款Excel處理神器Spire.XLS,這篇文章主要為大家詳細(xì)介紹了第三方組件Spire.XLS,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09C#部署數(shù)據(jù)庫(kù)及IIS站點(diǎn)
這篇文章主要為大家詳細(xì)介紹了C#部署數(shù)據(jù)庫(kù)及IIS站點(diǎn)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03使用C#和SerialPort類(lèi)進(jìn)行實(shí)時(shí)數(shù)據(jù)采集與控制
在很多工業(yè)控制、設(shè)備監(jiān)控、傳感器數(shù)據(jù)采集等應(yīng)用場(chǎng)景中,上位機(jī)通過(guò)串口與下位機(jī)(如嵌入式設(shè)備、PLC、傳感器等)進(jìn)行實(shí)時(shí)數(shù)據(jù)采集與控制,C#提供了System.IO.Ports.SerialPort類(lèi),使得串口通信變得簡(jiǎn)單高效,本文介紹了如何使用C#和SerialPort類(lèi)進(jìn)行實(shí)時(shí)數(shù)據(jù)采集與控制2025-02-02