頂點/片元 shader 總結
Cg頂點程序必須在結構中傳遞頂點數據。幾種常用的頂點結構定義在文件UnityCG.cginc中,有如下三種結構體:
1、appdata_base: 包含頂點位置,法線和一個紋理坐標。
2、appdata_tan:包含頂點位置,切線,法線和一個紋理坐標。
3、appdata_full:包含位置、法線、切線、頂點色和兩個紋理坐標。
struct appdata_base { float4 vertex : POSITION; //頂點坐標 float3 normal : NORMAL;//法線 float4 texcoord : TEXCOORD0;//UV }; struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };struct appdata_full { float4 vertex : POSITION;//頂點坐標 float4 tangent : TANGENT;//正切 float3 normal : NORMAL;//法線 float4 texcoord : TEXCOORD0;//第一層UV float4 texcoord1 : TEXCOORD1; //第二層UV fixed4 color : COLOR; //顏色 };
註:頂點坐標和正切線為什麽是float4,這有點意思,因為這裏它表示是齊次坐標,比如我們這樣表示一個float4(x,y,z,w),當w = 1的時候它表示點(x,y,z),當w= 0的時候它表示一個向量(x,y,z)。區別就在這裏,當W為1時表示點,當W為0時表示向量。
texcoord0和texcoord1分別表示兩層UV,有時候我們模型上的貼圖需要多個圖片一起貼在一處,那麽貼兩層就會有兩層UV。
以上三種類型為Unity內置的頂點Shader傳入結構體,如果想自定義也是可以的,但是自定義結構體裏面的屬性,必須是基於appdata_full的,這樣才能識別出來,也就是自定義的結構裏的屬性必須到appdata_full裏的屬性裏去選。
下面給一個簡單的頂點/片元 shader 事例:
Shader "Custom/Example" { Properties { _MainTex ("Texture", 2D) = "white" { } //引號裏面的"Texture"則是Unity檢視面板中對應顯示的屬性名稱 } SubShader { pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; //_MainTex_ST的ST應該是SamplerTexture的意思 ,就是聲明_MainTex是一張采樣圖,也就是會進行UV運算。 //如果沒有這句話,是不能進行TRANSFORM_TEX的運算的。_MainTex_ST.xy為 圖中的Tiling,zw為圖中的offset. float4 _MainTex_ST; struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; } ; v2f vert (appdata_base v) { v2f o; o.pos = mul(UNITY_MATRIX_MVP,v.vertex); //MVP矩陣變換,將裁剪空間坐標轉換為相對屏幕位置的UV坐標 o.uv = TRANSFORM_TEX(v.texcoord,_MainTex); //TRANSFORM_TEX的作用是用頂點的UV v.texcoord和材質球的采樣圖片_MainTex做運算,確保頂點材質球裏的縮放和偏移是正確的。等價於o.uv = v.texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw; return o; } float4 frag (v2f i) : COLOR { float4 texCol = tex2D(_MainTex,i.uv); float4 outp = texCol; return outp; } ENDCG } } }
其中SV_POSITION,SV_前綴的變量代表system value,在DX10以後的語義綁定中被使用代表特殊的意義,和POSITION用法並無不同。唯一區別是 SV_POSTION一旦被作為vertex shader的輸出語義,那麽這個最終的頂點位置就被固定了(不能tensellate,不能再被後續改變它的空間位置?),直接進入光柵化處理,如果作為fragment shader的輸入語義那麽和POSITION是一樣的,代表著每個像素點在屏幕上的位置(這個說法其實並不準確,事實是fragment 在 view space空間中的位置,但直觀的感受是如括號之前所述一般)
最後這個回答者說了,在DX10版本之前沒有引入SV_的預定義語義,POSITION被用作vertex shader的輸入,輸出,fragment shader的輸入參數。但DX10之後就推薦使用SV_POSITION作為vertex shader的輸出和fragment shader的輸入了,註意vertex shader的輸入還是使用POSITION!切記。但是DX10以後的代碼依舊兼容POSITION作為全程表達,估計編譯器會自動判斷並替換的吧。
最後推薦兩篇不錯的博客,
https://onevcat.com/2013/07/shader-tutorial-1/
http://blog.csdn.net/ring0hx/article/details/46440037
頂點/片元 shader 總結