Unity Shader-紋理采樣流光,溶解,隱身效果(轉(zhuǎn))

簡介

今天來研究幾個(gè)效果,最近比較忙,所以來弄幾個(gè)比較簡單的效果玩一下。不過也是游戲中常用的一些效果,流光效果,按照方向的溶解效果。其實(shí)這幾個(gè)效果主要運(yùn)用的就是世界空間坐標(biāo)或者模型空間坐標(biāo)用于采樣的一個(gè)方法,總之就是有些非主流的紋理采樣方式。不多說,下面進(jìn)入正題。

流光效果

首先來看一下流光效果。流光效果是一個(gè)非常常見的效果,不僅僅是游戲,一些廣告之類的也都會有這種效果。流光的原理還是比較簡單的:首先就是需要一張流光圖,這張流光圖的大部分都是黑色,然后有一條亮線,然后我們在采樣的時(shí)候,最終輸出疊加上這張圖的采樣值,并根據(jù)時(shí)間調(diào)整采樣的UV就可以有流光的效果啦。下面是一個(gè)比較簡單的流光效果實(shí)現(xiàn):

//流光效果

//by:puppet_master

//2017.7.29

Shader "ApcShader/FlashEffect"

{

Properties

{

_MainTex("MainTex(RGB)", 2D) = "white" {}

_FlashTex("FlashTex", 2D) = "black" {}

_FlashColor("FlashColor",Color) = (1,1,1,1)

_FlashSpeedX("FlashSpeedX", Range(-5, 5)) = 0

_FlashSpeedY("FlashSpeedY", Range(-5, 5)) = 0.5

_FlashFactor ("FlashFactor", Range(0, 5)) = 1

}

CGINCLUDE

#include "Lighting.cginc"

uniform sampler2D _MainTex;

uniform float4 _MainTex_ST;

uniform sampler2D _FlashTex;

uniform fixed4 _FlashColor;

uniform fixed _FlashSpeedX;

uniform fixed _FlashSpeedY;

uniform fixed _FlashFactor;

struct v2f

{

float4 pos : SV_POSITION;

float3 worldNormal : NORMAL;

float2 uv : TEXCOORD0;

float3 worldLight : TEXCOORD1;

};

v2f vert(appdata_base v)

{

v2f o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

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);

//通過時(shí)間將采樣flash的uv進(jìn)行偏移

half2 flashuv = i.uv + half2(_FlashSpeedX, _FlashSpeedY) * _Time.y;

fixed4 flash = tex2D(_FlashTex, flashuv) * _FlashColor * _FlashFactor;

fixed4 c;

//將flash圖與原圖疊加

c.rgb = diff * albedo + flash.rgb;

c.a = 1;

return c;

}

ENDCG

SubShader

{

Pass

{

Tags{ "RenderType" = "Opaque" }

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

ENDCG

}

}

FallBack "Diffuse"

}

shader比較簡單,flashuv是隨著時(shí)間逐漸增大的,這個(gè)值肯定會大于1,而正常紋理的范圍是0-1,所以,要想讓貼圖在采樣時(shí)大于0-1也有效果,我們就必須要把貼圖的WrapMode設(shè)置為Repeat,否則當(dāng)這個(gè)值大于1之后,邊緣就被截?cái)嗔耍覀円簿筒粫吹搅鞴庑Ч?。注意,流光的貼圖是一個(gè)方向,采樣uv偏移是另一個(gè)方向,比如我的流光圖是水平方向的,那么流光運(yùn)動的方向就是豎直方向,效果如下面動圖所示:

更通用的流光效果

我們把流光shader用于一個(gè)3D模型,效果卻并不像我們預(yù)期的那樣會出現(xiàn)一條掃描線,而是亮起來的地方讓人捉摸不透,如下圖所示:

為什么會這樣呢?其實(shí)主要是我們采樣的方式導(dǎo)致的,正常的紋理采樣都是使用uv坐標(biāo)進(jìn)行采樣的,也就是說這個(gè)坐標(biāo)是與模型有關(guān),在這個(gè)模型上這個(gè)點(diǎn)需要采樣紋理的哪部分是由美術(shù)展uv時(shí)決定的。我們?nèi)绻胾v來進(jìn)行采樣,對于正常的diffuse貼圖或者法線貼圖等是對的,但是對于一些其他特殊的效果,uv采樣不能達(dá)到我們的需求了,所以我們就需要研究一下,用一個(gè)其他的東東作為采樣的坐標(biāo),這也是本篇文章主要研究的內(nèi)容。

如果不用uv進(jìn)行采樣,那么我們就需要一些其他的值作為采樣值,之前的文章我們也有使用過類似的方法,比如在熱空氣扭曲效果中我們使用了屏幕空間采樣,采樣時(shí)計(jì)算該點(diǎn)在屏幕空間的坐標(biāo)值反過來去采樣全屏GrabPass圖。不過這里我們不需要屏幕空間,畢竟這樣的話這個(gè)流動效果就會隨著我們觀察的角度而變化,所以我們選擇用世界空間采樣:

//流光效果

//by:puppet_master

//2017.7.30

Shader "ApcShader/FlashEffect"

