transform feedback是OpenGL中比较酷炫的特性之一,他让客户端应用程序可以获取到渲染流水线上的顶点数据。基于这一特性实现了基于z-pass场景决策渲染技术,当然在此并没有去了解何为z-pass场景决策渲染技术,总之是一个可以有效减少渲染数据的输送。这里只是通过一个简单的例子系统,去了解transform feedback对象的使用方法。
正文:
1、transform feedback:
transform feedback是OpenGL渲染管线中,顶点处理阶段结束之后,图元装配和光栅化之前的一个步骤。transform feedback可以重新捕获即将装配为图元(点,线段,三角形)的顶点,然后你将他们的部分或者全部属性传递到缓存对象。每个顶点在传递到图元装配阶段时(之前),将所有需要捕获的属性数据记录到一个或者多个缓存对象当中(至于捕获那些数据,都是在我们控制之下的),程序可以通过缓存回读这些数据,或者将他们用于后续的渲染操作。
tansform feedback所有状态通过一个transform feedback对象管理,这个状态包括所有用于记录顶点数据的缓存对象,用于标识缓存对象的计数器(名称glGen*系列函数返回),以及用于标识transform feedback当前是否启用的状态量。transform对象的创建绑定过程和一般的OpenGL对象相似:
a. void glGenTransformFeedbacks( GLsizei n, GLuint* ids ) 为transform feedback对象生成n个名称,并且将生成的名称记录到数组ids中。0是保留名称,openGL默认tranform feedback,函数将永远不会返回0.
b. void glBindTransformFeedback( GLenum target, GLuint id ) 将一个id(glGen*返回的名称)绑定到指定的target(必须是GL_TRANSFORM_FEEDBACK)所指定的环境中。他做了三个工作:1、如果第一次绑定这个名称,将创建一个tranform feedback对象,使用默认状态值对他进行初始化,并设为当前transform feedback;2、否则单纯的帮该transform feedback激活为当前;3、如果id为0,则相当于重新回到默认的transform feedback对象上(解除所有值钱绑定的transform feedback对象)
c. GLboolean glIsTransformFeedback( GLenum id )判断id是否为一个transform feedback对象。
d.当绑定了一个transform feedback对象之后,所有可能会影响到transform feedback状态的命令都会作用于这个对象。不过并不需要为了使用transform feedback相关功能而去特别定义一个transform feedback对象想,因为系统会内置一个默认的transform feedback对象(名称为id = 0)
e. void glDeleteTransformFeedbacks( GLsizei n, const GLuint* ids )删除n个transform feedback对象。在本次transform feedback结束之后才回去删除
2.transform feedback缓存
transform feedback主要用来管理将顶点捕捉到缓存对象的相关状态。这个状态中包含当前连接到的transform feedback缓存绑定点的缓存对象。可以同时给transform feedback绑定多个缓存,也可以绑定缓存对象的多个子块,甚至可以将同一个缓存对象不用子块绑定到不同的transform feedback缓存绑定点上。
绑定接口: void glBindBufferBase( GLenum target, GLuint index, GLuint buffer ) 其中target自然必须为GL_TRANSFORM_FEEDBACK_BUFFER,而index必须为当前绑定的transform feedback对象的缓存绑定点索引,绑定点最大数与设备实现有关可以通关GL_MAX_TRANSFORM_FEEDBACK_BUFFERS的值来查询。所有的OpenGL设备实现都可以至少支持64个绑定点。也可以将一个缓存对象的一部分绑定到某个transform feedback绑定点:void glBindBufferRange( GLenum GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) offset 和size单位都为字节,定义了buffer缓存的范围。需要特别注意的是亮点:1、保证一个缓存绑定到多个transform feedback绑定点时他们使用的区域不能重叠。2.、glBindBufferBase()和glBindBufferRange()都不会主动去创建缓存对象(这与glBindBuffer不同),而创建缓存对象的工作还是由glBindBuffer()来承担,数据操作还是由glBufferData(),glBufferSubData(),glGetBufferSubData()来完成。
(关于缓存绑定点的解释:在这里可能会问缓存绑定点指的是什么?其实就是一个点,也可以理解为一个名称,他有着最大限制,至少为64,是着色器访问缓存对象的一个桥梁(快速便捷的),略微搜了下,有个一个叫UBO(uniform Block Object)的应用,看了多少会对绑定点有所了解,遗憾的是并没有找到,transform feedback的关于这个桥梁保证准确找到数据的呢?现在也并不能很好的理解之,mark下一个地址:
http://www.zwqxin.com/archives/opengl/talk-about-transform-feedback.html 讲述了transform feedback的高级应用
)
初始化过程示例:
//缓存名称
GLuint buffer;
glGenBuffers( 1, &buffer )
//绑定到TRANSFORM_FEEDBACK创建缓存对象。
glBindBuffer( GL_TRANSFORM_FEEDBACK_BUFFER, buffer )
//glBufferData初始化数据,参数为NULL,申请空间保留使用
glBufferData( GL_TRANFORM_FEEDBACK_BUFFER, 1024*1024, NULL, GL_DYNAMIC_COPY )
//绑定到缓存绑定点,一般用于index = 1,一般用于index = 0
glBindBufferRange( GL_TRANSFORM_FEEDBACK_BUFFER, 0, buffer, 0, 512*1024 )
glBindBufferRange( GL_TRANSFORM_FEEDBACK_BUFFER, 1, buffer, 512*1024, 512*1024 )
3、transform feedback的变量配置
transform feedback所绑定的缓存是一个transform feedback对象关联在一起,顶点(或者几何)着色器的输出要记录在那些缓存当中,这些配置信息是保存在当前程序对象当中。openGL提供了相应的接口让我们配置那些变量应该被记录。
void glTransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar** varyings, GLenum bufferMode )
参数varyings指定了一个变量数组,也就是那些需要被feedback的变量。program是对应的着色器程序,count表示varyings中字符串的数量,bufferMode指定了捕获变量的模式:a、分离模式(GL_SEPARATE_ATTRIBS):每个变量将会被记录到单独的缓存对象中;b、交叉模式(GL_INTERLEAVED_ATTRIBS):
那么所有的变量是一个接着一个记录到绑定到当前transform feedback对象的第一个绑定点的缓存对象里!
openGL还提供了一些内置变量来帮助 我们更灵活的控制捕获的数据在缓存中的对齐方式:gl_SkipComponents1、gl_SkipComponents2、gl_SkipCompone