前言:本篇博客只是一個簡單的實現邊緣泛光功能的例子,主要是當做筆記使用。
核心要點:
1.使用法向量和視角向量的點積值來獲取明亮度,從模型邊緣到模型中心點積值從0~1變化。點積值爲負數說明當前頂點在平面背面,攝像機視角看不到,可以不做明亮度處理。點積值爲正值時,說明當前頂點在平面正面,可以結合衰減係數調用pow接口來獲取衰減後的明亮值。
2.第一個pass主要是沿着法向量方向縮放模型,並從模型中心點往模型邊緣處明亮度從1->0的變化,然後和顏色緩衝區中的顏色進行透明度混合處理。效果如圖所示:
3.第二個pass主要是在源模型大小進行原色輸出,然後用第一個pass中的顏色減去當前pass中的顏色和第一個pass中顏色的透明度值,從而來實現源模型處鏤空的效果。效果如圖所示:
4.使用第三個pass從模型中心點往模型邊緣處明亮度從0->1的變化,然後和上面pass中的顏色進行透明度混合處理。效果圖如下所示:
5.由於使用了多個pass,且每個pass都對模型做了處理。爲了得到正確的層級效果,需要關閉深度寫入。
核心代碼:如下所示:
Shader "Custom/Rim" {
Properties {
// 模型主顏色
_MainColor("MainColor", COLOR) = (1, 1, 1, 1)
// 模型明亮度衰減因子
_Scale("Scale", Range(1, 8)) = 2
// 模型外圍縮放因子
_Outer("Outer", Range(0, 1)) = 0.2
}
SubShader {
// 開啓透明度混合
Tags { "Queue" = "Transparent" "RenderType" = "Transparent" "IgnoreProjector" = "TRUE" }
pass {
// 與顏色緩衝區中的顏色進行混合處理:當前pass中獲取的顏色透明度越大,越顯示當前顏色多點。
blend SrcAlpha OneMinusSrcAlpha
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct v2f {
float4 pos:POSITION0;
float3 normal:POSITION1;
float4 vertex:POSITION2;
};
fixed4 _MainColor;
float _Scale;
float _Outer;
v2f vert(appdata_base v)
{
v2f o;
// 沿着法線方向縮放頂點
v.vertex.xyz += v.normal * _Outer;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.vertex = v.vertex;
o.normal = v.normal;
return o;
}
fixed4 frag(v2f v):COLOR0
{
float3 N = UnityObjectToWorldNormal(v.normal);
float3 V = normalize(WorldSpaceViewDir(v.vertex));
// 通過法向量和視角向量的點積值來獲取明亮度:
// 1.模型邊緣點積值爲0,模型中心點積值爲1。從模型中心到邊緣,明亮值從1-》0的變換。
// 2.點積負值表示當前視角看的頂點所在平面背面,可以不做處理。
float bright = saturate(dot(N, V));
// 通過衰減係數來獲取明亮度:衰減係數越大,越往模型邊緣偏移的明亮值會越小。
bright = pow(bright, _Scale);
// 通過明亮值來限定模型顏色的透明度,從而達到外圍光暈效果
_MainColor.a *= bright;
return _MainColor;
}
ENDCG
}
pass {
// 使用上一個pass中獲取的目標顏色來減去當前pass中獲取的源顏色,從而將當前模型鏤空
blendop revsub
blend dstalpha one
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct v2f {
float4 pos:POSITION0;
};
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
return o;
}
fixed4 frag(v2f v):COLOR0
{
return fixed4(1, 1, 1, 1);
}
ENDCG
}
pass {
// 與上面pass中的顏色進行混合處理:當前pass中獲取的顏色透明度越大,越顯示當前顏色多點。
blend SrcAlpha OneMinusSrcColor
zwrite off
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "unitycg.cginc"
struct v2f {
float4 pos:POSITION0;
float3 normal:POSITION1;
float4 vertex:POSITION2;
};
float _Scale;
v2f vert(appdata_base v)
{
v2f o;
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
o.vertex = v.vertex;
o.normal = v.normal;
return o;
}
fixed4 frag(v2f v):COLOR0
{
float3 N = UnityObjectToWorldNormal(v.normal);
float3 V = normalize(WorldSpaceViewDir(v.vertex));
// 通過法向量和視角向量的點積值來獲取明亮度:
// 1.模型邊緣點積值爲0,模型中心點積值爲1。
// 2.使用1.0減去點積結果值就可以表示從模型邊緣到模型中心,明亮值從1-》0的變換。
float bright = 1.0 - saturate(dot(N, V));
// 通過衰減係數來獲取明亮度:衰減係數越大,越往模型中心偏移的明亮值會越小。
bright = pow(bright, _Scale);
return fixed4(1, 1, 1, 1) * bright;
}
ENDCG
}
}
}
運行效果:如下圖所示: