Апгрейд ландшафтного движка #2

Продолжаю работу над обновлённым ландшафтным движком. Сегодня расскажу подробнее про детальные текстуры.
До сих пор для текстурирования ландшафта 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". Я планирую для них сделать систему, похожую на вышеописанную (комбинирование трёх и более текстур), только в этом случае будут накладываться текстуры, сделанные на основе спутниковых снимков Земли, Марса и других тел. Теоретически, если раздобыть ещё и спутниковые карты высот тех же областей, можно накладывать их на сгенерированный процедурный рельеф, и получить таким образом реалистичные горы.
Обсудить пост можно на форуме.