實踐篇:簡單邊緣泛光處理

前言:本篇博客只是一個簡單的實現邊緣泛光功能的例子,主要是當做筆記使用。

核心要點
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
		}
	}
}

運行效果:如下圖所示:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章