一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

GLSL 在OpenGL中向shader傳遞信息

 勤奮不止 2014-01-26
引言

一個(gè)OpenGL程序可以用多種方式和shader通信。注意這種通信是單向的,因?yàn)閟hader的輸出只能是渲染到某些目標(biāo),比如顏色和深度緩存。

OpenGL的部分狀態(tài)可以被shader訪問(wèn),因此程序改變OpenGL某些狀態(tài)就可以與shader進(jìn)行通信了。例如一個(gè)程序想把光的顏色傳給shader,可以直接調(diào)用OpenGL接口,就像使用固定功能流水線時(shí)做的那樣。

不過(guò),使用OpenGL狀態(tài)并不是設(shè)置shader中使用數(shù)據(jù)的直觀方式。比如一個(gè)shader需要一個(gè)表示時(shí)間變化的變量來(lái)計(jì)算動(dòng)畫,在OpenGL狀態(tài)中就沒有現(xiàn)成的變量可用。當(dāng)然,你可以使用沒有用到的“鏡面光截止角度(cutoffangle)”這樣一個(gè)變量表示時(shí)間,但顯然讓人難以接受。

幸運(yùn)的是,GLSL允許用戶自定義變量,實(shí)現(xiàn)OpenGL應(yīng)用程序與shader通信。有了這個(gè)功能,你就可以命名一個(gè)叫做timeElapsed的變量表示經(jīng)過(guò)的時(shí)間。

上文的討論涉及到了GLSL提供的兩種類型修飾符(更多的類型將在后面提到):

·一致變量(Uniform)

·屬性(Attribute)

在shader中定義的變量如果用這兩種類型修飾符,表示對(duì)shader來(lái)說(shuō),它們是只讀的。下面將詳細(xì)講述怎樣使用這些類型的變量。

還有一種將變量送給shader的方法:使用紋理。一個(gè)紋理不止可以表示一張圖片,它還可以表示一個(gè)數(shù)組。事實(shí)上,你完全可以決定如何在shader中解釋紋理數(shù)據(jù),即使它真是一幅圖片。

 

數(shù)據(jù)類型和變量

下面是GLSL中的基本數(shù)據(jù)類型:

·float

·bool

·int

浮點(diǎn)類型與C中類似,布爾類型可以為true或false。這些基本類型可以組成2、3或4維向量,如下所示:

·vec{2,3,4} a vector of 2,3,or 4 floats

·bvec{2,3,4} bool vector

·ivec{2,3,4} vector of integers

GLSL還包括2×2、3×3或4×4型矩陣,因?yàn)檫@些矩陣類型在圖形處理中很常用:

·mat2

·mat3

·mat4

此外,還有一組用來(lái)實(shí)現(xiàn)紋理訪問(wèn)的特殊類型,它們被稱為采樣器(sampler),在讀取紋理值(也稱為紋素texel)時(shí)用到。下面就是紋理采樣用到的數(shù)據(jù)類型:

·sampler1D – for 1D textures

·sampler2D – for 2D textures

·sampler3D – for 3D textures

·samplerCube – for cube map textures

·sampler1DShadow – for shadow maps

·sampler2DShadow – for shadow maps

在GLSL中,可以像C一樣聲明和訪問(wèn)數(shù)組,但是不能在聲明時(shí)初始化數(shù)組。GLSL還可以定義結(jié)構(gòu)體:

struct dirlight
{
    vec3 direction;
    vec3 color;

};

變量聲明一個(gè)基本類型變量的方法與C類似,你還可以在聲明它的同時(shí)進(jìn)行初始化。

float a,b;       // two vector (yes, the comments are like in C)
int c = 2;       // c is initialized with 2
bool d = true;  // d is true

聲明其它類型變量也是按照這種方法,但是初始化與C語(yǔ)言有區(qū)別。GLSL非常依賴構(gòu)造函數(shù)實(shí)現(xiàn)初始化和類型轉(zhuǎn)換。、

float b = 2;          // incorrect, there is no automatic type casting
float e = (float)2; // incorrect, requires constructors for type casting
int a = 2;
float c = float(a); // correct. c is 2.0
vec3 f;                // declaring f as a vec3
vec3 g = vec3(1.0,2.0,3.0); // declaring and initializing g

在GLSL中使用一些變量初始化其它變量是非常靈活的。你只需要給出需要的數(shù)據(jù)成員即可。請(qǐng)看下面的例子:

vec2 a = vec2(1.0,2.0);
vec2 b = vec2(3.0,4.0);
vec4 c = vec4(a,b)   // c = vec4(1.0,2.0,3.0,4.0);
vec2 g = vec2(1.0,2.0);
float h = 3.0;
vec3 j = vec3(g,h);

矩陣的初始化也是類似方法,矩陣包含很多種構(gòu)造函數(shù),下面的例子給出了一些初始化矩陣的構(gòu)造函數(shù):

mat4 m = mat4(1.0)   // initializing the diagonal of the matrix with 1.0
vec2 a = vec2(1.0,2.0);
vec2 b = vec2(3.0,4.0);
mat2 n = mat2(a,b); // matrices are assigned in column major order
mat2 k = mat2(1.0,0.0,1.0,0.0); // all elements are specified

下面的例子給出了初始化結(jié)構(gòu)體的方法:

struct dirlight     // type definition
{
    vec3 direction;
    vec3 color;
};
dirlight d1;
dirlight d2 = dirlight(vec3(1.0,1.0,0.0),vec3(0.8,0.8,0.4));

在GLSL中還有一些實(shí)用的選擇子(selector),可以簡(jiǎn)化我們的操作并讓代碼更簡(jiǎn)潔。訪問(wèn)一個(gè)向量可以使用如下的方法:

vec4 a = vec4(1.0,2.0,3.0,4.0);
float posX = a.x;
float posY = a[1];
vec2 posXY = a.xy;
float depth = a.w

在上面的代碼片段中,可以使用x、y、z、w來(lái)訪問(wèn)向量成員。如果是顏色的話可以使用r、g、b、a,如果是紋理坐標(biāo)的話可以使用s、t、p、q。注意表示紋理坐標(biāo)通常是使用s、t、r、q,但r已經(jīng)表示顏色中的紅色(red)了,所以紋理坐標(biāo)中需要使用p來(lái)代替。矩陣的選擇子可以使用一個(gè)或兩個(gè)參數(shù),比如m[0]或者m[2][3]。第一種情況選擇了第一列,第二種情況選擇了一個(gè)數(shù)據(jù)成員。

對(duì)于結(jié)構(gòu)體來(lái)說(shuō),可以像在C語(yǔ)言中一樣訪問(wèn)其成員。所以訪問(wèn)前面定義的結(jié)構(gòu)體,可以使用如下的代碼:

d1.direction = vec3(1.0,1.0,1.0);

變量修飾符

修飾符給出了變量的特殊含義,GLSL中有如下修飾符:

·const – 聲明一個(gè)編譯期常量。

·attribute– 隨不同頂點(diǎn)變化的全局變量,由OpenGL應(yīng)用程序傳給頂點(diǎn)shader。這個(gè)修飾符只能用在頂點(diǎn)shader中,在shader中它是一個(gè)只讀變量。

·uniform– 隨不同圖元變化的全局變量(即不能在glBegin/glEnd中設(shè)置),由OpenGL應(yīng)用程序傳給shader。這個(gè)修飾符能用在頂點(diǎn)和片斷shader中,在shader中它是一個(gè)只讀變量。

·varying –用于頂點(diǎn)shader和片斷shader間傳遞的插值數(shù)據(jù),在頂點(diǎn)shader中可寫,在片斷shader中只讀。


一致變量(Uniform Variables)

不同于頂點(diǎn)屬性在每個(gè)頂點(diǎn)有其自己的值,一個(gè)一致變量在一個(gè)圖元的繪制過(guò)程中是不會(huì)改變的,所以其值不能在glBegin/glEnd中設(shè)置。一致變量適合描述在一個(gè)圖元中、一幀中甚至一個(gè)場(chǎng)景中都不變的值。一致變量在頂點(diǎn)shader和片斷shader中都是只讀的。

首先你需要獲得變量在內(nèi)存中的位置,這個(gè)信息只有在連接程序之后才可獲得。注意,對(duì)某些驅(qū)動(dòng)程序,在獲得存儲(chǔ)位置前還必須使用程序(調(diào)用glUseProgram)。

獲取一個(gè)一致變量的存儲(chǔ)位置只需要給出其在shader中定義的變量名即可:

GLint glGetUniformLocation(GLuint program, const char *name);
參數(shù):
·program – the hanuler to the program
·name – the name of the variable

返回值就是變量位置,可以用此信息設(shè)置變量的值。根據(jù)變量的數(shù)據(jù)類型不同,有一系列函數(shù)可以用來(lái)設(shè)置一致變量。用來(lái)設(shè)置浮點(diǎn)值的一組函數(shù)如下:

