Всем привет! Сегодня хочу представить на ваш суд один из способов создания листвы (или массива других объектов) без пересечений с помощью встроенного в Макс генератора частиц – Particle Flow.
Итак… поехали!
1. Подготовка
Для начала я создал несколько вариаций листочков, ориентировав их по оси X и выставив Pivot в точку присоединения листа к ветке:
Так же у меня есть веточки (зелёные) дерева, на которых мы будем выращивать листву. Ещё я создал вспомогательную сферу, с помощью которой, на первом этапе, мы будем наблюдать поведение листьев в зависимости от направления нормали поверхности, на которой он вырос. А пока веточки можно скрыть.
2. Распределение листьев
Открываем Particle View (цифра 6 на клавиатуре) и перетягиваем Standard Flow в поле.
Заходим в настройки PF Source 001, ставим отображение частиц во вьюпорте и на рендере на 100%, Integration Step на половину кадра (Half Frame) или на 1/4, 1/8 – это увеличит качество просчёта пересечений, хотя в нашем случае это не так критично, т.к. не будет больших скоростей.
- Кликаем на Birth и делаем, чтобы все частицы рождались в 0 кадре (Emit Stop на 0). За количество частиц (листиков) будет отвечать параметр Amount.
- Мы хотим, чтобы частицы генерировались из нашего объекта, поэтому перетягиваем на место оператора Position Icon - оператор Position Object, где добавляем наш сферический объект. Так же ставим галочку на Separation со значением, близким к размеру листочков, чтобы они распределялись более равномерно – я поставил 5 см.
- Чтобы вектор скорости частиц был направлен по нормали к поверхности, заменяем оператор Speed на Speed by Surface, где выбираем наш объект. Значение скорости я пока поставил на 1 см.
- В настройках оператора Rotation выбираем Speed Space, чтобы наши листочки ориентировались по вектору скорости.
- Заменяем оператор Shape на Shape Instance, чтобы выбрать свою геометрию частиц. Предварительно надо сгруппировать все листики, а в настройках нажать галочку Group Members. Тут же, кстати, можно настроить размер листочков (Scale %) и его вариацию (Variation %).
- Чтобы во вьюпорте видеть не точки, на свою геометрию, в Display выбираем Type: Geometry.
Если сейчас проиграть анимацию, мы увидим, как листья, равномерно распределённые по поверхности сферы удаляются от неё с небольшой скоростью.
3. Располагаем листочки более горизонтально.
Итак, сейчас листики ориентированы по вектору скорости, который направлен по нормали от нашего объекта (в данном случае от сферы), поэтому в верхней и нижней частях они расположены вертикально.
Мы создадим свой оператор для управления этими векторами, чтобы листочки были больше ориентированы по горизонтали. Для этого нужно уменьшить вертикальную составляющую Z вектора скорости.
Добавляем под Speed By Surface, Data Operator, в его настройках ставим галочку Auto Update, чтобы видеть все изменения во вьюпорте и заходим в его редактор (Edit Data Flow).
- перетаскиваем Input Standard, выбираем там Speed: Z Component;
- добавляем число Scalar, скажем, 0,1 + можно добавить Variation;
- перетаскиваем Functions, выбираем Real единицы и функцию умножения;
- добавляем Output Standard и выбираем там Speed: Z Component;
Объединяем всё, как на схеме ниже:
Теперь наши листики стали более ориентированы по солнцу, т.к. вертикальная составляющая вектора скорости умножается на 0,1.
Схожим образом можно добавить ещё одну функцию, которая будет прибавлять к вертикальному вектору определённое число. Таким образом мы сможем регулировать вертикальный поворот всех листочков:
Обратите внимание, что мне пришлось уменьшить влияние этого коэффициента в функции.
Для удобства доступа к этим параметрам их можно вывести в настройки данного оператора через Expose Parameters…:
Я вывел коэффициент умножения и прибавления к Z компоненте вектора скорости, ну и переименовал сам оператор в ZComponent
4. Листочки тянутся к свету.
Следующим шагом я хочу сделать так, чтобы листики от центра дерева тянулись ближе к его краю, т.е. как бы тянулись к свету. В этом нам поможет более хитрый Data Operator.
Для начала создадим любой вспомогательный объект – я создал Dummy, который будет символизировать центр дерева.
Добавляем новый Data Operator над нашим ZComponent, ставим галочку Auto Update и заходим в его редактор.
Итак… исходными данными будут служить: вектор к нашему вспомогательному объекту, к каждому листочку и текущий вектор скорости.
Чтобы узнать вектор от центра дерева к листочку нужно из вектора положения листочка вычесть вектор до центра дерева.
- вытаскиваем Select Object и выбираем наш Dummy объект;
- вытаскиваем оператор Object и выбираем в нём Object Pivot (мы «построили» вектор к вспомогательному объекту);
- добавляем оператор Input Standard, Position: Vector (это вектора к каждому листочку);
- перетягиваем функцию вычитания векторов Function, Vector, Subtraction X-Y;
Теперь надо сложить наш вектор скорости объектов и вектор от центра дерева до каждого листочка:
- добавляем оператор Input Standard, Speed: Vector;
- добавляем функцию сложения векторов Function, Vector, Addition X+Y;
- вытаскиваем Output Standard, Speed: Vector (выводим все полученные значения в новый вектор скорости, т.е. направление листочков).
Общая схема представлена ниже. Обратите внимание, что с помощью коэффициентов Pre-Factor нужно добится оптимального влияния на направление листиков каждого из векторов (у меня это 0,001 и 1000,0):
Теперь, если перемещать вспомогательный объект, можно видеть, как листики как бы отворачиваются от него при этом влияние нормали поверхности сохраняется.
5. Переносим нашу модель на реальные веточки.
Для этого в операторах Position Object и Speed by Surface выбираем наши ветки, а сферу оттуда можно Remove. В Birth я увеличил число листиков (Amount) до 1000 штук:
Результат меня вполне устраивает. Если нет – можно поиграться различными коэффициентами, чтобы добиться требуемого результата или добавить какие-то свои операторы.
6. Убираем пересечение между листиками.
Теперь, используя операторы с приставкой mP.., которые позволяют проводить расчёт столкновений частиц, попробуем избавиться от пересечений.
- под Shape Instance перетаскиваем mP Shape с параметрами Collide As: Convex Hill, Display As: Wireframe (создалась сетка,которая будет участвовать в расчёте столкновений);
- под него перетаскиваем mP World (чтобы расчёт заработал) и жмём кнопочку Create New Driver;
Если проиграть анимацию Вы увидете, как листочки, которые пересекались, разлетаются в разные стороны. Чтобы они не разлетались мы добавим вязкости среде:
- переносим оператор mP Drag, с галочками и высокими значениями Linear и Angular в Damping Factor (я поставил по 1000).
Теперь уже на первых кадрах пересекающиеся листики отодвигаются друг от друга и останавливаются.
Здесь стоит сказать о несовершенстве метода, которое состоит в том, что листики становятся не привязанными к веткам и в некоторых случаях от них тоже отодвигаются и, чем плотнее листва, тем дальше от своих мест отодвинутся листочки.
7. Убираем пересечение листиков с ветками.
Следующим шагом я хочу попробовать убрать пересечения листьев и с ветками, на которых они растут. Для этого я создал копии веток и применил к ним модификатор Push со значением -0,2.
Затем назначим модификатор PFlow Collision Shape и нажмём кнопочку Activate.
В Particle View добавляем оператор mP Collision и указываем там наши объекты веток.
Теперь расчитывается пересечения и с нашими веточками, но, как показала практика.. далеко не везде :/ Если лист изначально был «проколот» веткой, то он остаётся на месте:
Теперь возникает вопрос.. Как много листиков таким методом можно одновременно просчитать? Видимо зависит от компьютера, но, к моему удивлению, всё достаточно шустро работает:
У меня на 1 000 листьев нет заметных тормозов.
5 000 листочков рассчиталось с небольшими тормозами.
На превью над 10 000 листиками без пересечений комп думал 30 секунд:
8. Сохраняем полученный результат в геометрию.
Ищем Mesher в Compound Objects, создаём объект в нулевых координатах и там выбираем нашу систему частиц:
Полученный объект конвертируем в Editable Poly и.. на этом всё!
Я удалил и вручную подправил несколько листочков, пересечения которых с ветками бросалось в глаза. Можно спрятать или удалить системы частиц и отрендерить полученный результат:
Благодарю за внимание! Конструктивная критика и идеи только приветствуются!
Небольшое видео процесса создания листвы:
Комментарии (36)


































