Shader實例(流光實現)
- 2019 年 12 月 2 日
- 筆記
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/CJB_King/article/details/78869642
Shader實例(流光實現)
流光效果
首先來看一下流光效果。流光效果是一個非常常見的效果,不僅僅是遊戲,一些廣告之類的也都會有這種效果。流光的原理還是比較簡單的:首先就是需要一張流光圖,這張流光圖的大部分都是黑色,然後有一條亮線,然後我們在採樣的時候,最終輸出疊加上這張圖的採樣值,並根據時間調整採樣的UV就可以有流光的效果啦。下面是一個比較簡單的流光效果實現:

下面看屬性參數:

接下來是SubShader中的一些參數定義

頂點函數處理

光照處理

以上是對於2D圖像常用的流光實現方式,如果是3D物體用這種方式的話,可能會出現問題,所以對於3D物體,採用按照物體的世界坐標按時間偏移查詢紋理貼圖就行了

具體參數按需求改下就好了
按照方向消失或重現效果
我們再來看一個用模型空間坐標作為採樣的uv的栗子,也是一種比較好玩的效果。比如我們需要一個模型身體按照一定的方向逐漸消失,直至全部消失掉的一個效果。下面說一下思路,與世界空間採樣的流光效果一樣,我們在vertex階段記錄一下vertex坐標,傳遞給fragment階段,在fragment階段用這個值和一個設定好的閾值進行比較,不滿足條件的像素點直接discard,逐漸調整閾值,就可以得到讓模型按照某個方向消失的效果了。代碼如下:
//按照方向消失的效果 //by:CJB_King //2017.12.23 Shader "SelfShader/DissolveEffectX" { Properties { _MainTex("MainTex(RGB)", 2D) = "white" {} _DissolveVector("DissolveVector", Vector) = (0,0,0,0) } CGINCLUDE #include "Lighting.cginc" uniform sampler2D _MainTex; uniform float4 _MainTex_ST; uniform float4 _DissolveVector; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : NORMAL; float2 uv : TEXCOORD0; float3 worldLight : TEXCOORD1; float4 objPos : TEXCOORD2; }; v2f vert(appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); //頂點轉化到世界空間 o.objPos = v.vertex; o.worldNormal = UnityObjectToWorldNormal(v.normal); o.worldLight = UnityObjectToWorldDir(_WorldSpaceLightPos0.xyz); return o; } fixed4 frag(v2f i) : SV_Target { half3 normal = normalize(i.worldNormal); half3 light = normalize(i.worldLight); fixed diff = max(0, dot(normal, light)); fixed4 albedo = tex2D(_MainTex, i.uv); //不滿足條件的discard clip(i.objPos.xyz - _DissolveVector.xyz); fixed4 c; c.rgb = diff * albedo; c.a = 1; return c; } ENDCG SubShader { Pass { Tags{ "RenderType" = "Opaque" } CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } FallBack "Diffuse" }
還有一個小問題,其實上圖中的例子裏面,模型從上到下,理想情況應該是調整Y軸,不過例子裏面調整的確實X軸,原因應該與Unity導入之後會繞着X軸旋轉90度有關,也就是原本在max裏面的Y軸變成Unity裏面的X軸。
下面,我們再看一下增加了邊緣高亮的消失效果,為了讓模消失的型邊緣高亮,我們通過將用於clip的factor值與另一個高亮閾值值進行比較,如果factor小於高亮閾值,則返回一個高亮的顏色值,否則正常渲染。這樣模型就總共有三種顯示狀態:clip狀態,高亮狀態,正常狀態。代碼如下:
//消失效果 //by:CJB_King //2017.12.23 Shader "SelfShader/DissolveEffectX" { Properties{ _Diffuse("Diffuse", Color) = (1,1,1,1) _DissolveColor("Dissolve Color", Color) = (0,0,0,0) _MainTex("Base 2D", 2D) = "white"{} _ColorFactor("ColorFactor", Range(0,1)) = 0.7 _DissolveThreshold("DissolveThreshold", Float) = 0 } CGINCLUDE #include "Lighting.cginc" uniform fixed4 _Diffuse; uniform fixed4 _DissolveColor; uniform sampler2D _MainTex; uniform float4 _MainTex_ST; uniform float _ColorFactor; uniform float _DissolveThreshold; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD1; float4 objPos : TEXCOORD2; }; v2f vert(appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); o.objPos = v.vertex; return o; } fixed4 frag(v2f i) : SV_Target { float factor = i.objPos.x - _DissolveThreshold; clip(factor); //Diffuse + Ambient光照計算 fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 lambert = saturate(dot(worldNormal, worldLightDir)); fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 color = tex2D(_MainTex, i.uv).rgb * albedo; //等價於下面注釋代碼的操作 fixed lerpFactor = saturate(sign(_ColorFactor - factor)); return lerpFactor * _DissolveColor + (1 - lerpFactor) * fixed4(color, 1); /* if (factor < _ColorFactor) { return _DissolveColor; } return fixed4(color, 1);*/ } ENDCG SubShader { Tags{ "RenderType" = "Opaque" } Pass { //不讓模型穿幫,關掉了背面裁剪 Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } FallBack "Diffuse" }
溶解效果進階版
之前的文章里,我們研究過溶解效果,不過這個效果是基於全身的,我們來嘗試一下,把上面按照方向消失的效果與溶解效果結合起來,做成一個按照某個方向逐漸溶解的效果。要得到隨機的溶解效果,我們需要採樣一張噪聲圖,然後在原本會直接clip掉的部分根據採樣的噪聲圖進行clip,就能得到按照方向的溶解效果啦。
//溶解效果 //by:CJB_King //2017.12.23 Shader "SelfShader/DissolveEffectX" { Properties{ _Diffuse("Diffuse", Color) = (1,1,1,1) _DissolveColor("Dissolve Color", Color) = (1,1,1,1) _MainTex("Base 2D", 2D) = "white"{} _DissolveMap("DissolveMap", 2D) = "white"{} _DissolveThreshold("DissolveThreshold", Range(0,1)) = 0 _DissolveSpeedFactor("DissolveSpeed", Range(0,5)) = 2 _DissolveControl("ColorFactorB", Float) = 0 } CGINCLUDE #include "Lighting.cginc" uniform fixed4 _Diffuse; uniform fixed4 _DissolveColor; uniform sampler2D _MainTex; uniform float4 _MainTex_ST; uniform sampler2D _DissolveMap; uniform float _DissolveThreshold; uniform float _DissolveSpeedFactor; uniform float _DissolveControl; struct v2f { float4 pos : SV_POSITION; float3 worldNormal : TEXCOORD0; float2 uv : TEXCOORD1; float4 objPos : TEXCOORD2; }; v2f vert(appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.texcoord, _MainTex); o.worldNormal = mul(v.normal, (float3x3)unity_WorldToObject); o.objPos = v.vertex; return o; } fixed4 frag(v2f i) : SV_Target { fixed4 dissolve = tex2D(_DissolveMap, i.uv); //Diffuse + Ambient光照計算 fixed3 worldNormal = normalize(i.worldNormal); fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz); fixed3 lambert = saturate(dot(worldNormal, worldLightDir)); fixed3 albedo = lambert * _Diffuse.xyz * _LightColor0.xyz + UNITY_LIGHTMODEL_AMBIENT.xyz; fixed3 color = tex2D(_MainTex, i.uv).rgb * albedo; float factor = i.objPos.x - _DissolveControl; if(factor < 0) { clip(_DissolveThreshold - dissolve.r * abs(factor) * _DissolveSpeedFactor); } return fixed4(color, 1); } ENDCG SubShader { Tags{ "RenderType" = "Opaque" } Pass { Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag ENDCG } } FallBack "Diffuse" }


