Особенности OpenGl VBO в C ++ - PullRequest
5 голосов
/ 10 июля 2010

Я немного сбит с толку относительно правильного использования VBO в программе OpenGL.

Я хочу создать алгоритм пейджинга ландшафта, используя карту, вызываемую из карты высот шкалы серого 4096x4096 как «целое»map.

Из того, что я прочитал, каждая вершина, хранящаяся в VBO, займет 64 байта.

Проблема, с которой я столкнулся, состоит в том, что большинство источников утверждают, что один VBO должен быть между 1-4 Мб в размере, и меньше VBOs лучше.Тем не менее, согласно моим расчетам, хранение каждой вершины заняло бы около гигабайта данных!(4096x4096x64) Это не включает в себя то, что каждая вершина может нуждаться в хранении несколько раз для каждого треугольника.

Также это не подходит для разных транспортных средств и людей, которые будут на этой карте, как только я получу отработанную часть кода для ландшафта.

другое решение, на которое я смотрел, было выстраивание данныхс жесткого диска во время работы программы, но другой источник говорит, что создавать и уничтожать во время работы программы - плохая идея, и также рекомендуется иметь как можно меньше VBO.

То, что я на самом делехочу знать, чего мне не хватает?Я уверен, что я делаю какой-то массивный надзор здесь, потому что максимальный размер VBO в 4 МБ кажется крайне низким, даже если я загружал текстуру в блоках 64x64 и различные интерактивные объекты, которые также заполняют карту.

Или мои ожидания от того, чего я могу достичь, просто нереальны?Есть ли лучший метод, который мне не известен?Я смотрю на такие игры, как Oblivion или Fallout 3, и в некоторой степени Boundless Planet, и вижу огромные ландшафты, и удивляюсь, как на земле это возможно.

Я понимаю, как кодировать, это не такМой первый опыт работы с OpenGL, но я впервые пытаюсь понять и использовать VBO.

Если кто-то сможет пролить свет на то, где мое понимание VBO идет не так, было бы очень признательно.

Ответы [ 6 ]

9 голосов
/ 10 июля 2010

Из того, что я прочитал, каждая вершина, хранящаяся в VBO, займет 64 байта.

Это может занять столько байтов, сколько вы хотите, в зависимости от формата вершины.
position + normal + texcoords = 4 * (3 + 3 + 2) = 32 байта на вершину
позиция + нормаль + текскорды + касательный вектор (для удара) = 4 * (3 + 3 + 2 + 3) = 44 байта

Это не означает, что каждая вершина может нуждаться в хранении несколько раз для каждого треугольника.

Одинаковые вершины не должны храниться несколько раз. Используйте индексированные примитивы (списки треугольников или полосы треугольников). Привязать буфер для указателей, затем использовать glDrawElements и glDrawRangeElements . Имейте в виду, что в OpenGL вы можете использовать четырехугольники - вам не нужно использовать только треугольники.

(4096x4096x64)

Вам не нужно создавать квад для каждого пикселя на карте. Некоторые области абсолютно плоские (то есть высота не изменяется), поэтому добавление дополнительных треугольников приведет к пустой трате ресурсов. Если вы добавите какой-то алгоритм упрощения сетки к готовому ландшафту, вы сможете отбросить довольно много треугольников. Кроме того, слишком много полигонов приведут к проблемам - треугольник или квад должны занимать несколько пикселей. Если есть несколько примитивов, которые должны занимать один и тот же пиксель, результат рендеринга будет немного «шумным». Так что вам придется учитывать желаемый уровень детализации.

Проблема, с которой я сталкиваюсь, заключается в том, что большинство источников заявляют, что размер одного VBO должен составлять от 1 до 4 МБ, и чем меньше VBO, тем лучше.

Я бы не стал доверять каждому источнику, особенно в Интернете. Многие люди, пишущие учебные пособия, далеко не "эксперты". Другое дело, что в DirectX (не OpenGL) рекомендуется по возможности помещать все (т.е. все объекты с совместимым форматом вершин) в один большой статический буфер вершин (аналог VBO) и избегать переключения буферов уменьшить нагрузку на процессор при рендеринге звонков. Так что совет, что «VBO не должно быть больше 4 МБ» выглядит для меня крайне подозрительно.

Информация может быть достоверной только , если она поступает от разработчика API или от разработчика драйверов (ATI или NVidia). Или когда абсолютно уверен, что автор (учебника или статьи) имеет большой опыт в этой области, а не другой бестолковый разработчик игр-подражателей. Документы, которые приходят из GDC, Siggraph, ATI, NVidia, могут быть доверенными. Некоторое учебное пособие, написанное анонимным "кто-то", должно быть проверено на правильность.

В любом случае, в отношении производительности у Microsoft было два документа: «Основные проблемы заголовков Windows» «Оптимизация производительности (Direct3D 9)» (DirectX, но некоторые советы могут быть применимы к OpenGL).

Кроме того, NVidia имеет коллекцию ресурсов OpenGL , которые включают служебные программы, связанные с производительностью ( GLexpert может быть вам полезно, а также есть NVIdia OpenGL SDK и т. Д.). В общем, когда вы пытаетесь улучшить производительность, попробуйте другие методы и измерьте результаты, а не слепо следуйте чьему-либо совету. Посмотрите, сколько дополнительных кадров в секунду вы получаете, используя ту или иную технику.

