Тайлинг процедурных текстур в Blender

Процесс создания отдельных элементов процедурных текстур в Blender достаточно прост — подбираем нужную формулу, воплощаем ее с помощью математических нодов, и в результате получаем нужный рисунок. Однако созданная подобным образом текстура обладает одним свойством — она не тайлится. И хотя тайлинг — циклическое повторение участка или целой текстуры, по большей части считается вредным, и хорошим тоном в 3D считается не допускать текстурного тайлинга, иногда, например при создании узоров или орнаментов, он бывает необходим.

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

Для примера возьмем текстуру процедурного круга. Создадим экспериментальную сцену с одной плоскостью, на которую назначен материал, генерирующий в ее центре процедурную текстуру круга с радиусом 1.

Для удобства уменьшим общий масштаб текстуры в 10 раз с помощью нода Mapping, установив все три значения Scale равными 10.

Как мы еще раз убедились, круг не тайлится, а остается в единственном экземпляре в центре плоскости. Подумаем, почему так происходит?

Вернемся к исходной формуле, которую мы заложили в основу нашей текстуры:

это функция, зависящая от трех координат X, Y и Z, значения которых начинаются от 0 и постоянно увеличиваются. Все получившиеся значения левой части формулы сравниваются с заданным радиусом. Те, что меньше — используются для отрисовки текстуры, те что больше — отбрасываются.

Мы ограничили радиус круга значением 1. Следовательно координаты X, Y и Z ограничиваются промежутком от -1 до 1.

Давайте мысленно проследим за координатой X начиная от нуля. 0, 0.1, 0.2 … — мы внутри круга, эти координаты используются для расчета. 0.3, 0,4 … 0.9, 1 — мы все еще внутри круга. 1.1 — все, это уже не диапазон круга, мы вышли за его пределы. 1.2, 1.3 … — мы за пределами круга, эти цифры ничего нам не дают. Но…

Что если, на место числа 1.1 мы снова подставим в формулу 0.1? Вместо 1.2 — подставим 0.2? То есть возьмем диапазон нужных для построения круга координат и переставим его на место тех, которые уже не используются?

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

Проделать подобный трюк нам поможет математическая операция «остаток от целочисленного деления», обычно обозначающаяся как «Mod». Она работает следующим образом: для двух чисел A и B  все целые B из A отбрасываются и в результате определяется остаток. Например:

Как видно из таблицы, Mod позволяет нам задать базу равную 1 и получать на промежутке координат кратном этой базе постоянный диапазон значений от 0 до 1.

Реализуем эту возможность при помощи нод.

Добавим новый нод Math

shift+a — Convertor — Math

и переключим его в режим Modulo. Вставим его между нодом Separate XYZ и группой нодов, формирующих круг. Соединим выход X нода Separate XYZ с верхним входом нода Modulo. Значение на втором входе нода Modulo установим равным 1. Выход Value соединим со входом X группы круга.

Добавим еще два нода Modulo для координат Y и Z.

Как мы видим, текстура с кругом затайлилась, но только частично. Это произошло из-за того, что диапазон координат по которым строится круг меняется от -1 до 1, а мы с помощью нода Modulo затайлили диапазон от 0 до 1.

Для того, чтобы ввести полный круг в затайленный диапазон уменьшим его радиус в 2 раза, установив значение Radius = 0.5 и сдвинем его начальную точку на 0.5, назначив значения X0 = 0.5, Y0 = 0.5 и Z0 = 0.5.

Значения диапазона в Modulo и радиуса и начальной точки в группе Circle можно менять для регулировки размеров круга, но проще менять его размер через нод Mapping.

Как мы видим, текстура с кругом тайлится, но только в положительном направлении координатных осей. Для того, чтобы учитывать и отрицательные направления, перед каждым нодом Modulo вставим дополнительный нод Math в режиме Absolute. В этом режиме нод возвращает модуль от значения, поданного на его верхний вход.

Теперь наша процедурная текстура с кругом корректно тайлится по всем направлениям.

Можно объединить все ноды в единую группу для дальнейшего использования.