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 } } }
這個例子畫圈圈。能夠設定圈圈的大小和個數。
關於參數的綁定能夠參考系列文章的第一篇。