Unity shader 官網文檔全方位學習(三)

Vertex and Fragment shader 是unity三大shader家族之一,勢力最大,且範圍最廣。官方的對此的說法,若是不須要對光照方向進行處理,僅是對於貼圖方面或者形狀特效等,可使用vertex and fragment shader。所以從這方面來看,vertex and fragment shader使用域將會更廣。如下詳細說明:html

http://docs.unity3d.com/Documentation/Components/SL-ShaderPrograms.html算法

1、總述app

1.做用:顧名思義,這種shader針對頂點與塊,區別於surface shader的針對表面。所以更多狀況用於貼圖,與相關的特效處理。dom

2.語法:函數

=>整體:以Pass之外圍塊,寫在SubShader裏。學習

Pass {      

      
      
       vert       frag      

      
      
  }

 

在CGPROGRAM 及 ENDCG之間用Cg或HLSL語言寫上處理的代碼。spa

=>經常使用的一些pragma函數定向:3d

  • #pragma vertex name - 頂點的函數定向orm

  • #pragma fragment name - 塊的函數定向htm

  • #pragma geometry name - DX10 geometry shader的函數定向. 將自動打開 #pragma target 4.0.

  • #pragma hull name - DX11 hull shader的函數定向. 自動打開#pragma target 5.0.

  • #pragma domain name - DX11 domain shader的函數定向. 自動打開#pragma target 5.0.

     

還有一些,很少列舉,這些均可從官網查到。

=>根據平臺選擇合適的pragma

#pragma target 默認是2.0的,對於Cg中的ARB_vertex_program 和ARB_fragment_program分別限制在256和96條指令以內。平臺是在D3D9下的。

#pragma target 3.0,相對於2.0,總體有所提升,對ARB_vertex_program再也不限制,但ARB_fragment_program可在1024以內,其中512材質和512算法相關的。

#pragma target 4.0,5.0分別是對於DX10和DX11的。但目前只能使用DX11來渲染纔有效。

如下是unity所支持的各類渲染機制的問題:

  • d3d9 - Direct3D 9.

  • d3d11 - Direct3D 11.

  • opengl - OpenGL.

  • gles - OpenGL ES 2.0.

  • xbox360 - Xbox 360.

  • ps3 - PlayStation 3.

  • flash - Flash.

從上面瞭解到,若是你使用的是MAC,是沒有DX的,所以好多針對於DX的shader許多渲染是出不來的。同時有時爲了加快GPU的處理速度,還可使用#pragma only_renderers 和 #pragma exclude_renderers 幫助聲明只包含指定形式的的渲染機制,或者去除一些不使用的渲染機制。

2、實例學習

1.Window Coordinates

Shader "Custom/WindowCoordinates/Base" {
	SubShader {
		Pass {
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0  //1

			#include "UnityCG.cginc"

			float4 vert(appdata_base v) : POSITION { //2
				return mul (UNITY_MATRIX_MVP, v.vertex);
			}

			fixed4 frag(float4 sp:WPOS) : COLOR {
				return fixed4(sp.xy/_ScreenParams.xy,0.0,1.0); //3
			}

			ENDCG
		}
	}
}

 

這個例子是利用物體座標與屏幕視角座標的比值來設置物體的顏色。

第一處(//1):使用3.0的target,比默認的2.0參數的限制較少了。

第二處(//2):這裏經過include進來的UnityCG.cginc的appdata_base的結構體做爲輸入,內容以下:

 

struct appdata_base {

    float4 vertex : POSITION;

    float3 normal : NORMAL;

    float4 texcoord : TEXCOORD0;

};
 

 

函數體首先將物體的點的位置轉成模型視角投射三窗口上的,這樣得出的座標是與MODEL,VIEW,PROJECTION三者就關係了。就能夠實際應用到。

第三處(//3):WPOS是一個CG的語義,我理解成就是一種類型標籤,就是告訴顯卡,我要拿這個float值做爲何樣的用途。_screenParams是屏幕參數的一個結構體,注意是屏幕參數,這個值在選定模擬的窗口大小時就固定了,此處從中取出xy座標。所以,當移動物體,而不用視角時,往左移,則x比值越小,反映到這個例子就是R顏色值越小,就越綠,反之越紅。上下的原理相似。這樣當稍稍放大物體並居中,就能夠獲得比較清晰的顏色變化。

上效果:

 

2.Behind Bars

Shader "Custom/WindowCoordinates/Bars" {
	SubShader {
		Pass {
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			#include "UnityCG.cginc"

			struct vertOut {
				float4 pos:SV_POSITION;
				float4 scrPos;
			};

			vertOut vert(appdata_base v) {
				vertOut o;
				o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
				o.scrPos = ComputeScreenPos(o.pos);   //1
				return o;
			}

			fixed4 frag(vertOut i) : COLOR0 {
				float2 wcoord = (i.scrPos.xy/i.scrPos.w); //2
				fixed4 color;

				if (fmod(20.0*wcoord.x,2.0)<1.0) { //3
					color = fixed4(wcoord.xy,0.0,1.0); //4
				} else {
					color = fixed4(0.3,0.3,0.3,1.0);
				}
				return color;
			}

			ENDCG
		}
	}
}

 

這個例子首先較第一例使用新的方式獲取屏幕座標,其次使用取模函數作一個顏色間隔出來。

第一處:unityCG裏的函數:定義以下:

 

inline float4 ComputeScreenPos (float4 pos) { float4 o = pos * 0.5f; #if defined(UNITY_HALF_TEXEL_OFFSET) o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw; #else o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w; #endif #if defined(SHADER_API_FLASH) o.xy *= unity_NPOTScale.xy; #endif o.zw = pos.zw; return o; }

 

整體來講,是對x,y的座標按當前屏幕座標換算。這樣以獲得更精確的屏幕顯示座標。

第二處:齊次座標化成世界三維座標。此處只取xy座標。

第三處:取當前x座標的20倍取模,以獲得間隔效果。

第四處:同例一,以xy爲顏色值渲染。

上效果:

3.Vignetting

Shader "Custom/WindowCoordinates/Vignetting" {
	SubShader {
		Pass {
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			#include "UnityCG.cginc"

			float4 vert(appdata_base v) : POSITION {
				return mul (UNITY_MATRIX_MVP, v.vertex);
			}

			float4 frag(float4 sp:WPOS) : COLOR {
				float2 wcoord = sp.xy/_ScreenParams.xy;
				float vig = clamp(3.0*length(wcoord-0.5),0.0,1.0); //1
				return lerp (float4(wcoord,0.0,1.0),float4(0.3,0.3,0.3,1.0),vig );     //2
			}
			ENDCG
		}
	}
}

 

這個例子主要經過lerp函數,經過對界面上各點與原點的距離作爲lerp的參數,進行顏色的混合。

第一處:這裏的clamp函數,若是在第一參數在後兩個參數(分別爲左右邊界值)值之間,直接返回。若是小於左邊界,取左邊界,大於右邊界,取右邊界。這個地方,首先wccord的座標範圍是0到1之間的,0點在左下角,減去0.5,保證圓心被提到中間。這樣就能夠取出一個以物體中心爲圓心的區域。

第二處:lerp函數就是根據0-1的比例取對應參數。可參考這個圖:左邊爲0.右邊1。左右三角形分別爲第一個和第二個參數。

4.Circles Mask

Shader "Custom/WindowCoordinates/CirclesMask" {
	Properties {
		_CirclesX ("Circles in X", Float) = 20
		_CirclesY ("Circles in Y", Float) = 10
		_Fade ("Fade", Range (0.1,1.0)) = 0.5
	}
	SubShader {
		Pass {

			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0

			#include "UnityCG.cginc"

			uniform float _CirclesX;
			uniform float _CirclesY;
			uniform float _Fade;

			float4 vert(appdata_base v) : POSITION {
				return mul (UNITY_MATRIX_MVP, v.vertex);
			}

			float4 frag(float4 sp:WPOS) : COLOR {
				float2 wcoord = sp.xy/_ScreenParams.xy;
				float4 color;
				if (length(fmod(float2(_CirclesX*wcoord.x,_CirclesY*wcoord.y),2.0)-1.0)<_Fade) {//1
					color = float4(sp.xy/_ScreenParams.xy,0.0,1.0);
				} else {
					color = float4(0.3,0.3,0.3,1.0);
				} 
				return color;
			}
			ENDCG
		}
	}
}

這個例子畫圈圈。能夠設定圈圈的大小和個數。

關於參數的綁定能夠參考系列文章的第一篇。

相關文章
相關標籤/搜索