在OpenGL中,着色器对象是用于编写图形渲染流程中的特定阶段代码的对象。创建、编译、附加和使用着色器对象是构建OpenGL图形渲染流程的关键步骤。
创建着色器对象:使用 glCreateShader
函数创建着色器对象。着色器对象可以表示顶点着色器、片段着色器等不同类型的着色器。
加载着色器源码:使用 glShaderSource
函数将着色器源码加载到着色器对象中。源码通常是用OpenGL着色器语言(GLSL)编写的文本字符串。
编译着色器对象:使用 glCompileShader
函数编译着色器对象中的源码。编译后,可以检查编译状态以确定是否成功编译。
创建程序对象:使用 glCreateProgram
函数创建程序对象,程序对象用于管理一组着色器对象。
附加着色器对象:使用 glAttachShader
函数将编译后的着色器对象附加到程序对象上。程序对象可以管理多个着色器对象。
链接程序对象:使用 glLinkProgram
函数将程序对象链接到OpenGL渲染流程中。链接后的程序对象可以在渲染时使用。
使用着色器程序:将程序对象设置为当前的活动着色器程序,然后将图形数据发送到着色器程序进行渲染。
删除着色器对象和程序对象:使用 glDeleteShader
和 glDeleteProgram
函数删除不再需要的着色器对象和程序对象,释放资源。
创建程序对象的命令如下:
GLuint CreateProgram(void);
当一个程序对象被创建时,它是空的。该函数调用成功后会返回一个非零值,该值可以用来引用这个新创建的程序对象。如果在创建过程中发生错误,则返回0。
将着色器对象附加到程序对象上的命令如下:
void glAttachShader(GLuint program, GLuint shader);
这个OpenGL函数允许您在向着色器对象加载源代码之前,或者在着色器对象被编译或特殊化之前,将其附着到一个程序对象上。这意味着您可以先创建和附加着色器,然后再为其填充和编译相应的着色器代码。
要从程序对象中分离一个着色器对象,可以使用以下命令:
void glDetachShader(GLuint program, GLuint shader);
这个函数用于将指定的shader
(着色器)从给定的program
(程序)对象中移除。当某个着色器已被标记为删除,并且不再被任何其他程序对象所附加时,在调用glDetachShader
后,该着色器将会被自动删除。
要使用程序对象中包含的着色器,必须先对程序对象进行链接。执行以下命令来完成链接操作:
void glLinkProgram(GLuint program);
该命令将对名为program
的程序对象进行链接。每个程序对象都有一个布尔状态标志LINK_STATUS
,它会在链接后被修改。通过调用glGetProgramiv
函数可以查询此状态。如果成功生成了一个有效的可执行文件,则该状态设置为TRUE;否则设置为FALSE。
链接可能失败的原因:链接操作可能因以下原因之一失败:
如果一个程序通过LinkProgram
成功链接或通过glProgramBinary
加载(参见第7.5节),则可以使用以下命令将其作为所有着色器阶段当前渲染状态的一部分:
void glUseProgram(GLuint program);
如果program
非零,则此命令会将program
设为当前程序对象,从而安装在上次成功链接时存在的各个着色器阶段中的可执行代码作为当前渲染状态的一部分。如果glUseProgram
被调用时program
设置为零,则不存在当前程序对象。
设置程序对象的参数:
void glProgramParameteri(uint program, enum pname, int value);
pname
是 PROGRAM_SEPARABLE
,则 value
必须是 TRUE
或 FALSE
,指示程序是否可以在下次链接后使用 UseProgramStages
绑定到各个管线阶段。pname
是 PROGRAM_BINARY_RETRIEVABLE_HINT
,则 value
必须是 TRUE
或 FALSE
,指示是否有可能在稍后检索程序二进制,如 ProgramBinary
中描述的那样。LinkProgram
或 ProgramBinary
之后才会生效。程序对象可以通过以下命令删除:
void glDeleteProgram(GLuint program);
如果program
不是任何OpenGL上下文的当前程序,也不是任何程序管道对象的活动程序,并且也不是任何程序管道对象中任何阶段的当前程序,则它会被立即删除。否则,program
将被标记为待删除,并在所有这些条件都满足时(即该程序不再处于使用状态)进行删除。
判断一个名称是否为程序对象的名称:
GLboolean glIsProgram(GLuint program);
glCreateShaderProgramv
用于从一组单个着色器类型的以空字符结尾的源代码字符串数组中创建一个独立程序。
GLuint glCreateShaderProgramv(GLenum type, GLsizei count, const char *const *strings);
参数说明:
GLenum type
: 指定要创建的着色器类型,可以是 GL_VERTEX_SHADER、GL_FRAGMENT_SHADER 或其他支持的类型。GLsizei count
: 表示 strings
数组中字符串的数量。const char *const *strings
: 一个指向字符串数组的指针,其中每个字符串都是一个完整的着色器源代码。如果为顶点着色器和片段着色器,则只需提供相应类型的着色器代码。const uint shader = CreateShader(type);
if (shader) {
ShaderSource(shader, count, strings, NULL);
CompileShader(shader);
const uint program = CreateProgram();
if (program) {
int compiled = FALSE;
GetShaderiv(shader, COMPILE_STATUS, &compiled);
ProgramParameteri(program, PROGRAM_SEPARABLE, TRUE);
if (compiled) {
AttachShader(program, shader);
LinkProgram(program);
DetachShader(program, shader);
}
append-shader-info-log-to-program-info-log
}
DeleteShader(shader);
return program;
} else {
return 0;
}
glGetProgramInterfaceiv
用于 获取着色器程序(program)中指定接口(programInterface)的属性。允许开发者查询关于着色器变量、接口块、子例程等资源的相关信息。
void glGetProgramInterfaceiv(GLuint program, GLenum programInterface, GLenum pname, GLint *params);
参数说明:
GLuint program
: 指定要查询的已链接着色器程序对象。GLenum programInterface
: 指定要查询的接口类型,例如 GL_UNIFORM
, GL_BUFFER_VARIABLE
, GL_PROGRAM_INPUT
, GL_PROGRAM_OUTPUT
, GL_TRANSFORM_FEEDBACK_VARYING
, GL_ATOMIC_COUNTER_BUFFER
, GL_SHADER_STORAGE_BLOCK
, 或者是与子例程相关的接口等。GLenum pname
: 指定要查询的特定属性。根据上述描述,可能的选项包括但不限于:
GL_ACTIVE_RESOURCES
: 查询指定接口下活动资源的数量。GL_MAX_NAME_LENGTH
: 查询指定接口下最长活动资源名称字符串的长度(包括结束符NULL)。GL_MAX_NUM_ACTIVE_VARIABLES
: 对于接口块或原子计数器缓冲区资源,查询其中拥有最多活跃变量的资源所包含的活跃变量数量。GL_MAX_NUM_COMPATIBLE_SUBROUTINES
: 查询对于具有最多兼容子例程的活跃子例程 uniform 的兼容子例程数量。GLint *params
: 输出参数,存储查询结果的指针。需要注意的是,只有在着色器程序成功链接后,才能正确地使用此函数获取有关其接口的信息。如果程序没有成功链接,则某些属性可能无法返回有效值。
glGetProgramResourceIndex
用于 获取着色器程序中指定接口类型(programInterface)下资源(如 uniforms、attributes、subroutines 等)的索引。该函数通过资源名称来查找并返回对应的无符号整数索引。
函数签名如下:
GLuint glGetProgramResourceIndex(GLuint program, GLenum programInterface, const GLchar *name);
参数解释:
GLuint program
: 指定已链接的着色器程序对象的 ID。
GLenum programInterface
: 表示要查询的资源接口类型,例如:
GL_UNIFORM
:uniform 变量GL_UNIFORM_BLOCK
:uniform 块GL_PROGRAM_INPUT
:顶点着色器的输入属性GL_PROGRAM_OUTPUT
:片段着色器的输出变量(或几何着色器、 tessellation 控制/评估着色器的相应输出)GL_TRANSFORM_FEEDBACK_VARYING
:变换反馈变量const GLchar *name
: 要查询的资源名称字符串。
如果找到了与给定名称匹配的资源,则此函数将返回该资源在指定接口内的唯一索引。根据上述描述,对于某些资源类型,特别是数组类型的资源,名字匹配规则有特殊的处理方式。如果无法找到匹配的资源,则会返回 INVALID_INDEX
,通常定义为 GLuint(~0)
。
对于 TRANSFORM_FEEDBACK_VARYING 资源,名称必须与之前调用 glTransformFeedbackVaryings 指定要捕获的变量之一匹配,否则返回 GL_INVALID_INDEX。
glGetProgramResourceName
用于获取已链接着色器程序中指定接口类型(programInterface)下某个资源的名称。该函数允许开发者通过资源索引(index)来检索对应的资源名称,并将其以空终止符结尾的字符串形式存储在指定的缓冲区中。
函数原型:
void glGetProgramResourceName(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name);
参数说明:
GLuint program
: 已经链接的着色器程序对象的 ID。GLenum programInterface
: 资源接口类型,比如 GL_UNIFORM、GL_BUFFER_VARIABLE 等。GLuint index
: 指定要查询资源的索引。GLsizei bufSize
: 提供的缓冲区大小,用以存储返回的资源名称字符串,包括结束符 ‘\0’ 在内。GLsizei *length
: 输出参数,指向一个整数变量,该变量将接收实际写入到 name
缓冲区中的字符数量(不包括结束符)。如果不需要长度信息,可以传入 NULL
。GLchar *name
: 用于接收资源名称字符串的缓冲区指针。当调用此函数时,它会将与给定索引相对应的资源名称复制到 name
所指向的缓冲区中,并在其后添加一个空字符作为终止符。如果提供的缓冲区大小不足以容纳整个资源名称(包括终止符),则只会写入部分名称和一个终止符。如果需要知道资源名称的确切长度,可以通过检查 length
参数来获取。另外,若想预先得知所需的最大缓冲区大小,可以使用 glGetProgramInterfaceiv
函数并设置 pname
为 MAX_NAME_LENGTH
来查询对应接口类型的最长资源名称长度。
glGetProgramResourceiv
用于获取已链接着色器程序中特定接口(programInterface)下索引为index的活动资源的多个属性值。函数原型如下:
void glGetProgramResourceiv(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params);
参数说明:
GLuint program
: 已经链接的着色器程序对象的ID。GLenum programInterface
: 指定要查询的资源接口类型,例如 GL_UNIFORM、GL_PROGRAM_INPUT 等。GLuint index
: 要查询的资源在指定接口下的索引。GLsizei propCount
: 需要查询的属性数量,由 props
数组指定。const GLenum *props
: 一个指向枚举类型的数组指针,包含需要查询的属性列表,如 GL_NAME_LENGTH、GL_TYPE、GL_ARRAY_SIZE 等。GLsizei count
: 提供的输出缓冲区(params)可以接收的最大属性值数量。GLsizei *length
: 输出参数,可选地指向一个整数变量,用于接收实际写入到 params
缓冲区中的属性值数量。GLint *params
: 输出参数,指向一个整型数组缓冲区,用于接收查询结果。当调用此函数时,它会按照 props
数组中的顺序,将指定索引资源的相关属性值连续写入 params
缓冲区中。如果没有发生错误,只会写入最多 count
个整数值;如果有更多的属性值,则不会被写入。如果 length
参数不为 NULL
,则实际写入到 params
缓冲区中的属性值数量会被写入到 length
所指向的变量中。
glGetProgramResourceiv
函数用于获取已链接着色器程序中指定资源的各项属性值。以下是一些该函数能够查询的属性及其含义:
ACTIVE_VARIABLES:返回与原子计数缓冲区、活动统一块、着色器存储块或变换反馈缓冲区关联的活跃变量数组索引。
ARRAY_SIZE:返回一个整数,表示活动变量作为基本类型数组时的元素数量,对于非基本类型数组的变量,则写入1。如果数组大小未在链接程序时声明或确定,则写入0。
ARRAY_STRIDE:返回一个整数,表示活动变量中数组元素之间的步长,对于基本类型数组变量,写入连续数组元素偏移量的差值(以基本机器单位计)。对于非基本类型数组声明的变量,写入0;对于不依赖于缓冲对象的活跃变量,写入-1。
ATOMIC_COUNTER_BUFFER_INDEX:返回一个整数,标识包含活跃变量的活跃原子计数缓冲区的索引。若变量不是原子计数统一变量,则写入-1。
BLOCK_INDEX:返回一个整数,标识包含活跃变量的活跃接口块的索引。对于接口块数组成员,写入数组第一个块的索引。如果不是接口块成员,则写入-1。
BUFFER_BINDING:返回一个整数,标识与活动统一块、原子计数缓冲区、着色器存储块或变换反馈缓冲区关联的缓冲绑定点索引。
BUFFER_DATA_SIZE:返回一个整数,表示实现相关的最小总缓冲对象大小,即活动统一块、着色器存储块或原子计数缓冲区内所有活跃变量所需的、以基本机器单位计的内存大小。
IS_PER_PATCH:返回一个整数,表示输入或输出是否为每补丁属性。如果是每补丁属性(使用patch限定符声明),则写入1;否则,写入0。
IS_ROW_MAJOR:返回一个整数,表示活跃变量是否为行主序矩阵。对于由缓冲对象支持、声明为单个矩阵或矩阵数组且按行主序存储的活跃变量,写入1;其他情况下,写入0。
LOCATION:返回一个整数,表示活动统一变量、输入、输出或子例程统一变量的分配位置。根据布局限定符指定位置,或者在没有布局限定符时由链接程序分配的位置。
LOCATION_COMPONENT:返回一个整数,表示分配给活动输入或输出变量的第一个组件。
LOCATION_INDEX:返回一个整数,表示活动片段着色器输出变量的颜色索引。如果不是片段着色器的输出变量,则写入-1。
MATRIX_STRIDE:返回一个整数,表示列主序矩阵或行主序矩阵中各列或行之间的步长。
NAME_LENGTH:返回一个整数,表示与活动变量、接口块或子例程关联的名字字符串长度,包括终止空字符。
NUM_ACTIVE_VARIABLES:返回一个整数,表示与活动统一块、原子计数缓冲区、着色器存储块或变换反馈缓冲区关联的活跃变量数量。
OFFSET:返回一个整数,表示活跃变量相对于其值所在的缓冲区范围基址的偏移量。
REFERENCED_BY_…_SHADER:一系列属性,分别返回一个整数,表示活跃资源是否被顶点着色器、曲面细分控制/评估着色器、几何着色器、片段着色器或计算着色器引用。
TOP_LEVEL_ARRAY_SIZE 和 TOP_LEVEL_ARRAY_STRIDE:分别返回顶级着色器存储块成员中活跃变量的数组元素数量和数组元素之间的步长。
TRANSFORM_FEEDBACK_BUFFER_INDEX 和 TRANSFORM_FEEDBACK_BUFFER_STRIDE:分别返回与活跃变量关联的变换反馈缓冲区索引以及连续顶点写入变换反馈缓冲区之间的步长。
TYPE:返回一个整数,表示活跃变量的类型。
COMPATIBLE_SUBROUTINES:返回一个整数数组,其中每个整数表示可以分配给所选子例程统一的活跃子例程的索引。写入params中的值数量由NUM_COMPATIBLE_SUBROUTINES属性值决定。
glGetProgramResourceLocation
和 glGetProgramResourceLocationIndex
这两个函数分别用于获取着色器程序中指定接口(programInterface)内名为 name
的变量的绑定位置或片段颜色索引。
int glGetProgramResourceLocation( uint program, enum programInterface, const char *name );
int glGetProgramResourceLocationIndex( uint program, enum programInterface, const char *name );
对于 glGetProgramResourceLocation
函数:
programInterface
参数必须是 UNIFORM、PROGRAM_INPUT、PROGRAM_OUTPUT、VERTEX_SUBROUTINE_UNIFORM、TESS_CONTROL_SUBROUTINE_UNIFORM、TESS_EVALUATION_SUBROUTINE_UNIFORM、GEOMETRY_SUBROUTINE_UNIFORM、FRAGMENT_SUBROUTINE_UNIFORM、COMPUTE_SUBROUTINE_UNIFORM。name
未标识任何活动变量,或者该变量没有被分配有效的位置,将返回 -1。对于 glGetProgramResourceLocationIndex
函数:
programInterface
只能是 PROGRAM_OUTPUT。当提供给这两个函数的字符串作为变量名进行匹配时,满足以下条件之一则认为匹配成功:
除此之外的其他字符串均被认为是未标识任何活动变量。如果提供的字符串表示数组变量的某个元素,这两个函数将返回该元素的绑定位置或片段颜色索引。如果它指向数组的基本名称,则识别的是数组第一个元素关联的资源。