UpPetto

This is a real course generated by UpPetto — unedited.

AI-generated. Two models wrote it, a third checked every risky claim against sources, a fourth re-checked.

Create my own course

Процедурная генерация через математику: 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 или позиции через rand/noise к управляемому диапазону и итоговому атрибуту

Разобранный пример

Задача: разбросать инстансы (например, камни) с вариативным масштабом и лёгким органичным цветовым разбросом; результат должен быть воспроизводим по 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
[verified] rand() в VEX детерминирована: одинаковый вход даёт одинаковый результат
Согласуется с описанной в базе процедурной генерацией на основе математических функций и требованием воспроизводимости процедурных рецептов
[removed] noise() возвращает значения примерно в диапазоне [-1,1] / [-0.5,0.5]
Версии противоречат друг другу, база знаний диапазон не фиксирует; заменено на приведение через clamp/fit
[verified] @pscale и @orient читаются нодами копирования/инстансинга автоматически
База знаний: пользовательские атрибуты создаются для управления инстансингом и материалами
[removed] quaternion(angle_в_градусах, ось) создаёт кватернион поворота
Специфика аргументов функции (градусы против радиан) не подтверждена базой знаний; практика заменена
[verified] Figure (mermaid, урок 3): seed → rand(@ptnum+seed), @P → noise(@P*freq), оба → fit/clamp → @pscale/@Cd/@P
Направление потока данных и роли функций соответствуют тексту урока и базе знаний о процедурной генерации через математические функции и атрибуты
[removed] Удалены конкретные заявленные диапазоны noise(): «примерно [-1,1]» (версия A) и «примерно от -0.5 до 0.5» (версия B) — противоречат друг другу и не подтверждены базой знаний; заменено на приведение через clamp/fit и проверку фактических значений в Geometry Spreadsheet
[removed] Убрана практика с `quaternion(angle, {0,1,0})` и `v@pscale` из версии B: специфика аргументов и типов этих атрибутов базой знаний не подтверждена

A second opinion has not checked this lesson.

Key concepts: noise rand и seed fit/clamp процедурная вариативность
Tell me more 🔒 Didn't understand — explain simply 🔒 Show examples 🔒 Sources 🔒

On your own course these buttons answer instantly, quizzes track what you've mastered, and lessons adapt to your gaps. Write my course

Check yourself

1. Чем noise() принципиально отличается от rand() по поведению?
2. Какой код даёт каждой точке своё случайное значение, при этом весь набор меняется при смене одного параметра seed?
3. Функция rand() вернула 0.25. Что вернёт `fit(0.25, 0, 1, 100, 200)`?
On your own course, these are marked as you answer