overview

  1. glCreateShader创建一个shader,可以指定shader的类型等信息。
  2. 通过glShaderSource导入shader的源文件。
  3. 通过glCompileShader编译指定的shader。
  4. 通过glCreateProgram创建一个program。
  5. 通过glAttachShader来将一对shader绑定到一个program中。
  6. 通过glLinkProgram来将这对shader链接到该program中。
  7. 通过glUseProgram来使用该program。
  8. 如果shader使用了默认的uniform块,用glGetUniformLocation来查询uniform变量的地址,并且通过glUniform来设置它们的值。
  9. 如果shader使用了命名的uniform块,用glGetUniformBlockIndexglGetActiveUniformBlockiv来查询该uniform块的信息。查询uniform块中uniform变量的偏移值是通过glGetActiveUniformsiv来得到的。uniform块和绑定一些点(points)的buffer object的关联是通过glUniformBlockBinding来完成的。且,buffer object到这些点的绑定是通过glBindBufferRange来完成的。
  10. 如果vertex shader使用了用户定义的变量,application必须提供之,这是通过opengl api的调用来定位vertex attribute位置的。在一个vertex shader中,在这些属性数据被传给shader之前,泛型顶点属性的索引应该和一个变量相关联,这通常有2种方法。application可以显式创建之,通过在链接(linking)之前调用glBindAttribLocation。或者,如果没有显式的关联被创建,opengl会在linking这步自动关联。一个application可以查询这种关联,通过调用glGetAttribLocation。所以,泛型的顶点属性可以通过glVertexAttrib来传递给vertex shader;或者使用glVertexAttribPointerglEnableVertexArrayPointer结合标准的opengl命令来描画vertex arrays。
  11. 如果fragment shader使用了用户定义的输出(out)变量,application可能要创建用户定义的变量和fragment数据索引之间的关联,这通过在linking前调用glBindFragDataLocation来完成。或者,如果没有显式的关联,opengl会在linking时自动进行关联。一个application可以查询赋值,通过glGetFragDataLocation
  12. 一个application可能选择性地记录vertex shader的输出(out)变量到一个或多个可以tranform feedback的buffer。在vertex shader输出变量被记录前,vertex shader输出变量通过glTransformFeedbackVarying和绑定一些点的feedback buffer相关联;且buffer对象和这些点的绑定是通过glBindBufferRange来完成的。

1. obtaining version information

OpenGL和OpenGL shading language的版本号均可通过glGetString来获得。

void getGlVersion(int *major, int *minor) {const char *verstr = (const char *) glGetString(GL_VERSION);if ((verstr == NULL) || (sscanf(verstr, "%d.%d", major, minor) != 2)){*major = *minor = 0;fprintf(stderr, "Invalid GL_VERSION format!!!\n");}
}void getGlslVersion(int *major, int *minor) {int gl_major, gl_minor;getGlVersion(&gl_major, &gl_minor);*major = *minor = 0;if (gl_major == 1){const char *extstr = (const char *) glGetString(GL_EXTENSIONS);if ((extstr != NULL) &&(strstr(extstr, "GL_ARB_shading_language_100") != NULL)){*major = 1;*minor = 0;}}else if (gl_major >= 2){const char *verstr = (const char *) glGetString(GL_SHADING_LANGUAGE_VERSION);if ((verstr == NULL) ||(sscanf(verstr, "%d.%d", major, minor) != 2)){*major = *minor = 0;fprintf(stderr, "Invalid GL_SHADING_LANGUAGE_VERSION format!!!\n");}}
}

2. creating shader objects

创建shader的函数原型:

GLuint glCreateShader(GLenum shaderType) // GL_VERTEX_SHADER/GL_FRAGMENT_SHADER

然后指定shader的源文件:

void glShaderSource(GLuint shader, GLsizei count, // 源码字符串数组的个数 const GLchar **string, // 源码字符串数组 const GLint *length) // 如果为NULL,源码字符串以null为终止符;否则指定了字符串数组中指定字符串的大小。 

3. compiling shader objects

当源码字符串被导入shader object后,源码必须被编译,且编译结果被shader object保持:

void glCompileShader(GLuint shader)

编译结果为GL_TRUE或者GL_FALSE,它作为一部分来存储在shader object中。该状态可通过以GL_COMPILE_STATUS为参数调用glGetShader来查询。

一个shader的编译可能有词法、语法、语义的错误。无论编译是否正确,编译信息可通过glGetShaderInfoLog来查看,但不可作为编译成功与否的说明。只是保留了编译shader的编译信息而已。

4. linking and using shaders

每个shader object都是被独立编译的。为了创建一个program,application需要制定需要被绑定(attach)进来的shader object的清单。

先创建一个program object:

GLuint glCreateProgram(void)

program object会检查这些shader的完整性等。不再使用的shader object可以从program中解绑定(detach)。

void glAttachShader(GLuint program,GLuint shader)

绑定的shader数目没有天生的限制,绑定可以在shader被导入或者被编译前被绑定。换句话说,该函数只是简单的制定了被链接的shader清单而已,依赖检查等工作由后续函数完成。

为了创建一个有效的program,所有被绑定的shader object必须被编译,且program object自己也必须链接进来。链接操作分配了uniform变量的位置,初始化用户定义的uniform,解决独立编译的shader object间的引用依赖,并且检查确保vertex shader和fragment shader相互兼容。

void glLinkProgram(GLuint program)

同样的,查询该阶段的结果状态可通过glGetProgram来完成,查询参数为GL_LINK_STATUS。成功链入后,所有属于该program object的active的用户定义的uniform变量都被初始化为0。并且所有active的uniform变量都被分配了位置,该位置可通过glGetUniformLocation来查询。

成功链入后,所有属于program的active的用户定义的uniform变量会被初始化为0,且每个program对象的active的uniform变量会被分配一个location,该location可用glGetUniformLocation来查询。并且,任何还没有绑定到一个generic vertex attribute index的active的用户定义的attribute变量会在这时进行绑定。

如果program没有成对包含顶点和片元shader,会链接到隐式的固定管线以凑成一对。

如果链接成功,glLinkProgram还会install产生的可执行程序作为渲染状态的一部分。然后通过glUseProgram来使用该链接后的program。如果当前使用的program对象relink不成功,其链接状态被设置为GL_FALSE,但是之前生成的可执行程序和相关的状态将会保持,直到再次调用glUseProgram才会移除它们。只有成功relink后,可执行程序和相关的状态才会作为当前状态的一部分。

链接program对象失败的几种原因:

  • active attribute变量超出数量
  • active uniform变量超出数量
  • shader缺少main函数
  • fragment shader的in变量类型与对应的vertex shader的out变量类型不匹配
  • 对函数或变量的引用没有解析
  • 共享的全局变量被声明为两种不同的类型或不同的初始化值
  • 一个或多个被attach的shader对象没有被成功编译
  • 绑定一个generic attribute矩阵导致矩阵的一些行超出GL_MAX_VERTEX_ATTRIBS
  • 没有足够的顶点属性槽来绑定属性矩阵

program对象的信息log在link的时候被更新。如果link操作成功,一个program就会被创建。它可能包含一个顶点处理器的可执行程序,一个片元处理器的可执行程序,或者二者全部。无论link操作成功与否,上一次link操作的信息和可执行程序都会丢失。link操作之后,application就可以自由改变绑定的shader对象,编译绑定的shader对象,解绑shader对象,绑定额外的shader对象。这些操作均不会影响信息log或该program直到该program对象的下一次link操作。

关于link操作的信息可以通过以program为参数调用glGetProgramInfoLog来得到。如果该program对象被成功链接,信息log或者是一个空字符串或者link操作的信息。如果program对象没有成功链接,信息log包含发生的任意link错误,还有警告信息和linker提供的信息。

当link操作成功完成,其包含的program会被安装,并作为当前渲染状态的一部分。这是通过如下命令来完成的:

void glUseProgram(GLuint program)

如果program为0,可编程处理器则被禁止,固定管线功能将用于替代顶点和片段处理器。

成功install可编程处理器会导致OpenGL的固定管线功能被禁止。

当一个program正在被使用的时候,application可以自由地修改绑定的shader对象,编译绑定的shader对象,绑定附加的shader对象,解绑shader对象,删除任意绑定的shader对象,或者删除program对象自身。这些操作均不会影响当前状态的执行。然而,relink这个当前正被使用的program对象会install这个program以成为新的当前渲染状态,如果link操作成功的话。当一个program对象正在被使用的时候,控制这些被禁止的固定管线功能的状态也能通过一般的OpenGL调用被更新。

5. cleaning up

当不再被使用的时候,对象需要被删除,这通过一下命令来完成:

void glDeleteShader(GLuint shader)

这个函数将会释放内存并使shader值可再用。它和glCreateShader的效果刚好相反。

如果一个要被删除的shader对象绑定到了一个program对象,该函数将会标记它以将来删除,但是直到它不再被绑定到任何渲染上下文的任何program对象,它才被真正删除(例如,它在被删除前,必须在其被绑定的地方解绑)。

shader值为0的时候,该函数只是简单地忽略它。

为了明确一个shader对象是否被标记为待删除,可以以GL_DELETE_STATUS为参数来调用glGetShader而得到。

void glDeleteProgram(GLuint program)

这个函数将会释放内存并使program值可再用。它和glCreateProgram的效果刚好相反。

如果一个program对象作为当前渲染状态正在被使用,该函数将会标记其为待删除,但是直到它不再作为任意渲染上下文的当前状态时,它才真正被删除。如果一个要删除的program有shader对象绑定到它,这些shader对象会自动解绑但不会被删除,除非它们用glDeleteShader标记为待删除。

为了明确一个program对象是否被标记为待删除,可以以GL_DELETE_STATUS为参数来调用glGetProgram而得到。

当一个shader对象不再需要绑定到一个program对象的时候,它可以用如下命令来解绑:

void glDetachShader(GLuint program, GLuint shader)

该函数效果与glAttachShader正好相反。

如果shader已经用glDeleteShader被标记为待删除,并且没有被绑定到任何其他program对象,它会在解绑后被删除。

一个可能很有用的编程小贴士就是,在shader对象被绑定到一个program对象后尽快删除shader对象。它们不会在此时被删除,但当他们不再被引用的时候,他们被标记为待删除。稍后,为了清除干净,application只需要删除program对象。所有绑定的shader对象会自动解绑,并且,因为他们被标记为待删除,它们此时会自动被删除。

6. query functions

OpenGL shading language API包含几个查询对象状态的函数。为了获得一个shader对象的信息,使用如下命令:

void glGetShaderiv(GLuint shader, GLenum pname, GLint *params)
  • GL_SHADER_TYPE GL_VERTEX_SHADER/GL_FRAGMENT_SHADER
  • GL_DELETE_STATUS GL_TRUE/GL_FALSE
  • GL_COMPILE_STATUS GL_TRUE/GL_FALSE
  • GL_INFO_LOG_LENGTH info log的长度,包含null;可以为0
  • GL_SHADER_SOURCE_LENGTH shader source的长度,包含null;可以为0

同样地,

void glGetProgramiv(GLuint program, GLenum pname, GLint *params)
  • GL_DELETE_STATUS GL_TRUE/GL_FALSE
  • GL_LINK_STATUS GL_TRUE/GL_FALSE
  • GL_VALIDATE_STATUS GL_TRUE/GL_FALSE
  • GL_INFO_LOG_LENGTH info log的长度,包含null;可以为0
  • GL_ATTACHED_SHADERS 绑定的shader数量
  • GL_ACTIVE_ATTRIBUTES active的属性变量数量
  • GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 最大属性名的长度,包含null;可以为0
  • GL_ACTIVE_UNIFORMS active的uniform变量数量
  • GL_ACTIVE_UNIFORM_MAX_LENGTH 最大uniform名的长度,包含null;可以为0

从当前shader对象获取shader字符串的命令是:

void glGetShaderSource(GLuint shader,GLsizei    bufSize, // 最大缓存值GLsizei *length, // 真实的源码长度,不包含null;可以为0GLchar *source)

shader源码字符串是以null结尾的。最大缓存值可以通过以GL_SHADER_SOURCE_LENGTH为参数来调用glGetShader来获得。

获取shader和program的info log的命令分别如下:

void glGetShaderInfoLog(GLuint shader,GLsizei maxLength,GLsizei *length,GLchar *infoLog)void glGetProgramInfoLog(GLuint program,GLsizei maxLength,GLsizei *length,GLchar *infoLog)

一个使用范例:

void printShaderInfoLog(GLuint shader) {int infologLen = 0;int charsWritten = 0;GLchar *infoLog;glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infologLen);printOpenGLError();if (infologLen > 1) {infoLog = (GLchar*) malloc(infologLen);if (infoLog == NULL) {printf("ERROR: Could not allocate InfoLog buffer\n");exit(1);}glGetShaderInfoLog(shader, infologLen, &charsWritten, infoLog);printf("InfoLog:\n%s\n\n", infoLog);free(infoLog);}printOpenGLError();
}

你还可以以GL_CURRENT_PROGRAM来调用glGet函数来获取当前正在使用的program对象。

查询绑定到一个特定的program对象的shader对象清单的函数是:

void glGetAttachedShaders(GLuint program,GLsizei maxCount,GLsizei *count,GLuint *shaders)

可以以GL_ATTACHED_SHADERS为参数来调用glGetProgram从而获取真实的绑定的shader数量。

还有两个判断是否是shader和program对象的函数:

GLboolean glIsShader(GLuint shader)GLboolean glIsProgram(GLuint program)

7. specifying vertex atributes

OpenGL提供了一小组泛型位置,被称为“当前顶点状态”(CURRENT VERTEX STATE),用于传递顶点属性,将v赋值给index指定的每个顶点。

void glVertexAttrib{1|2|3|4}{s|f|d}(GLuint index, TYPE v)
void glVertexAttrib{1|2|3}{s|f|d}v(GLuint index, const TYPE *v)
void glVertexAttrib4{b|s|i|f|d|ub|us|ui}v(GLuint index, const TYPE *v)

还有一组归一化版本的相关函数:

void glVertexAttribNub(GLuint index, TYPE v) void glVertexAttribN{b|s|i|f|d|ub|us|ui}v(GLuint index, const TYPE *v)

对于mat2,mat3,mat4,也可以导入。例如,mat4需要以列为单位导入4次。

顶点数组API允许泛型顶点属性以顶点数组的形式导入:

void glVertexAttribPointer(GLuint index,GLint size, // 1,2,3,4GLenum type,GLboolean normalized,GLsizei stride,const GLvoid *pointer)

type: GL_BYTE,GL_UNSIGNED_BYTE,GL_SHORT,GL_UNSIGNED_SHORT,GL_INT,GL_UNSIGNED_INT,GL_FLOAT,GL_DOUBLE

开启和禁止这些顶点属性需要以下函数:

void glEnableVertexAttribArray(GLuint index)
void glDisableVertexAttribArray(GLuint index)

顶点属性数组主要用于以下函数:

glArrayElement
glDrawArrays
glDrawElements
glDrawRangeElements
glMultiDrawArrays
glMultiDrawElements

那么这些数据如何在shader中使用呢?那就是要将数据绑定到shader中的一个in变量。怎么绑定呢?有两种方式:

  1. linker自动绑定。
  2. 手工绑定。

手工绑定通过以下函数:

void glBindAttribLocation(GLuint program,GLuint index,const GLchar *name)

可以将同一index指定的数据绑定到不同name,但反之不行。如果name是一个矩阵的变量名,则index指定的是数据的第一列,其他数据则会自动绑定到index+i。例如:对于mat2,则为index+1;mat3则为index+1和index+2;mat4则为index+1,index+2和index+3。

glBindAttribLocation可以在顶点shader对象被绑定到特定program对象前调用;还可以绑定永远不会使用的属性变量名到一个顶点shader中。

glBindAttribLocation可以在任意时刻来绑定变量名和数据。属性绑定不会发生作用,直到glLinkProgram被调用,所以任何属性绑定操作需要在glLinkProgram之前进行。当一个program对象被成功链接,属性绑定的index的值保持不变,直到下一次link操作。

GLint glGetAttribLocation(GLuint program,const GLchar *name)

如果name是一个矩阵,则返回的index值引用绑定数据的第一列。如果指定的program对象中,name指定的属性变量不是active的或者name以保留前缀“gl_”开头,-1被返回。

例子:

// 绑定,发生在link时
glBindAttribLocation(myProgram, 1, "Opacity");
// 对相关index赋值
glVertexAttrib1f(1, opacity);
// 或者可以调用glEnableVertexAttribArray来使传递好值的绑定生效
glEnableVertexAttribArray(1)

又例如:

glBindAttribLocation(myProgram, 1, "Opacity");
glBindAttribLocation(myProgram, 2, "Binormal");
glBindAttribLocation(myProgram, 3, "MyData");

当一个顶点shader被执行的时候,可访问到的属性变量被称为“ACTIVE ATTRIBUTES”。可以使用以下命令来获取active attribute的信息:

void glGetActiveAttrib(GLuint program,GLuint index,GLsizei bufSize,GLsizei *length,GLint *size,GLenum *type,GLchar *name)

可以通过参数GL_ACTIVE_ATTRIBUTES调用glGetProgram来获得active的属性数量。index为0会导致该函数返回第一个active的属性信息。index的有效值为[0,N-1]。

program参数要求,需要在之前调用一次glLinkProgram

bufSize可以通过参数GL_ACTIVE_ATTRIBUTE_MAX_LENGTH调用glGetProgram来获取,从而得到属性名字符串的最大长度。属性名字符串以null结尾。

type返回属性变量的数据类型,包括GL_FLOAG,GL_FLOAT_VEC2,GL_FLOAT_VEC3,GL_FLOAT_VEC4,GL_FLOAT_MAT2,GL_FLOAT_MAT3,GL_FLOAT_MAT4

size返回类型为type的数据的单位大小。

active attribute变量清单可能包含内置的属性变量名,例如以gl_开头的,同时也包含用户定义的属性变量名。

如果链接步骤出错,length可能为0;如果有错误发生,返回值length,size,type,name是不会被修改的。

glGetActiveAttrib在shader开发和application开发分开进行的时候是非常有用的。这是因为在shader开发侧和application开发侧的属性变量命名习惯上有一致的地方,application侧可以在运行时通过该函数来查询,从而确定该使用哪个属性变量。

查询特殊的泛型顶点属性的状态,可以通过下面的函数来得到:

void glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params)void glGetVertexAttribiv(GLuint index, GLenum pname, GLint *params)void glGetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params)

