OpenGL 4.3 或 4.5 变换反馈不起作用

OpenGL 4.3 or 4.5 Transform Feedback Not Working

有两个调试 printf 段。第一个打印出正确的数据,但第二个没有。我哪里做错了? 哦,我正在使用相同的顶点和片段着色器来获取顶点数据并再次绘制它们。

#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;
}

变换反馈不会仅仅因为反馈对象被绑定而发生。您的着色器必须明确告诉 OpenGL 哪些输出进入反馈缓冲区。由于您使用的是 GLSL 4.50,因此有 a variety of mechanisms for doing this. Personally, I'd go for the in-shader setup

鉴于您的 VAOs[1] 布局和反馈缓冲区,以下着色器代码应该可以工作:

#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;
};

您的代码还有一个小问题。这个:

glVertexAttribFormat(color, 4, GL_FLOAT, GL_FALSE, sizeof(vPosition));

并不总是有效。缓冲区内属性的偏移量限制为 GL_MAX_VERTEX_ATTRIB_STRIDE。该实现定义的值至少为 2048,因此您当前的代码是安全的。但这只是安全的,因为 vPosition 太小了。使 vPosition 对于偏移来说太大并不需要太多。

属性格式的偏移量旨在成为从缓冲区开始到第一个顶点信息所在位置的偏移量。它并不意味着用于跳过整个属性数组的数据价值,这是您在此处所做的。格式的偏移量用于交错顶点的偏移量。

当您有两个这样的非交错数组时,处理此问题的最佳方法是使用两个缓冲区绑定。也就是说,positioncolor 应该使用不同的缓冲区绑定。

请注意,我没有说不同的缓冲区 objects。您可以在两个绑定中使用相同的缓冲区;您只需使用提供给 glBindVertexBuffer 的偏移量来提供颜色数组开头的偏移量。与格式偏移量不同,该偏移量没有限制。