【Shader基礎篇】之第一個shader程序

The shader is  miraculous,I love it!


本文知識總結於------------Unity Shader 入門精要--馮樂樂

1:

首先看一段代碼:

Shader "Unity Shader Book/Chapter 5/Simple Shader"
{

     Properties //不是必有的
    {
       _MyTexture("Texture (RGB)",2D)="White"{}//圖片形式的屬性
     }
  SubShader{   
     Pass
	 {   Name "FIRST"//設置pass命名
	 //CGPROGRAM與ENDCG之間是CG代碼
	    CGPROGRAM 

		//下面兩句是編譯指令,用來告訴unity哪些是頂點着色器代碼,哪些是片元着色器代碼
		#pragma vertex vert
		#pragma fragment frag
		//:POSITION和:SV_POSITION是CG中的語義,不能省略,用於告知系統用戶輸入輸出值格式
		float4 vert(float4 v :POSITION):SV_POSITION  
		{
		  return mul (UNITY_MATRIX_MVP,v);//將頂點座標從模空間轉換到裁剪空間中,UNITY_MATRIX_MVP是內置轉換矩陣
		}

		//SV_Target是一個默認的語義,用於告訴渲染器,把用戶的輸出顏色存儲在幀緩存中
		fixed4 frag():SV_Target
		{
		  //這是一個顏色,每一個分量在0-1之間
		  return fixed4(1.0,1.0,0.5,1.0);
		}
		ENDCG
	 }
  }
}


首先對程序進行分析:

     1:vert函數頂點着色器,是逐頂點執行的。在vert函數中,POSITION相當於告訴unity把模型頂點座標填充到參數v中,而SV_POSITION表示這個函數輸出的是裁剪空間中的頂點座標。這個函數只有一句代碼:作用是將模型頂點座標轉換到裁剪空間中去。

     2:frag函數是片元着色器,用於告訴渲染器,把用戶的輸出顏色存儲在幀緩存中。


注意:SV_POSITION是裁剪空間的頂點座標,其中的SV代表系統數值,在渲染流水線中有特殊的含義。(而對於POSITION,COLOR等語義,我們可以存儲任何變量到其修飾的變量中去)用SV_POSITION語義修飾頂點着色器的輸出變量,用系統數值描述的變量是不可以隨便賦值的,渲染引擎會把用SV_POSITION修飾過的變量經過光柵化後在屏幕中進行渲染。其中的UNITY_MATRIX_MVP是:內置模型視圖轉換矩陣,UNITY_MATRIX_MV:內置模型視圖矩陣。


2:

          在上面代碼中,我們將模型頂點的位置座標作爲參數傳遞到轉換矩陣函數中,進行轉換,但如果我們想將模型其他的參數(紋理座標,法線座標等),轉換到裁剪空間去,難道在vert函數中設置很多個參數嗎?

          不,我們的想法是,構造結構體a2v來存儲模型的屬性值。

代碼如下:

Shader "Unity Shader Book/Chapter 5/Simple Shader"
{
  Properties
 {
    _MyTexture("Texture (RGB)",2D)="White"{}//圖片形式的屬性
	_Color("Color Tint",Color)=(1.0,1.0,1.0,1.0)
 }
  SubShader{
     Pass
	 {
	 //pass的名字可以在其他地方引用
	   Name "FIRST"

	 //CGPROGRAM與ENDCG之間是CG代碼
	    CGPROGRAM 

		//下面兩句是編譯指令,用來告訴unity哪些是頂點着色器代碼,哪些是片元着色器代碼
		#pragma vertex vert
		#pragma fragment frag

		struct a2v
		{
		  //模型空間中的頂點位置
		  float4 vertex :POSITION;
		  //頂點法線
		  float3 normal :NORMAL;
		  //紋理座標,這是用TEXCOORD0描述texcoord變量,TEXCOORD0表示第一組紋理
		  //unity會識別TEXCOORD0語義將模型的第一組紋理填充到texcoord中
		  float4 texcoord :TEXCOORD0;
		};

		//:POSITION和:SV_POSITION是CG中的語義,不能省略,用於告知系統用戶輸入值的格式,輸出值的格式
		float4 vert(a2v v):SV_POSITION  
		{
		    return mul (UNITY_MATRIX_MVP,v.vertex);//將頂點座標從模空間轉換到裁剪空間中,UNITY_MATRIX_MVP是內置矩陣
		}

		//SV_Target是一個默認的語義,用於告訴渲染器,把用戶的輸出顏色存儲在幀緩存中
		fixed4 frag():SV_Target
		 {
		   //這是一個顏色,每一個分量在0-1之間
		  return fixed4(1.0,1.0,0.5,1.0);
		 }

		ENDCG
	 }
  }
}

  自定義結構體定義:struct  StructName {

                         Type  Name : Semantic ;

                         Type  Name : Semantic ;

                     };                                              就像這樣:struct v2f
                                                                  {
                                                                         float4   pos :SV_POSITION;
                                                                         fixed3  color :COLOR0;
                                                                   };

             然後我們就可以在函數中通過結構體變量來引用結構體中的數據。如v.vertex。


3:在頂點着色器中我們輸出了法線,紋理座標等數據,而這些數據將輸入到片元着色器中,我們希望將這些數據也封裝到一個結構體中,於是我們定義v2f結構體來存儲頂點着色器的輸出。


代碼如下:

Shader "Unity Shader Book/Chapter 5/Simple Shader"
{
  Properties
 {
    _MyTexture("Texture (RGB)",2D)="White"{}//圖片形式的屬性
	_Color("Color Tint",Color)=(1.0,1.0,1.0,1.0)
 }
  SubShader{
     Pass
	 {
	 //pass的名字可以在其他地方引用
	   Name "FIRST"

	 //CGPROGRAM與ENDCG之間是CG代碼
	    CGPROGRAM 

		//下面兩句是編譯指令,用來告訴unity哪些是頂點着色器代碼,哪些是片元着色器代碼
		#pragma vertex vert
		#pragma fragment frag

		fixed4 _Color;

		struct a2v
		{
		  //模型空間中的頂點位置
		  float4 vertex :POSITION;
		  //頂點法線
		  float3 normal :NORMAL;
		  //紋理座標,這是用TEXCOORD0描述texcoord變量,TEXCOORD0表示第一組紋理
		  //unity會識別TEXCOORD0語義將模型的第一組紋理填充到texcoord中
		  float4 texcoord :TEXCOORD0;
		};

		struct v2f
		{
		  float4 pos :SV_POSITION;//pos包含了頂點在裁剪空間中的位置信息
		  fixed3 color :COLOR0;//COLOR0可以用於存儲顏色信息
		};

		//:POSITION和:SV_POSITION是CG中的語義,不能省略,用於告知系統用戶輸入值的格式,輸出值的格式

		v2f vert(a2v v)
		{
		  v2f o;
		  o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
		  o.color=v.normal*0.5 + fixed3(0.5,0.5,0.5);
		  return o;
		}

		//SV_Target是一個默認的語義,用於告訴渲染器,把用戶的輸出顏色存儲在幀緩存中

		fixed4 frag(v2f i):SV_Target
		{
		   fixed3 c= i.color;
		   c *=_Color.rgb;
		   return fixed4(c,1.0);
		}

		ENDCG
	 }
  }
}


   v2f實現了頂點着色器與片元着色器之間的通信。


總結:以上三段代碼其實效果都是相同的。頂點着色器是逐頂點調用的,而片元着色器是逐片元調用的,片元着色器的輸入其實是對頂點着色器的輸出進行插值得到的。




效果截圖:                                                                                                                                                 Properties中Texture屬性面板:



發佈了136 篇原創文章 · 獲贊 25 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章