w23 / xash3d-fwgs

Vulkan Ray Tracing fork of Xash3D FWGS engine. Intended to be merged into master at some point in the future.
164 stars 16 forks source link

Blending textures with each other on borders #704

Open 0x4E69676874466F78 opened 11 months ago

0x4E69676874466F78 commented 11 months ago

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

Сейчас у нас наблюдается подобное: image PBR-текстурами это особо не спасти: image

Можно зафорсить одну текстуру, но это не везде поможет и в целом текстура начнёт угадываться.

w23 commented 11 months ago

Не очень понятно вообще, как к этому подступаться.

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

Но эту идею придумать было быстро, а реализовать хз как, и долго.

0x4E69676874466F78 commented 11 months ago

Обычно в играх это делается через terrain blending, опишу своими словами как понимаю (дилетанстки) без всякого гуглежа сам:

  1. У нас есть конкретные поверхности, на них вешается единственный материал. Этот материал отдельный шейдер в котором иначе работает текстурирование. В нашем случае можно пойти двумя путями: 1.1. переиспользовать в системе материалов для конкретной карты inherit со специальным параметром-режимом текстурирования ("texture_mode" "blend") и таким образом задать слоты этих текстур. 1.2. через патч карты указать "_xvk_blend_textures" "список тайлящихся текстур" (наверное логичнее и тем более потом можно ограничить списком сурфейсов если вдруг потребуется). Если не указано конкретики, за кадром рендер определит какие грани имеют эти текстуры и следовательно для них надо включить другой режим текстирования.
  2. Сам шейдер имеет слоты текстур. В нашем случае это все тайлящиеся-анимированные текстуры которые мы так или иначе задали.
  3. Дальше автоматически появляются маски, одна текстура в видеопамяти это до четырёх масок (RGBA) которые можно между собой смешать, на самом деле 5, учитывая базовый слой. Если нужно больше 5 тогда добавляем ещё одну текстуру с масками.
  4. При желании мы можем сдвигать базовые текстурные координаты каждого слоя куда-то в сторону. Текстуры мостятся.
  5. Дальше в типичной ситуации маски мазюкают кистями в редакторе. В нашем же случае потребуется нарисовать маски процедурно для каждой поверхности с разной "анимационно"-тайлящейся текстурой. Таким образом каждая поверхность будет спроецирована на своей маске и её канале где размыта типа гауссом.
  6. Мы по маскам смешиваем текстуры между собой.

Дальше идём искать примеры:

https://habr.com/ru/companies/pixonic/articles/490226/ обширная статья на все случаи, конкретно крути вниз к "текстуры с весовыми коэффициентами для смешивания слоев" https://github.com/jensnt/TerrainHeightBlend-Shader пример реализации для юнити https://codeberg.org/sparseMatrix/Height-Blending-Terrain-Shader/src/branch/master/Adam-HeightBlendTerrain ещё один https://www.shadertoy.com/view/WsB3zc какой-то пример на шейдертое не знаю уместный ли.

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

В целом @lifekilled сам вроде писал подобный шейдер, можно узнать у него как такое можно сделать более оптимально.

Для других игр где есть ландшафт это будет необходимо.

LifeKILLED commented 11 months ago

Базовый функционал шейдера для terrain это splat map - текстуры масок. Один цветовой канал (R, G, B или A) это маски текстур. Очень удобно, если текстуры лежат в массиве. Можно сэмплить только те, у которых маска больше 0. Этих масок может быть много, если надо больше четырех текстур. Логика простая. Фактически это просто задачка смешивания нескольких текстур по одной маске, такими пользуются дизайнеры в Анриле.

Я писал шейдер для terrain в Юнити, потому что в базовом шейдере не хватало фич. Я добавлял triplanar, cellshading и heightmap blending. То есть не просто мягкое смешивание текстур по маске, а особый алгоритм, чтобы на границе был резкий переход по формам, заданным текстурой высоты. Например, чтобы на границе травы и камней пучки травы пробивались между щелей в камнях

1567847111

w23 commented 11 months ago

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

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

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

LifeKILLED commented 11 months ago

Если будет какой-то буфер с декалями ("коробка", которая ее проецирует в виде матрицы, номер материала), то можно в отдельном пассе спроецировать их на уже готовые буферы base_color_a, material_rmxx и normals_gs, не используя лучи. Главное просто сделать их список в шейдере. Остальное просто

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

LifeKILLED commented 11 months ago

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