Unity&Shader基礎篇-Cg語法

https://blog.csdn.net/zhangxiao13627093203/article/details/52850518


轉載請注明出處凱爾八阿哥專欄

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、綁定語義放在函數的參數列表的參數聲明后面中:

[const][in|out|inout|uniform][ :][=]

voidvert(float4 obj_position:POSITION,

? float4 obj_normal:NORMAL,

outfloat4 outPos:POSITION,

? uniform float4 uColor:COLOR

{

...

}

其中,const作為可選項,const修飾符同C和C++語言里的一樣,表示這個變量的值是不能改變的;in、out、inout作為可選項,說明數據的調用方式;

uniform也是可選項,表示變量的值的初始化是來自外部應用程序;type是必選項,聲明數據的類型;identifier是必選項,形參變量名:一個冒號“:”加上一個綁定語義,是可選項;最后是初始化參數,是可選項。

參數1、2、5綁定到輸入語義;參數3、4綁定到輸出語義;盡管參數1和3的綁定語義詞一樣,但前者是輸入語義,后者是輸出語義,所以這兩個參數數據所對應存儲的硬件位置是不一樣的。

2、綁定語義可以放在結構體的成員變量后面:

Struct

{

[:binding-semantic>];

};。

如在結構體vertexOutput中兩個成員變量分別綁定語義SV_POSITOIN和TEXCOORD0,這個結構體在頂點程序vert中作為輸出,為頂點程序的輸出語義,同時頂點程序的輸入即是片段程序的輸入,該結構體也為片段程序的輸出語義。

structvertexOutput {

? ? ? ? ? ? float4 pos : SV_POSITION;

? ? ? ? ? ? float4 col : TEXCOORD0;

? ? ? ? };

vertexOutputvert(appdata_full input)

? ? ? ? {

? ? ? ? ? ? vertexOutput output;

? ? ? ? ? ? output.pos =? mul(UNITY_MATRIX_MVP, input.vertex);

? ? ? ? ? ? output.col = input.texcoord;

returnoutput;

? ? ? ? }

float4frag(vertexOutput input) : COLOR

? ? ? ? {

returninput.col;

? ? ? ? }

3、綁定語義詞可以放在函數聲明的后面,其形式為:?

() [:

{


}

如下面的代碼中,片段程序的后面帶有“COLOR”語義,表示該程序最后要返回一個顏色的值給GPU,所以在最后,返回的變量值類型是float4類型的。那這里為什么不直接使用float4呢,語義綁定,顧名思義綁定的變量是要有含義的,直接使用發咯float4就不能理解它到達表示什么含義,因為float4類型的變量可以是顏色、位置等。

float4frag(vertexOutput input) : COLOR

? ? ? ? {

float4 oColor =float4(1,0,0,1);

returnoColor;

? ? ? ? }

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容