There are two debug printf segments. The first one prints out right data but the second does not. Where did I do wrong? Oh, I'm using the same vertex and fragment shader for both getting the vertices data and drawing them again process.
#include "Dependencies\glew\glew.h"
#include "Dependencies\freeglut\freeglut.h"
#include <cstdio>
GLuint program;
GLuint VAOs[2];
GLuint VBOs[2];
GLuint TFBs[1];
char *vertSrc =
"#version 450 core\n"
"in vec4 vPosition;"
"in vec4 vColor;"
"out vec4 fColor;"
"uniform mat4 vMatrix;"
"void main(void)"
"{"
"gl_Position = vMatrix * vPosition;"
"fColor = vColor;"
"}";
char *fragSrc =
"#version 450 core\n"
"in vec4 fColor;"
"out vec4 color;"
"void main(void)"
"{"
"color = vec4(1.0, 0, 0, 1.0);"
"}";
GLfloat vPosition[6][4] = {
{ 0.25, -0.25, -0.7, 1.0 },
{ -0.25, -0.25, -0.7, 1.0 },
{ 0.25, 0.25, -0.7, 1.0 },
{ 0.1, -0.1, -0.8, 1.0 },
{ -0.1, -0.1, -0.8, 1.0 },
{ 0.1, 0.1, -0.8, 1.0 }
};
GLfloat vColor[6][4] = {
{ 1.0, 0, 0, 1.0 },
{ 0, 1.0, 0, 1.0 },
{ 0, 0, 1.0, 1.0 },
{ 1.0, 1.0, 0, 1.0 },
{ 0, 1.0, 1.0, 1.0 },
{ 1.0, 0, 1.0, 1.0 }
};
GLfloat vMatrix[16] = {
1.0, 0, 0, 0,
0, 1.0, 0, 0,
0, 0, 1.0, 0,
0, 0, 0, 1.0
};
void renderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float q[48];
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vPosition) + sizeof(vColor), q);
for (int i = 0; i < 48; i++)
{
printf("%f\n", q[i]);
}
printf("\n");
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(VAOs[0]);
glBindVertexBuffer(0, VBOs[0], 0, 4 * sizeof(GL_FLOAT));
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFBs[0]);
glBeginTransformFeedback(GL_TRIANGLES);
glDrawArrays(GL_TRIANGLES, 3, 3);
glDrawArrays(GL_TRIANGLES, 0, 3);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindVertexArray(0);
float p[48];
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
glGetBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vPosition) + sizeof(vColor), p);
for (int i = 0; i < 48; i++)
{
printf("%f\n", p[i]);
}
glDisable(GL_RASTERIZER_DISCARD);
glBindVertexArray(VAOs[1]);
glBindVertexBuffer(0, VBOs[1], 0, 8 * sizeof(GL_FLOAT));
//glDrawArrays(GL_TRIANGLES, 3, 3);
//glDrawArrays(GL_TRIANGLES, 0, 3);
glDrawTransformFeedback(GL_TRIANGLES, TFBs[0]);
glBindVertexArray(0);
glutSwapBuffers();
//glutPostRedisplay();
}
void Init()
{
glEnable(GL_DEPTH_TEST);
GLuint vert = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vert, 1, &vertSrc, 0);
glCompileShader(vert);
GLuint frag = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(frag, 1, &fragSrc, 0);
glCompileShader(frag);
GLuint program = glCreateProgram();
glAttachShader(program, vert);
glAttachShader(program, frag);
glLinkProgram(program);
glUseProgram(program);
GLint matrix = glGetUniformLocation(program, "vMatrix");
glUniformMatrix4fv(matrix, 1, GL_TRUE, vMatrix);//second parameter indicates the number of matrices
GLint position = glGetAttribLocation(program, "vPosition");
GLint color = glGetAttribLocation(program, "vColor");
glGenVertexArrays(2, VAOs);
glBindVertexArray(VAOs[0]);
glVertexAttribFormat(position, 4, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(position, 0);
glVertexAttribFormat(color, 4, GL_FLOAT, GL_FALSE, sizeof(vPosition));
glVertexAttribBinding(color, 0);
glEnableVertexAttribArray(position);
glEnableVertexAttribArray(color);
glBindVertexArray(0);
glBindVertexArray(VAOs[1]);
glVertexAttribFormat(position, 4, GL_FLOAT, GL_FALSE, 0);
glVertexAttribBinding(position, 0);
glVertexAttribFormat(color, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GL_FLOAT));
glVertexAttribBinding(color, 0);
glEnableVertexAttribArray(position);
glEnableVertexAttribArray(color);
glBindVertexArray(0);
glGenBuffers(2, VBOs);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
//glBufferStorage(GL_ARRAY_BUFFER, sizeof(vPosition) + sizeof(vColor), 0, 0);
glBufferData(GL_ARRAY_BUFFER, sizeof(vPosition) + sizeof(vColor), 0, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vPosition), vPosition);
glBufferSubData(GL_ARRAY_BUFFER, sizeof(vPosition), sizeof(vColor), vColor);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
//glBufferStorage(GL_ARRAY_BUFFER, sizeof(vPosition) + sizeof(vColor), 0, 0);
glBufferData(GL_ARRAY_BUFFER, sizeof(vPosition) + sizeof(vColor), 0, GL_STREAM_READ);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenTransformFeedbacks(1, TFBs);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, TFBs[0]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, VBOs[1]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(400, 300);
glutInitWindowSize(800, 600);
glutInitContextVersion(4, 5);
glutInitContextProfile(GLUT_CORE_PROFILE);
glutCreateWindow("Drawing my first triangle");
glewInit();
GLubyte const *v = glGetString(GL_VERSION);
printf("%s\n", v);
Init();
// register callbacks
glutDisplayFunc(renderScene);
glutMainLoop();
glDeleteProgram(program);
return 0;
}
Transform feedback does not happen simply because a feedback object is bound. Your shader must explicitly tell OpenGL which outputs go to the feedback buffer(s). There are a variety of mechanisms for doing this. Personally, I'd go for the in-shader setup since you're using GLSL 4.50.
Given the layout of your VAOs[1]
and the feedback buffers, the following shader code should work:
#version 450 core
in vec4 vPosition;
in vec4 vColor;
//Use buffer 0 by default.
layout(xfb_buffer = 0) out;
//Must redeclare `gl_PerVertex` to apply TF to it.
out gl_PerVertex
{
layout(xfb_offset = 0) vec4 gl_Position;
};
//4 floats after gl_Position
layout(xfb_offset = 16) out vec4 fColor;
uniform mat4 vMatrix;
void main(void)
{
gl_Position = vMatrix * vPosition;
fColor = vColor;
};
A small other issue with your code. This:
glVertexAttribFormat(color, 4, GL_FLOAT, GL_FALSE, sizeof(vPosition));
Will not always work. The offset for an attribute within a buffer is restricted to GL_MAX_VERTEX_ATTRIB_STRIDE
. That implementation-defined value will be at least 2048, so your current code is safe. But it is only safe because vPosition
is so small. It won't take much at all to make vPosition
too big for the offset.
The attribute format's offset is intended to be an offset from the start of the buffer to where the first vertex's information is. It's not meant to be used to skip over an entire attribute array's worth of data, which is what you have done here. The format's offset is meant for the offset of an interleaved vertex.
When you have two non-interleaved arrays like this, the best way to handle this is with two buffer bindings. That is, position
and color
should use different buffer bindings.
Note that I did not say different buffer objects. You can use the same buffer in both bindings; you just use the offset supplied to glBindVertexBuffer
to provide the offset to the start of the color array. That offset has no limitations, unlike the format offset.