变换反馈 Transform Feedback

在变换反馈模式中,经过变换后的图元顶点属性会在变换反馈阶段被写入一个或多个缓冲对象。这一过程发生在平面着色和平面裁剪之前。转换后的顶点在存储到缓冲对象后,可以选择性地丢弃,或者继续传递至裁剪阶段进行进一步处理。捕获的属性集合在程序链接时确定。

变换反馈捕获的是最后一个顶点处理阶段发出的每个图元的所有顶点信息。如果使用了可分离的程序对象(separable program objects),那么所捕获的属性集将取自于最后的顶点处理阶段激活的程序对象。对于在此之前的任何其他活跃着色器阶段中的程序对象,在变换反馈模式下要捕获的属性集将被忽略。

在图形管线中,变换反馈机制允许开发者捕获和重用顶点着色器输出的结果数据,并且这些数据可以是根据当前激活的顶点处理阶段程序定义的一组特定顶点属性。

变换反馈对象 Transform Feedback Objects

void glCreateTransformFeedbacks( sizei n, uint *ids );void glGenTransformFeedbacks( sizei n, uint *ids );void glBindTransformFeedback( enum target, uint id );void glDeleteTransformFeedbacks( sizei n, const uint *ids );boolean glIsTransformFeedback( uint id );

生成新的变换反馈对象名称

void glGenTransformFeedbacks( sizei n, uint *ids );
  • 这些名称在生成时会被标记为已使用,但在它们通过glBindTransformFeedback()绑定并进行相应配置之前,不会持有任何变换反馈状态。

删除变换反馈对象

void glDeleteTransformFeedbacks( sizei n, const uint *ids );
  • OpenGL中的默认变换反馈对象是不能被删除的(id 为 0)。

查询一个名称标识符是否为有效的变换反馈对象

boolean glIsTransformFeedback( uint id );
  • 如果id是已创建并处于使用状态的变换反馈对象的名称,此函数将返回GL_TRUE
  • 如果id0,或者虽非0但并非任何已创建变换反馈对象的有效名称,则此函数将返回GL_FALSE

将变换反馈对象绑定到 OpenGL 的状态中

void glBindTransformFeedback( enum target, uint id );
  • target: 必须设置为 GL_TRANSFORM_FEEDBACK,表示将要操作的目标是变换反馈。

创建变换反馈对象

void glCreateTransformFeedbacks( sizei n, uint *ids );
  • 创建指定数量(n个)的变换反馈对象,并将它们的标识符存入你提供的 ids 数组中。每个新创建的对象都会初始化到其默认状态。

变换反馈图元捕获 Transform Feedback Primitive Capture

void glBeginTransformFeedback( enum primitiveMode );void glEndTransformFeedback( void );void glPauseTransformFeedback( void );void glResumeTransformFeedback( void );void glTransformFeedbackBufferRange( uint xfb, uint index, uint buffer, intptr offset, sizeiptr size );void glTransformFeedbackBufferBase( uint xfb, uint index, uint buffer );
Transform Feedback primitiveModeAllowed render primitive modes
POINTSPOINTS
LINESLINES, LINE_LOOP, LINE_STRIP
TRIANGLESTRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN

变换反馈操作的详细说明:

  1. 启动与结束变换反馈:

    • void glBeginTransformFeedback(GLenum primitiveMode);
      此函数激活当前绑定的变换反馈对象,并开始捕获指定类型图元的输出。primitiveMode 可以设置为 GL_TRIANGLESGL_LINESGL_POINTS,这决定了在变换反馈期间允许生成并存储的数据所对应的图元类型。

    • void glEndTransformFeedback(void);
      此函数结束当前的变换反馈会话,使其变为非活动状态。如果变换反馈处于暂停状态时调用此函数,它首先会隐式地恢复,然后再结束。变换反馈的开启和关闭必须成对出现,并且初始状态下变换反馈是不活跃的。

  2. 暂停与恢复变换反馈:

    • void glPauseTransformFeedback(void);
      暂停当前正在执行的变换反馈操作,虽然此时变换反馈仍被视为活跃状态,但不会继续写入数据,并且大部分针对该变换反馈对象的状态修改将导致错误。

    • void glResumeTransformFeedback(void);
      在变换反馈被暂停后,可以调用此函数来恢复其捕获数据的过程。

  3. 兼容性要求:
    当变换反馈处于活跃并且未暂停状态时,渲染的所有几何图元必须与之前调用 glBeginTransformFeedback 时传入的 primitiveMode 参数相匹配。

  4. 绑定缓冲区作为目标:

    • 使用 glBindBuffer* 系列函数(如 glBindBufferRangeglBindBufferBase),可以通过将目标设置为 TRANSFORM_FEEDBACK_BUFFER 来将缓冲区对象的部分或整个区域绑定到当前绑定的变换反馈对象上。

    • 特定于变换反馈的命令:

      • void glTransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
        此函数直接将缓冲区对象的一个范围绑定到变换反馈索引 index 上,从给定偏移量 offset 开始,大小为 size
      • void glTransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer);
        此函数将整个缓冲区对象绑定到变换反馈索引 index 上。
    • 在这两个特定的变换反馈绑定函数中,参数 xfb 是要操作的变换反馈对象的名字(默认对象为0),而 buffer 则是要绑定的现有缓冲区对象的名字。这些函数只影响绑定到变换反馈对象本身,而不改变通用 TRANSFORM_FEEDBACK_BUFFER 目标的绑定状态。通过这种方式,应用程序能够控制哪些输出变量的数据被捕获并存储在指定的缓冲区对象中。

