Как сделать удаление лица в мире юнит-куба a la Minecraft? - PullRequest
17 голосов
/ 12 июня 2011

Важное примечание: Этот вопрос НЕ о отбраковке геометрии (отбраковке по ребрам, отбраковке спины, окклюзии или о ком-либо из их друзей.) время, задолго до того, как мы перейдем к выбраковке и рендерингу.

В мире визуализации единичного куба ( a la MineCraft) я пытаюсь найти алгоритмы удаления из моего списка геометрических граней, которые невозможно увидеть под любым углом, независимо от того, где находится камера.

Например, представьте 2 квадрата:

+----+      +----+
|    |      |    |
|    |      |    |
+----+      +----+

ясно, что есть 8 видимых сторон (4 на каждом квадрате). Теперь я сдвигаю квадраты вместе, vis :

+----+----+
|         |
|         |
+----+----+

Вместо того, чтобы иметь 8 сторон, теперь у меня только 6! Два элемента, которые соприкасаются посередине, не видны, независимо от того, где находится камера и под каким углом она расположена. (Квадраты текстурированы по-разному, поэтому мы не можем назвать это 4 сторонами.)

(То же самое работает в 3D с кубами, но 12 граней (6 на куб) становятся 10, так как устраняются 2 касания.)

Мой вопрос: какие алгоритмы помогают мне распознать эти скрытые лица? (Я счастлив сделать свой собственный поиск в Google, но я даже не знаю, как это называется!) В частности, я ищу что-то, что обрабатывает полые пятна в средних точках, которые МОГУТ быть видны, если бы вы были там, но, поскольку они окружены геометрией, вы не можете их видеть.

Например:

+----+----+----+----+
|                   |
|                   |
+    +----+         +
|    |    |         |
|    | A  |         |
+    +----+         +
|                   |
|                   |
+----+----+----+----+

В этом случае можно подумать, что существует 18 «видимых» сторон, но, поскольку мы точно знаем, что камера находится за пределами геометрии, 4 стороны в квадрате «А» не видны.

Чтобы еще больше усложнить ситуацию, я надеюсь найти алгоритм, который может быстро обновлять, если блок добавляется или удаляется (снова а-ля MineCraft.)

Спасибо!

1 Ответ

22 голосов
/ 12 июня 2011

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

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

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

Более сложная проблема - удаление запечатанных интерьеров. Мое предложение: оно того не стоит. При попытке удалить запечатанные интерьеры, размещение или удаление блока становится нелокальной операцией. Вероятно, вы бы повысили производительность, потратив время на оптимизацию количества пакетов (по возможности используйте текстовые атласы / массивы) и данные вершин.

Чтобы удалить запечатанные интерьеры, вы должны быть в состоянии обнаружить интерьеры. И поэтому вам нужно будет поддерживать двунаправленный график смежных граней. Для каждого лица у него будет четыре смежных лица. Лица, которые были отбракованы из-за того, что они находились между двумя смежными кубами (ранее назывались «мертвыми лицами»), не должны быть частью графика.

Когда куб помещается, вы должны обновить информацию о смежности для графа лица. Мертвые лица должны быть удалены. Смежность для живых граней после размещения должна включать новые лица, которые были добавлены из-за нового блока, который был размещен. Алгоритм для этого должен быть довольно простым, если вы сядете и наметите возможности. Например, если у вас есть этот квадрат:

  A
+++++
+   +
+   + B
+   +
+++++

Грани А и В смежны. Если вы размещаете новый блок, вы меняете смежность:

     +++++
     +   +
   C +   +
     +   +
  A  +++++
+++++  D
+   +
+   + B
+   +
+++++

A теперь находится рядом с C и B рядом с D.

Когда куб удален, вы должны снова обновить информацию о смежности для грани лица. По сути, вы должны отменить предыдущую операцию.

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

Большой вопрос заключается в следующем: как вы находите видимый цикл? Следующий алгоритм предполагает, что блоки размещаются / удаляются объектом. Это означает, что по крайней мере одна грань любого размещенного блока является видимой. Это также означает, что любые мертвые лица, которые становятся живыми после удаления блока, видны.

Когда вы размещаете блок, вы можете создать один или несколько новых циклов граней. Чтобы обнаружить это, вы сначала находите все не мертвые лица (те, которые непосредственно не примыкают к чему-либо), которые вы создали, разместив блок. По крайней мере один из них будет виден; найди это лицо.

Затем для каждого другого не мертвого лица в новом блоке используйте поиск по графику A * (A-star), чтобы найти это лицо. A * - алгоритм поиска графа на основе очереди приоритетов. В этом случае «расстояние» для алгоритма - это расстояние между квадратом, на котором находится текущая грань, и квадратом, на котором находится видимая грань.

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

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

Теперь, если вы можете телепортировать блоки, все становится более сложным. Когда вы размещаете блок, есть вероятность, что ни одна из граней этого блока не видна. Так что вам нужно найти лицо где-то в видимом мире. Затем сделайте свой A *, ищущий к этому лицу, как обычно. Было бы хорошо, если бы видимое лицо было где-то поблизости, поэтому поиск не должен был заходить слишком далеко.

При удалении вам нужно найти все невидимые циклы граней рядом с блоком. Тогда вам нужно найти это видимое лицо, как и раньше. Затем вы удаляете блок и просматриваете эти циклы с помощью A *, чтобы увидеть, могут ли они найти видимое лицо. Те циклы, которые могут быть видны. Те циклы, которые не могут быть не видны.

Кроме того, вам нужно иметь специальный случай для удаления блока, у которого не было живых граней (то есть: он полностью встроен в другие блоки). Это создает 6-гранный цикл, который невидим.

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

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

...