Воксельный движок OpenGL медленный

Я делаю воксельный движок на C++ и OpenGL (а-ля Minecraft) и не могу получить приличный fps на моем 3 ГГц с ATI X1600... У меня нет идей.

Когда у меня на экране около 12000 кубов, скорость падает ниже 20 кадров в секунду - жалко.

На данный момент у меня есть следующие оптимизации: отсечение усеченного конуса, отсечение задних граней (через glEnable(GL_CULL_FACE) OpenGL), движок рисует только видимые грани (конечно, кроме отбракованных), и они находятся в октодереве.

Я пробовал VBO, они мне не нравятся, и они не сильно увеличивают fps.

Как движок Minecraft может быть таким быстрым... Я борюсь с 10000 кубов, тогда как Minecraft может легко рисовать гораздо больше при более высокой частоте кадров.

Любые идеи?


person Solenoid    schedule 30.12.2010    source источник
comment
Как вы создаете свою геометрию? Например, если у вас есть блок кубов 3x3x3, вы генерируете/рендерите каждый куб (включая невидимый центральный куб) или анализируете связность и просто генерируете треугольники для внешней, видимой поверхности?   -  person genpfault    schedule 30.12.2010
comment
возможный дубликат методов отбраковки для рендеринга множества кубов   -  person Yakov Galka    schedule 30.12.2010
comment
Когда вы говорите, что пробовали VBO, у вас был один VBO, содержащий единственный куб, который вы использовали glTranslate() повсюду, или вы упаковали целую кучу кубов в один VBO?   -  person genpfault    schedule 30.12.2010
comment
Я не верю, что Minecraft на самом деле отображает более пары тысяч кубов одновременно, а в большинстве игр их может быть 20-30. Тем не менее, относительно современная карта не должна иметь проблем с более чем 12 тысячами кубов.   -  person Puppy    schedule 30.12.2010
comment
@genpfault: я анализирую связь и просто создаю лица для внешней видимой поверхности. У VBO был единственный куб, который я выполнил с помощью glTranslate().   -  person Solenoid    schedule 30.12.2010
comment
Используйте VBO. Они помогут.   -  person Anubian Noob    schedule 23.01.2014
comment
В настоящее время я визуализирую более 80000 вокселей со скоростью 50 кадров в секунду, используя инстансный рендеринг, VBO и VAO. Это действительно имеет значение. Размер партии составляет около 4096 экземпляров одновременно.   -  person StarShine    schedule 17.09.2014


Ответы (5)


Вы должны профилировать свой код, чтобы выяснить, находится ли узкое место в вашем приложении на ЦП или ГП. Например, может случиться так, что ваши алгоритмы отбраковки/восьмистрочного дерева работают медленно, и в этом случае это вообще не проблема OpenGL.

Я бы также подсчитывал количество кубов, которые вы рисуете в каждом кадре, и отображал их на экране. Просто чтобы вы знали, что ваши процедуры отбраковки работают, как и ожидалось.

Наконец, вы не упоминаете, текстурированы ли ваши кубики. Попробуйте использовать текстуры меньшего размера или отключите текстуры и посмотрите, насколько увеличится частота кадров.

gDEBugger — отличный инструмент, который поможет вам найти узкие места в OpenGL.

person Ville Krumlinde    schedule 30.12.2010
comment
Спасибо! Попробую профилировать. Мой подход очень прямолинеен, так как у меня в принципе нет никакого опыта работы с 3D... так что алгоритмы? - person Solenoid; 30.12.2010

@genpfault: я анализирую связь и просто создаю лица для внешней видимой поверхности. У VBO был единственный куб, который я glTranslate()d

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

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

person Matthew Blanchard    schedule 30.12.2010

Я не знаю, можно ли здесь «поднять» старый вопрос, но мне пришло в голову несколько вещей:

Если ваши воксели статичны, вы можете ускорить весь процесс рендеринга, используя октодерево для отбраковки усеченного конуса и т. д. Кроме того, вы также можете скомпилировать статическую сцену в набор потенциальной видимости в октодереве. Основной принцип PVS заключается в предварительном вычислении для каждого узла дерева, какие другие узлы потенциально видны из него, и сохранении указателей на них в векторе. Когда дело доходит до рендеринга, вы сначала проверяете, в каком узле размещена камера, а затем запускаете отсечение усеченной пирамиды для всех узлов в PVS-векторе узла. (Кармак использовал что-то подобное в движках Quake, но с деревьями разделения двоичного пространства)

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

Еще одна вещь, которая определенно ускорит работу, — это использование Instancing. Вы сохраняете только положение каждого вокселя и, при необходимости, его масштаб и другие параметры в объекте текстурного буфера. Затем в вершинном шейдере вы можете прочитать позиции вокселей, которые должны быть созданы, и создать экземпляр вокселя (т. е. куб, который передается шейдеру в объекте вершинного буфера). Таким образом, вы отправляете 8 вершин + 8 нормалей (3 *sizeof(float) *8 +3 *sizeof(float) *8 + float для цвета/текстуры и т. д...) только один раз на карту в VBO, а затем только позиции экземпляров куба (3*sizeof(float)*количество вокселей) в TBO.

Возможно, можно распараллелить вещи между GPU и CPU, объединив все 3 шага в 2 потока, в потоке CPU вы проверяете pvs октодеревьев и обновляете TBO для экземпляра в следующем кадре, поток GPU тем временем выполняет рендеринг 2 проходит при использовании TBO для экземпляра, который был создан потоком ЦП на предыдущем шаге. После этого вы меняете TBO. Если камера не сдвинулась, вам даже не нужно снова выполнять расчеты ЦП.

Еще один тип дерева, который меня заинтересует, — это так называемое k-d-дерево, которое является более общим, чем октодеревья.

PS: извините за мой английский, он не самый чистый....

person gary    schedule 26.04.2012
comment
Я пробовал октодеревья успешно, но у Minecraft есть смысл делать куски, а не октодеревья: вы в основном находитесь на плоскости, и в среднем гораздо больше видимых плоскостей в направлении xy, чем в направлении z, поэтому 2D-сетка требует гораздо меньше вычислений, поскольку выполнять проверку видимости 2D проще. Это что-то действительно специфичное для этой игры. - person Solenoid; 23.05.2012

Существуют сторонние библиотеки, которые можно использовать для повышения эффективности рендеринга. Например, библиотека PolyVox C++ может взять объем и сгенерировать сетку для вас в эффективном способ. Он имеет встроенные методы для уменьшения количества треугольников и помогает создавать такие вещи, как окружающее затенение. Вокруг него хорошее сообщество, поэтому получить поддержку на форуме должно быть легко.

person Milliams    schedule 05.03.2011

Использовали ли вы общий список отображения для всех ваших кубов?
Пропускаете ли вы вызов кода отрисовки кубов, которые не видны пользователю?

person rlods    schedule 30.12.2010
comment
Да, каждая грань находится в списке отображения, и каждый куб содержит данные о том, какие грани рисовать, и положение куба (glTranslatef, а затем glCallList). Кроме того, часть рисования пропускается, когда куб не отображается, благодаря октодереву. - person Solenoid; 30.12.2010
comment
Я думаю, что куб (а не грань) должен быть в списке отображения. - person rlods; 30.12.2010
comment
В этом случае я буду рисовать все грани несмотря ни на что, даже те, что между 2-мя кубами (не видны), что требует еще больше ресурсов. - person Solenoid; 30.12.2010