Как загрузить куски укладки на лету?


8

В настоящее время я работаю над бесконечным миром, в основном вдохновленным Minecraft. Кусок состоит из 16x16x16 блоков. Блок (куб) имеет размер 1x1x1.

Это работает очень гладко с ViewRange из 12 блоков (12x16) на моем компьютере. Хорошо.
Когда я изменяю высоту чанка на 256, это становится - очевидно - невероятно медленным.

Итак, что я в основном хочу сделать - это сложить куски. Это означает, что мой мир может быть [∞, 16, ∞] Большие куски.

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

Как важной стороне записки здесь: Я тоже хочу иметь биомы, с различными мин / макс высоты. Таким образом, в равнинах Биома самый высокий слой с блоками будет 8 (8x16) - в горах Биома самый высокий слой с блоками будет 14 (14x16). Просто в качестве примера.

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




Переходы между биомами




Моя текущая загрузка чанка в действии

Пример загрузки чанка



Для полноты здесь мой текущий блок загрузки "алгоритм"

private IEnumerator UpdateChunks(){
    for (int i = 1; i < VIEW_RANGE; i += ChunkWidth) {
        float vr = i;
        for (float x = transform.position.x - vr; x < transform.position.x + vr; x += ChunkWidth) {
            for (float z = transform.position.z - vr; z < transform.position.z + vr; z += ChunkWidth) {

                _pos.Set(x, 0, z); // no y, yet
                _pos.x = Mathf.Floor(_pos.x/ChunkWidth)*ChunkWidth;
                _pos.z = Mathf.Floor(_pos.z/ChunkWidth)*ChunkWidth;

                Chunk chunk = Chunk.FindChunk(_pos);

                // If Chunk is already created, continue
                if (chunk != null)
                    continue;

                // Create a new Chunk..
                chunk = (Chunk) Instantiate(ChunkFab, _pos, Quaternion.identity);
            }
        }
        // Skip to next frame
        yield return 0;
    }
}

Ответы:


1

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

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

Допустим, ваш мир будет иметь высоту 256 чанков (* 16 = 4096 блоков вокселей), и в любой момент, если стек находится в пределах диапазона просмотра, в этом стеке будет фактически загружено от 1 до 3 чанков, которые будут рендериться.

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


0

То, что вы можете сделать, это сделать кусок 256 высотой в направлении y и разделить его на 16 секций, каждая из которых имеет высоту 16 блоков. Затем вы генерируете данные для чанка и строите геометрию внутри секций.

Одним из преимуществ будет то, что у вас есть доступ к данным полного блока, что облегчает доступ к данным выше и ниже раздела.

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

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


1
Ну, может быть, я объяснил себя немного расплывчато. Я уже запланировал разделить один кусок на 16 слоев. Но как мне решить, какие слои загрузить? Каждый биом имеет свою собственную минимальную / максимальную высоту. Представьте себе Биом А [100,20] Биом В [160,200] - я на грани обоих биомов. У них плавный переход. Как решить, какие слои загрузить? Но когда я пишу это, я думаю, что мне просто нужно проверить каждый слой (сверху вниз) и создать его, когда слой выше будет пустым / прозрачным - и остановиться, когда будет создан первый слой. Надеюсь, вы получите это;) Это раздражает, что вы не можете добавлять пустые строки в комментарии
Brettetete

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

Эта техника просто потрясающая. Я постараюсь реализовать это в моем движке. Данный код немного странный, вы бы поделились своей реализацией? :)
Brettetete

2
Я вставил сюда свою реализацию C ++ и добавил несколько комментариев. Надеюсь, это поможет :)
user000user

Круто, это кажется очень полезным. Спасибо! Я постараюсь перевести это сейчас. Но на # 67 - # 68 есть двойной && - вы случайно пропустили / удвоили что-то, чтобы скопировать? :) А не могли бы вы вкратце объяснить / опубликовать методы SHIFT_ ? Также я не вижу никаких заявлений / использования tmp - ну, извините за все эти вопросы
Brettetete

0

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

Я бы хотел хранить метаданные с каждым фрагментом:

1) Является ли блок полностью воздушным. Если так, то нет необходимости делать это.

2) Для каждого лица блока это непрозрачно. Непрозрачное лицо означает, что вам не нужно учитывать следующий кусок. (Тем не менее, обратите внимание, что в зависимости от того, где находится чанк, может быть задействовано до трех граней - чанк должен быть визуализирован, если любое из трех не является непрозрачным. Я подозреваю, что это лучше всего предварительно рассчитать - сделать так долго либо b1 видимый и имеет непрозрачную грань f1, либо b2 видимый имеет непрозрачную грань f2, либо b3 видимый имеет непрозрачную грань f3.)

К сожалению, в пределах 12-ти углового диапазона видимости имеется более 7000 фрагментов. Тем не менее, я ожидал бы, что в нескольких местах будет более трех вертикальных чанков, которые на самом деле нужно рендерить, используя этот подход, который сокращает количество чанков до, вероятно, не более 1500.

Я бы применил такую ​​же логику внутри чанка - когда вы загружаете чанк, вычисляете, какие соединения прозрачны, а какие - непрозрачные, а прикосновения - непрозрачные - вам нужно только визуализировать лица там, где их могут видеть. (Обратите внимание, что в Minecraft у вас есть три типа блоков - прозрачный, непрозрачный и изменяющий зрение - стекло, двери, заборы и т. Д. Вы можете пропустить только прозрачный-прозрачный и непрозрачный-непрозрачный.)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.