OpenGL 4.3 или 4.5 Transform Feedback не работает

Есть два отладочных сегмента 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;
}

1 ответ

Решение

Преобразование обратной связи не происходит просто потому, что объект обратной связи связан. Ваш шейдер должен явно указать OpenGL, какие выходы идут в буфер (ы) обратной связи. Существует множество механизмов для этого. Лично я бы пошел на установку In-Shader, так как вы используете GLSL 4.50.

Учитывая макет вашего 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 слишком большой для смещения.

Смещение формата атрибута предназначено для смещения от начала буфера до того места, где находится информация первой вершины. Он не предназначен для пропуска данных всего массива атрибутов, что вы здесь и сделали. Смещение формата предназначено для смещения чередующейся вершины.

Когда у вас есть два таких массива без чередования, лучший способ справиться с этим - использовать две привязки буфера. То есть, position а также color следует использовать разные привязки буфера.

Обратите внимание, что я не говорил разные объекты буфера. Вы можете использовать один и тот же буфер в обеих привязках; вы просто используете смещение, предоставленное glBindVertexBuffer обеспечить смещение к началу цветового массива. Это смещение не имеет ограничений, в отличие от смещения формата.

Другие вопросы по тегам