Shader初學者的學習筆記
第二天 開始Unity Shader的學習之旅之熟悉頂點著色器和片元著色器
文章目錄
- Shader初學者的學習筆記
- 前言
- 一、頂點/片元著色器的基本結構
- ① Shader "Unity Shaders Book/Chapter 5/ Simple Shader"
- ② SubShader
- ③ CGPROGRAM和ENDCG
- ④ 指明頂點著色器和片元著色器函數名稱
- ⑤ 頂點著色器
- ⑥ 片元著色器
- 二、模型數據從哪來?
- ① a2v
- ② 語義中的數據從何而來
- ③ v2f
- ④ 如何使用屬性
- 總結
前言
今天對入門精要第五章進行一個小小的總結和歸納,主要是學習頂點著色器和片元著色器的結構.
一、頂點/片元著色器的基本結構
Shader "Unity Shaders Book/Chapter 5/ Simple Shader" ①
{SubShader ②{Pass{CGPROGRAM ③#pragma vertex vert ④#pragma fragment fragfloat4 vert (float4 : POSITION) : SV_POSITION ⑤{return mul (UNITY_MATRIX_MVP, v):}fixed4 frag() : SV_Target ⑥{return fixed4 (1.0, 1.0, 1.0, 1.0);}ENDCG}}
}
① Shader “Unity Shaders Book/Chapter 5/ Simple Shader”
該語句定義了Unity Shader的語義 – “Unity Shaders Book/Chapter 5/ Simple Shader”,這個名字有利于我們快速選擇到自定義的Shader.
② SubShader
你會發現,我們沒有聲明任何的材質屬性,因為Properties不是必須的, 同時在這個SubShader中沒有Tags, RenderSetup等,因此SubShader會使用默認的渲染設置和標簽設置.
并且我們在SubShader中定義的Pass也沒有設置Tags和RenderSetup.
③ CGPROGRAM和ENDCG
我們把cg代碼片段放在CGPROGRAM和ENDCG中;
④ 指明頂點著色器和片元著色器函數名稱
#pragma vertex name1
#pragma fragment name2
name1, name2是我們自己指定的函數名,可以告訴Unity,name1包含了頂點著色器的代碼,name2包含了片元著色器的代碼,這個函數的名字不一定要使用vertex和frag,但是我們一般用使用這兩個來定義函數,因為他們很直觀.
⑤ 頂點著色器
float4 vert (float4 : POSITION) : SV_POSITION
{return mul (UNITY_MATRIX_MVP, v):
}
需要再提一次,頂點著色器是逐頂點執行的, vert函數的輸入是float4類型的頂點位置,這是通過POSITION語義指定的,vert函數的輸出也是float4類型的,即頂點在裁剪空間的位置,由SV_POSITION的語義指定的;
POSITION 和 SV_POSITION都是Cg/HLSL的語義,他們是不可忽略的,他們會告訴Unity輸入和輸出,例如:POSITION告訴Unity,將模型的頂點坐標填充到參數v中,SV_POSITION告訴Unity,頂點著色器的輸出是裁剪空間的坐標,所以使用這些語義現在輸入輸出參數是非常有必要的.
再看頂點著色器的代碼,這一句代碼的含義就是將頂點坐標從模型空間轉換到裁剪空間.
補充:UNITY_MATRIX_MVP矩陣是Unity內置的模型觀察投影矩陣.
⑥ 片元著色器
fixed4 frag() : SV_Target
{return fixed4 (1.0, 1.0, 1.0, 1.0);
}
在片元著色器中,frag函數沒有任何輸入,他的輸出是一個fixed4類型的變量,并且使用了SV_Target語義進行限定,SV_Target也是HSLSL中的一個系統語義,他等同于告訴渲染器,把用戶的輸出顏色存儲到渲染目標中,這里將輸出到默認的幀緩存中.
片元著色器的代碼也很簡單,返回一個白色的fixed4變量.
二、模型數據從哪來?
我們如果想要得到模型上的每個頂點的紋理坐標和法線方向,那么我們就不能只是將float4作為頂點著色器的輸入了,我們就需要自己定義一個結構體,如下:
Shader "Unity Shaders Book/Chapter 5/ Simple Shader"
{Properties{_Color ("Color Tint", Color) = (1.0, 1.0, 1.0, 1.0)}SubShader{Pass{CGPROGRAM#pragma vertex vert#pragma fragment fragfixed4 _Colorstruct a2v ①{float4 vertex : POSITION; ②float3 normal : NORMAL;float4 texcoord : TEXCOORD0;}struct v2f ③{float4 pos : SV_Position; fixed3 color : COLOR0;}v2f vert (a2v v) : SV_POSITION {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;}fixed4 frag(v2f i) : SV_Target{fixed3 c = i.color;c *= _Color.rgb;return fixed4(c, 1.0);}ENDCG}}
}
① a2v
在上面的代碼中,我聲明了新的結構體a2v,這里面包含很多數據:模型空間的頂點坐標,法線方向,以及模型的第一套紋理坐標,這些都是通過特定的語義進行修飾的,unity支持的語義有:POSITION, TANGENT, NORMAL, TEXCOORD0, TEXCOORD1, TEXCOORD2, TEXCOORD3, COLOR等
注意:語義是不可以被忽略的
是不是很疑惑為什么要起名字為a2v,因為a是應用,v表示頂點著色器,a2v的意思就是從應用階段到頂點著色器.
② 語義中的數據從何而來
這些語義的數據是從哪來的呢?他們其實是由Mesh Render組件剔紅的,在每幀調用Draw Call的時候, Mesh Render組件會把它負責渲染的模型數據發送給Unity Shader.
我們知道,一個模型通常包含一組三角面片,每個三角面片由三個頂點組成,每個頂點又包含一些數據:頂點位置,法線,切線,紋理坐標,頂點顏色等,通過上面的方法,我們就可以在頂點著色器中訪問頂點的模型數據了.
③ v2f
我們在頂點著色器進行了一些變換之后,希望把模型的法線,紋理坐標等傳遞給片元著色器,那么這個傳遞過程是怎樣的呢?
我們首先定義了一個v2f的結構體,用于在頂點著色器和片元著色器之前傳遞信息,為了將模型渲染到屏幕上,我們必須在頂點著色器的輸出中定義一個變量,他的語義是SV_POSITION,COLOR0一般用于存儲顏色,也可由用戶自行定義.
④ 如何使用屬性
在上面的代碼中,我們聲明了屬性:_Color,為了可以在cg中訪問它,我們需要在Cg代碼片段中提前定義一個名稱和類型與Properties中屬性相匹配的變量.
下面表格記錄了屬性的類型和變量類型的匹配關系
ShaderLab屬性的類型 | Cg變量的類型 |
---|---|
Color, Vector | float4, half4, fixed4 |
Range, float | float, half, fixed |
2D | sampler2D |
Cube | samplerCube |
3D | sampler3D |
補充
uniform fixed4 _Color;
在上述Cg變量前,有uniform變量進行修飾,他僅僅用于提供一些關于該變量的初始值是如何指定和存儲的相關信息,在Unity Shader中是可以省略的.
總結
今天我對第五章的頂點著色器和片元著色器的知識進行了總結,為以后復雜的Unity Shader的學習打下了堅實的基礎!!!