Voxel Face Crawling (упрощение сетки, возможно использование жадного алгоритма)

9

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

Это касается Minecraft-подобного двигателя местности. Я храню блоки в блоках (блоки 16x256x16 в блоках). Когда я генерирую кусок, я использую несколько процедурных методов, чтобы установить ландшафт и разместить объекты. При генерации я сохраняю один одномерный массив для полного блока (сплошной или нет) и отдельный одномерный массив сплошных блоков.

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

Используя 2D-атлас с этим маленьким трюком шейдера, предложил Эндрю Рассел, я хочу полностью объединить похожие лица. То есть, если они находятся в одном и том же списке (одинаково нормально), находятся рядом друг с другом, имеют одинаковый уровень освещенности и т. Д. Я знаю, что я все равно получу прямоугольники, но это должно легко уменьшить количество моих вершин на 50% или лучше, если мои оценки верны.

Я предполагаю, что каждый из 6 списков будет отсортирован по оси, на которой они лежат, а затем по двум другим осям (список для верхней части блока будет отсортирован по его значению Y, затем X, затем Z).

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

Итак, мой вопрос: чтобы выполнить объединение граней, как описано (игнорируя, является ли это плохой идеей для динамического рельефа / освещения), есть ли алгоритм, который проще реализовать? Я также с радостью приму ответ, который проведет меня по жадному алгоритму гораздо проще (ссылка или объяснение).

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

PS: Я уже отбираю фрустум на кусок и, как описано, я также отбираю грани между сплошными блоками. У меня пока нет окклюзии и, возможно, никогда.

* Редактировать: я реализовал свою собственную маленькую технику, которая, вероятно, имеет имя, но я просто просматриваю свои 6 списков, которые отсортированы по осям, на которых они лежат, затем по типу блока и затем по уровню освещения. Я перебираю их, создавая новые прямоугольники по мере того, как иду и расту их одновременно (с сильным уклоном к определенной оси). Это определенно не оптимально, но это действительно довольно быстро, и это уменьшает мое количество вершин в среднем почти на 50%. Комментарий Byte56 - это шкаф, который я считаю реальным ответом, но я не могу выбрать его для ответа / награды.

Вот мой быстрый и упрощенный способ решения этой проблемы ПОСЛЕ генерации полной начальной местности без какой-либо оптимизации. Предполагая, что все приведенные квадраты - это одно и то же изображение, уровень освещенности, нормаль и т. Д., Каждый цвет - это отдельный квад, который я бы отрисовал. С моими списками, отсортированными так, как они есть, это очень простой / быстрый подход.

Mythics
источник
После всех ваших оптимизаций вы все еще сталкиваетесь с проблемами производительности? Вы пробовали профилировать код, чтобы увидеть, где проблемы?
MichaelHouse
@ Byte56 О, это определенно не проблема производительности вообще. Это может произойти в будущем, когда я попытаюсь использовать то, что я учусь, для настоящей игры. Хотя сейчас я просто хочу учиться. Я не утверждал ничего из этого, потому что мне кажется, что мне меньше помогают, если я просто хочу изучать вещи, просто изучая их.
Мифы
Я чувствую, что должен также сказать, что если я действительно попытаюсь сделать правильную игру с этим, я хочу, чтобы видимый мир был ОГРОМНЫМ. Я бы не хотел, чтобы у персонажа было 2 блока в высоту и 1 блок в ширину, как в Minecraft и многих других, но больше как в 3 блоках в ширину / в длину и 6-9 в высоту. Вероятно, статическая местность, хотя.
Мифы
1
Ах, хорошо, Тим. Спасибо за объяснение. Я провел некоторые исследования в этой области, когда создавал движок для своей игры. Поскольку мой ландшафт динамичен, я не думал, что это будет стоить затрат на производительность каждый раз, когда что-то меняется. Тем не менее, вы можете найти некоторую пользу из этой статьи о проблеме максимального прямоугольника. По сути, это алгоритм, о котором вы говорите, для объединения похожих лиц (возможно, не жадный, но оптимальный). Удачи!
MichaelHouse
@ Byte56 Спасибо, я очень ценю это. Это, конечно, выглядит ближе к тому алгоритму, который я ищу, если не на месте. Мне придется немного повозиться с этим, чтобы посмотреть, смогу ли я получить все максимальные прямоугольники за один проход. Я также могу немного выиграть за это, так как думаю, что и вопрос, и подробный ответ могут помочь многим другим в будущем.
Мифы

