Комментарии 18
Нетрудно видеть, что реализация алгоритма на Direct3D 11 работает быстрее, чем на OpenGL 4.3.
Скорее всего из-за того, что используется
discard
в шейдере.Пробовали ли найти причину?
+4
Я сомневаюсь, что причина кроется в использовании discard, на HLSL я, например, использую clip. На небольших-средних объемах реализация на OpenGL почти не уступает, проблемы начинаются на больших объемах. Как я писал, существенно бОльшая часть времени кадра в этом случае тратится на сортировку и смешивание фрагментов, так что у меня единственное предположение — это перегруженный фрагментный шейдер и, как следствие, низкий fillrate. Перегрузка шейдера возникает, скорее всего, из-за большого количества используемых временных регистров и обращений к storage block'у с произвольным доступом. Произвольный доступ, к слову, еще и кэш гробит. Ну, и последнее, вполне возможно, что оптимизатор компилятора HLSL чуть лучше.
А почему вы считаете, что discard может быть проблемой?
А почему вы считаете, что discard может быть проблемой?
+1
Опыт показывает, что замедление происходит в основном в 3 случаях:
1. Много переключений между буферами
2. discard
3. Неправильно построенный шейдер. К примеру в плане if-конструкций, когда много временных переменных внутри блока.
Я с Direct3D и HLSL вообще не знаком и на сколько мне подсказывает поиск, clip и discard далеко не тоже самое. Тут есть интересный ответ.
1. Много переключений между буферами
2. discard
3. Неправильно построенный шейдер. К примеру в плане if-конструкций, когда много временных переменных внутри блока.
Я с Direct3D и HLSL вообще не знаком и на сколько мне подсказывает поиск, clip и discard далеко не тоже самое. Тут есть интересный ответ.
+4
Интересная статья. Чисто с точки зрения познавательности. За это в карму плюсик.
ИМХО данный метод еще долго(может быть никогда?) не пойдет глобально в продакшн.
В повседневных геймдев задачах очень редко встает необходимость делать пересекающиеся полупрозрачные объекты.
И как правило полупрозрачные объекты имеют простые формы с минимумом пересечений — оконные стекла, посуда.
А эти ситуации вполне решаются ручной сортировкой без потери производительности.
ИМХО данный метод еще долго(может быть никогда?) не пойдет глобально в продакшн.
В повседневных геймдев задачах очень редко встает необходимость делать пересекающиеся полупрозрачные объекты.
И как правило полупрозрачные объекты имеют простые формы с минимумом пересечений — оконные стекла, посуда.
А эти ситуации вполне решаются ручной сортировкой без потери производительности.
+1
ИМХО данный метод еще долго(может быть никогда?) не пойдет глобально в продакшн.
Тут вы ошибаетесь. Как раз работаю над продуктом, не игра, где это очень нужно. Но мы пока не используем OIT, т.к. модели очень деталезированны и имеют очень много полигонов. Не на каждом устройстве хватает производительности, а нужно поддерживать большой спектр.
0
НЕ игры — это другое дело.
И, наверняка, будут отдельные игры, в которых это реально будет нужно.
Ну там какая нибудь детская игра с кучей мыльных пузырей.
Я имею ввиду глобальное использование, например, как стало с бампом. Единственный шанс стать глобальным инструментом — это вынести функционал на уровень конвеера, чтобы он работал автоматически без телодвижений программиста. Потому что программистам в 99% случаев такой функционал не нужен.
И, наверняка, будут отдельные игры, в которых это реально будет нужно.
Ну там какая нибудь детская игра с кучей мыльных пузырей.
Я имею ввиду глобальное использование, например, как стало с бампом. Единственный шанс стать глобальным инструментом — это вынести функционал на уровень конвеера, чтобы он работал автоматически без телодвижений программиста. Потому что программистам в 99% случаев такой функционал не нужен.
0
Я бы сказал что в игровой идустрии уже применяются похожие методы. Обычно используют фоллбеки — шейдеры попроще, которые заменяют более продвинутые в случае если драйвер не умеет или производительность не позволяет.
+1
Задача блендинга кучи полупрозрачного и неотсортированного в геймдеве повсеместна: партиклы например, или волосы персонажей.
И там похожие методы используют, только хитрее кладут их на железо. Например сортируют только 4 ближайших объекта, остальное блендят как придется. При это буфер под каждый список получается фиксированного размера — меньше дорогих переходов по «указателям».
И там похожие методы используют, только хитрее кладут их на железо. Например сортируют только 4 ближайших объекта, остальное блендят как придется. При это буфер под каждый список получается фиксированного размера — меньше дорогих переходов по «указателям».
0
волосы очень легко сортируются с минимумом артефактов еще на момент построения модели.
по поводу системы частиц — с одной стороны согласен, с другой — эмиттеры легко сортируются, а внутри эмиттера разные типы частиц просто отображаются в правильном порядке, как правило дополнительная сортировка не нужна.
по поводу системы частиц — с одной стороны согласен, с другой — эмиттеры легко сортируются, а внутри эмиттера разные типы частиц просто отображаются в правильном порядке, как правило дополнительная сортировка не нужна.
0
Есть ещё одно относительно простое решение этой задачи Weighted, Blended Order-Independent Transparency
0
Вопрос.
У вас написано: «Выставляем задний буфер как нулевой render target, индекс 1 получит текстура головных элементов, индекс 2 – структурированный буфер элементов списков;»
Почему Backbuffer первый? Это же то, что мы выводим на экран.
Почему он не должен рендериться в последнюю очередь, по завершению всех вычислений?
У вас написано: «Выставляем задний буфер как нулевой render target, индекс 1 получит текстура головных элементов, индекс 2 – структурированный буфер элементов списков;»
Почему Backbuffer первый? Это же то, что мы выводим на экран.
Почему он не должен рендериться в последнюю очередь, по завершению всех вычислений?
0
Обратите внимание на дальнейшие шаги: полупрозрачная часть рисуется поверх при помощи полноэкранного квада. Поэтому в данном случае, непрозрачную часть можно рисовать в системный BB сразу.
0
Спасибо за быстрый ответ!
Теперь, если я правильно понял:
0-й пасс. Мы рисуем только непрозрачные объекты. В Backbuffer, формат текстуры R8G8B8A8_UNorm, флаги RenderTarget | ShaderResource. Тест глубины есть, по Z-buffer-у, все как обычно. Для чистоты эксперимента, я хочу от этого пасса отказаться.
1-й пасс. Рисуем прозрачные объекты в Unordered текстуру (или в Backbuffer?). Шейдер с флагом [earlydepthstencil]. Формат R32_Uint, флаги ShaderResource | Unordered Access. Размер по размеру экрана. Но дальше тест глубины без Z-буффера?
2-й пасс. Рисуем в структурированный буфер? (SizeInBytes = 30000000, ShaderResource | UnorderedAccess, StructureByteStride = 12, OptionFlag = BufferStructured) Заполняет его тот самый шейдер, который выполняет сортировку фрагментов insertionSort(index, sortedFragments, counter) и выводит float4(color, alpha). Оно не выводит на экран ничего, что не удивительно. Как это все дорисовать в Backbuffer?
И еще вопрос по: RWTexture2D headBuffer; каким образом шейдер знает, что нужно записывать значения именно в ту unordered текстуру, которую я ему выделил?
Теперь, если я правильно понял:
0-й пасс. Мы рисуем только непрозрачные объекты. В Backbuffer, формат текстуры R8G8B8A8_UNorm, флаги RenderTarget | ShaderResource. Тест глубины есть, по Z-buffer-у, все как обычно. Для чистоты эксперимента, я хочу от этого пасса отказаться.
1-й пасс. Рисуем прозрачные объекты в Unordered текстуру (или в Backbuffer?). Шейдер с флагом [earlydepthstencil]. Формат R32_Uint, флаги ShaderResource | Unordered Access. Размер по размеру экрана. Но дальше тест глубины без Z-буффера?
2-й пасс. Рисуем в структурированный буфер? (SizeInBytes = 30000000, ShaderResource | UnorderedAccess, StructureByteStride = 12, OptionFlag = BufferStructured) Заполняет его тот самый шейдер, который выполняет сортировку фрагментов insertionSort(index, sortedFragments, counter) и выводит float4(color, alpha). Оно не выводит на экран ничего, что не удивительно. Как это все дорисовать в Backbuffer?
И еще вопрос по: RWTexture2D headBuffer; каким образом шейдер знает, что нужно записывать значения именно в ту unordered текстуру, которую я ему выделил?
0
Смотрите, непрозрачную часть вы должны нарисовать до того, как начинаете работать с полупрозрачной, так как непрозрачная часть должна заполнить буфер глубины. Без этого полупрозрачные объекты не смогут быть перекрыты непрозрачными. earlydepthstencil отбрасывает такие фрагменты до обработки, а шейдер строит списки связности. Затем вы начинаете рисовать экранный квад, в котором читаете из текстуры, хранящей в списки связности, получаете N фрагментов, сортируете и смешиваете. Результирующий цвет рисуется прямо на BB в случае DX11.
>каким образом шейдер знает, что нужно записывать значения именно в ту unordered текстуру, которую я ему выделил?
Вы выставляете ее как render target.
>каким образом шейдер знает, что нужно записывать значения именно в ту unordered текстуру, которую я ему выделил?
Вы выставляете ее как render target.
0
OpenGL умеет производить ранний тест глубины только для фрагментных шейдеров без «побочных эффектов». К сожалению, к «побочным эффектам» относится запись в storage block.Это решается с помощью спецификатора:
layout(early_fragment_tests) in;
+1
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Алгоритм Order-Independent Transparency c использованием связных списков на Direct3D 11 и OpenGL 4