Тем не менее, согласно моим расчетам, хранение каждой вершины заняло бы около гигабайта данных! (4096x4096x64)

Это правильно, если вы построите всю карту таким образом. Но нет никакой причины загружать всю карту сразу, поэтому вам просто нужен сразу видимый кусок карты.

Я смотрю на такие игры, как Oblivion или Fallout 3, и, в некоторой степени, на Boundless Planet, и вижу огромные ландшафты, и удивляюсь, как на земле это может быть возможно.

Они не загружают все сразу.В любой момент времени загружаются только видимые объекты, текущий «кусок» ландшафта и низкополигональная версия нескольких кусков близлежащего ландшафта.В игре хранятся только те объекты, которые используются в настоящее время или будут использоваться в ближайшее время.Он постоянно получает данные с жесткого диска.

1 голос
/ 10 июля 2010

Я подозреваю, что вы не используете карты высот, как предполагалось.У вас есть изображение 4096x4096, которое представляет собой массив пикселей, , не предназначенный для использования в качестве вершин .Весь смысл сохранения высот в текстуре (она же карта высот) состоит в том, чтобы избежать такого уровня детализации в геометрии (то есть в буферах вершин).

Точная техника использования зависит от вашего контекста.Если рельеф предназначен только для визуализации, я бы рекомендовал представить его на одном квадре ( 4 вершины ) и использовать шейдеры, такие как карты освещения , отображение смещения или отображение параллакса .Если он предназначен для некоторого взаимодействия с другими объектами (например, персонажами, идущими по нему), то некоторая геометрия в порядке - но определенно не 4096x4096. Вот один из способов адаптивной выборки карты высот по локальному уровню детализации.

1 голос
/ 10 июля 2010

Как уже упоминалось, размер вершины в VBO зависит от формата вашей вершины, поэтому нет фиксированного формата и, следовательно, размер не является фиксированным. Статистика по оптимальным размерам VBO, как правило, устарела, не ожидайте, что вы сделаете это правильно в первый раз, просто поиграйте с размером и профилем, это не займет у вас так много времени.

О том, сколько VBO у вас может быть, да для многих VBO означает много дро-коллов. Также никто не сказал, что вы уничтожили их полностью, вы можете использовать их столько раз, сколько захотите.

То, что вы думали о том, чтобы иметь какой-то алгоритм поискового вызова, совсем не плохо, есть один хорошо известный алгоритм рендеринга ландшафта, который использует этот подход, называемый Chunked LOD . Этот алгоритм использует отдельный поток подкачки для рендеринга статического ландшафта вне ядра.

Не пытайтесь найти совершенное идеальное решение, учитесь принимать несовершенство. Не полагайтесь на то, что кто-либо даст вам ответ или все детали, просто сделайте это сами и посмотрите. Вы всегда можете выполнить рефакторинг и / или оптимизировать позже, когда это действительно станет проблемой, иначе вы никогда не закончите.

1 голос
/ 10 июля 2010

Размер вершины определяет, сколько места она займет в буфере вершин. Если ваша вершина состоит только из трехмерной позиции, у вас будет 12 байтов на вершину.

Это не означает, что каждая вершина может нуждаться в хранении несколько раз для каждого треугольника.

Вы можете индексировать свои данные, используя буфер индекса, чтобы исключить необходимость дублирования вершин.

другое решение, на которое я обратил внимание, - это перелистывание данных с жесткого диска во время работы программы, но другой источник говорит, что создавать и уничтожать во время работы программы - плохая идея, и что также лучше иметь несколько VBO, насколько это возможно.

Да, создание и уничтожение будут отрицательно влиять на производительность, но не так сильно, как наличие огромного буфера вершин. Если вы хотите иметь огромный ландшафт; путь / загрузка меньших частей данных о местности в течение всего пути.

Я уверен, что я делаю какой-то массивный надзор здесь, потому что максимальный размер VBO в 4 МБ кажется крайне низким, даже если я загружал текстуру в блоках 64x64 и различные интерактивные объекты, которые заполняли карта тоже.

Если вы используете вершину, которая имеет 64 байта; 4MB покупает вам 65536 вершин. (256х256) Этого должно быть достаточно для чего угодно, и если вам нужно больше вершин, вы разделяете их на несколько буферов вершин.

Отказ от ответственности: Лично я только недавно начал использовать OpenGL, и не очень помогу ответить на конкретные вопросы OpenGL.

0 голосов
/ 13 января 2011

Не уверен насчет некоторых из этих вещей, но, насколько я понимаю, вы можете иметь любой размер vbo, используя 1 vbo для текстуры, даже если данные модели и текстуры охватывают несколько частей нескольких объектов. Может быть перепутано однако.

http://www.swiftless.com/tutorials/opengl/6_vbo.html

0 голосов
/ 10 июля 2010

Если вы вводите / выводите данные, вам понадобится как минимум 4 VBO на случай, если вы рендерите около границы «четырех углов». Но когда вы перемещаетесь, вы можете заменить данные в этих четырех VBO вместо того, чтобы создавать / освобождать их все время. Для этого метода вы должны использовать один из «динамических» флагов использования, чтобы позволить OpenGL знать, что данные могут изменяться, но они будут использоваться более одного раза каждый раз.

...