Создание заснеженной дороги
Не успело пройти и три месяца, как у меня появилось свободное время написать The Making of Snowy road. Это наполовину мейкинг оф, наполовину урок - решайте сами.
Речь идет вот об этой снежной дороге:
Итак, доброго всем дня, меня зовут Дмитрий Ярков, и сегодня я хочу поделиться с вами техникой создания снежной жижи с использованием Thinking Particles и Multiscatter.
Немного введения. Thinking Particles сегодня знают многие, однако, в основном, эта система по-прежнему остается сложной и загадочной. Не последнюю роль в этом играет интерфейс системы, а также ее внутренняя логика. Тем не менее, Thinking Particles были и остаются самой мощной системой частиц для 3ds max (и не очень дешевой – около 2000$). Я начал изучать ее полгода назад, и с тех пор решил в ней множество задач. Эта система полностью программируема, в ней можно создавать сложные операторы условий, основанные на выражениях (expressions), однако для некоторого круга задач можно обойтись стандартными операторами.
Если вы хотите выучиться работать в данной системе, вам необходимо пройти и усвоить видеокурс Thinking Particles 4 for production. Система настолько многогранна, что невозможно объяснить в двух словах многочасовые лекции этого курса. Можно утешиться тем, что не обязательно смотреть все видео, можно ограничить вводным, и далее перейти к группе «Production Shots» для базового понимания.
Thinking Particles в данном уроке мы используем в качестве решения для создания формы снежных комков, которые будут заполнять дорогу и колеи на ней. А Multiscatter, про который, несомненно, знают все, будем использовать во второй части урока для создания более реалистичной снежной поверхности. Кроме того, мы рассмотрим шейдер VRayFastSSS2 и немного композитинга.
Часть 1: Thinking Particles.
Итак, начнем с моделирования лоу-польной болванки в качестве основания для снежной жижи. Это должен быть замкнутый объем нужной вам формы. В моем случае, всё делалось строго под камеру, поэтому форма получилась несколько изогнутой:
Здесь грубо набросаны будущие колеи и большой сугроб слева. Синяя поверхность – условный «пол», на который будут падать фрагменты снега. Сзади вы видите два лоу-поли колеса от автомобиля, которые проедут по траектории колеи за отрезок времени в 100 кадров. Вот их траектория:
Все эти объекты нужно соответствующим образом назвать и переместить в слой TP_source, чтобы в будущем можно было легко скрыть его.
На этом приготовления закончены, всё остальное мы сделаем в Thinking Particles. Открываем вкладку Create->Geometry->Particle systems->Thinking и создаем систему частиц Thinking Particles в любом месте сцены. Для этого объекта можно создать отдельный слой с названием TP. Внешне Thinking Particles выглядит как скромный крестик с буквами TP, с единственной настройкой Properties внутри панели модификаторов. Нажав на кнопку, мы попадем внутрь системы, где и будем проводить дальнейшие действия.
Поскольку это наполовину урок, наполовину Making of, я не буду показывать скриншоты, демонстрирующие создание программы с нуля. Вместо этого я покажу скриншоты уже готовой программы и объясню, что они означают.
Как вы уже должны представлять по вводному видеокурсу, в левой верхней части окна у нас находятся группы частиц, а в левой нижней группы динамических наборов. Не все новички сразу понимают отличие групп от наборов. Группы позволяют разделять частицы с различными условиями рождения, смерти, просто разные наборы частиц. Они позволяют задавать разные цвета этим группам, разные режима отображения, или же вообще скрывать их. Динамические наборы (Dynamic sets) предназначены для программирования частиц, где частицы каких-либо групп создаются, двигаются и умирают по определенным законам, взаимодействуя друг с другом.
Первый динамический набор, который мы видим на экране, это Birth – рождение частиц:
Все три оператора на основном экране – это операторы рождения Object to particle. Это достаточно специфические операторы. Они переводят любые объекты в частицы, по принципу «один объект – одна частица». Частица помещается в центр объекта и принимает его форму (Particle Shape). Как вы видите в настройках справа, там стоит галочка Instance Shape – это как раз и значит, что частица принимает форму объекта. А также, конкретно для группы Wheels, режим трэкинга переключен на Object to Particle: это означает, что анимация частиц колеса будет наследоваться от анимации колеса.
Все три оператора рождения создают частицы в соответствующих группах: wheels (колеса), snow_source (источник снега) и ground (земля).
Далее нам нужно разбить источник снега на объемные фрагменты, которые будут использоваться при рассыпании снежной жижи. Для этого служит следующий динамический набор под названием VB1:
Здесь всё просто: берется группа частиц snow_source и разбивается оператором Volume Break. Как вы видите, в настройках справа стоит галочка Use helper, threshold: 500 cm, group: Wheels. Это означает, что разбиение будет происходить по ходу анимации на расстоянии 500 cm от группы частиц Wheels. Еще ниже мы видим настройку Spreading Size: 80%, Spreading Time: 40. Это означает, что, единожды начавшись на расстоянии 500 cm, разбиение будет на протяжении 40 кадров увеличиваться вплоть до 80% первоначального расстояния. Параметр Raster 0.6 – относительная величина ячеек.
Оператор Volume Break не только разбивает частицы, но и переводит получившиеся осколки в другую группу. В нашем случае это группа frag1. Оператор Scale в конце ветки нужен для уменьшения всех получившихся частиц до 97% от первоначального размера. Это необходимо для облегчения взаимодействия частиц друг с другом. Вот как всё это примерно выглядит посередине анимации:
Здесь зеленый след, постепенно расширяющийся по мере продвижения колеса – как раз результат работы Volume Break. Красный след – это вторичное разбиение в группе VB2:
Здесь уже настройки хитрее, мне сложно будет объяснить каждый оператор, но я взял эти настройки из видеокурса, упомянутого выше. Название урока: «TP4 - Production Shot - 06 - Ground Crumble Setup.avi».
Тем не менее, я смогу объяснить принцип работы этой программы подробнее, чем в том уроке.
Суть в том, что для вторичных разбиений в операторе Volume Break используется не только Helper. Helper, аналогичный предыдущему разбиению, используется только для непосредственного дробления фрагментов в месте соприкасания с колесами. В остальной области используется опция Activate. Когда она равняется100%, разбиению подвергается полностью вся частица, когда 0% - частица разбиению не подвергается. Для каждой частицы значение Activate определяется отдельно и рандомно. Вот как это делается.
Для начала, к исходным частицам применяется оператор Timer. Этот оператор имеет желтый вход Start, куда подключается группа частиц frag1 – результат первичного разбиения. Во вход Particle подключается та же самая группа частиц. Все это означает, что таймер будет запущен для каждой входящей частицы независимо.
Таймер будет отсчитывать определенное количество кадров для каждой частицы – всегда разное за счет оператора Random (возвращает число от 15 до 50, режимanimation), подключенного к входу Frames. Как только отсчет прекращается, Timer передает команду на выход Out, который в свою очередь подключен к входу Onоператора Volume Break, который включается именно в этот момент и именно для этой частицы (благодаря также входу Particle). Но как Volume Break узнает, какой процент Activate нужно включить для этой частицы? Для этого от оператора Timer отходит еще один интересный оператор Value to Time.
Оператор Value to Time изначально предназначен для перевода скалярного значения во временной промежуток. Но его также можно использовать как сложный оператор пропорциональности. На вход подается некоторое значение (Value), которое мы берем из выхода Time Relative (нормализованное время от 0 до 1) оператора Timer. Настройки Value to Time просты:
Входящее значение Value интерполируется между двумя значениями: Value1 и Value2. При Value1 оператор возвращает Time=0, при Value2 оператор возвращаетTime=100 (или в нашем случае число, полученное оператором Random от 30 до 80 в режиме animation). Все средние значения Value интерполируются. Таким образом, на выходе мы получаем случайные значения от 0 до 80 для каждой отдельной частицы, в зависимости от разных условий. Далее посредством оператораFade In (в оригинале он называется Float) мы делаем плавный вход в это значение в течение 100 кадров, ну и, наконец, полученный результат подается на входActivate оператора Volume Break. Результат без использования Helper:
С использованием Helper для дополнительного дробления колеи группой wheels:
Остальные два динамических набора очень просты. Первый это гравитация, которая действует только на группу Active_objects:
Второй это ShapeCollision, позволяющий частицам взаимодействовать по физическим законам:
Теперь наша программа готова. Зайдя в Master Dynamic Set, мы можем выбрать путь для сохранения кэша и нажать Simulate. По окончании симуляции мы можем проиграть нашу анимацию. Вот так она выглядит у меня:
Часть 2: шейдинг и рендер.
Теперь мы получили чистую геометрию, причем разбитую на группы. Основных групп у нас две: крупные и маленькие фрагменты. Вот как это выглядит:
На всех снежных объектах в этой сцене у меня используется один и тот же шейдер VRayFastSSS2. Единственная разница между ними заключается в использовании разных карт. На крупные и маленькие фрагменты у меня накладываются текстуры разной яркости. Рассмотрим сначала общий шейдер:
На скриншоте видно, что на параметре SSS color лежит карта Composite. Эта карта применяется к большим фрагментам:
Для мелких фрагментов используется почти такой же шейдер, но с более темной текстурой на SSS color:
Кусочек рендера:
Настало время добавить Multiscatter. Перед этим нужно нарисовать объекты для рассадки. Чем меньше и разнообразнее будут эти объекты, тем лучше будет выглядеть итоговая поверхность. Мы нарисовали 50 вот таких булыжников:
Поскольку Multiscatter берет материалы прямо с объектов рассадки, материал на всех трех мультискаттерах один - тот самый базовый шейдер, который описывался выше, причем без карт. Однако, внутри самого мультискаттера есть параметр Object Color, куда можно бросить уже знакомую нам карту Composite:
Часть 3: композ.
Для полноценного композа нам понадобятся каналы. Вот какие каналы я использовал для этого изображения:
Затем высветлил по маске некоторые части колеи для пущего разнообразия:
Потом я добавил текстуру колеи. Ее пришлось рендерить отдельно на лоу-поли плашках, а потом подмешивать к финалу по маскам. Вот рендер колеи:
Далее я взял и увеличил яркость теней в 3 раза: