【遊戲渲染】Unity&Shader基礎篇-Cg語法,資料型別與關鍵字
1.2、Cg語法基礎
如C++、C#和Java等高階語言一樣,Cg語言也有自己的資料型別和關鍵字。掌握和理解這些關鍵字是寫好Cg程式的基礎。
1.2.1、Cg的資料型別與關鍵字
基本資料型別:Cg支援7種基本的資料型別
1、float,32位浮點資料,一個符號位。浮點資料型別被所有的圖形介面支援;
2、half,16位浮點資料;
3、int,32位整形資料
4,fixed,12位定點數,
5、bool,布林資料,被所有的圖形介面支援;
6、sampler*,紋理物件的控制代碼,分為sampler、sampler1D、sampler2D、sampler3D、samplerCUBE和samplerRECT。
內建的資料型別:基於基礎資料型別,如float3,表示float型別的三維向量;同理,bool2表示布林型別的二維向量。
注:向量最長不能超過四元,如float5 vector;//編譯錯誤
向量的賦值,float2 a=float(1.0,1.0); //編譯通過
float2 a=float(1.0f,1.0f); //編譯錯誤
float3 b=float(a,0.0); //編譯通過
矩陣資料型別,float1X1 m1; //即float m1,一維矩陣
float3X4 m34 //3*4階矩陣
注:X是字元,不是乘號,最大的維數為4*4階
矩陣的初始化 float 2*2 m22={1.0,2.0,3.0,2.3};
float3 x和floatx[3]是不同的,前者為向量是內建的資料型別,而陣列則是一種資料結構,不是內建的資料型別。
型別轉換:Cg中的型別轉換有強制轉換和隱式轉換;如果是隱式轉換則資料型別從低精度向高精度轉換。如:
float a=1.0;
half b=2.0;
float c=a+b; //等價於float c=a+(float)b;
Cg語言中可以對常量資料加上型別字尾表示該資料型別的資料,如:
float a=1.0h; //1.0h為half型別常量資料
這樣的字尾型別有三種:
f:表示float;
h:表示half;
x:表示fixed;
Swizzle操作符:Cg語言中的其他操作符和高階CPU語言C++類似,包括關係操作符、邏輯操作符和位移操作符以及條件操作符。而Swizzle操作符是Cg語言中特有的,它可以將一個向量的成員取出組成一個新的向量。對於座標或者角度等其他多維向量,Swizzle操作符(.)後接x、y、z、w分別表示原始向量的第一個、第二個、第三個和第四個元素;同樣,對於顏色可以後接r、g、b和a來表示同樣的索引。
例如:
float4(a,b,c,d).xwz 等價於 float(a,d,c)
float4(a,b,c,d).xxy 等價於 float(a,a,b)
注:Swizzle操作符只對結構體和向量使用,不能對陣列使用。
輸入資料關鍵字:Cg中輸入資料流一般分為兩類
1、varying 引數:在Cg程式中通過語義進行繫結變數, Cg語言提供了一組語義詞,用以表示引數是由頂點的那些資料初始化的,一旦這個變數使用了語義詞進行繫結,那麼這個變數值被初始化的同時也意味著它有了特殊的含義,如表示位置、法線等含義。語義提供了一種使用隨頂點變化或隨片段變化而變化的值來初始化Cg程式引數的方法,這些資料都是從應用程式輸入到GPU的資料,如頂點位置、法向量、紋理座標資料等。
2、Uniform引數:Uniform是用來限制一個變數的初始值的來源,當宣告一個變數為Uniform型別的時候,表示這個變數的初始值來自於外部的其他環境。除了獲取初始值的這點之外,Uniform關鍵字宣告的變數和其他變數是完全一樣的。通常用Uniform來定義一些與三維渲染有關的離散資訊資料,並通常不會隨著圖元資訊的變化而變化,如材質對光的反射資訊。Uniform表示一個引數,通常使用uniform表示函式的形參,不能定義一個uniform表示的區域性變數。
Unity的內建Uniform輸入引數如下:
uniform float4 _Time, _SinTime, _CosTime; // 時間量
uniform float4 _ProjectionParams; // x = 1 or -1 (如果投影翻轉就是-1)
// y = 近平面; z = 遠平面; w = 1/遠平面
uniform float4 _ScreenParams; // x = width; y = height; z = 1 +1/width; w = 1 + 1/height
uniform float3_WorldSpaceCameraPos;
uniform float4x4 _Object2World; //模型矩陣
uniform float4x4 _World2Object; // 模型矩陣的逆
uniform float4 _LightPositionRange; // xyz = pos, w = 1/range
uniform float4 _WorldSpaceLightPos0; // 光源的位置和方向
uniform float4x4 UNITY_MATRIX_MVP; // 模型檢視投影矩陣
uniform float4x4 UNITY_MATRIX_MV; // 模型檢視矩陣
uniform float4x4 UNITY_MATRIX_V; // 檢視矩陣
uniform float4x4 UNITY_MATRIX_P; // 投影矩陣
uniform float4x4 UNITY_MATRIX_VP; // 檢視投影矩陣
uniform float4x4 UNITY_MATRIX_T_MV; // 模型檢視矩陣的轉置矩陣
uniform float4x4 UNITY_MATRIX_IT_MV; // 模型檢視矩陣的逆矩陣的轉置矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE0; // 貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE1; //貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE2; //貼圖紋理矩陣
uniform float4x4 UNITY_MATRIX_TEXTURE3; //貼圖紋理矩陣
uniform float4 UNITY_LIGHTMODEL_AMBIENT; // 環境色
這些變數在Unity中可以直接使用,本章第三節中將會展現如何在Unity中使用這些內建的Uniform變數。
1.2.2、輸入輸出和語義
輸入輸出:在第一節中我們瞭解到對於程圖形渲染管線,可程式設計控制的部分只有兩個,頂點著色器和片段著色器。對於程式設計控制這兩個部分,首要的任務就是要怎麼給它們傳引數。Cg語言的引數傳遞同樣也有“值傳遞”和“引用傳遞”之分。因為GPU不支援指標,所以Cg語言採用瞭如下的方式來修辭引數傳遞:
1、in:修辭一個形參只是用於輸入,進入函式體時被初始化,且該形參值的改變不會影響實參值,傳遞方式為值傳遞。
2、out:修辭一個形參只是用於輸出,進入函式體時沒有被初始化,一般為函式的返回值。
3、inout:修辭一個形參即用於輸入也用於輸出,這是典型的引用傳遞。
語義:表示圖元資料的含義(頂點的位置、法向量或者紋理資訊),也表明這些圖元資料存放的硬體資源。因為頂點著色器的輸出即是片段著色器的輸入,所以頂點著色器的輸出必須和片段著色器的輸入語義是一致的。語義是頂點程式和片段程式之間輸入\輸出資料和暫存器之間的橋樑,因此語義只對這兩個處理階段有意義,並且只在入口函式才有效,在內部函式無效。語義概念的提出和圖形流水線工作機制大有關係。從前面所講的GPU處理流程中可以看出,一個階段處理資料,然後傳輸給下一個階段,那麼每個階段之間的介面是如何確定的呢?例如:頂點處理器的輸入資料是處於模型空間的頂點資料(位置、法向量),輸出的是投影座標和光照顏色;片段處理器要將光照顏色做為輸入,問題是“片段處理器怎麼知道光照顏色值的存放位置”。在高階語言中(C/C++),資料從介面的一端流向另一端,是因為提供了資料存放的記憶體位置(通常是指標資訊);由於Cg 語言並不支援指標機制,且圖形硬體處理過程中,資料通常暫存在暫存器中,故而在Cg 語言中,通過引入語義繫結(binding semantics)機制,指定資料存放的位置,實際上就是將輸入\輸出資料和暫存器做一個對映關係(在OpenGL Cg profiles 中是這樣的,但在DirectX-based Cgprofiles 中則並沒有這種對映關係)。根據輸入語義,圖形處理器從某個暫存器取資料;然後再將處理好的資料,根據輸出語義,放到指定的暫存器。
語義詞和語義繫結:Unity的頂點著色器(程式)中常用的語言詞有如下:
1、POSITION\SV_POSITION :模型座標的位置,
2、TANGENT:正交於表面法線的向量
3、NORMAL:表面法線向量,需要進行歸一化
4、TEXCOORDi:第i組紋理座標(也即UV座標,座標範圍在0~1之間),i是0~7中的一個數字
5、COLOR:顏色
6、PSIZE:點的大小
7、BLENDINDICES:通用屬性,可以用它和TANGENT來替換TEXCOORDi
注:SV_POSTION和POSTION的唯一區別是用在頂點著色器中作為輸出語義時,SV_POSTION表示的頂點位置會被固定,不能被改變。如果作為片段著色器的輸入語義就是一樣的,都可以被改變。
頂點著色器的輸出語義詞有:
1、COLOR:顏色
2、FOG:輸入霧座標
3、PSIZE
4、 POSITION
5、TEXCOORD0-TEXCOORD7
片段著色器的輸入語義即為頂點著色器的輸出語義。
片段著色器的輸出語義如下:
1、COLOR:顏色
2、DEPTH:片段的深度
語言繫結的三種方法:
1、繫結語義放在函式的引數列表的引數聲明後面中:
1 2 3 4 5 6 7 8 9 |
[ const ][ in | out |inout|uniform][
:][=]
void
vert(float4 obj_position:POSITION,
float4
obj_normal:NORMAL,
out
float4 outPos:POSITION,
uniform
float4 uColor:COLOR
{
...
}
|
其中,const作為可選項,const修飾符同C和C++語言裡的一樣,表示這個變數的值是不能改變的;in、out、inout作為可選項,說明資料的呼叫方式;
uniform也是可選項,表示變數的值的初始化是來自外部應用程式;type是必選項,宣告資料的型別;identifier是必選項,形參變數名:一個冒號“:”加上一個繫結語義,是可選項;最後是初始化引數,是可選項。
引數1、2、5繫結到輸入語義;引數3、4繫結到輸出語義;儘管引數1和3的繫結語義詞一樣,但前者是輸入語義,後者是輸出語義,所以這兩個引數資料所對應儲存的硬體位置是不一樣的。
2、繫結語義可以放在結構體的成員變數後面:1 2 3 4 5 6 7 |
Struct< struct -tag>
{
[:binding-semantic>];
};。
|