繪制紋理
精度限定符用于指定任何基于浮點(diǎn)或者整數(shù)變量的精度轰胁,關(guān)鍵字有高谒主、中朝扼、低赃阀。
highp vec4 position;
varying lowp vec4 color;
mediump float specularExp;
精度限定符,還有默認(rèn)精度的概念擎颖,如果沒有設(shè)置榛斯,就設(shè)置默認(rèn)的,默認(rèn)精度限定符使用以下語法在頂點(diǎn)或片段著色器的頂部指定:
precision highp float;
precision mediump int;
為浮點(diǎn)指定的精度將用作基于浮點(diǎn)值的所有變量的默認(rèn)精度搂捧。同樣驮俗,為int指定的精度將用作所有基于整數(shù)的變量的默認(rèn)精度。在頂點(diǎn)著色器中允跑,如果沒有指定默認(rèn)精度王凑,則int和float的默認(rèn)精度都很高搪柑。
精度選擇:
- 對于通常在頂點(diǎn)著色器中執(zhí)行的操作,最可能需要的精度限定符是高精度限定符索烹。
- 用矩陣變換位置工碾,變換法線和紋理坐標(biāo),或者生成紋理坐標(biāo)的操作需要高精度地完成百姓。
- 顏色計(jì)算和光照方程很可能以中等精度完成渊额。
這將取決于正在執(zhí)行的顏色計(jì)算的種類以及正在執(zhí)行的操作所需的范圍和精度。我們相信highp很可能是頂點(diǎn)著色器中大多數(shù)操作使用的默認(rèn)精度垒拢,因此在下面的示例中使用highp作為默認(rèn)精度限定符旬迹。
Open gl es的著色器限制
這些限制應(yīng)該會有所幫助開發(fā)人員編寫了一個(gè)便攜式頂點(diǎn)著色器,可以在大多數(shù)OpenGL ES 2.0實(shí)現(xiàn)上編譯和運(yùn)行求类。
頂點(diǎn)著色器的長度
指令計(jì)數(shù)超過頂點(diǎn) 著色器允許的最大指令奔垦,頂點(diǎn)著色器源將無法編譯。所以出現(xiàn)了一些限制尸疆,來保證可以正常運(yùn)行宴倍。
臨時(shí)變量
臨時(shí)變量是指在函數(shù)內(nèi)部聲明的變量或存儲中間值的變量。
因?yàn)镺penGL ES著色語言是高級語言仓技,所以沒有辦法指定所有OpenGL ES 2.0實(shí)現(xiàn)必須支持的最小臨時(shí)變量數(shù)鸵贬。
因此,頂點(diǎn)著色器可能會遇到這個(gè)問題脖捻,并且不會在所有ES 2.0實(shí)現(xiàn)上編譯阔逼。
流量控制
OpenGL ES 2.0要求實(shí)現(xiàn)支持頂點(diǎn)著色器中的循環(huán),而不要求它們必須展開地沮。例如嗜浮,您可以有一個(gè)For循環(huán),循環(huán)索引從0到1023摩疑。這通常不會被著色器編譯器展開危融,因?yàn)檎归_的著色器的代碼大小對于大多數(shù)ES 2.0實(shí)現(xiàn)來說可能太大。以下限制適用于頂點(diǎn)著色器中使用的循環(huán):
【循環(huán)可以減小程序的大小】
- 在for循環(huán)中只能使用一個(gè)循環(huán)索引雷袋。
- 循環(huán)索引必須初始化為常數(shù)整數(shù)表達(dá)式吉殃。
- for循環(huán)中聲明的條件表達(dá)式必須是下列之一:
loop_indx < constant_expression loop_indx <= constant_expression loop_indx > constant_expression loop_indx >= constant_expression loop_indx != constant_expression loop_indx == constant_expression
- 只能使用以下表達(dá)式之一在for循環(huán)語句中修改循環(huán)索引:
loop_index-- loop_index++ loop_index -= constant_expression loop_index += constant_expression
- 循環(huán)索引可以作為只讀參數(shù)傳遞給for循環(huán)中的函數(shù)(即循環(huán)索引可以與使用in參數(shù)限定符聲明的參數(shù)一起使用)。
Examples of valid for loop constructs are shown here.
const int numLights = 4;
int i, j;
for (i=0; i<numLights; i++)
{
…
}
for (j=4; j>0; j--)
{
…
foo(j); // argument to function foo that takes j
// is declared with the in qualifier.
}
Examples of invalid for loop constructs are shown here.
uniform int numLights;
int i;
for (i=0; i<numLights; i++) // conditional expression is
// not constant
{
…
}
for (i=0; i<8; i++)
{
i = foo(); // return value of foo() cannot be
// assigned to loop index i
}
for (j=4; j>0;)
{
…
j--; // loop index j cannot be modified
// inside for loop
}
雖然OpenGL ES 2.0著色語言規(guī)范指定了while和do-while循環(huán)楷怒,但這并不是必需的蛋勺,因此可能不被所有OpenGL ES 2.0實(shí)現(xiàn)所支持。
條件語句
完全支持以下條件語句鸠删,沒有任何限制抱完。
if(bool_expression)
{
…
}
if(bool_expression)
{
…
}
else
{
…
}
圖形處理器通常并行執(zhí)行具有多個(gè)頂點(diǎn)的頂點(diǎn)著色器或具有多個(gè)片段的片段著色器。
并行執(zhí)行的頂點(diǎn)或片段的數(shù)量將取決于GPU的性能目標(biāo)刃泡。
if和if-else條件語句中的bool_expression對于并行執(zhí)行的頂點(diǎn)或片段可以有不同的值巧娱。
由于GPU并行執(zhí)行的頂點(diǎn)或片段數(shù)量減少碉怔,這可能會影響性能。
我們建議禁添,為了獲得最佳性能眨层,條件語句應(yīng)該與bool_expression值一起使用,這些值對于并行執(zhí)行的頂點(diǎn)或片段是相同的上荡。如果使用統(tǒng)一的表達(dá)式趴樱,就會出現(xiàn)這種情況.
數(shù)組索引
完全支持制服(不包括采樣器)的數(shù)組索引。數(shù)組索引可以是常量酪捡、統(tǒng)一值或計(jì)算值叁征。采樣器只能使用常數(shù)積分表達(dá)式進(jìn)行索引。常數(shù)積分表達(dá)式是文字值(如4)逛薇,常數(shù)整數(shù)變量(如const int sampler _ indx = 3捺疼;),或者常量表達(dá)式(例如3 + sampler_indx)永罚。
屬性矩陣和向量可以使用常數(shù)積分表達(dá)式進(jìn)行索引啤呼。不強(qiáng)制使用非常數(shù)積分表達(dá)式對屬性矩陣和向量進(jìn)行索引。然而呢袱,這是一個(gè)非常有用的特性官扣。下面的代碼顯示了一個(gè)執(zhí)行頂點(diǎn)蒙皮的頂點(diǎn)著色器。a_matrixweights是一個(gè)存儲矩陣權(quán)重的頂點(diǎn)屬性羞福,最多可存儲四個(gè)矩陣惕蹄。
attribute vec4 a_matrixweights; // matrix weights
attribute vec4 a_matrixindices; // matrix palette indices
int i;
for (i=0; i<=3; i++)
{
float m_wt = a_matrixweights[i];
int m_indx = int(a_matrixindices[i]) * 3;
…
}
以粗體突出顯示的代碼a_matrixweights[i]和a_matrixindices[i]不需要支持,因此可能無法編譯治专。
注意:索引常數(shù)矩陣和向量卖陵、變量和變量或變量和變量數(shù)組的規(guī)則與已經(jīng)描述的屬性的規(guī)則相同
計(jì)算頂點(diǎn)著色器中使用的制服數(shù)量
gl _ MaxVertexUniformVectors描述頂點(diǎn)著色器中可以使用的最大制服數(shù)量。任何兼容的OpenGL ES 2.0實(shí)現(xiàn)都必須支持的gl _ MaxVertexUniformVectors的最小值是128個(gè)vec4條目张峰。統(tǒng)一存儲用于存儲以下變量:
- 用統(tǒng)一限定符聲明的變量泪蔫。
- 常量變量。
- ? Literal values.
- 特定于實(shí)現(xiàn)的常數(shù)
頂點(diǎn)著色器中使用的統(tǒng)一變量的數(shù)量以及用常量限定符喘批、文字值和特定于實(shí)現(xiàn)的常量聲明的變量必須符合第5章中描述的打包規(guī)則撩荣。如果這些不適合,那么頂點(diǎn)著色器將無法編譯谤祖。開發(fā)人員可以應(yīng)用打包規(guī)則婿滓,并確定存儲統(tǒng)一變量老速、常量變量和文字值所需的統(tǒng)一存儲量粥喜。無法確定特定于實(shí)現(xiàn)的常量的數(shù)量,因?yàn)樵撝挡粌H會因?qū)崿F(xiàn)而異橘券,還會根據(jù)頂點(diǎn)著色器使用的內(nèi)置著色語言函數(shù)而變化额湘。通常卿吐,當(dāng)使用內(nèi)置超越函數(shù)時(shí),需要特定于實(shí)現(xiàn)的常數(shù)锋华。
就文字值而言嗡官,OpenGL ES 2.0著色語言規(guī)范聲明不假設(shè)常數(shù)傳播。這意味著同一文字值的多個(gè)實(shí)例將被多次計(jì)數(shù)毯焕⊙苄龋可以理解,在頂點(diǎn)著色器中使用文字值(如0.0或1.0)更容易纳猫,但我們建議盡可能避免這種情況婆咸。應(yīng)該聲明適當(dāng)?shù)某A孔兞浚皇鞘褂梦淖种滴咴_@避免了多次使用相同的文字值計(jì)數(shù)尚骄,如果頂點(diǎn)統(tǒng)一存儲要求超過實(shí)現(xiàn)支持的范圍,這可能導(dǎo)致頂點(diǎn)著色器無法編譯侵续。
考慮下面的例子倔丈,它描述了頂點(diǎn)著色器代碼的一個(gè)片段,該代碼為每個(gè)頂點(diǎn)變換兩個(gè)紋理坐標(biāo):
#define NUM_TEXTURES 2
uniform mat4 tex_matrix[NUM_TEXTURES]; // texture matrices
uniform bool enable_tex[NUM_TEXTURES]; // texture enables
uniform bool enable_tex_matrix[NUM_TEXTURES]; // texture matrix
// enables
attribute vec4 a_texcoord0; // available if enable_tex[0] is true
attribute vec4 a_texcoord1; // available if enable_tex[1] is true
varying vec4 v_texcoord[NUM_TEXTURES];
v_texcoord[0] = vec4(0.0, 0.0, 0.0, 1.0);
// is texture 0 enabled
if (enable_tex[0])
{
// is texture matrix 0 enabled
if(enable_tex_matrix[0])
v_texcoord[0] = tex_matrix[0] * a_texcoord0;
else
v_texcoord[0] = a_texcoord0;
}
v_texcoord[1] = vec4(0.0, 0.0, 0.0, 1.0);
// is texture 1 enabled
if (enable_tex[1])
{
// is texture matrix 1 enabled
if(enable_tex_matrix[1])
v_texcoord[1] = tex_matrix[1] * a_texcoord1;
else
v_texcoord[1] = a_texcoord1;
}
剛才描述的代碼可能導(dǎo)致對文字值0状蜗、1需五、0.0、1.0的每個(gè)引用都按照統(tǒng)一存儲進(jìn)行計(jì)數(shù)轧坎。為了保證這些文字值在統(tǒng)一存儲中只計(jì)數(shù)一次警儒,頂點(diǎn)著色器代碼段應(yīng)該編寫如下
#define NUM_TEXTURES 2
const int c_zero = 0;
const int c_one = 1;
uniform mat4 tex_matrix[NUM_TEXTURES]; // texture matrices
uniform bool enable_tex[NUM_TEXTURES]; // texture enables
uniform bool enable_tex_matrix[NUM_TEXTURES]; // texture matrix
// enables
attribute vec4 a_texcoord0; // available if enable_tex[0] is true
attribute vec4 a_texcoord1; // available if enable_tex[1] is true
varying vec4 v_texcoord[NUM_TEXTURES];
v_texcoord[c_zero] = vec4(float(c_zero), float(c_zero),
float(c_zero), float(c_one));
// is texture 0 enabled
if(enable_tex[c_zero])
{
// is texture matrix 0 enabled
if(enable_tex_matrix[c_zero])
v_texcoord[c_zero] = tex_matrix[c_zero] * a_texcoord0;
else
v_texcoord[c_zero] = a_texcoord0;
}
v_texcoord[c_one] = vec4(float(c_zero), float(c_zero),
float(c_zero), float(c_one));
// is texture 1 enabled
if(enable_tex[c_one])
{
// is texture matrix 1 enabled
if(enable_tex_matrix[c_one])
v_texcoord[c_one] = tex_matrix[c_one] * a_texcoord1;
else
v_texcoord[c_one] = a_texcoord1;
}
希望這一節(jié)有助于很好地理解OpenGL ES 2.0著色語言的局限性,以及如何編寫應(yīng)該在大多數(shù)OpenGL ES 2.0實(shí)現(xiàn)上編譯和運(yùn)行的頂點(diǎn)著色器眶根。
一個(gè)簡單的頂點(diǎn)著色器
頂點(diǎn)著色器將位置及其相關(guān)的顏色數(shù)據(jù)作為輸入或?qū)傩允癫ㄟ^4 × 4矩陣轉(zhuǎn)換位置,并輸出轉(zhuǎn)換后的位置和顏色属百。
Example 8-1 A Simple Vertex Shader
// uniforms used by the vertex shader
uniform mat4 u_mvp_matrix; // matrix to convert P from
// model space to clip space.
// attributes input to the vertex shader
attribute vec4 a_position; // input position value
attribute vec4 a_color; // input vertex color
// varying variables – input to the fragment shader
varying vec4 v_color; // output vertex color
void
main()
{
v_color = a_color;
gl_Position = u_mvp_matrix * a_position;
}
然后记劝,設(shè)置和光柵化階段使用變換的頂點(diǎn)位置和圖元類型將圖元光柵化成片段。對于每個(gè)片段族扰,插值的v_color將被計(jì)算并作為輸入傳遞給片段著色器厌丑。