(转)GLSL教程在OpenGL…
Posted 泉_哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(转)GLSL教程在OpenGL…相关的知识,希望对你有一定的参考价值。
引言
一个OpenGL程序可以用多种方式和shader通信。注意这种通信是单向的,因为shader的输出只能是渲染到某些目标,比如颜色和深度缓存。
OpenGL的部分状态可以被shader访问,因此程序改变OpenGL某些状态就可以与shader进行通信了。例如一个程序想把光的颜色传给shader,可以直接调用OpenGL接口,就像使用固定功能流水线时做的那样。
不过,使用OpenGL状态并不是设置shader中使用数据的直观方式。比如一个shader需要一个表示时间变化的变量来计算动画,在OpenGL状态中就没有现成的变量可用。当然,你可以使用没有用到的“镜面光截止角度(cutoffangle)”这样一个变量表示时间,但显然让人难以接受。
幸运的是,GLSL允许用户自定义变量,实现OpenGL应用程序与shader通信。有了这个功能,你就可以命名一个叫做timeElapsed的变量表示经过的时间。
上文的讨论涉及到了GLSL提供的两种类型修饰符(更多的类型将在后面提到):
?一致变量(Uniform)
?属性(Attribute)
在shader中定义的变量如果用这两种类型修饰符,表示对shader来说,它们是只读的。下面将详细讲述怎样使用这些类型的变量。
还有一种将变量送给shader的方法:使用纹理。一个纹理不止可以表示一张图片,它还可以表示一个数组。事实上,你完全可以决定如何在shader中解释纹理数据,即使它真是一幅图片。
数据类型和变量
下面是GLSL中的基本数据类型:
?float
?bool
?int
浮点类型与C中类似,布尔类型可以为true或false。这些基本类型可以组成2、3或4维向量,如下所示:
?vec2,3,4 a vector of 2,3,or 4 floats
?bvec2,3,4 bool vector
?ivec2,3,4 vector of integers
GLSL还包括2×2、3×3或4×4型矩阵,因为这些矩阵类型在图形处理中很常用:
?mat2
?mat3
?mat4
此外,还有一组用来实现纹理访问的特殊类型,它们被称为采样器(sampler),在读取纹理值(也称为纹素texel)时用到。下面就是纹理采样用到的数据类型:
?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一样声明和访问数组,但是不能在声明时初始化数组。GLSL还可以定义结构体:
view plain copy to clipboard print ?- struct
dirlight -
-
vec3 direction; -
vec3 color; - ;
struct dirlight vec3 direction; vec3 color; ;变量
声明一个基本类型变量的方法与C类似,你还可以在声明它的同时进行初始化。
view plain copy to clipboard print ?- 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
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语言有区别。GLSL非常依赖构造函数实现初始化和类型转换。
view plain copy to clipboard print ?- 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
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中使用一些变量初始化其它变量是非常灵活的。你只需要给出需要的数据成员即可。请看下面的例子:
view plain copy to clipboard print ?- 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);
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);矩阵的初始化也是类似方法,矩阵包含很多种构造函数,下面的例子给出了一些初始化矩阵的构造函数:
view plain copy to clipboard print ?- 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
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
下面的例子给出了初始化结构体的方法:
view plain copy to clipboard print ?- 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));
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中还有一些实用的选择子(selector),可以简化我们的操作并让代码更简洁。访问一个向量可以使用如下的方法:
view plain copy to clipboard print ?- 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
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来访问向量成员。如果是颜色的话可以使用r、g、b、a,如果是纹理坐标的话可以使用s、t、p、q。注意表示纹理坐标通常是使用s、t、r、q,但r已经表示颜色中的红色(red)了,所以纹理坐标中需要使用p来代替。
矩阵的选择子可以使用一个或两个参数,比如m[0]或者m[2][3]。第一种情况选择了第一列,第二种情况选择了一个数据成员。
对于结构体来说,可以像在C语言中一样访问其成员。所以访问前面定义的结构体,可以使用如下的代码:
view plain copy to clipboard print ?- d1.direction
= vec3(1.0,1.0,1.0);
d1.direction = vec3(1.0,1.0,1.0);变量修饰符
修饰符给出了变量的特殊含义,GLSL中有如下修饰符:
?const - 声明一个编译期常量。
?attribute- 随不同顶点变化的全局变量,由OpenGL应用程序传给顶点shader。这个修饰符只能用在顶点shader中,在shader中它是一个只读变量。
?uniform- 随不同图元变化的全局变量(即不能在glBegin/glEnd中设置),由OpenGL应用程序传给shader。这个修饰符能用在顶点和片断shader中,在shader中它是一个只读变量。
?varying -用于顶点shader和片断shader间传递的插值数据,在顶点shader中可写,在片断shader中只读。
一致变量(Uniform Variables)
不同于顶点属性在每个顶点有其自己的值,一个一致变量在一个图元的绘制过程中是不会改变的,所以其值不能在glBegin/glEnd中设置。一致变量适合描述在一个图元中、一帧中甚至一个场景中都不变的值。一致变量在顶点shader和片断shader中都是只读的。
首先你需要获得变量在内存中的位置,这个信息只有在连接程序之后才可获得。注意,对某些驱动程序,在获得存储位置前还必须使用程序(调用glUseProgram)。
获取一个一致变量的存储位置只需要给出其在shader中定义的变量名即可:
view plain copy to clipboard print ?- GLint
glGetUniformLocation(GLuint program, const char *name); - 参数:
- ?program
- the hanuler to the program - ?name
- the name of the variable
GLint glGetUniformLocation(GLuint program, const char *name); 参数:?program - the hanuler to the program ?name - the name of the variable返回值就是变量位置,可以用此信息设置变量的值。根据变量的数据类型不同,有一系列函数可以用来设置一致变量。用来设置浮点值的一组函数如下:
view plain copy to clipboard print ?- 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
glUniform1,2,3,4fv(GLint location, GLsizei count, GLfloat *v); - 参数:
- ?location
- the previously queried location - ?v0,v1,v2,v3
- float values - ?count
- the number of elements in the array - ?v
- an array of floats
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 glUniform1,2,3,4fv(GLint location, GLsizei count, GLfloat *v);参数: ?location - the previously queried location?v0,v1,v2,v3 - float values ?count - the number of elements in the array?v - an array of floats
对integer类型也有一组类似的函数,不过要用i替换函数中的f。对bool类型没有专门的函数,但可以使用整数的0和1来表示真假。一旦你使用了一致变量数组,那么就必须使用向量版本的函数。
对sampler变量,使用函数glUniform1i和glUniform1iv。
矩阵也是一种GLSL的数据类型,所以也有一组针对矩阵的函数:
view plain copy to clipboard print ?- GLint
glUniformMatrix2,3,4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v); - 参数:
- 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.
GLint glUniformMatrix2,3,4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *v); 参数: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.
还有一点要注意的是:使用这些函数之后,变量的值将保持到程序再次连接之时。一旦进行重新连接,所有变量的值将被重置为0。
最后是一些示例代码。假设一个shader中使用了如下变量:
view plain copy to clipboard print ?- uniform
float specIntensity; - uniform
vec4 specColor; - uniform
float t[2]; - uniform
vec4 colors[3];
uniform float specIntensity; uniform vec4 specColor;uniform float t[2];uniform vec4 colors[3];
在OpenGL程序中可以使用下面的代码设置这些变量:
view plain copy to clipboard print ?- 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);
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://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl2_2.0.zip
注意设置一个数组(例子中的t)与设置四元向量(例子中的colors和specColor)的区别。中间的count参数指在shader中声明的数组元素数量,而不是在OpenGL程序中声明的。所以虽然specColor包含4个值,但glUniform4fv函数中的参数是1,因为它只是一个向量。另一种设置specColor的方法:
view plain copy to clipboard print ?- loc2
= glGetUniformLocation(p,"specColor"); - glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]);
loc2 = glGetUniformLocation(p,"specColor"); glUniform4f(loc2,sc[0],sc[1],sc[2],sc[3]);GLSL中还可以获取数组中某个变量的地址。比如,可以获得t[1]的地址。下面的代码片段展示了设置t数组元素的另一种方法:
view plain copy to clipboard print ?- loct0
= glGetUniformLocation(p,"t[0]"); - glUniform1f(loct0,threshold[0]);
-
- loct1
= glGetUniformLocation(p,"t[1]"); - glUniform1f(loct1,threshold[1]);
loct0 = glGetUniformLocation(p,"t[0]"); glUniform1f(loct0,threshold[0]);loct1 = glGetUniformLocation(p,"t[1]"); glUniform1f(loct1,threshold[1]);
注意在glGetUniformLocation中使用方括号指示的变量。
转自http://blog.csdn.net/racehorse/article/details/6634830
#Opengl以上是关于(转)GLSL教程在OpenGL…的主要内容,如果未能解决你的问题,请参考以下文章
glLightfv GL_POSITION GL_LINEAR_ATTENUATION glsl OpenGL3 或 OpenGL4(位置光)