1. 程式人生 > >頂點著色器與片段著色器之間資料的傳遞方式

頂點著色器與片段著色器之間資料的傳遞方式

在頂點著色器函式中,顧名思義,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函式中之後,每個畫素點的顏色完全由該函式中的計算結果來決定,而不再是對頂點穿過來的顏色值進行插值得到的結果。