Продолжаю работу над обновлённым ландшафтным движком. Сегодня расскажу подробнее про детальные текстуры.

До сих пор для текстурирования ландшафта SE генерирвовал или загружал с диска 4 вида текстур для каждого блока рельефа (буду называть их "картами", чтобы не запутать): карту высот, нормалей, альбедо (цвета) и, опционально, карту свечения городов/вулканов. Теперь для последних уровней quadtree генерируются ещё и т.н. splat карты, указывающие, какие материалы (детальные текстуры) и как накладывать в данной точке поверхности. Texture splatting - это техника, повсеместно используемая при рендере ландшафтов в различных игровых движках. Каждый пиксель splat карты обычно содержит 4 веса для 4 материалов, например камней, песка, травы, снега. Т.е. в каждой точке ландшафта могут одновременно накладываться до 5 различных материалов (пятый - это некий "дефолтный" материал, который проступает, когда все 4 веса около нуля).

Но 5 различных материалов на всю планету - маловато. Поэтому, кроме карты весов, нужна ещё карта с индексами (id) материалов. Т.е. в каждой точке всё ещё можно одновременно использовать не более 4+1 материалов, но эти комбинации в разных местах планеты могут быть разными. Всего различных материалов может быть до 256 (четыре 8-битных id), или 64 (пять 6-битных id, если хочется варьировать ещё и "дефолтный"). В реальности 256 это чересчур много, текстуры материалов ведь занимают определённую память; 64 выглядит вполне достаточным количеством. Для увеличения разнообразия между планетами можно для каждой из них использовать свой набор из 64 материалов, загружая их текстуры по мере надобности в один и тот же массив. Т.е. одновременно два набора использовать будет нельзя. Всё равно ситуация, когда очень близко видна поверхность одновременно двух планет, не должна встречаться (если только кто-то не сделает мод, в котором одна планета катится по другой -)) ).

Старый набор из 128 текстур с низким разрешением 256 x 256 заменён на новый разрешением 1024 x 1024 (пока я насобирал 4 десятка бесплатных текстур из разных источников). Даже со сжатием, одна текстура займёт в памяти 5 Мб (самом деле, это две текстуры - цвета и нормалей с displacement картой в альфа-канале). Набор из 64 сжатых текстур займёт 320 Мб, вполне терпимо (256 штук заняли бы более гигабайта).

Я пока экспериментирую с разными подходами к texture splatting. В первом случае была только текстура с id материалов, а веса вычислялись прямо в шейдере, реализуя плавный переход (интерполяцию) между разными материалами. В этом подходе всю планету можно было покрыть как угодно чередующимися материалами с шагом 2.5-10 метров (это предельное разрешение текстур ландшафта, то, что вы можете наблюдать во всех предыдущих версиях SE). Но в этом случае переход между материалами всегда имеет одинаковую ширину - те самые 2.5-10 метров. Это не позволяет сделать плавный переход на протяжении километров, например от песка к траве. Поэтому сейчас я экспериментирую с вышеупомянутым подходом с двумя дополнительными картами - id материалов и весов.

Материал, созданный из трёх разных текстур: мелкие камешки + большие булыжники, модулированные текстурой скалы. Смешивание мелкой и большой текстур сделано на основе их карт высот

Почему я пишу "материалы", а не "детальные текстуры"? Потому что простая текстура смотрится не так интересно, как скомбинированная из трёх разных: мелкого масштаба, крупного масштаба и модуляции для крупномасштабной, для устранения размытости последней. Это в три раза повышает нагрузку на шейдер, но, думаю, результат того стоит. Хотя, в будущем, возможно, придётся отказаться от такого подхода, т.к. при реализации POM (Parallax Occlusion Mapping) нагрузка будет слишком большой. Такие интересные материалы можно реализовать теми же splat картами, но придётся увеличить их разрешение.

Наверное, на анимации лучше видны этапы текстурирования

В шейдере, рендерящем планету, используется маленькая lookup текстурка, в которой хранятся параметры материалов: id четырёх детальных текстур, их масштабы и относительные веса, по 4 варианта для разного наклона поверхности, и так для всех материалов, заданных в файле пресета планеты. С её помощью можно по id материала, взятому из splat текстуры, узнать все необходимые параметры для "конструирования" данного материала. Сами детальные текстуры хранятся в одном текстурном массиве (OpenGL texture array).

Для устранения сильно бросающегося в глаза тайлинга (повторяемости узора) я пробовал разные методы, самым быстрым оказался метод 3 от Inigo Quilez. В каждом пикселе текстура сэмплится всего два раза, в сдвинутых относительно друг друга координатах, затем результат смешивается. Сдвиг координат происходит в областях, похожих на узор древесины (см. статью).

Редактирование пресетов материалов/биомов вынес в отдельный редактор, чтобы не загромождать редактор планет. В самом редакторе планет остался выпадающий список для выбора пресета, и кнопка вызова его редактора. Т.к. детальные текстуры накладываются в шейдере, рисующем планету, их изменение в редакторе становится видно немедленно, что очень удобно при настройке материалов. Текстуры, обозначенные в редакторе как "Large", накладываются при генерации текстур рельефа, поэтому при их изменении надо нажимать "Update planet". Я планирую для них сделать систему, похожую на вышеописанную (комбинирование трёх и более текстур), только в этом случае будут накладываться текстуры, сделанные на основе спутниковых снимков Земли, Марса и других тел. Теоретически, если раздобыть ещё и спутниковые карты высот тех же областей, можно накладывать их на сгенерированный процедурный рельеф, и получить таким образом реалистичные горы.

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