Description: I am experiencing an issue with OpenGL transform feedback where the correct vertices are captured only during the first pass of the render loop. In subsequent frames, the transform feedback captures a duplicate of one vertex instead of the expected unique vertices for two triangles that form a square.
Vertex Shader:
GLSL
#version 330 core
layout(location = 0) in vec3 position;
out vec3 vertexPosition; // Custom varying for transform feedback
void main() {
vertexPosition = position; // Pass position to custom varying
gl_Position = vec4(position, 1.0);
}
Index Buffer Content (confirmed correct):
GLuint squareindices[] = {
0, 1, 2, // First triangle
2, 3, 0 // Second triangle
};
// Define the vertices present in square...
GLfloat squareVertices[] = {
-0.9f, -0.9f, 0.0f, // Bottom left
0.9f, -0.9f, 0.0f, // Bottom right
0.9f, 0.9f, 0.0f, // Top right
-0.9f, 0.9f, 0.0f // Top left
};
Here’s the pertinent snippet (I hope this is clear enough)
// Compile shaders and create shader program with transform feedback
GLuint shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource);
// Set up VAO, VBO, and EBO
GLuint VAO, VBO, EBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
// Bind VAO
glBindVertexArray(VAO);
// Bind and set VBO
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof (squareVertices), squareVertices, GL_STATIC_DRAW);
// Bind and set EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof (squareindices), squareindices, GL_STATIC_DRAW);
// Set vertex attribute pointers
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof (GLfloat), (void*) 0);
glEnableVertexAttribArray(0);
// Unbind VBO (not EBO, as it's stored in VAO)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// Calculate the number of indices
size_t numIndices = sizeof (squareindices) / sizeof (squareindices[0]);
// Calculate the number of components per vertex (x, y, z)
size_t numComponentsPerVertex = 3;
// Calculate the total size for the buffer
size_t totalSize = numIndices * numComponentsPerVertex * sizeof (GLfloat);
// Create a buffer for transform feedback
GLuint tbo;
glGenBuffers(1, &tbo);
glBindBuffer(GL_ARRAY_BUFFER, tbo);
glBufferData(GL_ARRAY_BUFFER, totalSize, NULL, GL_DYNAMIC_COPY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Create a query object to count the number of primitives
GLuint primitivesQuery;
glGenQueries(1, &primitivesQuery);
// Bind the EBO and read back the indices
GLuint readBackIndices[6]; // Adjust the size based on the number of indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof (readBackIndices), readBackIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // Unbind the EBO
glUseProgram(shaderProgram);
// Print the indices to verify their content
std::cout << "Index Buffer Content:" << std::endl;
for (int i = 0; i < 6; ++i) { // Adjust the loop based on the number of indices
std::cout << "Index " << i << ": " << readBackIndices[i] << std::endl;
}
// Render loop
while (!glfwWindowShouldClose(window)) { //&& !WindowShouldClose()) {
glfwMakeContextCurrent(window);
glClear(GL_COLOR_BUFFER_BIT);
// Set up transform feedback buffer and query object
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, primitivesQuery);
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
// Enable transform feedback
glEnable(GL_RASTERIZER_DISCARD);
glBeginTransformFeedback(GL_TRIANGLES);
// Draw the square using elements
glDrawElements(GL_TRIANGLES, sizeof (squareIndices) / sizeof (GLint), GL_UNSIGNED_INT, 0);
// End transform feedback
glEndTransformFeedback();
// Ensure all transform feedback operations are complete
glFinish(); // or glFinish() for a stronger guarantee
// End the query
glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
// Fetch the number of primitives generated
GLuint primitivesCount;
glGetQueryObjectuiv(primitivesQuery, GL_QUERY_RESULT, &primitivesCount);
// Now map the buffer
glBindBuffer(GL_ARRAY_BUFFER, tbo);
capturedVertices = (GLfloat *) glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
// Check for errors after mapping the buffer
GLenum err = glGetError();
if (err != GL_NO_ERROR) {
std::cerr << "OpenGL Error: " << std::hex << err << std::endl;
}
if (capturedVertices) {
// Process the captured vertices here
for (GLuint i = 0; i < primitivesCount * 3; ++i) {// 3 vertices per primitive (triangle)
std::cout << "Vertex " << i << ": "
<< capturedVertices[i * 3] << ", " // x-coordinate
<< capturedVertices[i * 3 + 1] << ", " // y-coordinate
<< capturedVertices[i * 3 + 2] << std::endl; // z-coordinate
}
// Unmap the buffer after you're done processing
glUnmapBuffer(GL_ARRAY_BUFFER);
} else {
std::cerr << "Error mapping the buffer." << std::endl;
}
glDisable(GL_RASTERIZER_DISCARD);
// Enable the vertex attribute array for position data
glEnableVertexAttribArray(0);
// Specify the format of the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*) 0);
// Set the point size to make it clearly visible
glPointSize(10.0f);
// Draw the points using the captured vertex data
glDrawArrays(GL_POINTS, 0, primitivesCount * 3);
// Unbind the VAO
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
glfwPollEvents();
// while (1 == 1) {
// }
}
Observed Behavior:
- On the first frame, the transform feedback captures the following vertices correctly:
Vertex 0: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: -0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
- From the second frame onwards, the transform feedback captures the following vertices:
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
Vertex 0: -0.9, -0.9, 0
Vertex 1: 0.9, -0.9, 0
Vertex 2: 0.9, 0.9, 0
Vertex 3: 0.9, 0.9, 0
Vertex 4: 0.9, 0.9, 0
Vertex 5: -0.9, -0.9, 0
Note the duplicate capture of the top-right vertex and the missing top-left vertex.
i.e vertex 4 should be: -0.9, 0.9, 0
Questions:
- What could be causing the transform feedback to capture incorrect vertices after the first frame?
- Are there any common pitfalls or state changes that could affect transform feedback behaviour between frames?
- How can I ensure that the transform feedback captures the correct vertices consistently in every frame?
With an ngon. A similar result but this time the corrupted vertices increases every frame. (all I can say is about about 2/3 are corrupted each frame until (as before) the first 4 are the only ones that are correct…