GLSL - вершинный шейдер и пакетная обработка с использованием единого буферного объекта - PullRequest
1 голос
/ 29 апреля 2019

У меня есть следующий вершинный шейдер:

#version 450 core
...
layout (binding=2, std140) uniform MATRIX_BLOCK
{
   mat4 projection;
   mat4 view;
   mat4 model[128];
   mat4 mvp[128];
};

layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
layout (location = 3) in uint object_idx;

out vec2 TexCoord;
flat out uint instance_idx;

void main()
{  
  gl_Position = mvp[object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);  
  TexCoord = aTexCoord;
  instance_idx = object_idx;
}

Я использую единый буфер для передачи 128 матриц модели и проекции вида модели, проиндексированных идентификатором объекта. Идентификатор объекта передается в шейдер с использованием атрибута вершины object_idx; в основном каждая вершина, кроме координат x, y, z и текстурных координат u, v, также имеет идентификатор объекта, связанный с ней. Идея заключается в том, чтобы иметь возможность хранить данные для нескольких объектов в одних и тех же буферах, но при этом использовать конкретные матрицы преобразования для каждого отдельного объекта. Это моя (возможно, глупая) попытка объединить несколько объектов, чтобы нарисовать их одним вызовом рисования, без необходимости что-либо перепривязывать, используя glDrawElements для рендеринга треугольников.

Однако это не работает. Когда я делаю

gl_Position = mvp[object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

тогда треугольники с object_idx, равным 0, визуализируются очень хорошо в ожидаемой позиции, но треугольники с вершинами, у которых object_idx отличен от 0, нигде не появляются. Я подумал, что, возможно, неправильно понял матрицы преобразования, поэтому для отладки я уменьшил количество возможных объектов до 2 (0 и 1) и инвертировал индексирование, используя

gl_Position = mvp[1-object_idx] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

Это привело к тому, что все треугольники с object_idx = 0 были отрисованы в ожидаемой позиции для mvp [1], но опять же, нигде не появилось ни одного треугольника с object_idx = 1. По крайней мере, я знаю, что матрицы преобразования верны. Я тогда попробовал

gl_Position = mvp[0] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

и это всех треугольников (с использованием матрицы преобразования объекта 0) и

gl_Position = mvp[1] * vec4(aPos.x, aPos.y, aPos.z, 1.0);

отображает всех из них, используя матрицу преобразования объекта 1.

Итак, очевидно, я не понимаю чего-то действительно фундаментального в том, как работают вершинные шейдеры или glDrawElements.

Итак, мой вопрос:

Почему не все мои треугольники отрисовываются, когда я выполняю «динамический» поиск матрицы преобразования mvp с использованием object_idx, когда, насколько я в состоянии проверить, все данные передаются в вершинный шейдер так же, как и должно быть?

1 Ответ

2 голосов
/ 29 апреля 2019

Я делаю обоснованное предположение здесь:

layout (location = 3) in uint object_idx;

Использование uint для ввода атрибута требует установки указателя атрибута с помощью функции glVertexAttribIPointer() (обратите внимание на дополнительные I там).

Используя стандартную функцию glVertexAttribPointer, всегда будут устанавливаться атрибуты с плавающей точкой (а с использованием типа GL_INT будет конвертироваться целое число в число с плавающей точкой). Технически, когда вы читаете такой атрибут с плавающей точкой, как uint в шейдере, он будет неопределенным, но вполне вероятно, что 0 останется 0, так как операции с плавающей точкой и целочисленные значения обычно идентичны, но это работает только случайно.

Помимо этой проблемы, сохранение индекса объекта для каждой вершины также довольно неэффективно. Для эффективной пакетной обработки вызовов вы должны взглянуть на функции многократных вызовов и gl_DrawID (первоначально из GL_ARB_shader_draw_parameters). Вы также можете найти полезными приближающиеся к нулю драйверы (AZDO) полезные.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...