1. 程式人生 > >頂點/片元 shader 總結

頂點/片元 shader 總結

用法 nbsp lan 簡單的 one sam post 表達 coo

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 總結