big
VEX

Раздел посвящен изучению основ работы с VEX — встроенным языком программирования в Houdini FX, который позволяет управлять геометрией и атрибутами через код.

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

Референсы

В этом разделе мы завершим работу над ассетом и создадим композицию с использованием вариаций итоговой модели.

GOAT 1. Golden Hour / Dearme. Sacred Secret

Прежде чем перейти к финализации модели и созданию лэйаута, разберем основные инструменты и принципы, которые понадобятся для управления геометрией на этапе сборки сцены.

Attribute Wrangle

При написании VEX кода для работы с геометрией чаще всего используется Attribute Wrangle. Работая с этой нодой, важно выбрать верный режим (Run Over) — разные режимы предназначаются для работы с разными уровнями геометрии:

  • Detail (Serial Mode) — код исполняется один раз
  • Points/Primitives/Vertices (Parallel Mode) — код запускается на каждой точке / вершине / примитиве одновременно, это параллельный процесс

Чтобы увидеть разницу в работе этих режимов, создадим короткий код, выводящий в консоль координаты текущей точки. Создадим Attribute Wrangle, подключим любую геометрию в качестве входных данных, исполним выражение поочередно в Serial и Parallel Mode, и сравним результаты:

vector point_position = point(0, «P", @ptnum); printf(«position X = %s\n», point_position.x);

// Функция point () запишет в векторную переменную point_position значения позиции (@P) для каждой обрабатываемой точки (@ptnum) // Функция printf () выведет в консоль все значения point_position

Basic Assignments

Мы уже знакомы с атрибутами как способом хранения данных в точках, примитивах и других элементах геометрии. VEX позволяет создавать и изменять эти атрибуты напрямую: для того чтобы создавать или объявить атрибут, достаточно написать его в окне VEXpression в таком формате:

v@myVectorAttribute; f@myFloatAttribute; i@myIntegerAttribute; s@myStringAttribute;

При работе с встроенными (стандартными, уже существующими в Houdini) атрибутами, тип данных перед @ определять не нужно:

@P;
 @ptnum;
 @numpt;

Как и в других языках программирования, основанных на C, в VEX можно легко выполнять все стандартные арифметические действия. Например, градиент-маску для использования в шейдинге можно быстро создать с помощью простого выражения:

f@mask = float(@ptnum)/@numpt;

Original size 4167x2813

Attributes & Variables

Работая с VEX, важно понимать разницу между атрибутами и переменными:

  • Атрибуты — это данные, которые прикреплены к геометрии. Например, @P (позиция точки) или @Cd (цвет)
  • Переменные — это временные значения внутри Wrangle, которые не существуют вне ноды, исполняющей код
Original size 1754x1240

Например, при необходимости рассчитать угол изгиба стебля, можно записать в Attribute Wrangle такой код:

float bend = fit01(rand(@ptnum), 10, 45);
 @bend = bend;

// float bend является локальной переменной, которая создаётся для расчёта и существует только внутри Attribute Wrangle
 // @bend является атрибутом, которому присваивается значение локальной переменной bend. Он сохраняется не геометрии и может быть использован в последующих нодах

Noise Functions

Original size 3839x2500

В качестве финального этапа работы над моделью, добавим мелкие детали, которые будут видны на крупных планах: прожилки, заломы и неровности.
Опираясь на референсы выше, создадим похожий эффект с использованием Worley Noise с помощью функции wnoise() в ноде Attribute Wrangle.

В отличие от стандартной функции noise (), Worley Noise лучше подходит для имитации органических паттернов, так как формирует структуру из ячеек, похожую на сетку прожилок. Его формула выглядит так:

wnoise(position, &seed, &f1, &f2)

Функция wnoise () случайно размещает в трехмерном пространстве точки (feature points), а затем, на их основе, делит его на «ячейки». Знаком «&» отмечены переменные, значения которых возвращает wnoise () для каждой точки обрабатываемой геометрии:

  • f1 — расстояние до ближайшей feature point
  • f2 — расстояние до второй ближайшей feature point
Чтобы шум не зависел от положения лепестка в мировой сцене, в качестве position мы используем UV координаты:

int seed;
 float dist1, dist2; wnoise(@uv, seed, dist1, dist2); @P += dist1 * @N;

  • В первых строках объявляются локальные переменные типов int и float
  • Функция wnoise () вычисляет значения Worley Noise на основе @uv
  • Последняя строка сдвигает точки геометрии на значение шума (dist1) вдоль нормали (@N)

Чтобы регулировать силу выдавливания паттерна, создадим локальную переменную amp, которая будет выступать в роли коэффициента:

float amp = 0.5;
 wnoise(@uv * amp, seed, dist1, dist2);

Так как прожилки имеют горизонтальный характер, добавим также векторный коэффициент freq, чтобы изменять частоту по трем осям независимо друг от друга:

vector freq = {5,1,1}; wnoise(@uv * freq, seed, dist1, dist2);

Чтобы найти наилучший вариант деформации, добавим возможность смещать шум за счет локальной переменной offset:

float offset = 5; wnoise(@uv + offset, seed, dist1, dist2);

В итоге, готовый код будет выглядеть так:

float amp = 0.1;
 vector freq = {5,1,1};
 float offset = 5;
 int seed;
 float dist1, dist2;
 
 wnoise(@uv * amp * freq + offset, seed, dist1, dist2);
 @P += dist1 * @N;

Original size 1600x1080

UI Controls

Теперь, для более удобной настройки эффекта без необходимости ручного редактирования кода, можно вынести необходимые параметры в интерфейс ноды.

Пользовательские параметры можно объявить в Attribute Wrangle с помощью различных функций:

  • chf («name») — для значений типа float
  • chv («name») — для значений типа vector
  • chi («name») — для значений типа int
  • chs («name») — для значений типа string

В нашем случае, в параметры можно вынести amp, freq и offset, которые нужно будет часто изменять в ходе настройки внешнего вида модели.

float amp = chf(«amplitude»); vector freq = chv(«freq»); float offset = chf(«offset»); int seed = chi(«seed»);

wnoise (@uv * amp * freq + offset, seed, dist1, dist2);
 @P += dist1 * @N;

При использовании этих функции в коде, Attribute Wrangle автоматически предложит создать параметры в интерфейсе:

Original size 1600x1080

С добавлением пользовательских параметров в Attribute Wrangle, настраивать действие ноды станет удобнее. Кроме того, как и другие параметры, эти слайдеры позволяют создавать parameter references
.

Original size 1360x918

For Loops

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

Для выполнения множества итераций однотипных действий с изменяемыми параметрами удобно использовать цикл for. В VEX его базовая структура выглядит так:

for (начальное значение; условие; шаг) {
 ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ //Действие, пока выполняется условие
 }

Добавим эту конструкцию у уже готовому коду и укажем количество «слоев» шума в локальной переменной iter:

float amp = ch («amplitude»);
 vector freq = chv («freq»);
 float offset = chf («offset»);
 int seed = chi («seed»);
 float dist1, dist2;
 vector pos = @uv; int iter= chi(«number_of_iterations»);



for (int i = 0; i < iter; i++) { 
‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ wnoise (pos* freq + offset + i, seed, dist1, ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎dist2); 
‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ @P += dist1 * amp * @N; }

// int i = 0 — это начальная инициализация счётчика. Переменная i создаётся внутри цикла и в первой итерации равна 0. Именно с неё начинается отсчёт количества повторений
 // i < iter — это условие продолжения цикла
 // i++ — это инкремент счётчика, то есть увеличение i на единицу при каждой итерации (аналогично записи i = i+ 1) // внутри цикла переменная i используется в качестве дополнительного offset для Worley Noise

Original size 1600x1080

Get Values from Other Inputs

post

Чтобы добиться еще более естественной деформации, можно комбинировать несколько шумовых паттернов с разным масштабом и уровнем детализации. Попробуем сделать это, используя разные входы Attribute Wrangle.

Attribute Wrangle, как и многие другие ноды, поддерживает несколько входов: по умолчанию используется первый (Input 0), но при необходимости можно обращаться и к другим, подключая дополнительные потоки данных для совместной обработки в одном коде.

Например, на первый вход Attribute Wrangle подаётся геометрия с мелкочастотным шумом, а на второй — с более крупным паттерном. В этом случае с помощью функции point () можно считать данные с второго входа и создать простой блендшейп а основе функции lerp ():

vector pos = point (1, «P» ,@ptnum); @P = lerp (@P, pos, ch(«intensity»));

// В переменную pos записываются данные о положении (@Р) каждой точки (@ptnum), из второго входа (1) // Функция lerp () линейно интерполирует позиции точек из первого (@P) и второго (pos) входов, в соответствии с значением Intensity, который регулирует силу смешивания

Для более точного соответствия референсу, крупные искажения следует оставить только на кончиках. Чтобы ограничить области воздействия шумов остается только добавить маску (f@blend):

vector pos = point (1, «P» ,@ptnum); @P = lerp (@P, pos, f@blend);

Original size 1600x1080

Условия в VEX: If Statement

Когда работа над детализацией закончена, соберем готовые модели в небольшую композицию, поместив их на несколько стеблей, созданных в ноде curve. Для того чтобы изолировать точки для копирования (вершины стеблей), необходимо создать условие: удалены должны быть все точки, кроме последних (по номеру) на каждой кривой.

Для процедурного удаления точек используем If statement:

If
 (условие) {
 ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ // Действие, если условие истинно
 }

При необходимости, можно добавить альтернативное действие:

If
 (условие) {
 ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ // Действие, если условие истинно
 } else {
 ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ // Действие, если условие ложно
 }

В нашем случае условием будет удаление последней по номеру точки на каждом примитиве:

int pts[] = primpoints(0, @primnum); int last = pts [len (pts)-1]; 
 if (@ptnum != last) { ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ removepoint(0, @ptnum);
 }

// С помощью primpoints () получаем массив всех точек, принадлежащих примитиву с номером @primnum // В строке last = pts[len (pts)-1] получаем индекс последней точки на каждом примитиве, и записываем его в переменную last // Функция removepoint () срабатывает для всех точек, кроме последних (@ptnum != last)

Original size 1600x1080

В завершение, с помощью конструкции «If…Else», поместим на точки модели бутонов. По итогам прошлого раздела мы экспортировали на диск несколько вариаций модели бутона:

  • Bud_1 — закрытый;
  • Bud_2 — полураскрытый;
  • Bud_3 — полностью раскрытый;
Вместо случайного копирования, создадим правило: чем ниже цветок наклонен к земле, тем сильнее он закрыт.

Сначала вычислим наклон — это скалярное произведение между встроенным атрибутом точки @tangentu и вектором {0,1,0}, которое можно вычислить с помощью функции dot (). Результат запишем в переменную tilt:

float tilt = dot (@tangentu, {0,1,0});

post

Так как диапазон значений tilt от -1 (вектора противоположны, кончик стебля смотрит вниз), до 1 (вектора сонаправлены, кончик стебля смотрит вверх), мысленно разделим его на три сегмента и добавим условие с использованием if Statement:

float tilt = dot(@tangentu, @up);

 int bud_variant;



if (tilt > 0.25) { ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ bud_variant = 3; 
 } else if  (tilt > -0.25&& tilt <= 0.25) {
‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ bud_variant = 2;
 } else {

‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ ‎ bud_variant = 1;
 }

s@instancepath = sprintf ( "$HIP/Assets/Bud_%d.bgeo.sc" , bud_variant);

Так, s@instancepath на разных точках будет принимать значения:

  • «$HIP/Assets/Bud_1.bgeo.sc» — для стеблей, ориентированных вниз
  • «$HIP/Assets/Bud_2.bgeo.sc» — для слегка наклоненных стеблей
  • «$HIP/Assets/Bud_3.bgeo.sc» — для стеблей, ориентированных вверх
Original size 1600x1080

Так, мы получаем завершенный ассет и основу для лэйаута:

Original size 1920x1380

Задание

Описание Финализируйте ассет и соберите лэйаут с использованием вариаций модели

Результат .hip-файл проекта

Ссылки

We use cookies to improve the operation of the website and to enhance its usability. More detailed information on the use of cookies can be fo...
Show more