void glUniform1f(GLint location, GLfloat v0);
void glUniform2f(GLint location, GLfloat v0, GLfloat v1);
void glUniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
void glUniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
或者
GLint glUniform{1,2,3,4}fv(GLint location, GLsizei count, GLfloat *v);
參數(shù):
·location – the previously queried location
·v0,v1,v2,v3 – float values
·count – the number of elements in the array
·v – an array of floats

對(duì)integer類型也有一組類似的函數(shù),不過(guò)要用i替換函數(shù)中的f。對(duì)bool類型沒有專門的函數(shù),但可以使用整數(shù)的0和1來(lái)表示真假。一旦你使用了一致變量數(shù)組,那么就必須使用向量版本的函數(shù)。

對(duì)sampler變量,使用函數(shù)glUniform1i和glUniform1iv。

矩陣也是一種GLSL的數(shù)據(jù)類型,所以也有一組針對(duì)矩陣的函數(shù):

GLint glUniformMatrix{2,3,4}fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v);
參數(shù):
location – the previously queried location.
count – the number of matrices. 1 if a single matrix is being set, or n for an array of n matrices.
transpose – wheter to transpose the matrix values. A value of 1 indicates that the matrix values are specified in row major order, zero is column major order
v – an array of floats.

還有一點(diǎn)要注意的是:使用這些函數(shù)之后,變量的值將保持到程序再次連接之時(shí)。一旦進(jìn)行重新連接,所有變量的值將被重置為0。

最后是一些示例代碼。假設(shè)一個(gè)shader中使用了如下變量:

uniform float specIntensity;
uniform vec4 specColor;
uniform float t[2];
uniform vec4 colors[3];

在OpenGL程序中可以使用下面的代碼設(shè)置這些變量:

GLint loc1,loc2,loc3,loc4;
float specIntensity = 0.98;
float sc[4] = {0.8,0.8,0.8,1.0};
float threshold[2] = {0.5,0.25};
float colors[12] = {0.4,0.4,0.8,1.0,
                0.2,0.2,0.4,1.0,
                0.1,0.1,0.1,1.0};

loc1 = glGetUniformLocation(p,"specIntensity");
glUniform1f(loc1,specIntensity);

loc2 = glGetUniformLocation(p,"specColor");
glUniform4fv(loc2,1,sc);

loc3 = glGetUniformLocation(p,"t");
glUniform1fv(loc3,2,threshold);

loc4 = glGetUniformLocation(p,"colors");
glUniform4fv(loc4,3,colors);

例子代碼的下載地址:

http:///wptest/wp-content/uploads/2011/03/glutglsl2_2.0.zip

注意設(shè)置一個(gè)數(shù)組(例子中的t)與設(shè)置四元向量(例子中的colors和specColor)的區(qū)別。中間的count參數(shù)指在shader中聲明的數(shù)組元素?cái)?shù)量,而不是在OpenGL程序中聲明的。所以雖然specColor包含4個(gè)值,但glUniform4fv函數(shù)中的參數(shù)是1,因?yàn)樗皇且粋€(gè)向量。另一種設(shè)置specColor的方法:

loc2 = glGetUniformLocation(p,"specColor");
glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]);

GLSL中還可以獲取數(shù)組中某個(gè)變量的地址。比如,可以獲得t[1]的地址。下面的代碼片段展示了設(shè)置t數(shù)組元素的另一種方法:

loct0 = glGetUniformLocation(p,"t[0]");
glUniform1f(loct0,threshold[0]);

loct1 = glGetUniformLocation(p,"t[1]");
glUniform1f(loct1,threshold[1]);

注意在glGetUniformLocation中使用方括號(hào)指示的變量。


屬性變量(Attribute Variables)

在前一節(jié)提到,一致變量只能針對(duì)一個(gè)圖元全體,就是說(shuō)不能在glBegin和glEnd之間改變。

如果要針對(duì)每個(gè)頂點(diǎn)設(shè)置變量,那就需要屬性變量了。事實(shí)上屬性變量可以在任何時(shí)刻更新。在頂點(diǎn)shader中屬性變量是只讀的。因?yàn)樗氖琼旤c(diǎn)數(shù)據(jù),所以在片斷shader中不能直接應(yīng)用。

與一致變量相似,首先你需要獲得變量在內(nèi)存中的位置,這個(gè)信息只有在連接程序之后才可獲得。注意,對(duì)某些驅(qū)動(dòng)程序,在獲得存儲(chǔ)位置前還必須使用程序。

GLint glGetAttribLocation(GLuint program,char *name);
參數(shù):
program – the handle to the program.
name – the name of the variable

