Гладкий Воксель Terrain

13

В качестве личного проекта я пытаюсь создать генератор ландшафта, который создаст ландшафт, похожий на гладкий ландшафт Castle Story.

Если вы не видели этого раньше, здесь: введите описание изображения здесь

Как видите, это комбинация блоков и «гладких» блоков.

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

введите описание изображения здесь

Проблема в том, что каждый блок имеет размер 1x1x1, но иногда высота в определенном месте отрицательна или> 1. В этом случае я обрезаю его и устанавливаю высоту 0 или 1.

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

Чтобы сгенерировать высоту, я в основном делаю:

genColumn(int x, int z)
{
    int highestBlockY = (int)noise2d(x, z);

    bool is_surface = true;

    for(int y = max_height - 1; y >= 0; y--)
    {
        Block b;

        if(is_surface)
        {
            b = Block.Grass;
            b.HasHeightMap = true;

            // generate heightmap
            for(int ix = 0; ix < 5; ix++)
            {
                for(int iz = 0; iz < 5; iz++)
                {
                    float heightHere = noise2d(x + ix / 4, z + iz / 4) - y;

                    // clip heights
                    if(heightHere > 1)
                        heightHere = 1;

                    if(heightHere < 0)
                        heightHere = 0;

                    b.HeightMap[ix][iz] = heightHere;
                }
            }

            is_surface = false;
        }
        else
        {
            b = Block.Dirt;
        }

        setBlock(x, y, z, b);
    }
}

Возможно, я неправильно подхожу к этому, используя «истинное» значение шума Перлина?

Любая помощь будет принята с благодарностью!

без названия
источник

Ответы:

11

Castle Story выглядит следующим образом из-за технических ограничений: если бы для каждого вокселя была целая карта высот во всем томе, а не только карта высот для каждого вокселя поверхности , стоимость хранения была бы значительно выше, порядка O (n ^ 3 ), который может быть запретительным, в отличие от более благоприятного O (n ^ 2), где n - длина стороны кубического воксельного пространства, представляющего ваш мир. Имейте в виду, что информация карты высот для подземных вокселей неявно присутствует в структуре сетки, поэтому информация карты высот необходимо явно хранить только для тех вокселей, которые лежат на поверхности. Так что ребята из Castle Story привязали вершины к междоузлиям сетки, чтобы сэкономить на стоимости хранения и сложности построения сетки ... читайте дальше.

Прежде всего, давайте посмотрим на ваши варианты:

введите описание изображения здесь

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

(2) Возможно, это лучший вариант; это означает, что угловые вершины привязываются к междоузлиям сетки вокселей. Но как тогда мы решаем проблему экстремального уклона? Ну, нам нужно выбрать некоторый градиент, где мы просто привязываемся к вертикальному столбцу и, таким образом, гарантируем, что у нас нет градиентов, которые могли бы пересечь n верхних вокселей. Градиент в 45 градусов - это естественное ограничение по причинам, которые я объясню ниже. Таким образом, вместо (3) у нас будет (4):

введите описание изображения здесь

(4) Решением является привязка угловой вершины вокселя к ближайшему междоузлию сетки. Визуальный эффект - диагональный псевдоним - можно увидеть на скриншоте Castle Story. Наклон среза для вокселей составляет 1: 1 или 45 градусов (если смотреть ортогонально). Работая в обратном направлении от решения, давайте посмотрим на причины:

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

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

инженер
источник
Я просто попытался реализовать это, и я столкнулся с некоторой путаницей - что вы подразумеваете под "междоузлиями"? Вы имеете в виду интегральные координаты сетки?
без названия
@ThomasBradworth. «Пространство, которое вмешивается между вещами». Для 2D, если у вас есть тревожная сетка ячеек, у вас будет (n + 1) x (n + 1) междоузлия. Это распространяется непосредственно на 3D. Это «вершины», которые ограничивают каждую ячейку, которые в основном распределяются между несколькими ячейками / вокселями. Если свести его к 1D (линия), то если и ячейки, и промежутки представлены в виде массива, то ячейка 0 ограничена промежутком 0 и промежутком 1, а ячейка 1 ограничена промежутком 1 и промежутком 2 ... и т. д.
инженер
Спасибо за ответ! Я пытался сделать именно это, но я получил некоторые неблагоприятные результаты. Сначала я попытался просто округлить значения высоты по краям (когда x равен 0 или 4, или z равно 0 или 4), но это меня достало : i.imgur.com/eQW7Y.png ( pastebin.com/Lr8vyyHB ) Затем я попытался сгладить точки посередине, поэтому я добавил «функцию исправления высоты»: pastebin.com/AazQ07Xm Это, однако, также дало мне более угловатый, но и плохой результат: i.imgur.com/q1JVP .png Возможно, что-то не так с моей шумовой функцией?
без названия
@ThomasBradsworth К сожалению, я чувствую, что вы только наполовину прочитали / поняли ответ, который я написал более часа, чтобы написать и отредактировать. Забыть шум; более того, если вы не понимаете функцию шума, удалите ее из уравнения на данный момент. Ваша проблема заключается в том, как создаются отдельные данные воксельной сетки, и шум не имеет к этому никакого отношения, потому что вы можете создать карту высот в отсутствие шума. Работайте с самым простым тестовым примером, то есть жестко закодируйте массив высоты. Затем просмотрите свои результаты и настройте алгоритм генерации сетки. Повторяйте, пока он не сделает то, что ожидалось. Затем вставьте шум обратно и проверьте.
инженер
Вы говорите, что я должен просто хранить значения высоты для углов, а не хранить значения высоты "промежуточных" точек?
без названия