Почему я получаю половину треугольников, отображаемых на экране? - PullRequest
1 голос
/ 26 октября 2019

Я следовал этому уроку и смог нарисовать 20 треугольников на экране. Однако в этом примере и данные о положении, и данные о цвете хранятся в одном массиве и передаются как один вызов glBufferSubData. Я не уверен, должен ли я всегда следовать этому подходу или создавать отдельные массивы для хранения атрибутов вершин и вызывать glBufferSubData для каждого атрибута. Я попытался сохранить положение и цвет отдельно и попал в странную проблему. Вместо того, чтобы нарисовать 20 треугольников на экране, я получаю только 10!

[Я использовал glfw вместо Qt для создания окна.]

Подход 1:

Я определил глобальные переменные следующим образом:

float dx = 0.1f;
unsigned int triangleCount = 0;

const unsigned int TRIANGLE_MAX_COUNT = 20;
const unsigned int TRIANGLE_VERTEX_COUNT = 3;
const unsigned int VERTEX_FLOAT_COUNT = 8;
const unsigned int TRIANGLE_BYTE_SIZE = TRIANGLE_VERTEX_COUNT * VERTEX_FLOAT_COUNT * sizeof(float);

Моя функция рисования треугольника определена как

void sendAnotherTriangle()
{
    if (triangleCount == TRIANGLE_MAX_COUNT)
        return;
    const float x = -1 + triangleCount * dx;

    glm::vec4 newTriangle[] = {
        glm::vec4(x, +0.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f),
        glm::vec4(x + dx, +1.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f),
        glm::vec4(x, +1.0f, +0.0f,1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f,1.0f)
    };

    glBufferSubData(GL_ARRAY_BUFFER, triangleCount * sizeof(newTriangle), sizeof(newTriangle), newTriangle);

    triangleCount++;
}

Макет буфера вершин определяется следующим образом:

unsigned int vb;
glGenBuffers(1, &vb);
glBindBuffer(GL_ARRAY_BUFFER, vb);
glBufferData(GL_ARRAY_BUFFER, TRIANGLE_MAX_COUNT*TRIANGLE_BYTE_SIZE, NULL, GL_STATIC_DRAW);


glEnableVertexAttribArray(0);
glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE, 2 * sizeof(glm::vec4), (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 2 * sizeof(glm::vec4), (const void*)(sizeof(glm::vec4)));

Насколько я понимаю, поскольку атрибуты позиции и цвета чередуются, шаг для обоих атрибутов: 2 * sizeof (glm :: vec4), поскольку каждый атрибут имеет тип glm:: vec4. Поскольку данные позиции начинаются в самом начале, смещение позиции равно 0, а смещение цвета - sizeof (glm :: vec4), поскольку оно начинается после первой позиции вершины.

Наконец, вызов отрисовки выглядит следующим образом:

while (display.isRunning(window))
{
    glClear(GL_DEPTH_BUFFER_BIT);
    sendAnotherTriangle();
    glDrawArrays(GL_TRIANGLES, 0, triangleCount * TRIANGLE_VERTEX_COUNT);

    display.update();
}

Это дает мне желаемый результат, то есть 20 красных треугольников, нарисованных на экране.

Подход 2:

После этого я попыталсясделать то же самое, используя несколько вызовов glBufferSubData. В этом подходе модифицированная функция рисования треугольника:

void sendAnotherTriangle()
{
    if (triangleCount == TRIANGLE_MAX_COUNT)
        return;
    const float x = -1 + triangleCount * dx;

    glm::vec4 newPositions[] = {
        glm::vec4(x, +0.0f, +0.0f, +1.0f),
        glm::vec4(x + dx, +1.0f, +0.0f, +1.0f),
        glm::vec4(x, +1.0f, +0.0f, +1.0f)
    };


    glm::vec4 newColors[] = {
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f),
        glm::vec4(+1.0f, +0.0f, +0.0f, +1.0f)
    };

    glBufferSubData(GL_ARRAY_BUFFER, triangleCount*(sizeof(newPositions) + sizeof(newColors)), sizeof(newPositions), newPositions);
    glBufferSubData(GL_ARRAY_BUFFER, triangleCount*(sizeof(newPositions) + sizeof(newColors)) + sizeof(newPositions), sizeof(newColors), newColors);
triangleCount++;
}

И макет буфера вершин изменяется следующим образом:

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE, 0, (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 0, (const void*)(TRIANGLE_VERTEX_COUNT * sizeof(glm::vec4)));

Поскольку данные о положении и цвете хранятся отдельно, мойпонимание состоит в том, что они плотно упакованы и, следовательно, их шаг равен 0, и поскольку данные о цвете начинаются после данных о положении, смещение цвета равно TRIANGLE_VERTEX_COUNT * sizeof (glm :: vec4).

С этим новым параметром яожидается, что на экране нарисовано 20 треугольников. Тем не менее, я получаю только 10 треугольников, нарисованных на экране. Я предполагаю, что это связано с присвоением неверных значений шагам и смещениям. Тем не менее, я не мог понять это.

Поэтому я хотел бы сначала спросить, какой из них лучше и безопаснее.

Во-вторых, как я могу получить желаемый результат после второго подхода

1 Ответ

1 голос
/ 26 октября 2019

У вас есть основное недоразумение. Если вы разделили координаты вершины и цвета, то атрибуты не разделены на примитив.
Все координаты вершины 20 треугольников должны находиться в последовательной области буфера, и все цвета 20 треугольников должны иметьнаходиться в последовательной области буфера.

Вы должны хранить 60 (3 * 20) вершин треугольников в буфере и после этого 60 цветов. Смещение цветов: 20*3*sizeof(glm::vec4).

glBufferSubData(GL_ARRAY_BUFFER, 
                triangleCount*sizeof(newPositions),
                sizeof(newPositions), newPositions);
glBufferSubData(GL_ARRAY_BUFFER, 
                triangleCount*sizeof(newPositions) + 20*3*sizeof(glm::vec4), 
                sizeof(newColors), newColors);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, glm::vec4::length(), GL_FLOAT, GL_FALSE,
                      0, (const void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, glm::vec4::length(), GL_FLOAT, GL_FALSE, 
                      0, (const void*)(20*3*sizeof(glm::vec4)));
...