Смешивание текстур ландшафта

:

В данной статье я расскажу об алгоритме смешивания текстур, который позволяет привести внешний вид ландшафта ближе к естественному. Этот алгоритм легко может быть использован как в шейдерах 3D игр, так и в 2D играх.

Статья рассчитана на начинающих разработчиков игр.

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

Теперь перейдем к самому интересному — алгоритмам смешивания текстур. Для простоты и наглядности наш ландшафт будет состоять из песка переходящего в крупные булыжники.

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

float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
	return texture1.rgb * a1 + texture2.rgb * a2;
}

Именно такая техника используется в Unity 3D в стандартном редакторе ландшафта. В глаза сразу бросается плавный, но неестественный переход. Камни выглядят равномерно испачканными песком, а ведь так не бывает в реальности. Песок не прилипает к камням, наоборот, он осыпается и заполняет щели между ними, оставляя верхушки камней более чистыми.

Давайте попробуем смоделировать эту ситуацию в самом обыкновенном Excel с его таблицами и графиками. Так как мы хотим, чтобы песок «проваливался» между булыжниками, для каждой текстуры нам понадобится карта ее глубины. В данном примере я сгенерировал ее из самой текстуры в оттенках серого и поместил в альфа-канал.

Первым делом рассмотрим упрощенную модель карты глубин песка и камней.

Синей линией условно обозначена карта высот песка, а красной — булыжников. Можно заметить, что верхушки булыжников выступают над уровнем песка. Учитывая этот факт, попробуем выводить пиксели той текстуры, которая находится выше.

float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
	return texture1.a > texture2.a ? texture1.rgb : texture2.rgb;
}

Отлично! Верхушки камней остаются чистыми, тогда как песок кажется осыпавшимся в щели между ними. Но мы еще не учли степени прозрачности слоев. Для этого мы просто сложим карту высот с картой прозрачности.

float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
	return texture1.a + a1 > texture2.a + a2 ? texture1.rgb : texture2.rgb;
}

За счет суммирования менее прозрачная текстура будет находиться выше, чем обычно.

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

float3 blend(float4 texture1, float a1, float4 texture2, float a2)
{
	float depth = 0.2;
	float ma = max(texture1.a + a1, texture2.a + a2) - depth;

	float b1 = max(texture1.a + a1 - ma, 0);
	float b2 = max(texture2.a + a2 - ma, 0);

	return (texture1.rgb * b1 + texture2.rgb * b2) / (b1 + b2);
}

В коде выше мы сначала выделяем часть видимого на определенной глубине рельефа.

А потом нормализуем его для того, чтобы получить новые степени прозрачности.

В итоге мы получили механизм смешивания текстур, который дает результат близкий к естественному виду ландшафта.

В заключение я хочу рассказать о том, для чего был разработан этот алгоритм и как мы его используем.

Шейдер разрабатывался для инди-игры Steam Squad в жанре изометрической 2D стратегии. В качестве фреймворка для разработки мы используем Unity 3D. А так как среда разработки Unity чрезвычайно гибка, мы сделали свое расширение — редактор уровней. По большому счету, редактор является упрощенной копией стандартного редактора ландшафтов с элементами взятыми из редактора игры Titan Quest.

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