Вид с высоты 1.5 метра

Недавно начал переделку ландшафтного движка. Сподвигло на это все та же работа над интеграцией новой классификации планет. Дело в том, что процедурный генератор использует специальный файл palette.cfg для назначения "раскраски" (палитры) генерируемым планетам. Для каждого класса планет в файле описаны несколько "пресетов" - различных вариантов раскраски. Изменение системы классов повлекло необходимость изменить и этот файл. Но я решил сделать лучше, полностью пересмотрев систему пресетов и устранив существующие недостатки. Есть известные сложности с моддингом палитр - мод может только заменить весь файл целиком, нельзя просто добавить новый пресет к уже существующим. Расстановка вероятностей выбора того или иного пресета в файле - тоже дело хлопотное. Кроме палитры, движок назначает каждой планете набор текстур, которые используются для генерации самых мелких деталей на поверхности: камни, песок, трава, скалы и т.д. Но это назначение жёстко задано в коде - извне (из мода) изменить правила невозможно. Сами детальные текстуры хранятся в текстурном атласе planet_atlas.png - только его модификация позволяет влиять на вид поверхности планеты вблизи.

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

Поменялась также система биомов (типов поверхности). Раньше были только восемь биомов: sea, shelf, beach, desert, lowland, upland, rock, snow, которые назначались по порядку в зависимости от локального климата, который, в свою очередь, зависел от широты, высоты и плотности атмосферы. Поэтому переход от пустыни сразу к снегу был невозможен - между ними всегда наблюдались полоски промежуточных биомов (lowland, upland, rock). Теперь биомы независимы друг от друга, назначаются они в шейдере, который генерирует текстуры. Шейдер ведь знает, что он создаёт в данной точке - пустыню, горы, пляж или полярную шапку, поэтому может назначить биом принудительно. Некоторые биомы модифицируют (перекрывают) предыдущие - например, снег или трава. Переход между биомами всё ещё ограничен - в одной точке не может пересекаться слишком много биомов, поэтому я сделал переход через некий "стандартный" биом (каменистая поверхность нейтрального цвета). Но новая система шейдеров ещё в процессе разработки, так что это может поменяться в дальнейшем.

Самих биомов теперь гораздо больше, и каждому из них можно назначить свой цвет и 16 различных детальных текстур. Текстуры используются таким образом: 4 уровня наклона (от горизонтальной поверхности до отвесной стены) по 4 "слоя" текстур в каждом. Слои или уровни - это текстуры, накладывающиеся на поверхность на разных масштабах. Первые два "крупномасштабных" уровня задают детали разрешением вплоть до 10 метров на пиксель. Это то, что было в SE до сих пор, но смотрелось несколько странно (галька и травинки размером в десятки метров), в силу технических ограничений движка (вещественные числа одинарной точности, используемые в шейдерах, не позволяют генерировать детали меньше примерно десяти метров на планете размером с Землю). Теперь к этим генерируемым деталям добавляются ещё два слоя текстур, накладываемых непосредственно шейдером, который рисует планету (в предыдущей версии SE это был просто небольшой шум). Это позволяет достичь детализации поверхности вплоть до миллиметров, несмотря на то, что детализация геометрии и генерируемых текстур осталась прежней - до 10 метров треугольник/пиксель. В дальнейших планах реализовать дополнительную локальную тесселяцию, чтобы сделать геометрию более гладкой или детализированной.

А для "верхних" двух слоёв детальных текстур теперь можно использовать текстуры, сделанные из реальных снимков Земли и Марса:

Попытка наложить текстуру пустыни, взятой со спутникового снимка Земли

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

Для освещения используются карты нормалей. В будущем планирую реализовать POM (Parallax Occlusion Mapping) для придания объёма деталям вроде камней. Некоторые текстуры, например снег и лёд, имеют повышенный уровень отражения (specular):

Блестящий снег, или, скорее, ледяная корка

Для устранения сильно бросающегося в глаза тайлинга (повторяемости узора), применяется метод случайного сдвига текстурных координат в пределах случайных ячеек разбиения Вороного, но он, к сожалению, весьма ресурсоёмок. Детальные текстуры довольно сильно влияют на производительность. Будет несколько вариантов настроек качества, в том числе их полное отключение. К счастью, детальные текстуры видны только совсем вблизи, на расстояниях до 100 метров, поэтому для более далёких участков ландшафта и для видов из космоса можно использовать другой, более быстрый шейдер, который не накладывает детальные текстуры.

Для передачи информации о коде биома и кодах текстур, которые нужно накладывать, шейдеры-генераторы создают дополнительные текстуры, в добавок к текстурам цвета и нормалей. Я пока что экспериментирую с разными подходами - передавать только код биома и вычислять все остальное на ходу (всего один байт на пиксель дополнительной памяти, но большая нагрузка на шейдер рендера планеты), либо передавать коды текстур и их коэффициенты смешивания (8-16 байт на пиксель дополнительной памяти, но шейдер легче и быстрее). В любом случае, использования дополнительной памяти не избежать, но оно того стоит. К счастью, здесь тоже помогает тот факт, что эти дополнительные "текстуры материалов" нужны только для самых детальных (близких) патчей ландшафта.

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

Устранение пикселизации базовой текстуры, детальные текстуры отключены

Для моддинга появляются широкие возможности. Для своей планеты можно либо использовать один из существующих пресетов цветов и текстур биомов, либо отредактировать их по своему вкусу. В редактор планет встроен интерфейс для этого: можно выбрать текстуру для каждого из четырёх наклонов и четырёх слоев каждого биома (сам биом выбирается в выпадающем списке). Выбор возможен только среди ограниченного набора текстур - тех, что лежат в папке детальных текстур (data/common/tiles/). Сейчас там находится старый атлас, разрезанный на отдельные тайлы разрешением 256*256 (их аж 128 штук). Но к релизу я планирую перейти на текстуры разрешением 1024*1024 и даже больше, но их число придётся уменьшить. Моддеры конечно же смогут добавлять свои текстуры, на надо помнить о памяти, которую они занимают, и о их разрешении (оно должно быть одинаковым для всех текстур - это ограничение текстурных массивов OpenGL). Текстуры конечно же должны быть зациклены (seamless).

Сверху над табличкой с текстурами биома - старый выбор палитры, не обращайте внимания, просто я ещё не полностью перешёл на новую систему. А ещё выше - кнопки для загрузки и сохранения пресета: свой настроенный пресет можно сохранить, и он начнёт использоваться при процедурной генерации планет. Для назначения вероятности появления планеты с данным пресетом используется понятие веса. Вероятность - это вес, поделённый на сумму весов всех пресетов для планет данного класса (например, "temperate marine terra"). Например, если есть три пресета с весом 1, и ещё два с весом 0.5, то вероятность первых трёх будет 1/4, а последних двух - 1/8.

Обсудить пост можно на форуме.