Математика в 3Д ► 07. Noise Texture
Сегодня подробно рассматриваем все настройки и некоторые примеры использования Noise Texture. Буду очень благодарен всем, кто решит стать платными подписчиками или разово задонатить на означенные цели. Это сильно мотивирует на продолжение.
Noise Texture - это процедурно генерируемый трёхмерный шум. Он принимает на вход текстурные координаты, и если в векторный вход ничего не подключено, он использует по умолчанию систему координат Generated в Shader Editor и Position в Geometry Nodes. У него предельно мало настроек, но их комбинации даже при небольших изменениях позволяют достигать существенно отличающихся результатов, что делает его очень мощным, универсальным и эффективным инструментом для добавления неровностей, шероховатостей и более существенных искажений.
↑ На первом скриншоте показана текстура с дефолтными настройками. Math в режиме Power (возведение в степень, в данном случае - 4) используется, чтобы сделать текстуру визуально более контрастной и читаемой. Для демонстрации взяты настройки проекта из прошлого урока. Напомню, если смотреть слева-направо, показаны:
• сдвиг геометрии вдоль нормалей с использованием Geometry Nodes,
• материал на плэйне
• материал на нескольких полупрозрачных плэйнах
• волюметрик материал внутри куба
Все материалы используют одну и ту же нод-группу, а для геонодов она дублируется.
Чтобы более чётко отображались волюметрики, в настройках рендера (панель внизу справа) во вкладке Volumes параметр Max Steps увеличен до 100.
↑ Первый регулируемый параметр определяет, в скольких измерениях будет работать текстура. Если выставить его на 1D, то Noise Texture будет заливать всё пространство одним оттенком серого, который будет изменяться, в зависимости от параметра W. Эта буква является продолжением набора XYZ и обозначает 4-е измерение. Зачем может быть нужна одномерная текстура не выдающая никаких паттернов, а один только меняющийся цвет? Например, чтобы с помощью драйвера подавать на её вход W текущий кадр сцены, разделённый на какое-либо число, и использовать это для какого-нибудь мерцания. Или если говорить о геометрии - для хаотичного увеличения и уменьшения размера объекта (пульсации) или его вращения, или позиции. Да, то же самое можно сделать и с помощью анимационных модификаторов в Graph Editor, но вы хотели геоноды.
↑ Если внимательно присмотреться, то можно заметить что сфера на этом и предыдущем скриншотах немного разного размера. Добавьте умножение на 10, и разница станет намного более ощутима.
↑ В режиме 2D это тот же шум, только двумерный, ось Z игнорируется. Эффект такой же, как если бы для трёхмерной текстуры значения оси Z на всём протяжении трёхмерного пространства были равны 0, а микро-срез текстуры бесконечно растянулся бы вдоль оси Z. Иными словами, как и в случае с Image Texture в режиме Flat, получается проекция двухмерной картинки на плоскость, образованную осями X и Y - на протяжении всей оси Z. Поскольку для вычислений значений одного двумерного среза требуется гораздо меньше, чем для вычислений всех значений 3Д пространства, в режиме 2D Noise Texture забирает меньше ресурсов компьютера, поэтому во многих случаев, когда идёт работа с поверхностями а не с объёмом и, например, есть возможность, использовать координаты UV, используя 2Д, а не 3Д или не 4Д, можно увеличить производительность. Особенно это становится актуальным, когда таких текстур в материалах сцены накапливается несколько десятков, и по какой-то причине требуется, чтобы они оставались процедурными.
↑ В режиме 3D текстура работает наиболее интуитивно понятным способом - для каждой точки в пространстве полученные на входе значения трёхмерных текстурных координат она с помощью математической формулы преобразовывает в новые значения.
⚠ Обратите внимание! ⚠
У Noise Texture два выхода. Верхний выход Fac рассчитывает из значений входящих текстурных координат для каждой точки пространства одно значение по всем 3м-осям, поэтому текстура получается чёрно-белой. Нижний выход Color рассчитывает из значений входящих текстурных координат для каждой точки пространства индивидуальные значения. В качестве цвета для раскрашивания объектов его вряд ли можно использовать, если, кончено, вы не делаете документальный фильм про галлюциногены. Однако, он хорошо подходит для подмешивания к текстурным координатам векторного шума, чтобы в каждой точке пространства по всем трём осям они деформировались индивидуально - об этой технике речь пойдёт ниже. Или для добавления цветного "зерна" на пост-обработке во время композитинга для имитации аналоговой видео-съёмки.
↑ В режиме 4D добавляется параметр W. Это "приквел" к осям XYZ, четвёртое измерение, сквозь которое "протягивается" трёхмерное пространство. Это то же самое, как если взять плоский двумерный плэйн, наложить на него по осям X и Y трёхмерную текстуру и начать протягивать её сквозь этот плэйн по оси Z. Только текстура протягивается сквозь трёхмерное пространство по оси четвёртого измерения. У 3Blue1Brown есть визуализация того, как это могло бы выглядеть, на примере кватернионов:
🛈 Кстати если вы действительно интересуетесь математикой, весь его канал просто обязателен к изучению. Например, в своих видео по основам линейной алгебры он объясняет не просто, по каким формулам рассчитывать трансформации матриц, а показывает, как визуализировать производимые действия, чтобы буквально представлять, каким образом они выгибают пространство. Они даже есть переведённые на русский язык. В остальном, правда, всё на английском. Но знаете что? Если вы хотите стать действительно хорошим профессионалам, без него в любом случае далеко не уедешь. Та информация, которая нашими стараниями просачивается в русскоязычный сегмент - это без преувеличения капля в море.
↑ Звучит это всё сложно, и представить нам, неполноценным трёхмеркам, какого это жить в четырёхмерном мире, почти невозможно. Но мы можем просто принимать результаты и использовать их. Например, можно просто рассматривать параметр W, как эволюцию текстуры. Изменяем W - и шум плавно меняется, эволюционирует.
В Noise Texture можно выделить 3 её составляющие: Scale отвечает за размер базового паттерна, Details за уровень детализации (меняется при превышении каждого последующего целого числа), а Distortion - за искривления и того, и другого. Параметр Roughness определяет, насколько параметр Detail оказывает влияние на базовый паттерн.
↑ Чтобы более наглядно рассмотреть, как меняется текстура под воздействием тех или иных параметров, будем включать их по одному. Отключим сначала Detail, Roughness и Distortion, чтобы оставить только базовый паттерн.
↑ Изменяя Scale, мы изменяем размер паттерна
↑ Обратите внимание, что пока Roughness равен 0, при добавлении Detail результат не меняется.
↑ С добавлением Roughness к базовому паттерну начинают подмешиваться шероховатости, глубину детализации которых определяет параметр Detail
↑ Чем больше значение Roughness, тем ощутимее воздействие шероховатостей
↑ При Roughness, равном 1, базовый паттерн становится уже практически неразличим за мелкими деталями. Однако, он всё равно угадывается, а это означает, что Roughness, работает не как фактор смешивания двух составляющих, а скорее как фактор умножения.
↑ Отключим Detail и Roughness и добавим Distortion. Этот параметр работает независимо от Detail и Roughness и искажает базовый паттерн, как при добавлении векторного шума координатам (см. ниже)
↑ При добавлении Distortion завихрения становятся всё сильнее, что визуально приводит к увеличению количества изгибов. Форма базового паттерна при этом, в отличие от добавления Detail и Roughness, размывается полноcтью
↑ В сочетании с Detail и Roughness Distortion действует следующим образом: сначала высчитывается базовый паттерн, потом к нему подмешивается детализация, а потом Distortion искажает получившийся результат
Векторный шум
Я уже несколько раз за этот урок упоминал эту технику, и сейчас мы рассмотрим её подробно. В уроке про маски мы рассматривали способы смешивания разных градиентов между собой с помощью математических операций. Таким же образом к градиентам можно подмешивать и текстуры с предсказуемыми результатами. Однако, там мы смешивали уже сформированные, готовые результаты, а часто бывает нужно не смешать два разных результата, а немного (или много) изменить один - искривить его. И этим мы частично занимались в практическом занятии, создавая кастомную систему координат, чтобы расположить текстуру по кругу. Из этого можно сделать вывод, что для изменения распространения текстуры по поверхности мы должны воздействовать на её текстурные координаты, которые, собственно, и определяют, как именно она располагается на поверхности. И очень часто нам нужно не просто вывернуть или развернуть всю текстуру целиком, а добавить ей рандомных искажений. И - подходим к сути - это можно сделать, если подмешать к исходным текстурным координатам значения сгенерированных шумов. В частности - Noise Texture.
↑ Добавим для примера искажаемой текстуры Voronoi Texture в режиме 3D, Distance to Edge, со Scale равным 2 и Randomness равным 0. Получается идеально ровный паттерн, состоящий из кубических ячеек, в центре которых значение равно 1, а по краям 0.
↑ Добавим к текстурным координатам с помощью Vector Math в режиме Add (сложение) значения Color из нода Noise Texture. Напомню, выход Color для каждой точки пространства генерирует индивидуальные паттерны шума для каждой оси XYZ, поэтому по всем трём осям смещение будет происходить по-разному. В результате мы получаем очень сильные искажения паттерна.
Обратимся к математике, чтобы понять, почему. Noise Texture даёт на выходе значения примерно от 0.25 до 0.75 преимущественно сконцентрированные вокруг 0.5. Для текстурных координат в дефолтной метрической системе в Блендер это равноценно сдвигу от 25 до 75 сантиметров. То есть в среднем Noise Texture сдвигает паттерн Voronoi Texture на полметра, а в пиках - почти на метр. Далеко не всегда требуются настолько радикальные изменения, поэтому стоит придумать, каким образом контролировать объём добавляемого шума. Как обычно, объём логичнее всего контролировать при помощи умножения.
↑ Для математических операций с векторами - а поскольку цвет определяется тремя значениями для красного, зелёного и синего каналов, мы моем использовать эти значения в качестве вектора - используется нод Vector Math. Мы могли бы использовать его в режиме Multiply (умножение), регулируя объём добавляемых искажений для каждой оси индивидуально - и бывают задачи, в которых так и нужно сделать. Но поскольку сейчас для примера требуется просто контролировать общий объём шума, логичнее использовать Vector Math в режиме Scale (размер), который работает как умножение вектора на число. То есть мы в каждой точке пространства умножаем значения каждой оси на одно и то же число, вместо того, чтобы умножать значение каждой оси на индивидуальное число. Таким образом мы определяем сколько шума добавляется. Если значение Scale равно 0, то все числа умножаются на 0, получается 0, и мы приплюсовываем к исходным координатам только 0 - то есть ничего не приплюсовываем. Если значение Scale равно 1, то при умножении на 1 числа остаются самими собой, и мы используем оригинальные значения Noise Texture. Добавляя Scale мы увеличиваем искажения, а снижая - уменьшаем. При переходе в минусовой диапазон всё происходит ровно наоборот и в обратную сторону.
Обратите внимание, что сейчас паттерн вороного сносит в основном вправо и вверх (и назад, если посмотреть с третьей стороны). Давайте подумаем, почему это так происходит, и как нам это исправить. Подмешивая к текстурным координатам Noise Texture, мы подмешиваем значения примерно от 0.25 до 0.75, умноженные на значение Scale. Независимо от объёма добавляемых искажений, они все находятся в положительном диапазоне. То есть мы в любом случае что-то прибавляем к текстурным координатам и ничего не вычитаем. От этого движение искажения получается однонаправленным. Нам нужно сделать так, чтобы центр диапазона значений, который в исходном виде находится на уровне 0.5 переместился на 0, чтобы половина значений шума прибавлялась к текстурным координатам, а другая половина - вычиталась из них.
↑ Чтобы сместить диапазон значений на 0.5 ближе к нулю, нам, логично, нужно из всех значений диапазона вычесть 0.5. Это мы сделаем с помощью Vector Math в режиме Subtract (вычитание). Из входящих значений каждого канала (или, если угодно, каждой оси) вычитаем 0.5 - и искажения начинают происходить относительно центра, оставляя базовый паттерн на месте.
↑ Изменяя настройки Noise Texture, можно вносить как крупные искажения самой базовой формы паттерна...
↑ ...так и небольшие шероховатости
↑ А если вспомнить, что любые - ну то есть абсолютно любые - параметры в Блендер можно изменять не только отдельными числовыми значениями, но и использовать для них и градиенты, и текстуры, и если задуматься, что Scale, который определяет объём добавляемых с помощью Noise Texture искажений - это такой же параметр, как и любой другой, то можно прийти к выводу, что в качестве параметра Scale одной Noise Texture можно использовать вторую Noise Texture - и искажения будут добавляться не равномерно по всей поверхности, а согласно значениям второй текстуры. Для более явного результата можно скорректировать её с помощью Math в режиме Power (возведение в степень) и Multiply (умножение).
↑ А если вспомнить, что и сами-то текстурные координаты занимаются тем, что определяют для каждой точки пространства числовые значения, и Noise Texture, преобразуя эти значения, определяет другие - но всё ещё числовые значения и всё ещё по XYZ, то можно даже решить, что саму Noise Texture в каких-то случаях можно использовать в качестве новой системы координат для других текстур. Зачастую использование одной процедурной текстуры в качестве системы координат для другой процедурной текстуры может дать очень интересные результаты (может быть, не в этом конкретном случае, но бывают прямо очень эффектные сочетания)
Напоследок - пример применения на практике.
↑ Всего лишь 3 Noise Texture (плюс ещё одна в шейдере для добавления микродетализации на уровне шейдера с помощью Bump) потребовалось, чтобы процедурно сгенерировать реалистичный горный ландшафт из плоской сетки 10 на 10 метров, 100 на 100 полигонов, дополнительно 3 раза подразделённой с помощью геонодов.
↑ Причём смотрите: меняем всего один параметр W у одной из текстур, и каждый раз получаем совершенно новый результат
↑ Бэмс! Ну вот, опять! Круто, да? А теперь подумайте, что похожим образом это всё прямо здесь же, в шейдере, не отходя от кассы, можно затекстурить. Даю наводку: маска по оси Z, искажённая векторным шумом помноженная на текстурные маски.
И помните - ваши репосты помогают донести эти уроки до других людей. Не жадничайте, делитесь! Многие пишут, что у них не с кем делиться, но по моему опыту никогда не угадаешь, скольким людям из ленты может внезапно оказаться близкой и интересной тема 3Д. Может, кто-то из ваших знакомых прямо сейчас листает ленту, сидя на своей скучной и унылой работе, и мечтает, как бы ему начать создавать прекрасные 3Д миры - а вы его уроков лишаете. Испортите уже человеку жизнь, подсадите на трёхмерку, не всё ж нам с вами одним тут мучиться. Спасибо!