下面的panme枚举值,除了GL_CURRENT_VERTEX_ATTRIB,均表示client端的状态。

  • GL_VERTEX_ATTRIB_ARRAY_ENABLED 0代表false;非0代表true;初始值为GL_FALSE
  • GL_VERTEX_ATTRIB_ARRAY_SIZE 1,2,3,4;初始值为4
  • GL_VERTEX_ATTRIB_ARRAY_STRIDE 初始值为0
  • GL_VERTEX_ATTRIB_ARRAY_TYPE 见上;初始值GL_FLOAT
  • GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0代表false;非0代表true;初始值为GL_FALSE
  • GL_CURRENT_VERTEX_ATTRIB 当index为0会发生错误;初始值(0,0,0,1)

另外,

void glGetVertexAttribPointerv(GLuint index,GLenum pname,GLvoid **pointer)

pname的唯一参数为GL_VERTEX_ATTRIB_ARRAY_POINTER

8. specifying uniform variables

对于属性变量,application可以在link发生前指定属性位置;相反地,uniform的位置或偏移值不能被application指定。他们只能由OpenGL在链接时决定,从而application需要在链接发生后再查询uniform的位置或偏移值。

uniform变量被集中到uniform块来管理。有两种uniform块,一种是默认的,一种是命名的。