上述函數(shù)調(diào)用的返回變量在存儲(chǔ)器中的地址。下面就可以為它指定一個(gè)值,類似一致變量,每種數(shù)據(jù)類型都有對(duì)應(yīng)的函數(shù)。

void glVertexAttrib1f(GLint location, GLfloat v0);
void glVertexAttrib2f(GLint location, GLfloat v0, GLfloat v1);
void glVertexAttrib3f(GLint location, GLfloat v0, GLfloat v1,GLfloat v2);
void glVertexAttrib4f(GLint location, GLfloat v0, GLfloat v1,,GLfloat v2, GLfloat v3);
或者
GLint glVertexAttrib{1,2,3,4}fv(GLint location, GLfloat *v);
參數(shù):
location – the previously queried location.
v0,v1,v2,v3 – float values.
v – an array of floats.

對(duì)于integer類型,也有一組類似的函數(shù)。與一致變量不同,這里向量版的函數(shù)并不支持對(duì)向量數(shù)組的賦值,所以函數(shù)參數(shù)用向量或是分別指定的效果沒有太大區(qū)別,就好像OpenGL中g(shù)lColor3f和glColor3fv的關(guān)系。下面是一個(gè)簡(jiǎn)單的例子,假定頂點(diǎn)shader中聲明了一個(gè)名為height的浮點(diǎn)屬性變量,在程序連接之后可以進(jìn)行如下操作:

loc = glGetAttribLocation(p,"height");

在執(zhí)行渲染的代碼中間可以為shader中的變量賦值:

glBegin(GL_TRIANGLE_STRIP);
    glVertexAttrib1f(loc,2.0);
    glVertex2f(-1,1);
    glVertexAttrib1f(loc,2.0);
    glVertex2f(1,1);
    glVertexAttrib1f(loc,-2.0);
    glVertex2f(-1,-1);
    glVertexAttrib1f(loc,-2.0);
    glVertex2f(1,-1);
glEnd();

例子代碼的下載地址:

http:///wptest/wp-content/uploads/2011/03/glutglsl3_2.0.zip、

頂點(diǎn)數(shù)組和屬性變量也可以一起使用。首先需要使能數(shù)組,使用如下函數(shù):

void glEnableVertexAttribArray(GLint loc);
參數(shù):
loc – the location of the variable.

接下來(lái)使用函數(shù)提交包含數(shù)據(jù)的數(shù)組指針:

void glVertexAttribPointer(GLint loc, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer);
參數(shù):
loc – the location of the variable.
size – the number of components per element, for instance: 1 for float; 2 for vec2; 3 for vec3, and so on.
type – The data type associated: GL_FLOAT is an example.
normalized – if set to 1 then the array values will be normalized, converted to a range from -1 to 1 for signed data, or 0 to 1 for unsigned data.
stride – the spacing between elements. Exactly the same as in OpenGL.
pointer – pointer to the array containing the data.

下面是示例代碼,首先執(zhí)行初始化,定義了頂點(diǎn)數(shù)組和屬性數(shù)組。

float vertices[8] = {-1,1, 1,1, -1,-1, 1,-1};
float heights[4] = {2,2,-2,-2};
...
loc = glGetAttribLocation(p,"height");

glEnableClientState(GL_VERTEX_ARRAY);
glEnableVertexAttribArray(loc);
glVertexPointer(2,GL_FLOAT,0,vertices);
glVertexAttribPointer(loc,1,GL_FLOAT,0,0,heights);

接下來(lái)的渲染步驟與OpenGL中的通常做法一致,比如調(diào)用glDrawArrays。示例源代碼下載地址:

http:///wptest/wp-content/uploads/2011/03/glutglsl4_2.0.zip

易變變量(Varying Variables)

前面說(shuō)過(guò),shader包括兩種類型:頂點(diǎn)shader和片斷shader。為了計(jì)算片斷的值,往往需要訪問(wèn)頂點(diǎn)的插值數(shù)據(jù)。例如,當(dāng)使用逐片斷光照時(shí),我們需要知道當(dāng)前片斷的法線,但是在OpenGL中只為每個(gè)頂點(diǎn)指定了法線。頂點(diǎn)shader可以訪問(wèn)這些法線,而片斷shader不能,因?yàn)榉ň€是OpenGL程序作為屬性變量指定的。

頂點(diǎn)變換后的數(shù)據(jù)移動(dòng)到流水線的下一個(gè)階段,在這個(gè)階段通過(guò)使用連接信息,生成了所有圖元并完成片斷化。對(duì)每個(gè)片斷,有一組變量會(huì)被自動(dòng)進(jìn)行插值并提供給片斷shader,這些都是固定功能。片斷的顏色就是這么處理的,到達(dá)片斷shader的顏色就是組成圖元的頂點(diǎn)顏色插值的結(jié)果。

