четверг, 6 ноября 2008 г.

Объединение одинаковых пересекающихся объектов на сцене.

При сильно загруженной сцене бывает очень много вызовов от рисовок геометрии, всем известными под названием DIP (IDirect3DDevice9::DrawIndexedPrimitive для Direct3D9, glDrawElements для OpenGL и ID3D10Device::DrawIndexed для Direct3D10). Большое количество таких вызовов может нанести серьезный удар по быстродействию рендера, особенно это более актуально для Direct3D 9, именно в в момент вызова идет проверка на валидность пиксельного и вершинного шейдера, правильная линовка данных передаваемых из вершинного в пиксельный, проверка вершинных деклараций на соответствие того что использует вершинный шейдер и что находится в вершинном буфере, так-же индексы вершин и остальные параметры. В OpenGL все намного проще, после выполнения каждой функции может возникнуть ошибка. Таким образов время как-бы равномерно распределяется между всеми вызовами функция перед вызовом от рисовки.
Ну в Direct3D 10 DIP cost значительно снижен.
Так-же частые вызовы может серьёзно нагрузить CPU по вызовам функций. Обычно до 1000 DIP на кадр ещё не все так плохо.
Итак при загрузки сцены я сделал некую простейшую оптимизацию, ищем объекты с одинаковы мешами и если они пересекаются своими ограничивающими боксами, собираем их в 1 мешь с учтя матрицу трансформации. Что это дает?
1) уменьшение нагрузки на CPU при обходе Scene Graph и при сортировке объектов;
2) уменьшение DIP cost при отриcовке в Depth текстуру для теней;
3) уменьшение DIP cost при финальной от рисовке объектов;
Минусы в том что будет небольшой перерасход памяти. Но если к примеру у меня на сцене дерево ели имеет 350 полигонов и их несколько сотен, то объедение по 3-4 в 1 мешь будут значительно сокращать DIP cost. Пока тесты особых положительных результатов не дали но число DIP и число объектов в кадре значительно сокращены в грубом приближении на 30% в среднем. Повышение FPS вроде не более 10%. Буду тестировать на более слабом железе. На будущее конечно нужно подумать об использовании Instansing'а. Железо сейчас c такой функциональностью уже достаточно доступно и инстансинг есть уже в 3 API в том числе и поддержка у ATI для OpenGL.

3 комментария:

iOrange комментирует...

Вообще-то очень правильное решение, такой себе препросчитанный избирательный инстансинг =)
К сожалению в случае с прозрачными мешами это может вылезти боком, т.к. несколько мешей отсортируются, а один уже нет, хотя это надо смотреть по complexity.

Так держать!

Andrey комментирует...

Еще есть проблема с Fill Rate если объеденные объекты будут рендериться не в порядке от ближнего к дальним могут. Тут конечно возможно поможет утилита ATI Tootle(Triangle Order Optimization Tool).

iOrange комментирует...

Еще есть проблема с Fill Rate если объеденные объекты будут рендериться не в порядке от ближнего к дальним могут

Ну уже давно очень модно экономить FillRate отдельным Z-Pass, и потом уже пофигу в каком порядке рисовать. + Получаем z-buffer который все равно будит юзаться для скажем SoftParticles, DepthWater и т.д.