Пользовательский drawID glMultiDrawElementsIndirect с несколькими экземплярами для каждого DrawElementsIndirectCommand - PullRequest
0 голосов
/ 24 ноября 2018

Если я настраиваю пользовательский восходящий целочисленный поток буфера вершин drawID для данных каждого экземпляра с помощью:

glVertexAttribDivisor(drawIDVertexStreamIdx, 1)

Используя заданную glMultiDrawElementsIndirect ():

struct DrawElementsIndirectCommand
{
    uint  count;
    uint  instanceCount;
    uint  firstIndex;
    uint  baseVertex;
    uint  baseInstance;
};

При установке instanceCount на большечем один, я смущен, глядя на старые заметки и онлайн о том, что именно происходит с drawID, переданным шейдеру?

Если, скажем, есть две записи DrawElementsIndirectCommand, вызванные из одной glMultiDrawElementsIndirect (), причем первая запись имеетinstanceCount, равный 3, а второй instanceCount, скажем, 1, что в действительности видят экземпляры в шейдере?(Предполагая, что поток вершин drawID содержит 0,1,2,3 и т. Д.)

Должны ли они видеть 0,1,2 для первых экземпляров записи DrawElementsIndirectCommand и 3 для второго экземпляра записи DrawElementsIndirectCommand?

Все примеры, которые я могу найти в Интернете, по-видимому, специально устанавливают instanceCount равным единице и полагаются на несколько записей DrawElementsIndirectCommand, что заставляет меня теперь сомневаться в правильности этого понимания?

const int CustomDrawIDIdx = 1;
const int VertexCount = 4;
DrawElementsIndirectCommand drawCallRecords[2] =
{
    { VertexCount, 3, 0, 0, 0 },
    { VertexCount, 1, 0, 0, 0 },
};

...
//  Attempt to set up custom drawID from a vertex attribute, where the vertex stream for it is a sequence of integers 0, 1, 2 etc
glVertexAttribIPointer(CustomDrawIDIdx, 1, GL_UNSIGNED_INT, 0, NULL);
glVertexAttribDivisor(CustomDrawIDIdx, 1);
...

glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, &drawCallRecords, 2, 0);

В вершинном шейдере:

layout (location = 1) in uint customDrawID;

void main()
{
    bool match = (customDrawID== gl_InstanceID); 
    ...
}

Таким образом, это должно вызвать 4 фактических вызова отрисовки, поскольку фактические вызовы отрисовки, вызванные glMultiDrawElementsIndirect (), определяются числом записей DrawElementsIndirectCommand и их количеством содержащихся экземпляров.

Для каждого вызова отрисовки gl_InstanceID долженначинать с нуля и считать для каждого экземпляра, но возвращаться к нулю после обработки каждой записи DrawElementsIndirectCommand?

Таким образом, gl_InstanceID должен делать (0, 1, 2) для drawCallRecords [0], а затем (0)для drawCallRecords [1]?Что делает customDrawID?

Мне также любопытно, если ARB_shader_draw_parameters на nVidia (GTX1070 +) все еще не рекомендуется по сравнению с использованием настраиваемого drawID из потока вершин?

*** UPDATE для отраженияОтвет очень терпеливого и полезного Никола Боласа:

Итак, учитывая:

DrawElementsIndirectCommand drawCallRecords[2] =
{
    { VertexCount, 3, 0, 0, 0 },
    { VertexCount, 1, 0, 0, 3 /*baseInstance will push us along in customDrawID vertex stream*/ },
};

Затем customDrawID будет выполнять (0, 1, 2) и (3) во всех случаях вmultidrawindirect.

Это означает, что каждый отрисованный экземпляр через два вызова отрисовки и 3 + 1 отрисованных экземпляров (3 экземпляра одного «объекта», 1 экземпляр другого «объекта») в одном вызове multidrawindirectможет ссылаться на совершенно уникальные матрицы преобразования, например.И, по сути, это эмулирует функциональность gl_DrawID, пока вы продолжаете увеличивать baseInstance как этот (исключительный стиль суммы) для каждой записи DrawElementsIndirectCommand.

BaseInstance в каждой записи DrawElementsIndirectCommand будет сдвигать смещение в поток вершин customDrawID, давая customDrawID, который уникален для каждого экземпляра среди всех нарисованных объектов.

1 Ответ

0 голосов
/ 24 ноября 2018

Таким образом, это должно вызвать 4 фактических вызова отрисовки, поскольку фактические вызовы отрисовки, вызванные glMultiDrawElementsIndirect (), определяются числом записей DrawElementsIndirectCommand и их количеством содержащихся экземпляров.

Нет.Экземпляры и «вызовы отрисовки» - это не одно и то же.

Одиночный вызов отрисовки определяется, как если бы он вызывал glDraw*InstancedBaseVertexBaseInstance;это то, что происходит, когда система считывает одну запись из массива данных рисования.Этот одиночный вызов отрисовки включает в себя все экземпляры .Инстансинг - это то, что происходит в вызове отрисовки.

Именно поэтому не гарантируется, что значения для каждого экземпляра будут динамически однородными выражениями .

Отдельные отрисовки в пределахкоманда multi-draw, gl_DrawID в стороне, полностью отделена друг от друга.Они не взаимодействуют.Значения, которые ваш шейдер получает для экземпляров массивов, или gl_InstanceID не будут отличаться от выдачи каждого вызова отрисовки отдельно.

Ваш "пользовательский drawID" вообще не является идентификатором отрисовки;это значение экземпляра массива.Следовательно, он следует правилам инстансинга и не заботится о ничто , для которого он предназначен.


bool match = (customDrawID== gl_InstanceID); 

Нет.

Даже если фактический массив, который вы используете для подачи customDrawID, представляет собой просто целочисленный индекс, начинающийся с нуля, массивы экземпляров и gl_InstanceID не работают одинаково.

gl_InstanceID игнорирует базовый экземпляр,Массивы экземпляров не .Таким образом, значение экземпляра, извлеченное из любого массива экземпляра, всегда будет сначала смещено базовым экземпляром.

Поэтому, если вы хотите, чтобы customDrawID для определенного вызова отрисовки начинался с определенного значения, тогда вы устанавливаетеbaseInstance быть индексом экземпляра этого конкретного значения.Таким образом, учитывая массив целочисленных индексов, начинающийся с нуля, если вы хотите, чтобы конкретный вызов отрисовки имел, чтобы его первый экземпляр получил значение customDrawID, равное «3», вы устанавливаете baseInstance в 3.

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