使用TransFrom Feedback捕获图元数据,必须注意的几点:
-
必须在链接着色器之前设置要捕获的输出变量:glTransformFeedbackVaryings
-
顶点着色器、细分着色器、几何着色器的输出变量都可以被捕获,但只有最后一个顶点处理着色器的输出能被捕获。
开始捕获时捕获类型的设置:glBeginTransformFeedback
If a Geometry Shader is active, then it is the primitive type output by the GS.
当有几何着色器时,捕获类型是几何着色器的输出
If a Tessellation Evaluation Shader is active, then it is the primitive type generated by the tessellation process.
当有细分着色器时,捕获类型由细分着色器产生。
If neither of those are available, then it is the mode parameter of the command used to render.
没有几何着色器和细分着色器时,捕获类型就是渲染命令使用的类型。 -
捕获的是图元数据,图元的顶点数据会自动排好序,可以直接用于Feedback rendering
-
GL_TRANSFORM_FEEDBACK_BUFFER 的绑定:
glBindBuffer并不会影响transform feedback的状态,必须要由glBindBufferBase或者glBindBufferRange进行绑定。由于影响的是 transform beedback的状态,所以绑定buffer之前,要先绑定transform feedback object。
The GL_TRANSFORM_FEEDBACK_BUFFER buffer binding point may be passed to glBindBuffer,but will not directly
affect transform feedback state. Instead, the indexed GL_TRANSFORM_FEEDBACK_BUFFER bindings must be used
through a call to glBindBufferBase or glBindBufferRange. This will affect the generic GL_TRANSFORM_FEEDBACK_BUFFER binding.
程序示例:
顶点着色器:
#version 440 core
layout(location = 0) in vec4 VsInPos;
layout(location = 1) in vec4 VsInColor;
out vec4 color;
void main()
{
gl_Position = VsInPos;
color = VsInColor;
}
细分控制着色器:
#version 440 core
layout(vertices = 3) out;
in vec4 color[];
out vec4 TCcolor[];
void main()
{
gl_TessLevelInner[0] = 2.0;
gl_TessLevelOuter[0] = 2.0;
gl_TessLevelOuter[1] = 2.0;
gl_TessLevelOuter[2] = 2.0;
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
TCcolor[gl_InvocationID] = color[gl_InvocationID];
}
细分计算着色器:
#version 440 core
layout(triangles, equal_spacing, cw) in;
layout (binding = 0, offset = 0) uniform atomic_uint TessCoord;
in vec4 TCcolor[];
flat out vec4 color;
void main()
{
atomicCounterIncrement(TessCoord);
float u = gl_TessCoord.x;
float v = gl_TessCoord.y;
float w = gl_TessCoord.z;
gl_Position = u * gl_in[0].gl_Position + v * gl_in[1].gl_Position + w * gl_in[2].gl_Position;
color = TCcolor[0]*u + TCcolor[1]*v + TCcolor[2]*w;
}
片段着色器:
#version 440 core
out vec4 FragColor;
flat in vec4 color;
void main()
{
FragColor = color;
}
void init()
{
ShaderInfo si[] = {
{ GL_VERTEX_SHADER, "tess_tfb.v"},
{GL_TESS_CONTROL_SHADER, "tess_tfb.tesc"},
{GL_TESS_EVALUATION_SHADER, "tess_tfb.tese"},
{ GL_FRAGMENT_SHADER, "tess_tfb.g"},
{GL_NONE, ""}
};
program = LoadShaders(si);
static const char * varyings = "gl_Position";
glTransformFeedbackVaryings(program, 1, &varyings, GL_INTERLEAVED_ATTRIBS);
glLinkProgram(program);
glUseProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(float)*2*4));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
// Create the atomic counter buffer
glGenBuffers(1, &atomic_counter_buffer);
glBindBuffer(GL_ATOMIC_COUNTER_BUFFER, atomic_counter_buffer);
glBufferData(GL_ATOMIC_COUNTER_BUFFER, sizeof(GLuint), NULL, GL_DYNAMIC_COPY);
glGenTransformFeedbacks(1, &tfb);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK,tfb);
glGenBuffers(1, &tfb_buffer);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tfb_buffer);
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER, 1024 * sizeof(float), NULL, GL_DYNAMIC_READ);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfb_buffer);
glGenQueries(1, &tfb_queriy);
glClearColor(0.1, 0.1, 0.1, 1.0);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(program);
glPatchParameteri(GL_PATCH_VERTICES, 3);
// Reset atomic counter
if (output==false)
{
GLuint * data;
glBindBufferBase(GL_ATOMIC_COUNTER_BUFFER, 0, atomic_counter_buffer);
data = (GLuint *)glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_WRITE_ONLY);
data[0] = 0;
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
}
glBindVertexArray(vao);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, tfb_queriy);
glBeginTransformFeedback(GL_TRIANGLES);
glDrawArrays(GL_PATCHES, 0, 6);
glEndTransformFeedback();
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
static bool output = false;
if (output == false)
{
GLuint * data;
data = (GLuint *)glMapBuffer(GL_ATOMIC_COUNTER_BUFFER, GL_READ_ONLY);
cout << "coordCount:" << *data << endl;
glUnmapBuffer(GL_ATOMIC_COUNTER_BUFFER);
GLint triangleCount;
glGetQueryObjectiv(tfb_queriy, GL_QUERY_RESULT, &triangleCount);
cout <<"Triangle: " << triangleCount << endl;
vmath::vec4* tfb_coord = (vmath::vec4*)glMapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, GL_READ_ONLY);
for (int i = 0; i < triangleCount*3; i++)
{
int index = 4 * i;
cout << (*tfb_coord)[index+0] << " " << (*tfb_coord)[index+1] << " " << (*tfb_coord)[index+2] << endl;
}
glUnmapBuffer(GL_TRANSFORM_FEEDBACK_BUFFER);
output = true;
}
glutSwapBuffers();
}
coordCount是14,是由于绘制的是两个面片,共用的边上的顶点计算了两次。