1. 程式人生 > >3.頂點外擴方法實現的描邊shader

3.頂點外擴方法實現的描邊shader

描邊shader的實現有很多種,頂點外擴是其中之一。頂點外擴的原理是用2個Pass 渲染物體2次

第一遍:描邊,頂點沿法線方向外拓後用黑色渲染。外擴這一步的實現是在投影空間,也就是2D的,根絕法線的x和y值進行外擴,因為是沿著法線方向外擴,所以法線越和攝像機方向相同,也就是越接近面向攝像機的頂點,頂點的位置變化的越小,當法線和攝像機方向相同時,不會有任何變化。

第一遍渲染後,實際的影象如下:

第二遍:正常渲染物體,與第一遍渲染的混合在一起


優點:
(1)效果最好。
(2)適用範圍廣。
缺點:
(1)對效率有一定影響。因為有2個Pass,所以DrawCall為正常的2倍

(2)對於法線過度不均勻的模型,比如立方體,輪廓會有縫隙。

上邊的立方體例子我是特意把描邊的外擴值調到很大,便於理解。由第一遍渲染後的圖和第二遍渲染後的圖的對比,很容易理解這個方法的原理。其實就是通過法線來把邊緣進行位移,如果不是邊緣,則不位移,比如立方體的正面。在第二次渲染後,會覆蓋同位置的畫素,因為邊緣已經外擴,畫素的位置已經不是原來的位置,因此不會被覆蓋,而像位於立方體正面的畫素,則會被第二次渲染時覆蓋,最後就混合成了帶黑邊的效果圖。

Shader "Study/3_OutLine"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white"{}
	    _LineSize("OutlineSize", range(0, 0.1)) = 0.02
		_LineColor("LineColor", Color) = (0,0,0,1)
	}
	SubShader
	{
		Pass
		{
			Tags{ "LightMode" = "Always" }
			// 先繪製這個純色的頂點,然後在下一個pass繪製物件
			//這裡不存在前後面,關閉裁剪前後面,也不需要深度快取
			Cull Off // 關閉剔除,模型前後都會顯示
			ZWrite Off // 系統預設是開的,要關閉。關閉深度快取,後渲染的物體會根據ZTest的結果將自己渲染輸出寫入
			ZTest Always  // 深度測試[一直顯示],被其他物體擋住後,此pass繪製的顏色會顯示出來
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			float _LineSize;
			float4 _LineColor;
			struct v2f
			{
				float4 pos:SV_POSITION;
				float4 color : COLOR;
			};
			v2f vert(appdata_full v)
			{
				v2f o;
				// 獲取模型的最終的投影座標
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				// UNITY_MATRIX_IT_MV為【模型座標-世界座標-攝像機座標】【專門針對法線的變換】
				// 法線乘以MV,將模型空間 轉換 檢視空間
				float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);
				// 轉換 檢視空間 到 投影空間 【3D轉2D】
				float2 offset = TransformViewToProjection(norm.xy);
				// 得到的offset,模型被擠的非常大,然後乘以倍率
				o.pos.xy += offset * _LineSize;
				o.color = _LineColor;
				return o;
			}
			float4 frag(v2f i) : COLOR
			{
				return i.color;
			}
			ENDCG
		}
		Pass
		{
			// 直接使用頂點和片段shader顯示物體
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"
			sampler2D _MainTex;
			float4 _MainTex_ST;

			struct v2f 
			{
				float4 pos:SV_POSITION;
				float2 uv : TEXCOORD0;// 紋理,相對自身的座標軸,float2是一個平面
			};
			v2f vert(appdata_full v)
			{
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
				return o;
			}
			float4 frag(v2f i) : COLOR
			{
				float4 texCol = tex2D(_MainTex, i.uv);
				return texCol;
			}
			ENDCG
		}
	}
}

附上工程連線:http://download.csdn.net/detail/yinfourever/9565336