8.1 default uniform block

默认uniform快包含所有没有包含在命名uniform块的uniform变量。任何sampler类型的uniform必须在默认uniform块中。

默认uniform块的一大优点就是uniform存储与program对象相关,所以默认uniform块对于shader里的独有uniform变量是最佳的。一大缺点就是改变uniform变量的值相对昂贵,所以默认uniform块里的uniform变量最好不经常改变。

为了更新用户定义的uniform变量,application需要得到它的位置,然后才能赋值。uniform变量的位置是在link时确定的,并且不会改变,直到下一次link。

GLint glGetUniformLocation(GLuint program,const GLchar *name)

name以null结尾,并且中间不能有空白字符。name不能是一个结构体,结构体数组,向量的子元素或矩阵的名字。

以下情况,该函数会返回-1:

  • name没有和program的一个active uniform变量对应
  • name与一个命名uniform块关联
  • name以保留前缀“gl_"开头

name中可以使用”[]“和"."以查询数组和结构体。

导入用户定义的uniform值只可能当program对象正在使用时才会发生。所有用户定义的uniform变量都会在program对象被成功链接时初始化,或者是显式给定的默认值或者为0。用户定义的uniform值是当前program对象状态的一部分。他们的值只可能当program对象是当前渲染状态的一部分时才会被修改,但是program会在换入/换出当前渲染状态的时候保留其值。见如下函数:

void glUniform{1|2|3|4}{f|i}(GLint location, TYPE v)

对于bool值,f|i均可;0/0.0为false,其他为true。

void glUniform{1|2|3|4}{f|i}v(GLint location,GLuint count,const TYPE v)void glUniformMatrix{2|3|4}fv(GLint location,GLuint count,GLboolean transpose,const GLfloat *v)

transpose为GL_FALSE,列序;GL_TRUE行序。

glUniform1iglUniform1iv是唯一的两个来导入sampler类型的uniform变量的函数。试图用其他函数来导入会导致一个错误。

如下几点原因会导致glUnifom出错:

  • 没有正在使用的program对象
  • 对于当前program对象,location是不合法的uniform变量位置
  • count超出uniform变量/数组的界限
  • shader中定义的uniform变量的类型和大小与该函数中值的不一致

如下函数可以查询指定位置的uniform变量的当前值:

void glGetUniformfv(GLuint program, GLint location, GLfloat *params)void glGetUniformiv(GLuint program, GLint location, GLint *params)

例如:

uniform struct {struct {float a;float b[10];} c[2];vec2 d;
} e;loc1 = glGetUniformLocation(progObj, "e.d");            // is valid
loc2 = glGetUniformLocation(progObj, "e.c[0]");            // is not valid
loc3 = glGetUniformLocation(progObj, "e.c[0].b");        // is valid
loc4 = glGetUniformLocation(progObj, "e.c[0].b[2]");    // is validglUniform2f(loc1, 1.0f, 2.0f);        // is valid
glUniform2i(loc1, 1, 2);            // is not valid
glUniform1f(loc1, 1.0f);            // is not valid
glUniform1fv(loc3, 10, floatPtr);    // is valid
glUniform1fv(loc4, 10, floatPtr);    // is not valid
glUniform1fv(loc4, 8, floatPtr);    // is valid

当一个shader被执行的时候,可被访问到的uniform变量称为”ACTIVE UNIFORMS“。

如下函数获得一个program对象的active uniform变量的清单:

void glGetActiveUniform(GLuint program,GLuint index,GLsizei bufSize,GLsizei *length,GLint *size,GLenum *type,GLchar *name)

uniform变量名的最大字符串长度可以通过参数GL_ACTIVE_UNIFORM_MAX_LENGTH调用glGetProgram来得到。

type可以为:GL_FLOAT,GL_FLOAT_VEC2,GL_FLOAT_VEC3,GL_FLOAT_VEC4,GL_INT,GL_INT_VEC2,GL_INT_VEC3,GL_INT_VEC4,GL_BOOL,GL_BOOL_VEC2,GL_BOOL_VEC3,GL_BOOL_VEC4,GL_FLOAT_MAT2,GL_FLOAT_MAT3,GL_FLOAT_MAT4,GL_SAMPLER_1D,GL_SAMPLER_2D,GL_SAMPLER_3D,GL_SAMPLER_CUBE,GL_SAMPLER_1D_SHADOW,GL_SAMPLER_2D_SHADOW

使用glGetActiveUniform,application开发者可以编程查询在shader中真实使用的uniform变量,并且自动创建用户接口以使最终用户可以修改这些uniform变量。

8.2 named uniform blocks

OpenGL 3.1加入了命名uniform块和相关的OpenGL shading language API。命名uniform块是以uniform buffer对象为支撑的。这样用buffer数据操作命令或buffer对象映射操作命令,更新uniform就会更高效。一个完整的uniform buffer对象可以快速被改变,这是通过改变与其绑定的buffer对象来达到的。

uniform变量集合(除了sampler类型的uniform)可以被聚集到一个命名的uniform块中。例如:

uniform MatrixBlock {uniform mat4 MVmatrix;uniform mat4 MVPmatrix;uniform mat3 NormalMatrix;
};

命名uniform块的名字是MatrixBlock,它包含了3个uniform变量。

要想更新命名uniform块中的uniform变量,需要知道它们的偏移值,然后才能赋值。偏移值是在link时赋值的,且不会改变,直到下一次link。

GLuint glGetUniformBlockIndex(GLuint program,const GLchar* name)

如果name没有成功指定一个active的uniform块,GL_INVALID_INDEX将会返回。

uniform块的信息也可被查询:

GLuint glGetUniformBlockiv(GLuint program,GLuint index,GLenum pname,GLint *params)

pname参数为:

  • GL_UNIFORM_BLOCK_BINDING
  • GL_UNIFORM_BLOCK_DATA_SIZE
  • GL_UNIFORM_BLOCK_NAME_LENGTH
  • GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
  • GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
  • GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
  • GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER

然后,在命名uniform块中每个uniform变量的信息就可以查询了。

GLuint glGetActiveUniformsiv(GLuint program,GLsizei count,const GLuint *indices,GLenum pname,GLint *params)

pname参数如下:

  • GL_UNIFORM_TYPE
  • GL_UNIFORM_SIZE
  • GL_UNIFORM_NAME_LENGTH
  • GL_UNIFORM_BLOCK_INDEX
  • GL_UNIFORM_OFFSET
  • GL_UNIFORM_ARRAY_STRIDE
  • GL_UNIFORM_MATRIX_STRIDE
  • GL_UNIFORM_MATRIX_IS_ROW_MAJOR

link一个shader后,每个命名uniform块可能被绑定到一个uniform buffer绑定点:

void glUniformBlockBinding(GLuint program,GLuint index,GLuint index,GLuint binding)

index必须是一个active的命名uniform块,否则INVALID_VALUE就会产生。

9. samplers

glUniform1iglUniform1iv导入定义为sampler类型的uniform变量(例如,sampler1D/sampler2D/sampler3D/samplerCube/sampler1DShadow/sampler2DShadow)。它们可以定义在顶点或片段shader中。

sampler的值用于访问特定的纹理map,其值应小于通过参数GL_MAX_VERTEX_TEXTURE_IMAGE_UNITSGL_MAX_TEXTURE_IMAGE_UNITS调用glGet查询到的数值。如果超出了上限,link的时候会失败。对于顶点和片段shder二者的数值上限可以通过GL_COMBINED_TEXTURE_IMAGE_UNITS来查询到。

当一个program正在执行的时候,可被访问到的sampler被称为“ACTIVE SAMPLERS”。

10. multiple render targets

OpenGL 2.0添加的一个特性就是可以同时渲染多个buffer。OpenGL shading language以用户定义的片段shader的out变量来支持这个功能。一个片段shader的数据buffer的数量是与实现相关的,但是不能少于4个。

应用此功能,application可以开发片段shader以使得每个片段shader可以计算多个值并且将它们存储到离屏的内存中。这些值可以在将来的渲染中被访问到。这可以被充分利用从而使得applicaiton实现复杂的多值传递算法并且使用图形硬件用于一般目的的计算。

