Dynamic vertex pulling в Direct3D11 (комментарии)
Это сообщение сгенерировано автоматически.
Вий
> с виду они как раз совершенно одинаковые!
+1
Инстансинг какой то
Внимательнее читать надо :)
Вий
> а в чем уникальность кубиков?
Каждый кубик создаётся как отдельный меш. В данный момент там действительно одинаковые кубики, но это не один кубик, нарисованный 16 тысяч раз, а 16 тысяч кубиков, нарисованных 16 тысяч раз.
Код из примера:
for (int i = 0; i < kNumMeshes; ++i) { // create a lot of 'unique' meshes cubeVertexBuffers[i] = sgfx::createBuffer( sgfx::BufferType::Vertex, cubeVertices, sizeof( CommonVertex) * verticesSize, sizeof( CommonVertex)); cubeIndexBuffers[i] = sgfx::createBuffer( sgfx::BufferType::Index, cubeIndices, sizeof( uint32_t) * indicesSize, sizeof( uint32_t)); }
На днях выложу скриншот, где не кубики, а густой разнообразный лес с травой и кустами :)
bazhenovc
> Код из примера:
А где он? в репозитории его нет
Я вот что хочу спросить - а это чудо нормально отсекается по фрустуму? если 16 тысяч деревьев, то не все же они видимы.
1. DrawInstanced надо вызывать с максимальным количеством вершин, которое есть в буфере команд.
Это необходимо потому, что вызов отрисовки у нас 1, и если у мешей разное количество вершин или индексов — это нужно как-то учитывать. Я предпочитаю всегда рисовать наибольшее количество вершин, а лишние отсекать, отправляя их за clipping plane.
Таким образом появляется много дополнительной ненужной нагрузки на вершинный шейдер, поэтому надо следить за тем, чтобы разница между минимальным и максимальным vertex count была в разумных пределах (500—600 вершин). Нужно помнить, что эта разница равна количеству «мусорных» вершин на каждый инстанс, и она растёт со скоростью геометрической прогрессии в квадрате. Следите за художниками!
Открыл в надежде почитать, как это сделать без мусорных вершин, так как это и есть самый серьезный недостаток данного способа. Жопа будет когда будет куча маленьких ростков в далеке, с минимальным LOD, и одно большое дерево с максимальным LOD.
А вообще этот способ был доступен с тех пор, как появились текстуры в вершинных шейдерах. Складываем в текстуру, обращаемся по индексу. Так что DX11 или OpenGL 4.0 не обязателен.
Да и пример слабоват.
1. 4 базовых вида деревьев,
2. 3 стадии роста для каждого дерева (росток, деревце, большое дерево),
3. 3 стадии здоровья для каждой стадии роста дерева(здоровое, больное, умирающее),
4. 5 уровней детализации (LOD) для каждой стадии здоровья каждой стадии роста каждого дерева (включая импостеры).
180 батчей в пике. Не такой уж и оверхед для CPU. В особенности если хранить все в одном вертекс буфере, чтобы биндить лишь однажды.
В общем CPU то мы разгрузим, а вот GPU ушатаем кешмиссами и мусорными вершинами (которых будет львиная доля)
Да это же Mantle API ! :) Наверное , скоро будет и SDK от bazhenovc-ча
war_zes
> Я вот что хочу спросить - а это чудо нормально отсекается по фрустуму? если 16
> тысяч деревьев, то не все же они видимы.
Да, отсекается нормально и вкручивается в существующие движки очень прозрачно.
Код в репозитории немного поменялся, я сейчас работаю над полностью отдельной демкой - скоро будет :)
MrShoor
> Открыл в надежде почитать, как это сделать без мусорных вершин, так как это и
> есть самый серьезный недостаток данного способа.
В OpenGL есть MultiDrawIndirect, там можно без мусорных вершин сделать. У NVidia даже пример есть: http://docs.nvidia.com/gameworks/content/gameworkslibrary/graphic… ectsample.htm
> Жопа будет когда будет куча маленьких ростков в далеке, с минимальным LOD, и одно большое дерево с максимальным LOD.
Я большие деревья на этапе загрузки разбиваю на маленькие куски, чтобы совпадало с минимальным лодом. Импостеры рисуются отдельно обычным инстансингом.
> А вообще этот способ был доступен с тех пор, как появились текстуры в вершинных шейдерах. Складываем в текстуру, обращаемся по индексу. Так что DX11 или OpenGL 4.0 не обязателен.
В один пиксель текстуры помещается один float4, а формат вершины обычно подразумевает ещё и нормаль и прочую разный хлам. У нас вертех дерева занимает 64 байта(48 байт полезных, 16 байт паддинг), если хранить всё в текстуре - надо было бы делать несколько выборок, против одной выборки из StructuredBuffer.
> Да и пример слабоват.
Да, я знаю, я скоро пример получше выложу.
> В общем CPU то мы разгрузим, а вот GPU ушатаем кешмиссами и мусорными вершинами (которых будет львиная доля)
Ну я и не спорю, более того - это и было основной целью, разгрузить CPU любой ценой :) Ну и при правильном подходе мусорные вершины не будут серьёзной проблемой.
bazhenovc
> В OpenGL есть MultiDrawIndirect, там можно без мусорных вершин сделать. У NVidia даже пример есть: http://docs.nvidia.com/gameworks/content/gameworkslibrary/graphic… ectsample.htm
Дык так и надо было разгружать CPU, а не вот таким вот велосипедом.
> В один пиксель текстуры помещается один float4, а формат вершины обычно
> подразумевает ещё и нормаль и прочую разный хлам. У нас вертех дерева занимает
> 64 байта(48 байт полезных, 16 байт паддинг), если хранить всё в текстуре - надо
> было бы делать несколько выборок, против одной выборки из StructuredBuffer.
Существенной разницы не будет. Все 3-4 выборки лягут в кеш. Я уже давно так гоняю материалы и трансформации.
Вий
> А тогда опиши этот самый правильный подход при котором мусорные вершины не
> будут серьезной проблемой!
А что там описывать то? Правильный подход - Indirect буфера. Описано в документации к DX и OGL
MrShoor
> Дык так и надо было разгружать CPU, а не вот таким вот велосипедом.
Нам надо поддерживать D3D10-железки, где нет ни индиректа, ни 4-го OpenGL :)
Да и шипать проект на OpenGL я бы не рискнул, по крайней мере в ближайшие года 3.
> Существенной разницы не будет. Все 3-4 выборки лягут в кеш. Я уже давно так гоняю материалы и трансформации.
На самом деле там не всё так радужно из-за постоянного рандомного доступа к памяти.
> А что там описывать то? Правильный подход - Indirect буфера. Описано в документации к DX и OGL
Всё так, но в D3D10 feature level DrawIndirect отсутствует в каком-либо виде.
Помимо этого D3D11 не умеет MultiDrawIndirect, а в свете того, что DX12 будет только на Win10 - с DX11 мы не расстанемся ещё очень долго.
bazhenovc
Все это здорово. Но эта техника, больше на костыль похожа. Вроде и интересно , но и как то не то.
Какой смысл в этом будет, когда выйдет Mantle API SDK и Directx 12 ?
К весне-лету по слухам будет Mantle API SDK, а Directx 12 будет в конце 2015.
Мало того что Mantle API и Directx 12 прекрасно побеждают разгрузку CPU, так еще имеют новые техники рендера и большую гибкость.
Если мне не веришь то посмотри свои sdk по Mantle API и Directx 12, о которых ты успел всем тут на форуме растрезвонить, что они у тебя есть.
ronniko
> Все это здорово. Но эта техника, больше на костыль похожа. Вроде и интересно ,
> но и как то не то.
Это и есть костыль ;)
> Какой смысл в этом будет, когда выйдет Mantle API SDK и Directx 12 ?
Не будет никакого, но только тогда, когда мы сможем полностью отказаться от D3D11, что случится не скоро.
Эта техника специально предназначена как некий переходный вариант между D3D11 и D3D12, не стоит относится к ней как к чему-то революционному или универсальному.
> Если мне не веришь
Почему это не верю?:)
bazhenovc
> Да и шипать проект на OpenGL я бы не рискнул, по крайней мере в ближайшие года 3.
А почему не рискнул бы?
> На самом деле там не всё так радужно из-за постоянного рандомного доступа к памяти.
Ты сейчас о чем? Позиция/нормаль/ит.п. должны лежать рядом в текстуре. А если между вертексами, так со Structured буфер ровно то же самое, рандомный доступ.
> Помимо этого D3D11 не умеет MultiDrawIndirect
Да ну, правда?
ronniko
>Какой смысл в этом будет, когда выйдет Mantle API SDK и Directx 12 ?
>К весне-лету по слухам будет Mantle API SDK, а Directx 12 будет в конце 2015.
Mantle SDK работает только на AMD, а DX12 - только на Windows 10.
А что делать людям, которые сидят на nvidia + windows 7-8? А это, между прочим, крупнейший сегмент
рынка на данный момент (и, возможно, еще на много много лет). Да и перспективы Win10 весьма туманны, если микры опять нафакапят
с чем-нить, то никто не будет на неё переходить и dx12 вообще останется за бортом.
Как видишь, это не панацея.
> Мало того что Mantle API и Directx 12 прекрасно побеждают разгрузку CPU, так еще имеют новые техники рендера и большую гибкость.
Да ты кэп. Спасибо хоть картинки больше не пихаешь в каждое свое сообщение.
Mephisto std
А что делать людям, которые сидят на nvidia + windows 7-8?
Если так задавать вопрос.
То я точно так же могу задать такой же вопрос тебе Mephisto std.
А что делать людям которые сидят на Directx 9 ? И которые юзают даже Windows XP.
Там Directx 10 и 11 нет.
MrShoor
> Да ну, правда?
Ты не видишь разницы между DrawIndirect и MultiDrawIndirect?
Просто DrawIndirect:
const DrawArraysIndirectCommand *cmd = (const DrawArraysIndirectCommand *)indirect; DrawInstanced( mode, cmd->first, cmd->count, cmd->instanceCount, cmd->baseInstance);
MultiDrawIndirect:
for (int n = 0; n < drawcount; n++) { const DrawArraysIndirectCommand *cmd; if ( stride != 0) { cmd = ( const DrawArraysIndirectCommand *)( ( uintptr)indirect + n * stride); } else { cmd = ( const DrawArraysIndirectCommand *)indirect + n; } DrawInstanced( mode, cmd->first, cmd->count, cmd->instanceCount, cmd->baseInstance); }
Мусорные вершины можно убрать только использовав MultiDrawIndirect, которого в D3D11 нет, есть только обычный DrawIndirect.
Для справки:
https://www.opengl.org/wiki/GLAPI/glDrawArraysIndirect
https://www.opengl.org/wiki/GLAPI/glMultiDrawArraysIndirect
Тема в архиве.