Обратная связь преобразования OpenGL 4.3 или 4.5 не работает

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

person ACskyline    schedule 18.10.2016    source источник


Ответы (1)


Преобразование обратной связи не происходит просто потому, что объект обратной связи привязан. Ваш шейдер должен явно сообщать OpenGL, какие выходные данные направляются в буфер(ы) обратной связи. Для этого существует множество механизмов. Лично я бы выбрал настройку в шейдере, поскольку вы используете 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, чтобы обеспечить смещение начала массива цветов. Это смещение не имеет ограничений, в отличие от смещения формата.

person Nicol Bolas    schedule 18.10.2016
comment
Спасибо большое! Особенно в части glVertexAttribFormat. - person ACskyline; 19.10.2016