{

Properties

{

_MainTex("MainTex(RGB)", 2D) = "white" {}

_FlashTex("FlashTex", 2D) = "black" {}

_FlashColor("FlashColor",Color) = (1,1,1,1)

_FlashFactor("FlashFactor", Vector) = (0, 1, 0.5, 0.5)

_FlashStrength ("FlashStrength", Range(0, 5)) = 1

}

CGINCLUDE

#include "Lighting.cginc"

uniform sampler2D _MainTex;

uniform float4 _MainTex_ST;

uniform sampler2D _FlashTex;

uniform fixed4 _FlashColor;

//改為一個(gè)vector4,減少傳參次數(shù)消耗

uniform fixed4 _FlashFactor;

uniform fixed _FlashStrength;

struct v2f

{

float4 pos : SV_POSITION;

float3 worldNormal : NORMAL;

float2 uv : TEXCOORD0;

float3 worldLight : TEXCOORD1;

float4 worldPos : TEXCOORD2;

};

v2f vert(appdata_base v)

{

v2f o;

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);

//頂點(diǎn)轉(zhuǎn)化到世界空間

o.worldPos = mul(unity_ObjectToWorld, 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);

//通過時(shí)間偏移世界坐標(biāo)對flashTex進(jìn)行采樣

half2 flashuv = i.worldPos.xy * _FlashFactor.zw + _FlashFactor.xy * _Time.y;

fixed4 flash = tex2D(_FlashTex, flashuv) * _FlashColor * _FlashStrength;

fixed4 c;

//將flash圖與原圖疊加

c.rgb = diff * albedo + flash.rgb;

c.a = 1;

return c;

}

ENDCG

SubShader

{

Pass

{

Tags{ "RenderType" = "Opaque" }

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

ENDCG

}

}

FallBack "Diffuse"

}

好了,下面我們找個(gè)帥帥噠模型,看一下修改之后的流光效果:

然后我們也可以換一張貼圖,再調(diào)整一下參數(shù),讓流光換個(gè)方向:

按照方向消失或重現(xiàn)效果

我們再來看一個(gè)用模型空間坐標(biāo)作為采樣的uv的栗子,也是一種比較好玩的效果。比如我們需要一個(gè)模型身體按照一定的方向逐漸消失,直至全部消失掉的一個(gè)效果。下面說一下思路,與世界空間采樣的流光效果一樣,我們在vertex階段記錄一下vertex坐標(biāo),傳遞給fragment階段,在fragment階段用這個(gè)值和一個(gè)設(shè)定好的閾值進(jìn)行比較,不滿足條件的像素點(diǎn)直接discard,逐漸調(diào)整閾值,就可以得到讓模型按照某個(gè)方向消失的效果了。代碼如下:

//按照方向消失的效果

//by:puppet_master

//2017.8.10

Shader "ApcShader/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);

//頂點(diǎn)轉(zhuǎn)化到世界空間

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"

}

還是上面的模型,我們逐漸調(diào)整X,Y,Z軸三個(gè)方向的閾值,就可以有逐漸消失或者出現(xiàn)的效果啦,如下面動圖所示:

在這里,我們沒有像流光效果那樣使用世界空間坐標(biāo)采樣,而是使用了模型空間坐標(biāo)采樣,其實(shí)還可以使用屏幕空間坐標(biāo)或者視口空間坐標(biāo)采樣等等,幾種方式各有各的優(yōu)點(diǎn)和缺點(diǎn)。使用世界空間采樣,消失的方向是絕對的,比如是從上向下,那么這個(gè)模型如果趴在地上,消失的方向就會是從模型后背到前胸的方向,而且坐標(biāo)閾值會隨著模型處于世界中的位置不同而不同;使用模型空間采樣,消失的方向與模型本身有關(guān),比如站著的話消失方向是從頭到腳,那么趴著也是從頭到腳,而且坐標(biāo)的閾值與模型的高矮胖瘦有關(guān)(也與模型的原點(diǎn)位置有點(diǎn)關(guān)系);使用屏幕空間采樣的話,消失的方向就可能會與我們觀察的方向有關(guān),這種可能不太可控。

還有一個(gè)小問題,其實(shí)上圖中的例子里面,模型從上到下,理想情況應(yīng)該是調(diào)整Y軸,不過例子里面調(diào)整的確實(shí)X軸,原因應(yīng)該與Unity導(dǎo)入之后會繞著X軸旋轉(zhuǎn)90度有關(guān),也就是原本在max里面的Y軸變成Unity里面的X軸。

下面,我們再看一下增加了邊緣高亮的消失效果,為了讓模消失的型邊緣高亮,我們通過將用于clip的factor值與另一個(gè)高亮閾值值進(jìn)行比較,如果factor小于高亮閾值,則返回一個(gè)高亮的顏色值,否則正常渲染。這樣模型就總共有三種顯示狀態(tài):clip狀態(tài),高亮狀態(tài),正常狀態(tài)。代碼如下:

//消失效果

//by:puppet_master

//2017.8.11

Shader "ApcShader/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光照計(jì)算

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;

//等價(jià)于下面注釋代碼的操作

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

{

//不讓模型穿幫,關(guān)掉了背面裁剪

Cull Off

CGPROGRAM

#pragma vertex vert

#pragma fragment frag

ENDCG

}

}

FallBack "Diffuse"

}

這一次我們只讓模型在上下方向上逐漸消失,調(diào)整ColorFactor可以控制高亮區(qū)域的高度:

溶解效果進(jìn)階版

之前的文章里,我們研究過溶解效果,不過這個(gè)效果是基于全身的,我們來嘗試一下,把上面按照方向消失的效果與溶解效果結(jié)合起來,做成一個(gè)按照某個(gè)方向逐漸溶解的效果。要得到隨機(jī)的溶解效果,我們需要采樣一張?jiān)肼晥D,然后在原本會直接clip掉的部分根據(jù)采樣的噪聲圖進(jìn)行clip,就能得到按照方向的溶解效果啦。

//溶解效果

//by:puppet_master

//2017.8.11

Shader "ApcShader/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光照計(jì)算

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"

}

效果如下:

當(dāng)然,也可以參考之前溶解效果,增加溶解描邊高亮的效果:

轉(zhuǎn)自:http://m.blog.csdn.net/puppet_master/article/details/76359838

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容