Процедурная генерация через математику: noise, rand, sin
core Сгенерировать управляемую вариативность формы, масштаба или цвета объекта математической функцией в VEX с воспроизводимым сидом
Процедурная вариативность строится на трёх примитивах: noise() — плавные органичные отклонения, rand() — контролируемая случайность с seed, тригонометрия (sin, cos) — регулярные формы. Разница принципиальна: noise — непрерывная функция от координаты (соседние точки получают близкие значения), rand — псевдослучайное число без пространственной связи между соседями, зависящее только от переданного аргумента.
Случайность и воспроизводимость
rand() в VEX детерминирована: один и тот же вход всегда даёт один и тот же выход. Поэтому seed строят из стабильного идентификатора (@ptnum, @primnum) плюс параметр ноды:
float r = rand(@ptnum + chi("seed"));
chi() читает int-параметр ноды — аналог chf() из первого урока, только для целых. Меняя один слайдер seed, вы получаете другой, но полностью воспроизводимый набор значений — это требование для ассетов: художник должен уметь повторить результат.
Структурированный шум
Для плавной вариативности по пространству берут noise(@P * freq): значение зависит от позиции, а не от индекса, поэтому соседние точки поверхности получают похожие, а не рваные значения. Частотой (масштабом деталей) управляет множитель у @P:
float n = noise(@P * chf("freq")); // диапазон уточните в Geometry Spreadsheet
Приведение диапазонов: fit / clamp
Результат шума и рандома почти всегда нужно перевести в диапазон, осмысленный для целевого атрибута:
float s = clamp(n, 0.0, 1.0); // жёстко ограничиваем
s = fit01(s, 0.2, 1.0); // и растягиваем в целевой диапазон
float t = fit(v, -1, 1, 0.0, 1.0); // общий случай: из [-1,1] в [0,1]
fit(value, oldmin, oldmax, newmin, newmax) — линейный ремап; fit01(v, newmin, newmax) — короткая форма, когда вход уже в [0,1]; clamp(v, min, max) — обрезка по границам.
graph LR
A[seed параметр ноды] --> B["rand(@ptnum + seed)"]
C["@P"] --> D["noise(@P * freq)"]
B --> E["fit / fit01 / clamp"]
D --> E
E --> F["@pscale, @Cd, @P — конечная вариативность"]Разобранный пример
Задача: разбросать инстансы (например, камни) с вариативным масштабом и лёгким органичным цветовым разбросом; результат должен быть воспроизводим по seed.
// Attribute Wrangle после Scatter, Run Over: Points
int seed = chi("seed");
float freq = chf("noise_freq");
// случайный масштаб, свой на каждую точку
float rscale = rand(@ptnum * 17 + seed);
@pscale = fit01(rscale, 0.6, 1.4); // от 0.6x до 1.4x
// органичная цветовая вариация, связанная с положением в пространстве
float n = clamp(noise(@P * freq), 0.0, 1.0);
@Cd = set(fit01(n, 0.3, 0.5), fit01(n, 0.2, 0.35), fit01(n, 0.1, 0.2));
Разбор: масштаб через rand даёт разброс без пространственной связи — камни разного размера вперемешку. Цвет через noise(@P * freq) даёт плавные пятна, похожие на естественную вариацию породы. Множитель 17 в @ptnum * 17 просто разводит близкие индексы, чтобы соседние значения rand не выглядели похожими; смысла seed это не меняет. Атрибуты @pscale и @orient дальше «читаются» нодами копирования/инстансинга (Copy to Points) автоматически.
Попробуй сейчас
Возьмите Scatter (или любой набор точек) → Attribute Wrangle. Добавьте int-параметр seed и float-параметр freq. Напишите код: @pscale — значение rand(@ptnum + seed), отремапленное через fit01 в [0.5, 1.5]; @Cd — оттенок серого из noise(@P*freq), приведённый к [0,1] через clamp/fit. Проверьте колонки pscale и Cd в Geometry Spreadsheet.
Ожидаемый результат: при фиксированном seed повторный расчёт даёт идентичный набор масштабов и цветов; при смене только seed — другой набор, но статистически похожий (тот же диапазон значений).
Получилось, если…
Вы это поняли, если можете объяснить разницу одной фразой: «rand даёт несвязанные значения на соседних точках, noise — плавно меняющиеся в зависимости от координаты» — и знаете, зачем в обоих случаях нужен fit/clamp перед записью в атрибут.
Вывод
rand(@ptnum + seed) — воспроизводимая, но пространственно несвязанная случайность; noise(@P * freq) — плавная пространственная вариация. И то, и другое почти всегда пропускается через fit/clamp, чтобы попасть в осмысленный диапазон атрибута (@pscale, @Cd, @P).
AI-generated · source-grounded review
🛡 Fact-checked: 3 risky claims verified · 2 removed · confidence: medium · figures: 1
A second opinion has not checked this lesson.
On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Write my course