void glDrawBuffers(GLsizei n, const GLenum *bufs)

该函数定义了片段shader的数据写入的buffer数组。

bufs的数值为:

  • GL_NONE
  • GL_COLOR_ATTACHMENTi

用参数GL_MAX_DRAW_BUFFERS调用glGet以获取最大的draw buffer数量。

用户定义的片段shader的out变量可能与数据buffer绑定,这通过如下命令实现:

void glBindFragDataLocation(GLuint program,GLuint index,const GLchar *name)

index必须是active的用户定义的out变量,否则INVALID_VALUE会产生。

11. development aids

void glValidateProgram(GLuint program)

该函数产生的信息存储在program的信息log中。用参数GL_VALIDATE_STATUS来调用glGetProgram可以查看该函数的运行结果,GL_TRUE/GL_FALSE。典型地,该函数在开发的时候非常有用。

12. implementation-dependent API values

以下是一些实现中的限制,均可用glGet查询,有些是在OpenGL 3.0加入的。

GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: 顶点处理器和片段处理器绑定的用于访问纹理map的数量,最小值32。

GL_MAX_DRAW_BUFFERS: 片段处理器的out变量所写入的最大数量的buffer,最小值为8,OpenGL 3.0更倾向于是1。

GL_MAX_FRAGMENT_UNIFORM_COMPONENTS: 片段shader中uniform变量可访问到的最大的component。最小值1024,过去是64。

GL_MAX_TEXTURE_IMAGE_UNITS: 片段shader中能访问到的最大的纹理map硬件单元。最小值是16,过去是2。

GL_MAX_VARYING_COMPONENTS: 最小值64,过去是32位浮点值。

GL_MAX_VERTEX_ATTRIBS: 最大active的顶点属性。最小值16。

GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: 最小值16,过去是0。

GL_MAX_VERTEX_UNIFORM_COMPONENTS: 顶点shader默认uniform块可访问到的最大的component的数量。最小值1024,过去为512。

GL_MAX_CLIP_DISTANCES: 每个program可使用的clip distance的数量。最小值8。

GL_MAX_COMBINED_UNIFORM_BLOCKS: 每个program可使用的uniform块的数量。最小值24。

GL_MAX_FRAGMENT_UNIFORM_BLOCKS: 针对fragment,其他同上。

GL_MAX_VERTEX_UNIFORM_BLOCKS: 针对vertex,其他同上。

GL_MAX_UNIFORM_BLOCK_SIZE: 每个uniform块的大小(byte),最小值16384。

13. application code for brick shaders

一个demo程序ogl2brick。第6章已经见过“install”shader的代码,在讨论install代码之前,先看如何设置uniform变量。

GLint getUniLoc(GLuint program, const GLchar *name) {GLint loc;loc = glGetUniformLocation(program, name);if (loc == -1) {printf("No such uniform named \"%s\"\n", name);}printOpenGLError();return loc;
}

传递给OpenGL的shader是字符串。下面的函数,我们假设每个shader都是字符串。这个函数的工作有,load,compile,link,install我们的brick shader。

int installBrickShaders(const GLchar *brickVertex,const GLchar *brickFragment)
{GLuint brickVS, brickFS, brickProg;GLint vertCompiled, fragCompiled;GLint linked;brickVS = glCreateShader(GL_VERTEX_SHADER);brickFS = glCreateShader(GL_FRAGMENT_SHADER);glShaderSource(brickVS, 1, &brickVertex, NULL);glShaderSource(brickFS, 1, &brickFragment, NULL);glCompileShader(brickVS);printOpenGLError();glGetShaderiv(brickVS, GL_COMPILE_STATUS, &vertCompiled);printShaderInfoLog(brickVS);glCompileShader(brickFS);printOpenGLError();glGetShaderiv(brickFS, GL_COMPILE_STATUS, &fragCompiled);printShaderInfoLog(brickFS);if (!vertCompiled || !fragCompiled) {return 0;}brickProg = glCreateProgram();glAttachShader(brickProg, brickVS);glAttachShader(brickProg, brickFS);glLinkProgram(brickProg);printOpenGLError();glGetProgramiv(brickProg, GL_LINK_STATUS, &linked);printProgramInfoLog(brickProg);if (!linked) {return 0;}glUseProgram(brickProg);glUniform3f(getUniLoc(brickProg, "BrickColor"), 1.0, 0.3, 0.2);glUniform3f(getUniLoc(brickProg, "MortarColor"), 0.85, 0.86 , 0.0.84);glUniform3f(getUniLoc(brickProg, "BrickSize"), 0.30 , 0.15);glUniform3f(getUniLoc(brickProg, "BrickPct"), 0.90 , 0.85);glUniform3f(getUniLoc(brickProg, "LightPosition"), 0.0, 0.0, 4.0);return 1;
}

