Unity Shader - 頂點着色器與片段着色器之間數據的傳遞方式

在頂點着色器函數中,顧名思義,vert函數處理的對象是一個個的獨立的頂點,在完成對頂點的位置、法線、紋理座標等數據的處理之後,會將相關的數據傳遞給片段着色器繼續進行處理。需要注意的是,frag函數並非原封不動的對vert函數傳遞過來的數據進行接收,而是會對其進行插值運算。因爲,片段着色器處理的對象是每一個像素點,頂點着色器傳遞過來的頂點信息顯然無法滿足片段着色器的處理需求,所以片段着色器會將處於每一個三角形中的像素點相對於該三角形的三個頂點進行插值計算。

我們可以通過簡單shader腳本進行如下驗證。

首先,我們建立如下場景,一個立方體Cube,一個平面Plane,一個位於(0,0,0)點的球體Sphere。


接着,我們在Shader中進行如下算法的實現,當立方體中的頂點距離(0,0,0)點小於5的時候,設置頂點顏色爲綠色;當立方體中的頂點距離(0,0,0)點大於5的時候,設置頂點顏色爲紅色:

Shader "Custom/SetColorInVert" {
	Properties {
      	_ZeroPoint ("ZeroPoint", Vector) = (0, 0, 0, 0)
		_Distance ("Distance", Float) = 5.0
		_ColorNear ("Color_Near", Color) = (0.0, 1.0, 0.0, 1.0)
		_ColorFar ("Color_Far", Color) = (1.0, 0.0, 0.0, 1.0)
	}
	SubShader {
		Pass
		{
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4 _ZeroPoint;
			uniform float _Distance;
			uniform float4 _ColorNear;
			uniform float4 _ColorFar;
			
			struct vertexInput
			{
				float4 vertex : POSITION;
			};
			
			struct vertexOutput
			{
				float4 pos : SV_POSITION;
				float4 posInWorld : TEXCOORD0;
				float4 col : COLOR;
			};
			
			vertexOutput vert(vertexInput input)
			{
				vertexOutput output;
				output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
				output.posInWorld = mul(_Object2World, input.vertex);
				
				float dist = distance(output.posInWorld, _ZeroPoint);
				
				if(dist < _Distance) 
				{
					output.col = _ColorNear;
				}
				else
				{
					output.col = _ColorFar;
				}
				
				return output;
			}
			
			float4 frag(vertexOutput input) : COLOR
			{			
				return input.col;
			}
									
			ENDCG
		}
	} 
}
將該shader應用到Cube上之後,我們從遠方慢慢在X方向上移動立方體接近(0,0,0)點,依次得到如下的效果:

(1)所有頂點都距離原點大於5,因此每個頂點都爲紅色,因此,每個三角形的頂點都爲紅色,三角形內部的每個像素進行插值之後也都爲紅色。

(2)右下角的頂點距離原點小於5,可以看到右下角頂點的顏色已經變爲了綠色,所有以此類頂點爲頂點的三角形中的像素點出現了漸變的效果:越靠近綠色頂點的像素點顏色越偏向綠色,越靠近紅色頂點的像素點的顏色越偏向紅色。

(3)進一步的在X方向上靠近(0,0,0)點,右上方的頂點距離(0,0,0)點的距離也開始小於5,因此有更多的以此頂點爲頂點的三角形開始呈現漸變效果。

(4)進一步的在X方向上靠近(0,0,0)點,只有左上方的頂點距離(0,0,0)點的距離大於5,因此可以看到所有以綠色頂點爲頂點的三角形內的像素點都呈現爲綠色,不再有漸變效果。

(5)最終所有的頂點距離(0,0,0)點的距離都小於5,所以所有的頂點的顏色都爲綠色,所有的三角形內的像素點經過插值依然爲綠色。


我們再對上面的shader進行改造,將計算與(0,0,0)點的距離的方法放到frag函數中,也就是計算每一個像素點距離(0,0,0)點的距離:

Shader "Custom/SetColorInFrag" {
	Properties {
      	_ZeroPoint ("ZeroPoint", Vector) = (0, 0, 0, 0)
		_Distance ("Distance", Float) = 5.0
		_ColorNear ("Color_Near", Color) = (0.0, 1.0, 0.0, 1.0)
		_ColorFar ("Color_Far", Color) = (1.0, 0.0, 0.0, 1.0)
	}
	SubShader {
		Pass
		{
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4 _ZeroPoint;
			uniform float _Distance;
			uniform float4 _ColorNear;
			uniform float4 _ColorFar;
			
			struct vertexInput
			{
				float4 vertex : POSITION;
			};
			
			struct vertexOutput
			{
				float4 pos : SV_POSITION;
				float4 posInWorld : TEXCOORD0;
			};
			
			vertexOutput vert(vertexInput input)
			{
				vertexOutput output;
				output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
				output.posInWorld = mul(_Object2World, input.vertex);
				
				return output;
			}
			
			float4 frag(vertexOutput input) : COLOR
			{				
				float dist = distance(input.posInWorld, _ZeroPoint);
				
				if(dist < _Distance) 
				{
					return _ColorNear;
				}
				else
				{
					return _ColorFar;
				}
			}
									
			ENDCG
		}
	} 
}

將該shader應用到Cube上之後,我們再次從遠方慢慢在X方向上移動立方體接近(0,0,0)點,依次得到如下的效果:


從上面的幾幅圖中看以看出,我們將計算顏色的方法放到frag函數中之後,每個像素點的顏色完全由該函數中的計算結果來決定,而不再是對頂點穿過來的顏色值進行插值得到的結果。

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