Ответы:

4

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

Я также хотел бы отметить, что, сохраняя 6 списков на блок, вы в любой момент будете использовать 5 списков из блоков в основных направлениях и по крайней мере 3 в каждом другом. Вы тратите время здесь, когда не только видеокарта может выполнить эту оптимизацию для вас, но даже если вы сделали это самостоятельно, вам было бы лучше хранить все лица в одном месте и сравнивать нормаль к направлению с камера (исследование DOT произведения векторов).

Ссылки CaptainRedMuff на Greedy Mesh, которые вы уже видели, являются ответом на вашу проблему. Из этого также должно быть очевидно, что у вас получатся «полосатые» сетки, но они будут совершенно эффективными, а создание чего-то более оптимального будет более сложным, и вы уже говорили, что жадная сетка уже слишком сложна.

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

Моим первым предположением будет то, что вы слишком часто вызываете операцию рисования. Вы можете указать графической карте рисовать только от 50 до 400 раз в секунду, в зависимости от аппаратного обеспечения. Сколько звонков вы делаете в .setData или .draw ____ Примитивы?

Фил
источник
Прямоугольники - это то, что я хочу. Byte56 связал алгоритм намного проще, чем жадный, но я не могу принять комментарий в качестве ответа. Я предположил, что он прокомментировал вместо этого, потому что он только связывался с алгоритмом, а не объяснял его. Я не знаю, что вы имеете в виду относительно моих списков. У меня обычно есть 1-2 звонка на чанк. Мои списки хранятся в одном буфере на чанк. Я изменяю, какие диапазоны рисовать на кадр. Я могу ошибаться, но отправка ненужных данных в графический процессор кажется контрпродуктивной. Дополнительная дро или две на чанк кажутся лучше, чем отправка большего количества данных в gpu и принудительная выборка.
Мифы
У меня нет проблем с производительностью. Мне просто нравится изучать эти вещи. Я отредактирую свой вопрос, чтобы сказать это, но, как я уже сказал Byte56, я получаю меньше помощи, если то, что я пытаюсь сделать, на самом деле не решает проблему. Чтобы ответить на ваш вопрос, в настоящее время я отрисовываю не более 200-260 блоков на кадр. Это довольно распространенные 500ish DrawIndexedPrimitives на кадр. Я регулярно получаю 100-130 FPS без vsync, делая 65 000 вызовов в секунду. Я не пытаюсь быть грубым, но мало что ты сказал, имеет смысл для меня. Возможно, я не понимаю, поэтому, пожалуйста, уточните, если я неправильно понял. Может быть, это связано с XNA?
Мифы
Ах, извините, я хотел сказать за кадр, а не за секунду. Вы приближаетесь к верхнему пределу, и если вы находитесь только на местности, у вас почти все кончено.
Фил
Я добавил +1 к вашему ответу, так как он заставил меня задуматься о нескольких улучшениях, которые я мог сделать, но не имел никакого отношения к вопросу. Кроме того, я подумал, что должен поделиться ответом Натана Рида о возможной ссылке на
лимитный
Я должен найти статью, которую я прочитал, которая цитирует 400-500 как предел. Быстрый Google не помог мне.
Фил
0

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

В целом, однако, статья дает хорошее резюме: 1) наивное решение плохое, 2) есть оптимальное решение, но оно будет и трудоемким, чтобы писать и запускать, 3) быстрый отбор дает гораздо лучшие результаты ( и это все, что делает сам Minecraft), и, наконец, 4) может быть более разумное решение (жадный алгоритм).

«Решение», которое вы подразумеваете на изображении в своем вопросе, - это жадный алгоритм. Кажется, твой вопрос "правильно ли я реализовал его решение?" на что я должен ответить «он не дал решения; ты просто решил это сам».

Может ли ваше решение быть лучше? Мех. Конечно. Наверное, не стоит. Я думаю, что отбор окклюзии или LOD будет лучше в следующих шагах. Minecraft тратит большое количество циклов, рисуя поверхность, даже когда вы находитесь под землей, а также рисуя обширные сети пещерных и шахтных систем, когда вы находитесь на поверхности. Как только у вас получится хорошее разбиение сетки, да, избавление от затененных поверхностей может быть хорошей вещью - но (например), как правило, быстрее позволить вашей видеокарте отбирать заднюю поверхность, чем делать это на процессоре.

Andrews
источник