Как движки коммерческих игр организуют индексные / вершинные буферы?

8

Предисловие: Этот вопрос будет возникать с точки зрения Direct3D, потому что это то, с чем я знаком.

Очевидно, что каждый раз, когда мы меняем вершинные или индексные буферы в Direct3D (т.е. с помощью IASetIndexBuffer), мы несем небольшие накладные расходы . Но я полагаю, что если мы выделим один гигантский индексный / вершинный буфер, нам в конечном итоге придется управлять памятью вручную, и в результате мы столкнемся с проблемой фрагментации (или сделаем паузу во время обмена всеми данными).

Так как же коммерческие движки загружают / выгружают данные? Я склоняюсь к подходу, основанному на «пакете», поэтому «пакет» моделей имеет свой собственный буфер вершин / индексов, который мы можем загружать / выгружать, так как пакет больше не нужен; а затем попробуйте собрать все экземпляры из одного пакета вместе.

Но мне было бы интересно услышать, каков принятый / стандартный способ обработки?

Xenoprimate
источник
1
Это хороший вопрос, и он также применим к OpenGL.
Гламперт

Ответы:

13

Существует несколько различных способов организации данных, и во многих играх их используют.

Для статической геометрии лучше иметь меньше отдельных IB и VB.

Традиционно игры основаны на уровнях, что означает, что ресурсы для раздела игры загружаются, и затем начинается игровой процесс. Чтобы минимизировать время загрузки, информация идеально организована для поддержки этого (т. Е. Загружать все для уровня как можно быстрее, не просматривая носитель / диск), возможно, реплицируя информацию между уровнями. В этом подходе одна схема состоит в том, чтобы иметь большие VB и IB для модели или серии моделей, а затем представить поднаборы из этого для рисования.

Для поколения Xbox 360 / PS 3 объем оперативной памяти был довольно мал по сравнению с размерами игр, поэтому движки стали ориентироваться на потоковую передачу, что означает, что они загружают контент динамически, когда игрок проходит через них. Это также называется подходом «открытого мира». В этом подходе задача состоит в том, чтобы «разбить» геометрию на биты, которые можно загрузить на основе пространственных подсказок. Еще одна проблема, особенно для 32-разрядных платформ, заключается в том, чтобы гарантировать, что память не будет фрагментирована (или даже фрагментирована виртуальное адресное пространство) в течение длительного периода времени - основанные на уровнях игры часто сбрасывают память между уровнями, что потоковые движки не могут сделать как легко. Поэтому полезно упаковать в фиксированный размер или набор фиксированных размеров для IB / VB, которые были выделены и повторно использованы в качестве пула.

Для поколения Xbox One / PS 4 есть много ОЗУ для работы по сравнению с предыдущими консолями и много дополнительных ядер, поэтому многие игры агрессивно сжимают свои ресурсы, а затем используют «лишние» ядра ЦП для их распаковки в фон. При использовании 64-разрядного виртуального адресного пространства меньше внимания уделяется фрагментации виртуального адресного пространства. Такой подход позволяет сократить время загрузки, хорошо упаковывает ресурсы для цифровой загрузки и поддерживает рендеринг в открытом мире. Здесь используется групповой подход к управлению IB / VB.

Существует также динамическое представление геометрии, которое часто используется для рельефа местности, деформируемых / разрушаемых моделей и т. Д. Это неэффективно с точки зрения пропускной способности шины графического процессора, поэтому в играх часто используется сочетание статической и динамической геометрии. В этом случае шаблон обновления DISCARD карты Direct3D обычно означает, что вы используете только один IB / VB (или для сценариев многопоточного рендеринга - двойной IB / VB, в котором вы меняете местами заполнение / рендеринг каждого кадра).

Чак Уолборн
источник
Спасибо за Ваш ответ. Могу я задать несколько уточняющих вопросов? Что такое шаблон DISCARD для Direct3D Map?
Ксенопримат
1
Шаблон описан здесь для Direct3D 9 как Lock DISCARD, но этот шаблон используется с Direct3D 10.x / 11.x, а также Map DISCARD для динамических ресурсов. Вы можете увидеть пример того, как это реализовано для Direct3D 11, взглянув на класс PrimitiveBatch из набора инструментов DirectX .
Чак Уолборн