在图形编程中,尤其是在OpenGL等图形API中,顶点属性(Vertex Attributes)是图形管线处理过程中用于描述每个顶点特征的数据。这些数据通过绘制命令从应用程序传递给图形处理器,并与顶点着色器中的命名属性变量绑定。
属性绑定:
BindAttribLocation
函数明确指定绑定关系。数据类型和组件布局:
64位双精度类型:
自动绑定:
BindAttribLocation
、着色器文本内显式设置或SPIR-V二进制代码直接指定绑定,则图形系统(如OpenGL)会自动为这些属性分配通用顶点属性。已分配的绑定可通过GetAttribLocation
函数查询。链接限制:
SPIR-V 着色器和 BindAttribLocation
:
BindAttribLocation
函数对其无效。在SPIR-V着色器中,属性的位置必须按照特定章节的规定明确设置。如果同时在SPIR-V着色器内部和通过BindAttribLocation
设置了不同的绑定,将以SPIR-V着色器内部的设置为准。Data type | component layout qualifier | Components used |
---|---|---|
scalar | 0 or unspecified | x |
scalar | 1 | y |
scalar | 2 | z |
scalar | 3 | w |
two-component vector | 0 or unspecified | (x, y) |
two-component vector | 1 | (y, z) |
two-component vector | 2 | (z, w) |
three-component vector | 0 or unspecified | (x, y, z) |
three-component vector | 1 | (y, z, w) |
four-component vector | 0 or unspecified | (x, y, z, w) |
table 11.1:属性变量访问的通用属性组件
Data type | Column vector type layout qualifier | Generic attributes used |
---|---|---|
mat2, dmat2 | two-component vector | i, i + 1 |
mat2x3, dmat2x3 | three-component vector | i, i + 1 |
mat2x4, dmat2x4 | four-component vector | i, i + 1 |
mat3x2, dmat3x2 | two-component vector | i, i + 1, i + 2 |
mat3, dmat3 | three-component vector | i, i + 1, i + 2 |
mat3x4, dmat3x4 | four-component vector | i, i + 1, i + 2 |
mat4x2, dmat4x2 | two-component vector | i, i + 1, i + 2, i + 3 |
mat4x3, dmat4x3 | three-component vector | i, i + 1, i + 2, i + 3 |
mat4, dmat4 | four-component vector | i, i + 1, i + 2, i + 3 |
table 11.2: 绑定到通用属性索引i的矩阵变量的列向量所使用的通用属性和向量类型
Data type | Command |
---|---|
int | VertexAttribI1i |
ivec2 | VertexAttribI2i |
ivec3 | VertexAttribI3i |
ivec4 | VertexAttribI4i |
uint | VertexAttribI1ui |
uvec2 | VertexAttribI2ui |
uvec3 | VertexAttribI3ui |
uvec4 | VertexAttribI4ui |
float | VertexAttrib1* |
vec2 | VertexAttrib2* |
vec3 | VertexAttrib3* |
vec4 | VertexAttrib4* |
double | VertexAttribL1d |
dvec2 | VertexAttribL2d |
dvec3 | VertexAttribL3d |
dvec4 | VertexAttribL4d |
table 11.3: 标量和矢量顶点属性类型以及用于设置相应泛型属性值的VertexAttrib*命令
void glBindAttribLocation( uint program, uint index, const char *name );
program
: 无符号整数,表示目标着色器程序对象的ID,它是一个已经创建并且已经附加了顶点着色器的 OpenGL 程序对象。index
: 无符号整数,代表要绑定到的通用顶点属性索引位置。name
: 字符串指针,指向着色器源代码中定义的顶点属性变量名。请注意,这个绑定只在后续调用glLinkProgram时生效,并且如果着色器内部已经使用location布局限定符显式指定了位置,则内部布局会优先于glBindAttribLocation设置的值。
void glGetActiveAttrib( uint program, uint index, sizei bufSize, sizei *length, int *size, enum *type, char *name );
// 等价于
const enum props[] = { ARRAY_SIZE, TYPE };
glGetProgramResourceName(program, PROGRAM_INPUT, index, bufSize, length, name); // 获取变量名
glGetProgramResourceiv(program, PROGRAM_INPUT, index, 1, &props[0], 1, NULL, size); // 获取数组大小(元素个数)
glGetProgramResourceiv(program, PROGRAM_INPUT, index, 1, &props[1], 1, NULL, (int *)type); // 获取变量类型
对于 GetActiveAttrib,会枚举所有活动的顶点着色器输入变量,包括特殊的内建输入变量 gl_BaseInstance、gl_BaseVertex、gl_DrawID、gl_InstanceID 和 gl_VertexID。
int glGetAttribLocation( uint program, const char *name );
// 等价于
glGetProgramResourceLocation(program, GL_PROGRAM_INPUT, name);
需要注意的是,glGetAttribLocation 函数的调用是在程序对象已经链接之后进行的。
在OpenGL等图形编程API中,应用程序确实可以将多个顶点属性名(attribute name)绑定到同一个位置索引(location)。这种做法被称为“别名”(aliasing),但并不是所有情况下都支持这样做。
如果不同属性名代表的数据类型和组件数量相同,并且在实际运行时只有一个属性是活跃的,或者没有一个着色器路径同时使用了这些被别名绑定在同一位置的所有属性,则别名绑定通常是可行的。然而,如果两个或更多具有相同位置的顶点属性同时在着色器代码中有用到,那么可能会导致不可预知的结果,甚至链接错误。
在顶点着色器(Vertex Shader)中,可以定义和使用多种类型的变量来处理传入的顶点数据。这些变量主要分为以下几类:
顶点属性(Vertex Attributes):这些是每顶点都会有的输入数据,如位置坐标、纹理坐标、法线向量等。每个顶点属性必须与图形管线中的一个通用顶点属性索引关联,并通过glBindAttribLocation
或在着色器代码中使用layout(location = ...)
显式指定。在顶点着色器内部,可以通过声明相应的输入变量并使用它们进行计算。
Uniforms:全局常量,在整个渲染调用期间对所有顶点保持不变。例如,变换矩阵(模型、视图、投影矩阵)、光照参数等。顶点着色器可以通过uniform变量访问当前程序对象所拥有的 uniforms。
Varyings:在顶点着色器中声明并赋值的变量,其值会在光栅化阶段传递给片段着色器(Fragment Shader)。varying 变量主要用于将顶点级别的信息插值得到像素级别的结果,如颜色、纹理坐标等。
Samplers:用于纹理采样的接口,允许顶点着色器读取纹理贴图数据。尽管顶点着色器中使用纹理的情况较少见,但在某些情况下,如动态生成几何体时,可以从纹理中提取额外的信息。
临时局部变量(Temporary and Local Variables):顶点着色器可以拥有用于临时存储和计算结果的局部变量。
内置变量(Built-in Variables):OpenGL还提供了一系列预定义的内置变量,比如gl_VertexID
、gl_InstanceID
等,用来获取特定的顶点或实例编号信息。
Transform Feedback机制允许将顶点着色器(或其他支持阶段)的输出结果直接写回缓冲区,而不是仅仅为了渲染目的。这意味着可以通过GPU执行并行计算来生成新的顶点数据或者更新现有数据,而无需将其读回到CPU内存。这对于粒子系统、模拟物理效果、几何变形和其他需要在图形管线内部循环处理顶点数据的场景特别有用。
当启用Transform Feedback时,程序员需要通过glTransformFeedbackVaryings函数指定要记录的顶点着色器输出变量列表。这些变量的数据将在渲染过程中被写入绑定到特定反馈目标的缓冲区中。使用布局限定符(如xfb_buffer、xfb_offset、xfb_stride)可以更精细地控制如何存储这些数据。
Transform Feedback捕获的数据可以根据不同的缓冲模式(INTERLEAVED_ATTRIBS 或 SEPARATE_ATTRIBS)进行组织,并且遵循一系列限制,比如最大可捕获组件数量(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 和 MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS),以及对双精度浮点数的特殊处理要求(它们占用更多的存储空间)。通过查询函数glGetTransformFeedbackVarying可以获取变换反馈变量的具体属性,如名称、大小和类型等。
void glTransformFeedbackVaryings( uint program, sizei count, const char * const *varyings, enum bufferMode );
函数用于在编程阶段指定哪些着色器输出变量将在变换反馈(Transform Feedback)模式下被捕获。参数说明如下:
program
: 这是一个GLuint类型的值,代表你想要设置变换反馈变量的程序对象ID。这个程序对象必须已经包含了编译和链接完成的顶点、曲面细分控制、曲面细分评估或几何着色器。
count
: 一个sizei类型的值,表示接下来要指定的输出变量数组varyings
中的元素数量。
varyings
: 一个指向字符串常量指针的指针,它是一个包含输出变量名的数组。每个元素都是一个C风格的字符串,对应着着色器代码中声明并希望被记录到缓冲区的输出变量名。
bufferMode
: 一个枚举类型值,指定了变换反馈数据在缓冲区中的布局方式,它可以是:
GL_SEPARATE_ATTRIBS
:每个输出变量存储在一个独立的缓冲区对象中。GL_INTERLEAVED_ATTRIBS
:所有输出变量按照它们在数组中的顺序连续存储在一个缓冲区对象内。通过调用此函数,可以定义在启用变换反馈时,哪些输出变量将被写入绑定的缓冲区。但是,这些设置并不会立即生效,直到对程序对象执行LinkProgram操作后才真正关联到着色器输出,并且在满足上述提及的各种链接条件的情况下成功链接程序。
void glGetTransformFeedbackVarying( uint program, uint index, sizei bufSize, sizei *length, sizei *size, enum *type, char *name );
// 等价于
const enum props[] = { ARRAY_SIZE, TYPE };
glGetProgramResourceName(program, TRANSFORM_FEEDBACK_VARYING, index, bufSize, length, name);
glGetProgramResourceiv(program, TRANSFORM_FEEDBACK_VARYING, index, 1, &props[0], 1, NULL, size);
glGetProgramResourceiv(program, TRANSFORM_FEEDBACK_VARYING, index, 1, &props[1], 1, NULL, (int *)type);
参数说明:
program
: 一个无符号整数(GLuint),表示已链接的着色器程序对象ID。index
: 变换反馈变量的索引,也是一个无符号整数(GLuint)。从0开始计数,对应于通过TransformFeedbackVaryings
函数指定的输出变量列表中的位置。bufSize
: 一个大小类型(sizei)值,指定了缓冲区name
的大小,以字符为单位。这个大小必须足够大以便容纳要获取的变量名。length
: 指向大小类型(sizei)变量的指针,用于接收实际写入name
缓冲区的字符数量,包括终止空字符。size
: 指向大小类型(sizei)变量的指针,用于接收变换反馈变量的组件数量。type
: 指向枚举类型(GLenum)变量的指针,用于接收变换反馈变量的数据类型。name
: 一个指向字符数组的指针,用于存储变换反馈变量的名称。调用此函数后,它将返回在给定索引处的变换反馈变量的名称、大小和数据类型等信息。
void glValidateProgram( uint program );
调用glValidateProgram
后,OpenGL会检查当前程序对象的状态以及与之相关的上下文状态,例如绑定的着色器、着色器的Uniform变量是否正确设置等等。然后,OpenGL会对程序对象的状态进行验证,并根据验证结果更新程序对象的状态信息。
验证后的结果可以通过查询程序对象的信息日志来获取,通常通过glGetProgramiv
函数查询GL_VALIDATE_STATUS
参数来获取验证的结果。如果验证成功,则GL_VALIDATE_STATUS
的值为GL_TRUE
,否则为GL_FALSE
。
void glValidateProgramPipeline( uint pipeline );
调用glValidateProgramPipeline
后,OpenGL会检查当前程序管线对象的状态以及与之相关的上下文状态,例如绑定的程序对象是否正确设置等等。然后,OpenGL会对程序管线对象的状态进行验证,并根据验证结果更新程序管线对象的状态信息。
验证后的结果可以通过查询程序管线对象的信息日志来获取,通常通过glGetProgramPipelineiv
函数查询GL_VALIDATE_STATUS
参数来获取验证的结果。如果验证成功,则GL_VALIDATE_STATUS
的值为GL_TRUE
,否则为GL_FALSE
。