Shader "SelfShader/Dissolve" { Properties { _MainColor("MainColor",COLOR)=(1,1,1,1) _MainTex ("Texture", 2D) = "white" {} _Noise("Noise",2D)="white"{} _Dissolve("Dissolve",Vector)=(0.2,0.5,0.8) _DissolveThread("DissolveThread",float)=0.2 _DissolveColor("DissolveColor",COLOR)=(1,1,1,1) _DissolveColFactor("_DissolveColFactor",float)=2 _FlyFactor("FlyFactor",float)=3 } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" #include "Lighting.cginc" struct a2v { float4 vertex : POSITION; float2 uv : TEXCOORD0; fixed3 normal:NORMAL; }; struct v2f { float2 uv : TEXCOORD0; float4 pos : SV_POSITION; fixed3 worldNormal:TEXCOORD1; fixed3 worldPos:TEXCOORD2; fixed3 objPos:TEXCOORD3; }; sampler2D _Noise; sampler2D _MainTex; float4 _MainTex_ST; fixed4 _MainColor; fixed4 _Dissolve; float _DissolveThread; fixed4 _DissolveColor; float _DissolveColFactor; float _FlyFactor; v2f vert (a2v v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); o.worldPos=mul((float3x3)unity_ObjectToWorld,v.vertex); o.worldNormal=UnityObjectToWorldNormal(v.normal); o.objPos=v.vertex; o.uv = TRANSFORM_TEX(v.uv, _MainTex); o.pos.xyz+=v.normal*saturate(_DissolveThread-_FlyFactor)*_FlyFactor; return o; } fixed4 frag (v2f i) : SV_Target { fixed3 worldNor=normalize(i.worldNormal); fixed3 lightDir=normalize(_WorldSpaceLightPos0.xyz); fixed4 albedo = tex2D(_MainTex, i.uv)*_MainColor; fixed4 noiseColor=tex2D(_Noise,i.uv); float factor=noiseColor.r-_DissolveThread; clip(factor); fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.xyz*albedo.rgb; fixed3 diffuse=_LightColor0.rgb*albedo.rgb*(0.5*dot(lightDir,worldNor)+0.5); float lerpFactor=saturate(sign(_DissolveColFactor-factor)); return lerp(fixed4(ambient+diffuse,1),_DissolveColor,lerpFactor); } ENDCG } } }