像片斷shader接收到的這種插值產(chǎn)生的變量,就是“易變變量”類型。GLSL包含一些預(yù)先定義的易變變量,例如前面提到的顏色。用戶也可以自己定義易變變量,它們必須同時(shí)在頂點(diǎn)shader和片斷shader中聲明:

varying float intensity;

一個(gè)易變變量必須先在頂點(diǎn)shader中聲明,然后計(jì)算每個(gè)頂點(diǎn)的變量值。在片斷shader中,接收這個(gè)變量通過(guò)插值得到的結(jié)果,注意此時(shí)這個(gè)變量是只讀的。


語(yǔ)句和函數(shù)

控制流語(yǔ)句

與C語(yǔ)言類似,GLSL中有類似if-else的條件語(yǔ)句,for,while,do-while等循環(huán)語(yǔ)句。

if (bool expression)
    ...
else
    ...

for (initialization; bool expression; loop expression)
    ...

while (bool expression)
    ...

do
    ...
while (bool expression)

GLSL也有跳轉(zhuǎn)語(yǔ)句:

·continue – available in loops, causes a jump to thenext iteration of the loop

·break – available in loops, causes an exit of theloop

·discard

最后的discard關(guān)鍵字只能在片斷shader中使用,它將在不寫入幀緩存或者深度緩存的情況下,終止當(dāng)前片斷的shader程序。

 函數(shù)

與C語(yǔ)言類似,shader也是由函數(shù)組成的結(jié)構(gòu)化程序。至少每類shader都必須包含一個(gè)如下方式聲明的主函數(shù):

void main()

此外用戶還可以自定義函數(shù)。這些函數(shù)像C函數(shù)一樣,一般都會(huì)有返回值,返回值的類型沒有限制,但不能是數(shù)組。

函數(shù)參數(shù)可以有如下修飾符:

·in – for input parameters

·out – for outputs of the function. The returnstatement is also an option for sending the result of a function.

·inout – for parameters that are both input andoutput of a function

如果沒有指定修飾符,默認(rèn)情況下為in類型。

最后還有兩點(diǎn)要注意:

·允許函數(shù)重載,只要參數(shù)不同。

·在標(biāo)準(zhǔn)中沒有定義遞歸行為。

結(jié)束本節(jié)之前來(lái)看一個(gè)函數(shù)的例子:

vec4 toonify(in float intensity)
{
    vec4 color;
    if (intensity > 0.98)
       color = vec4(0.8,0.8,0.8,1.0);
    else if (intensity > 0.5)
       color = vec4(0.4,0.4,0.8,1.0);
    else if (intensity > 0.25)
       color = vec4(0.2,0.2,0.4,1.0);
    else
       color = vec4(0.1,0.1,0.1,1.0);

    return(color);
}


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    欧美中文字幕日韩精品| 肥白女人日韩中文视频| 黄色美女日本的美女日人| 在线欧洲免费无线码二区免费| 超薄丝袜足一区二区三区| 日韩人妻一区中文字幕| 午夜福利国产精品不卡| 日系韩系还是欧美久久| 日韩在线视频精品视频| 亚洲丁香婷婷久久一区| 视频一区二区黄色线观看| 国产在线小视频你懂的| 国产精品刮毛视频不卡| 国产欧美一区二区另类精品| 丰满的人妻一区二区三区| 国产高清三级视频在线观看| 日韩视频在线观看成人| 欧美美女视频在线免费看| 亚洲国产天堂av成人在线播放| 午夜精品国产精品久久久| 欧美日韩无卡一区二区| 手机在线观看亚洲中文字幕| 亚洲国产婷婷六月丁香| 伊人色综合久久伊人婷婷| 高清国产日韩欧美熟女| 好骚国产99在线中文| 亚洲中文在线中文字幕91| 亚洲国产精品国自产拍社区| 九九热精彩视频在线播放| 国产精品99一区二区三区| 欧美日韩一级黄片免费观看| 国产午夜精品亚洲精品国产| 91老熟妇嗷嗷叫太91| 91欧美日韩中在线视频| 91亚洲国产成人久久| 国产av一区二区三区久久不卡| 亚洲综合日韩精品欧美综合区| 免费观看一级欧美大片| 日本本亚洲三级在线播放| 久久国产青偷人人妻潘金莲| 亚洲国产日韩欧美三级|