当变换反馈处于激活且未暂停状态时,OpenGL 程序中的点、线或三角形图元的顶点输出变量数据会被追加写入到与变换反馈绑定点关联的缓冲对象中。起始偏移量由 BindBufferRange 设置,并根据顶点顺序连续写入数据。对于多顶点流和几何着色器的情况,只有指定流中的顶点输出才会被写入对应的变换反馈缓冲区。

在变换反馈暂停期间不会记录任何数据,恢复后则继续追加记录。对带状或扇形图元的处理是独立记录各个部分,不完整图元将被忽略。

若写入操作会导致超过缓冲区大小限制或者超出预设范围,则当前图元的数据不会被记录,且相关的反馈计数器不增加。此外,如果输出变量写入位置未对齐,其值将会是未定义的。

调用 BeginTransformFeedback 时,所有用于捕获顶点的绑定点都必须有适当的缓冲对象绑定,且对应步长非零的绑定点需要有效关联的输出变量。变换反馈开始时确定的输出变量集在整个反馈过程期间不可更改,且整个过程中需保持相应的程序对象活跃。

同时,GL 不推荐在同一时间将缓冲区既用于变换反馈又用于其他目的,尤其是当缓冲区已绑定到活动且未暂停的变换反馈对象时。在这种情况下,除针对该绑定点的写入外,其他对缓冲区的所有读取或写入操作可能导致未定义的结果。然而,如果顺序地通过变换反馈和其他机制对同一缓冲区进行读写操作,GL 应确保即使在流水线执行的情况下也能实现一致的数据访问。

变换反馈绘制操作 Transform Feedback Draw Operations

void glDrawTransformFeedback( enum mode, uint id );void glDrawTransformFeedbackInstanced( enum mode, uint id, sizei instancecount );void glDrawTransformFeedbackStream( enum mode, uint id, uint stream );void glDrawTransformFeedbackStreamInstanced( enum mode, uint id, uint stream, sizei instancecount );

直接从变换反馈(Transform Feedback)捕获的数据中进行绘制

void glDrawTransformFeedback( enum mode, uint id );
  • mode:这是一个枚举类型参数,定义了要使用的绘图模式,可以是GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP, 或者 GL_TRIANGLE_FAN 等等,取决于你希望如何组装和渲染捕获的顶点数据。
  • id:这是变换反馈对象(Transform Feedback Object)的ID。在先前的变换反馈操作期间,这个对象关联的缓冲区已经存储了由着色器输出的顶点数据。

根据变换反馈(Transform Feedback)捕获的数据执行实例化绘制

void glDrawTransformFeedbackInstanced( enum mode, uint id, sizei instancecount );
  • mode:与glDrawTransformFeedback中的mode参数相同,它是一个枚举类型,指定了绘图模式,如点、线、三角形等。
  • id:这是变换反馈对象的ID,该对象关联的缓冲区中存储了之前通过变换反馈捕获的顶点数据。
  • instancecount:这是一个整数参数,表示要渲染的实例数量。对于每个实例,可以使用不同的实例属性(比如颜色、旋转角度等),这些属性通常存储在单独的实例数组中,并且由着色器访问。

从变换反馈(Transform Feedback)对象的特定输出流中读取数据并进行绘制

void glDrawTransformFeedbackStream( enum mode, uint id, uint stream );
  • stream:一个无符号整数,表示要从中读取数据的输出流索引。在OpenGL 4.x及更高版本中,可以同时从不同输出流捕获顶点属性,每个流可以独立地传输不同的顶点数组数据。

基于变换反馈(Transform Feedback)捕获的数据进行实例化绘制

void glDrawTransformFeedbackStreamInstanced( enum mode, uint id, uint stream, sizei instancecount );