ARCore之路-環境理解之Cg語言
雖然Surface Shader是Unity極力推動的編寫Shader的方式,但由於Surface Shader做了大量的封裝,遮蔽了很多底層實現細節,包括光照、頂點變換、材質使用等,在提供了更簡單的使用之餘也喪失了靈活性,下面我們只對vertex shaders 和 fragment shaders進行學習,讀者可以參閱官方文件以瞭解更多Surface Shader細節。
一、vertex & fragment shaders基本結構
Shader "DavidWang/vertexAndFragment"{ SubShader{ pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag void vert(in float2 objPos:POSITION, out float4 pos:POSITION) { pos = float4(objPos,0,1); } void frag(out float4 col:COLOR) { col = float4(1,0,0,1); } ENDCG } } Fallback "Mobile/VertexLit" }
Vertex & Frament Shader至少有一個pass通道,一個pass就是對場景的一次渲染。在ShaderLab語法中需要使用關鍵詞“CGPROGRAM”和“ENDCG”將Cg程式碼段包含起來才能編譯使用,需要注意的是這兩個關鍵詞都是大寫的。#pragma vertex vert指令的意思是使用vert函式來做Vertex shader的處理工作, #pragma fragment fragt指令的意思是使用fragt函式來做Fragment shader的處理工作,即這是分別指定了執行頂點和片段處理的函式。
Vertex shader會對頂點做一系列的處理,最主要的是把頂點座標從物體Local空間轉換成齊次裁減空間的齊次座標,同時進行必要的光照處理,把處理後的資料傳遞給Fragment shader程式,Fragment shader拿到頂點程式處理後的資料繼續進行最終的計算。Fragment shader最主要的工作是對紋理進行取樣、對顏色進行最終的合成,其輸出是顏色值。
在上例中,“void vert(in float2 objPos:POSITION, out float4 pos:POSITION)” 中有兩個引數,其中第一個引數中的“in”表示引擎提供的輸入,“float2”表示資料的型別為二階的向量,引數名“objPos”冒號後需要帶上語義,語義指的是頂點程式和片段程式能夠被識別的變數,這裡使用“POSITION”。第二個引數中“out”表示輸出,資料型別為“float4”,語義也是“POSITION”。如果頂點程式要輸出一個“POSITION”語義的變數,這個變數必須要以“float4”四階向量的形式。“void frag(out float4 col:COLOR)”使用語義為“COLOR”的變數作為輸出,這裡使用“out float4 col:COLOR”作為顏色變數的輸出,語義“COLOR”就是指“COLOR0”。
語義詞“POSITION”,“COLOR”不僅僅是表示資料型別,更重要的是指示出資料存放的位置,這些語義詞都有特定的含義。 Cg 語言所有 vertex profile 支援的輸入語義關鍵詞有: POSITION、BLENDWEIGHT、NORMAL、 TANGENT、 BINORMAL、 PSIZE、BLENDINDICES、TEXCOORD0—TEXCOORD7。 Cg 語言所有 vertex profile 支援的輸出和 fragment profile 輸入語義關鍵詞有:POSITION 、PSIZE 、FOG,COLOR0-COLOR1、TEXCOORD0-TEXCOORD7 。 Cg 語言所有 fragment profile 支援的輸出語義關鍵詞有:COLOR 。
示例shader是最簡單但又是結構完整的vertex shaders 和 fragment shaders,讀者務必瞭解。關於輸入輸出語義更詳細的說明超出了本章的內容,請讀者查閱相關資料。
二、profile
一個Cg profile定義了一個“被特定圖形硬體或API所支援的Cg語言子集”,任意一種shader language都是基於可程式設計圖形硬體的(暫存器、指令集等),這也就意味著,不同的圖形硬體對應著不同的功能子集。這些可選的語言功能包括某些控制結構和標準庫函式。profile還定義了資料型別的精度,並且指定資料型別是否全部支援或僅部分支援。profile按照功能可以劃分為vertex profile和fragment profile,而vertex profile和fragment profile又基於OpenGL和DirectX的不同版本或擴充套件,劃分為各種版本。
profile是語言的一種特性,在不同的處理方法中會擁有不同的特性。在特殊情況下,語言profile就是關於一個使用for或者while迴圈的限制,意思就是有些情況下它不支援for或者while迴圈,有些profile僅僅loop迴圈。Cg不支援goto、switch、case、default等保留關鍵字;也不支援指標和指標相關的運算能力;Cg支援陣列,但是有尺寸和維度的限制;Cg沒有列舉和聯合;Cg在結構體當中沒有位成員;Cg中所有的整型都是有符號,沒有signed關鍵字。
Cg有繫結語義,比如POSITON、COLOR0等;Cg內建有swizzle操作;對於一個值來說,swizzle操作可以允許進行拼湊一個向量或矩陣;swizzle操作可以去訪問所有的分量;資料有不同的有限的型別,主要的型別有float、half、fixed,片段profile必須支援這三種資料型別,但是可以選擇使用half或fixed去實現float,頂點profile要求實現half和float,但是可以選擇實現halp和float,頂點profile可以忽略支援fixed,Cg允許profile去忽略支援執行時的int,實際上會把int轉換成float;Cg中的操作很多都是對於向量的操作,可以對向量的基本元素進行操作,Cg中也有?問號表示式,沒有全域性的非靜態變數;Cg有新的sampler*集合;函式擁有預設引數;函式和它們的操作可以被過載;變數可以定義在任何地方,但要在使用之前定義就行等等。
三、Cg基本資料型別
Cg支援7種基本的資料型別
資料型別 | 說明 |
---|---|
float | 32 位浮點資料,一個符號位。浮點資料型別被所有的 profile 支援。 |
half | 16 位浮點資料。 |
int | 32 位整形資料,有些 profile 會將 int 型別作為 float 型別使用。 |
fixed | 12 位定點數,被所有的 fragment profiles 所支援。 |
bool | 布林資料,通常用於 if 和條件操作符( ?: ) ,布林資料型別被所有的profiles 支援。 |
simpler* | 紋理物件的控制代碼( the handle to a texture object ) ,分為 6 類: sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, 和 samplerRECT 。 |
Cg還提供了內建的向量資料型別 (built-in vector data types) ,內建的向量資料型別基於基礎資料型別。 例如: float4, 表示 float 型別的 4 元向量; bool4, 表示 bool型別 4 元向量。 注意: 向量最長不能超過 4 元, 即在 Cg 程式中可以宣告 float1 、 float2 、 float3 、float4 型別的陣列變數,但是不能宣告超過 4 元的向量。