![](https://habrastorage.org/storage2/fdf/664/949/fdf66494923365fac26842e354b0d547.jpg)
С текстурами вечно какие-то проблемы! То оказывается, что нельзя взять любую фотку и налепить на модельку. То на стыке текстур появляются швы, которые замучаешься заглаживать. То вроде уже и загладил всё, но глаз, этакий проказник, всё равно замечает повторяющиеся узоры и рушит иллюзию.
Можно сделать текстуру побольше, чтобы повторяющиеся куски дальше отстояли друг от друга и были не так заметны. Можно даже сделать её совсем огромной, на пару сотен тысяч пикселей, чтобы она накрывала всю сцену целиком без швов и повторений. Подобную технику называют мегатекстурой. Но мегатекстуры и близкие к ним виртуальные текстуры усложняют работу с памятью, для работы с ними требуются особые инструменты, да и в целом это ещё молодая технология.
Как же быть? Есть один трюк — непериодические мозаики. Они лишены проблемы повторяемости и достаточно просты в реализации. Одну из таких мозаик придумал китайский математик Ван Хао в 1961 году. Элементы этой мозаики можно представить в виде прямоугольников с разноцветными гранями. Но чтобы понять принцип её работы, надо сначала разобраться в классическом методе заполнения площадей текстурами.
![](https://habrastorage.org/storage2/769/a39/059/769a39059d373472162e3e1b64fe9959.png)
А классический метод таков: берем понравившуюся картинку, мостим ею небольшую площадь для теста и сразу видим все плохие пограничные места. После этого переделываем картинку так, чтобы правая сторона совпадала с левой, а верхняя с нижней. Готово, текстурой можно пользоваться.
![](https://habrastorage.org/storage2/ef8/a02/f77/ef8a02f772bb8a50cf7468b38ebaf2ec.png)
Иными словами, нужно добиться того, чтобы горизонтальные и вертикальные края соседних текстур плавно перетекали друг в друга. Получается некий контейнер для картинки, который хорошо укладывается рядом с другими контейнерами.
![](https://habrastorage.org/storage2/137/188/59b/13718859bfb976878a2e3ef6a0958bbb.png)
Развиваем мысль дальше. Внутреннее наполнение контейнеров может быть каким угодно. Можно наделать много разных вариантов одной текстуры и мостить площадь случайными плитками из набора. Но как ни крути, даже при таком подходе остаётся повторяющаяся сетка от граней плитки. Следовательно, нужно придумать способ для перемешивания граней.
![](https://habrastorage.org/storage2/21c/2e8/c0b/21c2e8c0b2047a889d6f53d27444a5d6.png)
На самом деле, правая и левая сторона одной плитки не обязательно должны сочетаться друг с другом, главное, чтобы они сочетались с соседними плитками. Можно сделать несколько вариантов текстуры с разными краями и упаковать их в атлас. Затем, во время укладывания текстур, просто брать случайную плитку с краем, который подходит к соседним уложенным плиткам.
К сожалению, размер атласа для полного набора плиток очень быстро растёт с количеством вариаций граней. Расчёт ведётся по следующей формуле: N2*M2, где N — количество горизонтальных граней, M — количество вертикальных граней. Например, для двух вариантов на горизонталь и вертикаль выходит шестнадцать разных плиток. Если просто нужна гарантированная возможность продолжить мозаику, то формула будет попроще: 2*N*M.
![](https://habrastorage.org/storage2/779/709/ef1/779709ef1c6f417307186089c132fa65.png)
Плитками из атласа можно замостить сколь угодно большое пространство. Берётся одна случайная плитка, сбоку к ней прикладывается вторая с подходящей гранью, ко второй плитке — третья, и так далее до конца ряда. При выборе плитки во втором ряду дополнительно учитываются соседи из первого ряда. На картинке выше слева изображён атлас, а справа мозаика.
![](https://habrastorage.org/storage2/f1f/7aa/ca6/f1f7aaca6f88185a2494a618dc51c123.png)
Как создать атлас плиток? Можно взять одну большую картинку и наложить на неё сверху сетку из цветных граней. Затем выбрать подходящий шов для каждого цвета и размножить его по сетке. Либо пойти от обратного: сначала сделать сетку, потом заполнить пустые места. Ниже есть ссылки на более подробную инструкцию.
![](https://habrastorage.org/storage2/0a9/155/78f/0a915578fb2cb91b1fcd2b4635ef1c55.png)
На иллюстрации сверху слева — простое повторение созданного атласа, справа — мозаика Вана, собранная из него. У получившейся мозаики нет заметных повторений, она выглядит случайной и текучей.
Разумеется, мозаика Вана не идеальна, у неё есть проблема с углами плиток. Мозаика решает проблему горизонталей и вертикалей, но остаются ещё диагонали, из-за которых на стыке четырёх плиток могут появляться артефакты. Зато эта мозаика проста и может использоваться не только для текстурирования, но и для процедурной генерации планов помещений или подземелий.
![](https://habrastorage.org/storage2/c45/088/0f9/c450880f900f475cff91fb64c4d6f45a.png)
Я набросал нехитрый код на C# для Unity3d для работы с мозаикой Вана, можете посмотреть на него по ссылккам ниже.
Unity Web Player | Windows | Linux | Mac | Исходники на GitHub
Пробел — новая случайная текстура, 1, 2, 3 — выбор атласа, Esc — выход.
Для пользователей Linux: Сделайте файл WangTiles исполняемым с помощью «chmod +x WangTiles» и запускайте.
Полезные ссылки по теме:
Инструкция по созданию атласов
Процедурная генерация подземелий
Подробнее про создание атласов разных размеров
Полуавтоматический генератор атласов
По просьбам трудящихся небольшое дополнение про создание атласов:
Берём понравившуюся большую картинку, накладываем сверху сетку для удобства в фотошопе или где ещё.
![](https://habrastorage.org/storage2/103/c47/f65/103c47f658da6b28461bd245fd8c4613.jpg)
Для каждого цвета сетки нужно выбрать по сегменту картинки, чтобы создать новую сетку. Просто размножаем каждый сегмент и складываем копии в колонки и столбцы.
![](https://habrastorage.org/storage2/0ad/86a/eb0/0ad86aeb00b7e688050931fdb959187a.jpg)
Сетка изначально получается очень кривой и с кучей некрасивых швов. Применяем всю доступную магию фотошопа и делаем швы незаметными. В примере ниже я просто помазал сетку немного ластиком. Получается атлас — новая картинка, которую можно разрезать на кусочки, которые будут сочетаться друг с другом.
![](https://habrastorage.org/storage2/db5/a55/132/db5a551320ff308775e6be16b1c80105.jpg)
Дальше без элементарного программирования не обойтись, можно собрать всё руками, но на это уйдёт куча времени. Используете в коде созданный атлас, выбираете из него кусочки и делаете мозаику. Элементарно. Сложнее всего смастерить красивый атлас, но с текстурами всегда так.
На самом деле я просто пересказал инструкцию отсюда. Почитайте, там всё хорошо расписано.
![](https://habrastorage.org/storage2/386/cb5/568/386cb55682e529cc61db5c840eb3de56.png)