14. summary

人丑就要多读书!狗菜就要多编码!

OpenGL Shading Language 汇总相关推荐

  1. The OpenGL® Shading Language, Version 4.60.7 翻译第一章

    The OpenGL® Shading Language, Version 4.60.7 翻译第一章 Chapter 1. Introduction This document specifies o ...

  2. OpenGL 4.0 Shading Language Cookbook-中文版问世了

    OpenGL 4.0 Shading Language Cookbook-中文版问世了, http://item.taobao.com/item.htm?spm=a230r.1.14.13.K3kTO ...

  3. 纯Shading Language绘制飞机火焰效果

    为什么80%的码农都做不了架构师?>>>    上篇<纯Shading Language绘制HTML5时钟>体现了GLSL可编程性特点,但没有体现GLSL可编程出各种酷炫 ...

  4. css画钟表_纯Shading Language绘制HTML5时钟

    今天是2014年的最后一天,这个时刻总会让人想起时钟,再过几个小时地球人都要再老了一岁,于是搞个HTML5版的时钟就是我们今天要完成的任务,实现HTML5的时钟绘制一般会采用三种方式,第一种采用CSS ...

  5. OpenGL API - 笔记汇总

    这里只会记录一些使用到的API汇总. OpenGL 红宝书第9版的我也买了一本,但觉得这书买得不值. 主要我们要查找API什么的,没有电子版直接输入API名称定为的快. 如果你用书去翻的话,只能慢慢的 ...

  6. Metal之Shading Language Specification(着色语言规范)

    Metal简述 Metal着色器语言是用来编写 3D图形渲染逻辑.并行Metal计算核心逻辑 的一门编程语言,当你使用Metal框架来完成APP的实现时则需要使用Metal编程语言. Metal语言使 ...

  7. OpenGL绘图函数汇总

    留个档 FGAPI void FGAPIENTRY glutWireCube( double size ); //空心立方体 FGAPI void FGAPIENTRY glutSolidCube( ...

  8. 【Modern OpenGL】第一个三角形

    >说明:跟着learnopengl的内容学习,不是纯翻译,只是自己整理记录.>强烈推荐原文,无论是内容还是排版. [原文链接](http://learnopengl.com/#!Getti ...

  9. 【我的OpenGL学习进阶之旅】【持续更新】关于学习OpenGL的一些资料

    目录 一.相关书籍 OpenGL 方面 C方面 NDK 线性代数 二.相关博客 2.0 一些比较官方的链接 2.1 OpenGL着色器语言相关 2.2 [[yfan]](https://segment ...

最新文章

  1. keras优化算法_自然场景文本识别(OCR),keras-yolo3-densenet-ocr
  2. java流式传输对象_使用Java 8在地图上流式传输
  3. JAVA 面向对象程序设计的继承举例
  4. 华为留了一手!将继续发布P50、Mate50:搭载麒麟9000...
  5. linux 8002端口,linux – 如何限制反向SSH调整端口?
  6. Java基础教程之Java的变量
  7. 基于C++的顺序表的实现
  8. 在你公司Code Review是一种形式,还是一种开发文化?
  9. k8s集群部署二(自签TLS证书)
  10. 电大c 语言程序设计选择题,2020年国家开放大学电大C语言程序设计题库
  11. 物流学哪方面计算机知识,物流说丨物流专业的毕业生应该具备的6大技能
  12. 互联网巨头“赢家通吃”,会产生哪些严重后果?
  13. Linux 服务具体解释
  14. 小技巧---笔记本外接显示器设置全屏壁纸
  15. nodejs中使用jwt
  16. matlab 高斯随机场,条件随机场(Conditional random fields)
  17. 解决使用element-ui级联选择框内容空白且下拉框过高
  18. Vue百度地图标注点定位显示
  19. docker部署nginx+tomcat架构
  20. 2022-3-28 Leetcode 1003.检查替换后的词是否有效

热门文章

  1. CISSP考试各考场可预约时间(11.04日更新)
  2. C语言,自己当年编写的苹果(黑白)棋源程序代码
  3. Speedup Your Analytics: Automatic Parameter Tuning for Databases and Big Data Systems
  4. Fusion++: Volumetric Object-Level SLAM
  5. “AI助力计划”上线,3D点云等标注工具1折起
  6. avue中crue表单的属性
  7. [work] 如何理解泛函以及变分
  8. u盘安装linux系统 input/output error,U盘安装UBUNTU出现Input/Output error分析解决
  9. 【报告分享】2021-2022内容营销平台价值洞察白皮书-凯度知乎(附下载)
  10. python的头文件和源文件_为什么C/C++要分为头文件和源文件?