簡介
今天來研究幾個效果铃岔,最近比較忙,所以來弄幾個比較簡單的效果玩一下峭火。不過也是游戲中常用的一些效果毁习,流光效果,按照方向的溶解效果躲胳。其實(shí)這幾個效果主要運(yùn)用的就是世界空間坐標(biāo)或者模型空間坐標(biāo)用于采樣的一個方法蜓洪,總之就是有些非主流的紋理采樣方式纤勒。不多說坯苹,下面進(jìn)入正題。
流光效果
首先來看一下流光效果摇天。流光效果是一個非常常見的效果粹湃,不僅僅是游戲,一些廣告之類的也都會有這種效果泉坐。流光的原理還是比較簡單的:首先就是需要一張流光圖为鳄,這張流光圖的大部分都是黑色,然后有一條亮線腕让,然后我們在采樣的時候孤钦,最終輸出疊加上這張圖的采樣值歧斟,并根據(jù)時間調(diào)整采樣的UV就可以有流光的效果啦。下面是一個比較簡單的流光效果實(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);
//通過時間將采樣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是隨著時間逐漸增大的静袖,這個值肯定會大于1,而正常紋理的范圍是0-1俊扭,所以队橙,要想讓貼圖在采樣時大于0-1也有效果,我們就必須要把貼圖的WrapMode設(shè)置為Repeat萨惑,否則當(dāng)這個值大于1之后捐康,邊緣就被截?cái)嗔耍覀円簿筒粫吹搅鞴庑Ч擞拱W⒁饨庾埽鞴獾馁N圖是一個方向,采樣uv偏移是另一個方向姐仅,比如我的流光圖是水平方向的倾鲫,那么流光運(yùn)動的方向就是豎直方向,效果如下面動圖所示:
更通用的流光效果
我們把流光shader用于一個3D模型萍嬉,效果卻并不像我們預(yù)期的那樣會出現(xiàn)一條掃描線乌昔,而是亮起來的地方讓人捉摸不透,如下圖所示:
為什么會這樣呢壤追?其實(shí)主要是我們采樣的方式導(dǎo)致的磕道,正常的紋理采樣都是使用uv坐標(biāo)進(jìn)行采樣的,也就是說這個坐標(biāo)是與模型有關(guān)行冰,在這個模型上這個點(diǎn)需要采樣紋理的哪部分是由美術(shù)展uv時決定的溺蕉。我們?nèi)绻胾v來進(jìn)行采樣,對于正常的diffuse貼圖或者法線貼圖等是對的悼做,但是對于一些其他特殊的效果疯特,uv采樣不能達(dá)到我們的需求了,所以我們就需要研究一下肛走,用一個其他的東東作為采樣的坐標(biāo)漓雅,這也是本篇文章主要研究的內(nèi)容。
如果不用uv進(jìn)行采樣朽色,那么我們就需要一些其他的值作為采樣值邻吞,之前的文章我們也有使用過類似的方法,比如在熱空氣扭曲效果中我們使用了屏幕空間采樣葫男,采樣時計(jì)算該點(diǎn)在屏幕空間的坐標(biāo)值反過來去采樣全屏GrabPass圖抱冷。不過這里我們不需要屏幕空間,畢竟這樣的話這個流動效果就會隨著我們觀察的角度而變化梢褐,所以我們選擇用世界空間采樣:
//流光效果
//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;
//改為一個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);
//通過時間偏移世界坐標(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"
}
好了赵讯,下面我們找個帥帥噠模型,看一下修改之后的流光效果:
然后我們也可以換一張貼圖耿眉,再調(diào)整一下參數(shù)瘦癌,讓流光換個方向:
按照方向消失或重現(xiàn)效果
我們再來看一個用模型空間坐標(biāo)作為采樣的uv的栗子,也是一種比較好玩的效果跷敬。比如我們需要一個模型身體按照一定的方向逐漸消失讯私,直至全部消失掉的一個效果。下面說一下思路西傀,與世界空間采樣的流光效果一樣斤寇,我們在vertex階段記錄一下vertex坐標(biāo),傳遞給fragment階段拥褂,在fragment階段用這個值和一個設(shè)定好的閾值進(jìn)行比較娘锁,不滿足條件的像素點(diǎn)直接discard,逐漸調(diào)整閾值饺鹃,就可以得到讓模型按照某個方向消失的效果了莫秆。代碼如下:
//按照方向消失的效果
//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軸三個方向的閾值悔详,就可以有逐漸消失或者出現(xiàn)的效果啦镊屎,如下面動圖所示:
在這里,我們沒有像流光效果那樣使用世界空間坐標(biāo)采樣茄螃,而是使用了模型空間坐標(biāo)采樣缝驳,其實(shí)還可以使用屏幕空間坐標(biāo)或者視口空間坐標(biāo)采樣等等,幾種方式各有各的優(yōu)點(diǎn)和缺點(diǎn)归苍。使用世界空間采樣用狱,消失的方向是絕對的,比如是從上向下拼弃,那么這個模型如果趴在地上夏伊,消失的方向就會是從模型后背到前胸的方向,而且坐標(biāo)閾值會隨著模型處于世界中的位置不同而不同吻氧;使用模型空間采樣溺忧,消失的方向與模型本身有關(guān),比如站著的話消失方向是從頭到腳医男,那么趴著也是從頭到腳砸狞,而且坐標(biāo)的閾值與模型的高矮胖瘦有關(guān)(也與模型的原點(diǎn)位置有點(diǎn)關(guān)系)捻勉;使用屏幕空間采樣的話镀梭,消失的方向就可能會與我們觀察的方向有關(guān),這種可能不太可控踱启。
還有一個小問題报账,其實(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值與另一個高亮閾值值進(jìn)行比較识窿,如果factor小于高亮閾值,則返回一個高亮的顏色值脑融,否則正常渲染喻频。這樣模型就總共有三種顯示狀態(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)階版
之前的文章里姻蚓,我們研究過溶解效果,不過這個效果是基于全身的匣沼,我們來嘗試一下史简,把上面按照方向消失的效果與溶解效果結(jié)合起來,做成一個按照某個方向逐漸溶解的效果肛著。要得到隨機(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