Вы находитесь на странице: 1из 724

Сергей Цыпцын

В двух книгах

Книга вторая

0 0 0 "Арт Хаус медиа"


Москва 2007
ББК 68я73
УДК 004(75)
П75

Цыпцын Сергей.

П 75 Понимая MAYA

Издательство 0 0 0 "Арт Хаус медиа", 2007


В двух книгах/ - М. Издательство 0 0 0 "Арт Хаус медиа", 2007 - 1428 с.

ISBN 978-5-902976-03-5

Эта книга не о том, "как" сделать красиво и не от том, как освоить программу за 21
день. Эта книга о понимании принципов, по которым работает MAYA.
Автор, выпускник мехмата МГУ, соединил академический научный подход и легкий
стиль изложения. Среди прикладной литературы, посвященной компьютерным
программам, эта книга является совершенно уникальной, так как призывает читателя
вникнуть в саму суть построения программы и понять логику использования ее
инструментов.
Автор является официальным российским "проповедником" MAYA, а также
единственным в России сертифицированным инструктором компании Autodesk по
этому пакету.
Материал построен на основе семилетнего цикла лекций, прочитанных автором,
и является предельно субъективным и неформальным. В подготовке книги автору
помогали лучшие специалисты отечественной индустрии компьютерной графики.

ISBN 978-5-902976-03-5
© Цыпцын Сергей, 2007
® 0 0 0 "Арт Хаус медиа", 2007
Содержание

Книга 2
Глава 7 Персонажная анимация .718
Настройка персонажей 719
Использование готовых решений 720
«Мануальная терапия». Кости и суставы. Построение скелета 721
Вправление суставов.
Кошмары с локальными осями.
Автоматическая и ручная настройка ориентации 724
Степени свободы и неволи 726
Издевательство над костями. Удобные локаторы 728
Кинематика - инверсная и прямая 729
Свойства IK-манипуляторов 731
Алгоритмы вычисления инверсной кинематики.
Типы IK-манипуляторов. IK Solvers 732
Алгоритм Rotation Plane Solver 732
Алгоритм Single Chain Solver 735
Алгоритм Two Bone Solver 735
Алгоритм Multi Chain Solver 735
Анимация длинных цепочек 738
Атрибуты суставов, корректирующие поведение инверсной кинематики ... ....739
Joint Rotation Limit Damping - мягкое торможениие 741
Прямая и инверсная кинематика. Дело вкуса. Свобода воли 741
Смешивание прямой и инверсной кинематики. История вопроса 742
Смешивание прямой и инверсной кинематики - современный подход 743
Операция Set IK/FKKey. Анимация переключения кинематик 743
Переключение и смешивание FK и IK 744
Операция Connect IK/FK 745
IK Spline Solver - анимация хвостов, усов и щупалец 746
Борьба с перекручиваниями - IK Spline Handle 748
Практический пример настройки персонажа: сетап крыла 750
Настройка модели крыла 751
Строение крыла 755
Кожа да кости 756
Перья 756
Построение крыла 757
Построение «шаблона» будущего скелета 758
Построение скелета 760

76
Оперение крыла 763
Управление крылом 764
Управление задней кромкой 766
Перенос анимации. Навешивание ярлыков.
Animation Retargeting. Joint Labelling 777
Полнотельная кинематика: Full Body IK 786
Подготовка скелета к использованию Full Body IK 787
Создание системы управления Full Body IK 789
Пиннинг, или прикалывание 791
Анимация с помощью эффекторов.
Внутреннее устройство Full Body IK 792
Проблемы синхронизации. Немного о грустном 799
Двойной пивот. Secondary Controller 800
Жесткий контакт с землей 801
Некоторые комментарии к системе Full Body IK 803
Нелинейна анимация Non-linear Animation 805
Обобщенный «Персонаж». Character Set 806
Подперсонажи - SubCharacters 808
Позы и клипы 809
Работа с Trax Editor 810
Создание и редактирование клипов 811
Изнанка клипов 812
Абсолютные и относительные клипы и каналы 815
Склеивание и смешивание клипов 818
Немного тонкостей, или еще раз об абсолютных клипах 820
Редактирование анимационных кривых для клипа 823
Временная активизация ключей 825
Корректирующая анимация. Ключи поверх клипов 826
Монтаж анимации 827
Слияние и запекание клипов 828
Деформация времени. Retiming 828
Вес клипов 829
Некоторые комментарии на нелинейную тему 830
Практические замечания относительно нелинейной анимации 831
Клипы 832
Absolute и Relative 832
Blend 833
Motion Wrap 834
Time Warp 834
Нестандартное использование клипов.
Движение по пути, или Macro Driven Key 835
Некоренные переходы между клипами 836
«Шкурный вопрос»: скининг персонажей 837
Создание скининга 838
Методы мягкого и жесткого скининга 839
Нормализация весов 842
Нода skinCluster и tweak 843
Поза привязки: Bind Pose 843
Редактирование скининга. Paint Skin Weights Tool 844
Объекты влияния: Influences 847
Назначение и использование объектов влияния.
Некоторые анатомические и философские аспекты
мышечных деформаций 851
Копирование весов 852
Сохранив и восстановление весов 852
Изучение чужих персонажей 853
Практические замечания по скинингу персонажей 855
Дополнительные кости и раскладывание вращения на сгиб
и скручивание для корректного скининга 858
Глава 8 M E L , и л и MAYA E m b e d d e d Language 864
Про что эта глава 865
Что такое MEL? 865
Есть скрипт! 867
MEL-ресурсы 867
Освоение MEL. Как все начинается 868
MAYA API 868
Не для программистов. Как примерно все происходит 870
Немного MEL-команд. Работа с документацией 871
Структура MEL-команд 871
Особенности работы в Script Editor 872
Применение MEL для работы со списком выделенных объектов 873
Переменные и типы данных 875
Массивы 877
Полный путь к объекту или атрибуту 878
Работа с циклом. Перебор объектов в списке 879
Скобки и кавычки 881
Комментарии 882
Добавление вращения 882
Создание Noise Deformer 884
Граница применимости MEL 887
Процедурное моделирование 887
Важное замечание про округления и забытые точки 890
Проверка существования объекта. Условные переходы 891
Использование различных функций 892
Invalid redeclaration и область видимости переменных 897
Скрипты и expressions. Различия и сходства 898
Нетрадиционные выражения.
Выращивание объектов в анимации 899
Интерактивность построения кривых 902
Построение траекторий и хвостов 903
Поджигание хвоста 905
Пример использования MEL для решения проблем.
Интерактивный рендеринг нужного количества кадров 906
Программирование интерфейсов пользователя на MEL 908
Работа с кнопками 915
Объявление и вызов процедур 918
Разница между объявлением и выполнением 919
Работа с файлами. Чтение и запись 919
Спецсимволы. Косые и обратные черты. Кавычки в кавычках 922
Чтение данных из файла 924
Оформление скрипта в виде процедуры. Вызов его с диска 925
Порядок вызова и расположение пользовательских
и стандартных скриптов. Что происходит при вызове MEL-команды 928
Как запускать скрипты, скачанные из Интернета 929
Что такое Source Script 929
Script Node, или expression по вызову 930
Интерфейс для рисования процедурных кривых 934
Режимы команд построения элементов интерфейса 936
Имена элементов интерфейса 937
Работа с меню. Минимизация всех открытых окон 940
Как заставить MAYA выполнять команды при загрузке 943
Немногое хакерстве, или моя MAYA 944
О глобальных переменных 945
Создание интерфейса с помощью веб-браузера.
Радикально альтернативный подход 946
Все, что вы хотели узнать про MEL 947
Некоторые практические советы 947
История. Я опять не хочу в Париж 949
Глава 9 Paint Effects .954
Рисовальные эффекты 955
Рекомендации по освоению Paint Effects 955
Классовая принадлежность Paint Effects 956
Применения Paint Effects 956
Природа Paint Effects. Штрихи 958
Природа Paint Effects. Кисти 959
Смешивание кистей 961
Последняя кисть. Template Brush 962
Атрибуты кисти 962
Два ключевых типа кистей. Tubes 963
Размер кисти 964
Природа кистей. Спрайты. Визуализация штрихов 964
Природа кистей. Рендеринг. Композитинг. Постэффекты 965
Работа с обычными штрихами. Рендеринг кривых 965
Сохранение собственных кистей 970
Работа с кистями растительного и животного происхождения 971
Рисование по поверхности 971
Редактирование атрибутов кисти 972
Конвертация Paint Effects в полигоны 972
Настройка ширины 974
Выращивание конечностей. Работа с атрибутами кисти 976
Направление роста и ориентация по пути 976
Анимация листьев-конечностей 978
Визуализация и текстурирование 979
Методы рендеринга Paint Effects 980
Тектстурирование листьев-конечностей 981
Шипы и мохнатые лапы 982
Усы, цветы и прочие отростки 982
Размножение муравьев 983
Улучшение анимации 985
Изменение индивидуальных атрибутов вдоль пути 986
Тени 987
Природа кистей. Тени 988
Анимация кистей и штрихов 988
Ручная деформация штрихов Paint Effects 989
Встроенные пружины 992
Ручная анимация. Модификаторы 995
Анимация роста и старения 996
Искусственное размножение 998
Авторисование 999
Некоторые замечания по поводу рендеринга 999
Туман, глубина и прозрачные объекты 1000
Оптимизация просчета и интерактивной работы 1001
История 1002
Глава 10 Динамическая симуляция 1004
Динамика твердых тел 1007
Колбасинг 1007
Законы динамики 1009
Закон динамики 1 1010
Закон динамики 2 1011
Закон динамики 3 1011
Закон динамики 4 1012
Закон динамики 5 1012
Концепция твердости тел 1013
Свойства твердых тел 1015
Анимация активности твердых тел 1016
Закон динамики 6 1016
Катание шаров 1017
Избавление от динамики. Выпекание ключей 1023
Свойства полей 1025
Игра «Место под солнцем» 1025
Конструктивные констрейны для твердых тел 1028
Подвесной таран 1028
Твердые сабдивы 1031
Просчет ненужных столкновений 1033
Искусство бить посуду 1033
Секретные атрибуты и слежение за ударами 1036
Уловки и трюки при работе с динамикой 1040
Поведение, а не траектория 1040
Твердые тела всегда остаются твердыми 1041
Соблюдайте скоростной режим 1041
Используйте альтернативную динамику 1041
Почаще испекайтесь 1041
Глава 11 Динамика частиц 1044
Применения систем частиц 1045
Особенности работы с частицами 1045
Природа частиц 1046
Столкновения с препятствиями 1051
Испускание частиц с поверхностей и кривых 1052
Свойства и атрибуты частиц 1053
Продолжительность жизни и курение сигарет 1059
Время жизни и возраст частиц 1067
Массивные атрибуты (Per Particle Array Attributes) 1067
Индивидуальные динамические атрибуты 1068
Вопрос приоритетов 1070
Работа с индивидуальными атрибутами 1070
Component Editor 1070
Как обсыпать объект частицами? 1071
Обнуление скоростей. Начальное состояние 1072
Использование текстуры Ramp для управления частицами 1074
Particle Expressions - от порядка к хаосу и обратно 1078
Создание, выполнение и виды Particle Expressions 1081
Ода функции rand 1085
До и после динамики 1086
Работа со скоростью и ускорением 1087
Goal, или воля к победе 1090
Интерактивное взаимодействие с динамикой:
Interactive Playback 1093
Многоцелевые частицы 1094
goalU и goalV, или как уложить частицы точно на поверхность 1095
Концепция мягких тел 1098
Фальшивый занавес 1102
Как надуть модель? 1108
Инстансирование. Подстановка объектов в частицы 1112
Множественная подстановка 1120
Сжатие и растяжение динамики 1125
Ускорение/торможение падения твердых тел 1125
Замораживание частиц - остановка динамического времени 1128
Кэширование частиц 1141
Визуализация частиц 1143
Аппаратный дымок 1144
Аппаратный дымок нового типа 1147
Софтверный дым 1148
ParticleSamplerlnfo - переносчик информации 1150
Железный рендер 1152
Практические советы и ухищрения 1153
Прежде всего, некоторые советы: что и чем делать 1153
Работа со спрайтами 1153
Работа с мультистриками 1154
Особенности работы с motion blur 1154
Длинная история 1155
Глава 12 MAYA Fluids 1160
Область применения MAYA Fluids 1161
Типы флюидов 1162
Контейнеры и внутреннее устройство флюидов 1162
Размер и разрешение контейнера 1164
Содержимое и начинка контейнера 1165
Типы контейнеров и распределение свойств внутри них 1166
Заполнение контейнера 1167
Начальное состояние 1169
Примеры для изучения 1169
Заполнение контейнера раскрашиванием 1171
Как опустошить контейнер 1173
Динамическая анимация флюидов 1174
Так почему же все плывет вверх? 1175
Взаимодействие флюидов с «нормальной» динамикой 1177
Кэширование флюидов 1179
Визуализация флюидов. Поверхности 1181
Пресеты. Контейнер сыра 1189
Конвертирование в полигоны 1189
Визуализация объемных флюидов 1189
Практические советы по работе с контейнерами 1195
Оптимизация визуализации 1196
Флюиды как текстуры 1197
Акватория MAYA 1199
Визуальные свойства поверхности воды 1201
Рыбалка на озере 1202
Буйки и поплавки 1204
Внутреннее устройство океана 1205
Интерактивная визуализация морской поверхности 1206
Динамическая анимация морской поверхности 1208
Визуализация акватории 1209
Основной прием при работе с морской поверхностью 1210
История насыщенного контейнера 1210
Глава 13 Меховая глава 1214
Меховые применения MAYA Fur и отличия от MAYA Hair 1215
Устройство MAYA Fur 1216
Меховой вывод: мех - это большая процедурная текстура 1216
Подготовка модели к покрытию мехом 1217
Причесывание и редактирование меховых свойств 1219
Настройка формы и внешнего вида меха 1226
Главный метод изучения свойств меха 1228
Причесывание кистями несуществующего атрибута Direction 1228
Освещение меха 1232
Еще немного про визуализацию или взрослый мех 1236
Меховые проблемы 1238
Практические рекомендации по оптимизации просчета меха 1239
Использование Mental Ray для просчета меха 1240
Немного про Renderman 1241
Анимациямеха 1242
Глава 14 Волосатый симулятор 1254
Применения MAYA Hair 1255
Рекомендации по освоению MAYA Hair 1256
Закон динамики 1 1257
Закон динамики 2 1257
Закон динамики 3 1257
Закон динамики 4 1257
Закон динамики 5 1257
Неформальный закон динамики 1257
Архитектура и устройство MAYA Hair 1257
Создание системы волос 1258
Типы визуализации волос 1258
Требования к поверхности для создания волос 1259
Система волос и ее свойства 1263
Взаимодействиесостандартными полями 1265
Редактирование длины волос 1266
Сохранение начального положения 1267
Долгий разговор о коллизиях и взаимодействии с поверхностям 1268
Индивидуальные свойства волос 1273
Творческий выбор 1274
Изменение индивидуальной гибкости кривых 1275
Стартовые кривые: Start Curves 1276
Отображение стартовых кривых 1276
Редактирование начальной формы 1277
Три типа кривых при работе с системой волос 1282
Система констрейнов для динамических кривых 1282
Атрибуты констрейнов 1289
Симуляция столкновений с помощью констрейнов 1288
Выбор поверхностей и оптимизация столкновений 1289
Визуализация системы волос 1290
Различные способы визуализации системы волос 1290
Непосредственный рендерингкривых 1291
Стандартная визуализация с помощью Paint Effects 1292
Форма системы волос. Химзавивка 1294
Цвет волос. Мелирование и прочие глупости 1296
Волосы и текстуры цвета 1297
Визуализация волос с помощью кистей Paint Effects 1298
Традиционное применение MAYA Hair 1302
Создание волос 1302
Практическое создание прически 1303
Стрижка, укладывание и прическа 1306
Пассивные кривые. Увеличение густоты прически 1311
Визуализация. Настройка формы волос 1312
Визуализация. Настройка освещения 1314
Глобальное удлинение 1316
Практические методы увеличения визуальной густоты волос
и экономии вычислительного времени 1318
Заплетание косичек 1319
Рендеринг волос с помощью mental ray 1321
Работа с кэшированием 1322
Динамические кривые как самостоятельные объекты 1322
Разрезание веревки 1323
Наследование цвета волос с текстуры 1326
Универсальный совет для работы с волосами 1330
Аэродинамическая история 1330
Глава 15 Рендеринг 1333
Renderman 1338
Сношения с внешними рендерерами или присовокупление к Renderman'y 1339
Зачем? 1339
MAYA + внешние рендереры = ? 1342
MAYA + Renderman = хорошо 1344
Ужасная история в поезде 1351
RAT, или Рендерим Визуально 1352
MTOR 1352
Alfred 1354
Alfserver 1355
It 1355
SLIM 1357
Irma 1360
prman, или Закапываемся 1360
prman.exe 1361
Другие RIB'ы 1365
shader.exe 1365
txmake.exe 1369
Надпись 1370
Могучая кучка 1372
Альтернативы? 1375
Какие рендереры? 1376
Gelato 1377
Jot 1383
GRUNT 1387
Spore 1388
Renderman - альтернативы RAT 1389
Альтернативные интерфейсы для MTOR 1390
Альтернативные Renderman-совместимые рендереры 1391
Экспорт из MAYA в RIB-MEL 1391
Экспорт из MAYA в RIB-не MEL 1391
MayaMan 1391
Liquid 1395
ShaderMan 1396
ShadingRate 1404
PixelSamples 1407
LOD 1409
Архивы и Замороженные Архивы 1410
Разговаривающие и адаптивные шейдеры 1411
Только то, что видно (или «Стыдно - когда видно») 1411
По слоям 1412
Мантра про raytracing 1417
Собственное все 1418
Для любознательных - пример из жизни 1419
Думайте о неожиданном 1420
И под конец нашего списка 1422
К вопросу о благодарностях 1426
Персонажная анимация
Настройка персонажей
Вначале я по инерции хотел назвать главу «Персонажная анимация», но потом понял, что
про анимацию в этой главе не будет ни слова. Ну, если только чуть-чуть и то чисто теоретически.
Как правило, когда речь идет о технических аспектах персонажной анимации или о возможностях
MAYA в этой области, имеется в виду создание, настройка и подготовка объекта к анимации. Это
чисто техническая работа и к анимации (в классическом понимании этого слова) она не имеет
никакого отношения. Такой работе и посвящен целиком материал этой главы. Поэтому все
процессы связанные с созданием, тестированием и подготовкой персонажа я буду обобщенно
называть настройкой персонажа.

Терминологический комментарий. По-английски это звучит как «Character Setup»,


поэтому в майском жаргоне прочно прижились всевозможные вариации прямого
поминания этого термина, причем как только не говорят: «сетап», «засетапить»
- настроить; «сетапщик» - тот, кто настраивает; «обсетапленный персонаж» -
настроенный и готовый к анимации. Недавно также появился новый модный термин
"Rigging", также обозначающий настройку, поэтому наиболее экзальтированные
сетапщики стали щеголять словечком «риг», хотя оно обозначает то же самое,
что и «сетап».

Помните: все это - подготовка персонажа к анимации.

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

Итак, технологические решения, известные как настройка персонажа, включают в себя


прежде всего создание и редактирование скелета, формирование для него адекватных управляющих
элементов, включающих в себя прежде всего объекты инверсной кинематики. Настройка - это
также построение общей удобной системы управления скелетом, объединяющей все управляющие
элементы, с помощью различных инструментов: констрейнов, Set Driven Key, expressions. Сюда же
относится привязка модели к скелету, известная как «скининг», редактирование этой привязки,
дополнение ее различными деформациями для эффектов (типа мышечных сокращений и т.д.).

Но звучит все это как-то формально. Попробую сказать по-человечески.

Когда модель (поверхность) вашего персонажа будет готова, ее придется анимировать.


Для этой цели вы довольно быстро вставите внутрь поверхности скелет, так как это дело нехитрое
и похожее на построение кривых первого порядка. Расположив кости там, где надо, вы поймете,
что их, похоже, слишком много, чтобы, ворочать скелетом, анимируя каждую из них (если речь не
об анимации отрубленного пальца). Вам на помощь придет инверсная кинематика, позволяющая
сократить число управляющих, то есть анимируемых объектов, до разумного минимума. Навесив
манипуляторы IK вы, конечно же, обнаружите, что дергать персонаж за руки и ноги стало гораздо
удобнее, однако для того, чтобы развернуть локоть или колено, повращать кистью или хуже того,
стопой, придется выбирать уйму дополнительных объектов, рыться в ворохе их атрибутов, не
забывать ставить на них ключи. Вам, естественно, захочется сосредоточить управление вашим
скелетом (ну, не лично вашим, конечно) в одном месте или хотя бы на нескольких немногочисленных
объектах. Вот тут и начнется веселье. Точнее говоря, техническое творчество. С помощью
констрейнов вы сможете добавить к вашему скелету управляющие объекты, или, как их часто
называют, контроллеры. Обычно это локаторы, кубики или кривые забавной формы, к которым
«прибиваются» некоторые части скелета. Создав на этих контроллерах дополнительные атрибуты,
вы сможете привязать их (через Set Driven Key или прямую связь) к атрибутам дополнительных
объектов, чтобы управлять из одного места, например, и поворотом локтя, и сгибом пальцев.
Тут вам придется хорошенько подумать над тем, каким образом и где лучше всего расположить
контроллеры и как оптимально завязать на них необходимые атрибуты различных частей скелета.

Персонажная анимация 719


После того, как вы «оденете» скелет в управляющие элементы, возможно, вам сразу захочется
создать Персонаж (Character), для того, чтобы в дальнейшем пользоваться благами нелинейной
анимации. Персонаж будет, очевидно, состоять в основном из атрибутов контроллеров.

Далее веселье только усугубится. Потому что возникнет необходимость привязать


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

Передохнув после выламывания рук персонажу в процессе настройки весов, вам захочется
обеспечить модель дополнительными деформациями, основным примером которых служат
сокращения мышц в различных местах поверхности. Мышечные деформации должны работать
автоматически, например, при сгибе локтя или колена, поэтому на помощь к вам придут сонмы
деформеров и, конечно, операция Set Driven Key, обеспечивающая плавное включение деформаций
в зависимости от поворота костей или других атрибутов. Set Driven Key позволит вам реализовать
всевозможные автоматизации и зависимости поведения одних частей модели от других. Здесь же
на помощь придут интеллектуальные expressions и бесхитростные констрейны.

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

Те из вас, кто слегка напуган вышенарисованной перспективой, могут облегчить себе


жизнь (и сэкономить массу времени и нервов) двумя путями.

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

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


кем-то ранее и полностью настроенных скелетов, которые надо лишь ухитриться вставить в свою
модель. Этот путь не избавит вас от привязки поверхности модели к костям и задания деформаций,
однако в сравнении с общим кошмаром настройки персонажа, этот процесс занимает весьма
небольшую часть.

Использование готовых решений


Можно проследить некоторую историческую тенденцию, связанную с анимацией персонажей
в MAYA. Изначально MAYA представляла собой совершенно разрозненный конструктор для сборки
персонажей, не имеющий даже минимальных заготовок для повседневного использования.
Пользователи (особенно избалованные пакетом Character Studio) растерянно толклись в зарослях
многочисленных инструментов, операций, понятий и технологий. Однако в последнее время
появляется все больше решений, представляющих модель антропоморфного персонажа, полностью
готового к использованию. Пока что эти решения - типа Advanced Skeleton (http://www.animation-
studios.com.аu/) или aniMan (http://www.manus3d.be/) - еще не встроены в MAYA, однако, как
мне кажется, все более осязаемая потребность иметь некий аналог Character Studio для MAYA уже
скоро приведет к тому, что в составе MAYA появится что-то типа «супер-персонажа на все случае
жизни». (Пока я писал книгу, компания Alias успела приобрести компанию Kaydara, и это еще более
увеличивает вероятность появления в MAYA готовых к использованию решений для персонажной
анимации. Появление технологии Full Body IK в седьмой версии - наглядный тому пример.)

Примечание. Пока я писал, что компания Alias успела приобрести компанию Kay¬
dara, компания Autodesk успела приобрести компанию Alias. He думаю, что к
моменту выхода книги появится что-то типа Character Studio for MAYA (китайские
наработки не в счет), однако дело, похоже, все-таки реально идет к этому.

720 Книга Сергея Цыпцына


Среди готовых решений могу упомянуть еще несколько ссылок:

• Creature Tools (http://www.ant-online.co.uk/downloads/CreatureTools.htm)


• Final Fig (http://radiantsquare.com/welcome.html)
• FoeniX-SKELETON-(http://art.bgsu.edu/~ahalifax/)
• Puppet Master (http://www.maze3d.de/)
• PrimoBoy (http://www.macaronikazoo.com/mel/)
• ZooCST (http://www.macaronikazoo.com/mel/)
• Setup Machine (http://www.anzovin.com/setupmachine/setupmachinemaya.html)

На сайте http://www.rigging101.com/ вы можете найти еще некоторое количество готовых


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

В состав Bonus Pack for MAYA входит также довольно древний, но полезный (для изучения)
скрипт Skeleton Works, позволяющий строить скелеты не только человекообразных обезьян, но и
разных животных, а также некоторых типов насекомых.

В принципе, это очень неплохая идея - использовать уже однажды кем-то созданного
и настроенного скелета (может быть, даже вами самими). Оставляя за бортом коммерческие
аспекты и борьбу с непомерными амбициями, могу сказать: это - очень продуктивный путь.
Как правило, в профессиональных студиях используется скелет, уже однажды созданный и
настроенный гениальным техническим директором. Хочу заострить ваше внимание лишь на одной
проблеме. Готовый скелет придется «втискивать» во все ваши настоящие и будущие модели, так
как не модель подгоняется под скелет, а наоборот. Не все готовые решения позволяют делать это
безболезненно, а кости как объекты, ох, как не любят операцию масштабирования. Поэтому одним
из критериев отбора того или иного готового скелета должна быть его «втискиваемость» в любую
модель без болезненных последствий.

Вы можете вкрадчиво поинтересоваться, а какой из вышеперечисленных скелетов - «самый


лучший на свете»? Я же, совершенно не задумываясь, тут же вам и отвечу: самое лучшее на свете
готовое решение - это скелет, созданный нашим соотечественником Михаилом Бажуткиным (см. на
http://www.geocities.com/bazhutkin/). Ничего лучше я до сих пор не видел и сильно сомневаюсь,
что увижу в ближайшее время, если только Миша, конечно, не собирается выпустить какое-нибудь
обновление.

Но для всех тех, чья гордость или любознательность не позволяют использовать чужие
скелеты в процессе настройки персонажа, предназначен дальнейший материал этой главы.
Коль скоро это наверняка будут очень сильно мотивированные или невероятно технически
подготовленные читатели, я позволю себе изложение в лаконичной и стремительной манере.
Опять же повторю: про собственно анимацию дальше не будет ни слова. Кроме того, настройка
персонажей - это огромная, довольно занудная и крайне рыхлая тема, заслуживающая, без всякого
сомнения, отдельной книги. В соответствии с названием этого издания, я сосредоточусь на
понимании принципов работы инструментов для работы с персонажами, для того, чтобы вы могли
их адекватно использовать и комбинировать. Вы не найдете здесь большого количества готовых
примеров на все случаи жизни или инструкций по настройке персонажа «от и до». Персонажи
бывают, мягко говоря, разные и перечислять все возможные случаи - задача неблагодарная.

«Мануальная терапия». Кости и суставы. Построение скелета


Сначала я упомяну про инструменты построения и редактирования скелетов, а затем
поговорю о разных хитростях и неприятностях.

Основной инструмент построения скелетов находится по адресу Skeletons=>Joint Tool. При


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

Персонажная анимация 721


В процессе построения вы можете использовать среднюю кнопку мыши или клавишу In¬
sert, чтобы поправить положение последней поставленной точки. Кроме того, нажимая стрелки
вверх и вниз вы можете перемещаться «взад-вперед» по скелету, редактировать положение
промежуточных звеньев и продолжать построение, «ответвляясь» от любого сочленения. Чтобы
завершить построение, как и в случае с кривыми, надо просто нажать Enter. Однако в отличие
от кривых, если вы снова возьметесь за инструмент Joint Tool и первым щелчком укажете в
существующее сочленение, новое построение будет добавлять новые кости к существующему
скелету.

Сразу необходимо разобраться с составляющими скелета и терминологией. Основные


элементы скелета - это Joints, сочленения, или суставы. Именно они - реальные объекты сцены
и отображаются в виде сферических шарниров. Кости (или Bones) показаны в виде треугольных
соединений между суставами, они не являются объектами сцены, а представляют собой
декоративное отображение связей между суставами. Когда, выбирая объекты, вы щелкаете мышкой
в кость, всегда будет выбран вышестоящий сустав (Joint). Ниже, если я иногда, оговорившись,
скажу, например, «вышестоящая кость», я буду иметь в виду вышестоящий сустав. Если особо
не проявлять отличия, суставы (Joints) и кости (Bones) можно условно (я подчеркиваю, условно!)
считать синонимами до тех пор, пока речь не зайдет о скининге.

Совет. При построении скелета (особенно симметричного) очень полезно


использовать всяческие привязки. Имеет смысл временно «измельчить» деления
сетки, для более точного позиционирования частей скелета.

Если вы заглянете в Outliner или Hypergraph, то обнаружите, что скелет представляет


собой иерархию объектов типа Joint, где каждый вышестоящий сустав родитель (parent) для всей
нижестоящей цепочки. Именно поэтому, если вы будете перемещать один из суставов, вместе с
ним будет перемещаться вся нижележащая цепочка. Чтобы перемещать только выбранный сустав
независимо от других, следует нажать Insert и воспользоваться появившимся манипулятором.
Зато вращения суставов не требуют никаких ухищрения и выполняются обычным Rotate Tool. Про
масштабирование пока ничего говорить не будем.

Совет. Чтобы развернуть и увидеть всю цепочку костей в Outliner, следует нажать
на микроплюс, удерживая клавишу Shift.

722 Книга Сергея Цыпцына


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

Примечание. У человекообразных обезьян Root Joint располагается обычно в районе


копчика или поясницы.

Вы можете выбрать любой сустав (так и тянет писать «любую кость») и с помощью операции
Skeleton=>Reroot Skeleton превратить его в «корневой сустав», то есть в Root Joint. Вся структура
иерархии скелетона, естественно, изменится.

Коль скоро скелет - это обычная иерархия из объектов, то вы можете объединять два скелета
или, наоборот, разрывать скелет на части с помощью операций Edit=>Parent и Edit=>Unparent.
Поэкспериментируйте самостоятельно и обратите внимание, как появляются и исчезают
соединительные кости между суставами. Существуют также две альтернативные операции - Con¬
nect Joint и Disconnect Joint, позволяющие добавлять дополнительные соединительные кости или
удалять их.

Удалить промежуточный сустав, не удаляя всей нижележащей цепочки, можно с помощью


операции Skeleton=>Remove Joint.

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

Персонажная анимация 723


Вправление суставов.
Кошмары с локальными осями.
Автоматическая и ручная настройка ориентации.
Глазастые юные натуралисты, конечно, могут заметить, что во время построения скелета
предпоследний построенный сустав мгновенно «проворачивается» в момент создания нового
сустава. В этот момент происходит автоматическое ориентирование локальных вращательных
осей предпоследнего устава, так как в параметрах инструмента JointTool такая опция включена по
умолчанию. Разберем этот вопрос подробнее.

Откройте Option Box инструмента Joint Tool и установите Orientation=none.

Постройте небольшую конечность и обратите внимание, что суставы не будут


переориентироваться во время построения, а останутся в первоначальном положении.

Теперь включите в Option Box автоматическую ориентацию (Orientation=xyz) и снова


постройте конечность. Убедитесь теперь, что ориентация суставов отличается от предыдущего
случая.

Так как в обоих случая повороты суставов равны нулю (в чем нетрудно убедиться, взглянув
на Channel Box или Attribute Editor), ориентация суставов определяется локальными вращательными
осями (Local Rotation Axes). Чтобы увидеть локальные оси для всех суставов скелета, следует
выполнить следующие действия.

724 Книга Сергея Цыпцына


Надо выбрать верхний сустав (RootJoint), выполнить операцию Edit=>Select Hierarchy (это
выберет все нижележащие суставы как индивидуальные атрибуты), а затем включить отображение
локальных осей: Display=>Component Display=>LocaL Rotational Axes.

Совет. Заведите на полке две кнопки с вышеупомянутыми операциями или


изготовьте соответствующую горячую клавишу. Это сэкономит вам массу
времени.

Для начала разберемся, как работает автоматическая ориентация, а затем поговорим,


зачем это вообще нужно.

Сразу оговорюсь: существует операция Skeleton=>0rient Joint, позволяющая


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

Примечание. Я, видимо, немного невнятно использую термин «ориентировать».


Я имею в виду разворот локальных осей для выбранных суставов, а не повороты
самих суставов как объектов.

В Option Box этой операции используются те же параметры для ориентации локальных


осей, что и в Option Box инструмента Joint Tool, правда, оформленные несколько по-другому.

Итак, если вы выбрали, например, Orientation=xyz, a Second Axis World Orientation=+y, то


локальные оси суставов будут развернуты следующим образом: первая ось, X, будет направлена
вдоль кости, торчащей из сустава (в направлении следующего сустава), вторая ось ,Y, будет,
очевидно, перпендикулярна первой и развернута максимально вверх, в направлении +у, стремясь
повернуться вдоль глобальной оси Y, а третья ось, Z, будет перпендикулярна первым двум и
направлена по правилу правой руки.

Персонажная анимация 725


Что дает такая ориентация? Прежде всего, возможность вращать суставы вокруг оси,
проходящей через кость, как бы вокруг кости. Примером может служить поворот шеи или
скручивание в пояснице. Кроме того, это позволяет единообразно задать плоскость вращения для
выбранных суставов, например, ось Z, которую иногда принято использовать для сгибов (например,
в коленях, бедрах или локтях), а ось Y - для боковых вращений, типа разведения конечностей в
стороны.

Еще раз напомню: вы можете отключить автоматическую ориентацию в Option Box


инструмента JointTool и произвести настройку локальных осей позже, с помощью
операции Orient Joint. Кроме того, эта операция гарантированно направит одну
локальную ось (обычно ось X) вдоль кости, а две остальных вы всегда можете
довернуть вручную, выбрав локальные оси как компоненту объекта-сустава и
применив к ним обычный Rotate Tool.

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

Общий принцип ориентации осей таков: сделайте так, чтобы суставы было удобно
анимировать напрямую или чтобы ими было удобно управлять с помощью других объектов
(Set Driven Key и пр.). Если оси развернуты произвольно, покрутить их и добиться корректного
результата трудно, а порой невозможно. При этом совершенно не важно, какая ось «первая», а
какая «вторая» - важна ориентация этих осей относительно сустава.

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


ориентацию осей. Для начала нужно ответить на ряд вопросов. - Например, будет ли сустав в
исходной позе согнут или распрямлен? Если будет согнут, нужно ли иметь при этом нулевые
значения атрибутов Rotate? По скольким осям будет происходить вращение? Если по нескольким
и управление суставом будет не напрямую, а через Set Driven Key, то не будет ли происходить
искажение вращения при одновременном повороте по нескольким осям сразу? И т.д.

Степени свободы и неволи


Очевидно, что некоторые суставы скелета не должны вращаться во всех трех плоскостях.
Например, пальцам не рекомендуется вращаться вокруг своей продольной оси, а нога в колене,
наверное, должна иметь только одну степень свободы. Чтобы ограничить вращение в суставе лишь
некоторыми осями, можно заблокировать соответствующие атрибуты Rotate, а можно открыть At¬
tribute Editor для выбранного сустава и в разделе Joint снять соответствующие галки Degrees of
Freedom.

726 Книга Сергея Цыпцына


Кроме того, кости в некоторых суставах могут иметь довольно существенные ограничения
на диапазон углов вращения. Те же пальцы не должны сильно выгибаться назад, не говоря о
коленях. Ограничения (Limits) на вращения можно задать обычным для всех объектов способом:
в разделе Limits Information.

Если вы уже окончательно привыкли к майской идеологии, то глядя в Attribute Edi¬


tor для выбранного сустава и видя там одинокую закладку типа joint4, вы наверняка увидите
сходство сустава с обычной нодой типа transform или с пустой группой, также имеющей одну
похожую закладку. Однако наличие некоторых уникальных атрибутов делает ноду типа Joint
весьма особенной. В Attribute Editor в разделе Joint находится некоторое количество атрибутов,
определяющих не только внешний вид сустава, но и его поведение при использовании инверсной
кинематики.

Примечание. Draw Style=Box используется только, если из сустава выходят


несколько костей.

Атрибут Radius используется только для изменения визуального размера сустава на экране.
Кстати, в Option Box инструмента Joint Tool вы можете задать зависимость радиуса от длины кости.
Это сравнительно свежее нововведение, а раньше все персонажи в MAYA имели огромные лапы-
руки, так как абсолютный размер суставов для пальцев и колен был одинаков.

Коль скоро скелет представляет собой обычную иерархию, масштабирование любого


сустава должно вызывать изменение размера всех нижележащих костей, однако если вы
проделаете это, то увидите, что изменяется размер только выбранной кости. В этом еще одно
отличие суставов от обычных transform-нод. Атрибут Segment Scale Compensate по умолчанию
включен и позволяет скомпенсировать масштабирование отдельных суставов, сохраняя размер
остальных костей неизменным.

Остальные атрибуты относятся к области инверсной кинематики и поэтому мы поговорим


о них позже.

Совет. Если вы используете автоматическую ориентацию в процессе построения,


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

Персонажная анимация 727


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

Примечание. Совсем уж любознательные умы иногда задаются вопросом, а можно


ли отрендерить скелет в том виде, в каком он появляется на экране. Ответ
- нет, нельзя. Отставить вопросы!

Издевательство над костями. Удобные локаторы


Всем известно, что MAYA содержит огромную библиотеку нод, с помощью которых, как из
кирпичей, можно сделать много новых, нестандартных конструкций. Но иногда можно позволить
себе поиздеваться и над самими нодами. Например, изменить внешний вид костей (joints).
Конечно, первое, что приходит в голову: сделать какой-нибудь объект, например, полигональный,
который будет отображать кость в новом качестве и «припарентить» его к кости. Но, к сожалению,
это будет уже другой объект и выделяя его, мы выбираем его, а не саму кость. Или, например,
нам захотелось, чтобы стандартный ikHandle имел вид значка, сделанного из NURBS-кривой. Что
же для этого нужно сделать?

Действительно, в интерфейсе MAYA такое меню не присутствует. Нос помощью MEL-команд


это возможно сделать. В качестве примера возьмем кость и добавим к ней полигональный Shape.
Создайте полигональный объект, например, из кубика, форма которого будет использована
для нашей кости. Лучше всего его построить в начале координат, чтобы потом его не пришлось
искать.

Выделите «шейп» полигонального объекта и кость и выполните MEL-команду:


parent -add -s;

Совет. Не забывайте, что существует быстрый способ выделить «шейп» объекта


- нажатием на клавишу «стрелка вниз». А если «шейпов» несколько, то перебрать
их можно клавишами «стрелки право - влево».

Эта команда создаст еще одну копию (Instance) полигонального «шейпа» и «припарентит»
его к кости.

Теперь кость приняла нужный вид. Осталось только сдвинуть вершины полигона в нужное место.

728 Книга Сергея Цыпцына


Как видите, MAYA не запрещает подобные манипуляции. Теперь можно работать с костью как
полигональным объектом (старый вспомогательный объект можно уже удалить) или с полигоном
как с костью. Результат подобных трюков в файле joint_with_polygonal_shape.ma.

Теперь нужно не запутаться, что есть что. Главное - это запомнить, что многие ноды в MAYA
происходят от ноды transform, а разобраться в этом поможет документация. В начале описания
каждой ноды всегда имеется ссылка на «родителькую» ноду (не путать с «родительским» объектом
в сцене). А у каждой ноды происходящей от transform ноды, наследуется возможность иметь
«шейпы».

И напоследок хочется добавить, что хорошим тоном будет, если мы переименуем


добавленные «шейпы», используя имя родительской ноды, но добавив в конце «Shape» и номер.
Например, для «шейпа» кости joint1 это будет - jointShape1.

В качестве примера в файле any_control_shapes.mb содержится некоторое количество


контрольных объектов помогающих аниматору лучше ориентироваться в управлении персонажем.
Часть из них были созданы из нескольких кривых по описанной технике.

Для тех, кому по душе подобные локаторы, Мишей Бажуткиным был написан скрип multi-
Curve. mel, позволяющий создавать такие локаторы автоматически из нескольких кривых. Создайте
несколько кривых, и сделайте им Freeze Transformation, если у них «ненулевой транформ».
Выделите их и выполните команду multiCurve, которая создаст из них один объект.

Кинематика - инверсная и прямая


Предположим, вы построили скелет или хотя бы одну конечность, например, руку. Теперь
перед вам стоит задача санимировать эту руку так, чтобы достать до какого-нибудь объекта. Если
вы лихорадочно броситесь в бой и начнете ставить ключи на вращения костей, то скоро поймете,
что довольно непросто подобрать два угла в суставах для плеча и локтя, чтобы дотянуть конец руки
до цели. А если цель находится немного сбоку? Количество поворотов возрастет и сравнительно
простая рука перестанет слушаться совсем.

А теперь вспомните, как вы сами пытаетесь дотянуться до любимой игрушки (любимой


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

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

Персонажная анимация 729


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

Быстро проделайте экперимент.

В окне front нарисуйте цепочку из трех костей (четырех суставов) с помощью Joint Tool.
Затем возьмите в руки инструмент 5keleton=>IK Handle Tool и, читая Help Line, щелкните в
первый сустав, а затем в третий.

Enter нажимать не надо, MAYA сама разберется с тем, когда выйти из контекста.

Возникнет новый объект, IKHandle1.

Перемещайте его и смотрите, как реагирует скелет. Теперь вы можете дотянуться


третьим суставом до нужной точки без каких-либо проблем. Обратите внимание, что третья кость
совершенно не подверженная влиянию перемещений и вращение в третьем суставе остается
постоянным.
Вы можете воспринимать полученную схему так, как будто бы был создан expression,
который быстро пересчитывает перемещения IK Handle во вращения суставов, на которые он
влияет.
Действительно, открыв Attribute Editor для созданного IK Handle, можно обнаружить
закладку для такого «expression» по названием ikRPSolver. Это, конечно, никакой не expression, a
нода, выполняющая пересчет перемещений IK-манипулятора во вращения суставов. На атрибутах
этой ноды я не буду останавливаться в этой книге (не верьте Attribute Editor - атрибут Tolerance
равен 0.00001).

Терминологический комментарий. Переводить IK Handle как «рукоять» или «топорище


инверсной кинематики», я думаю, не стоит. Так как циничные майщики упрямо отказываются
от переводов, употребляя брутальный термин «хэндл», я постараюсь не переводить его, иногда,
впрочем, опускаясь до употребления названия «IK-манипулятор». Также я буду употреблять термин
«кинематическая цепочка», имея в виду набор суставов (или костей), имеющий общий IK Handle.

730 Книга Сергея Цыпцына


Свойства IK-манипуляторов
В соответствии с правилами препарирования MAYA, получив новый объект, следует тут же
осмотреть его в Attribute Editor на предмет обнаружения интересных атрибутов.

В нашем случает интерес представляют два раздела. Первый из них, IK Handle Attributes,
задает поведение и внешний вид объекта IK Handle. По умолчанию IK-манипулятор как бы привязан
резинкой к концевому суставу, и когда вы оттягиваете его слишком далеко, а затем отпускаете,
он мгновенно возвращается к своему суставу. Это поведение можно отменить, выключив атрибут
Snap Enable.

Если вы еще не поставили ключи на IK Handle, то перемещая самый верхний сустав, вы


будете передвигать всю конечность. Однако, если в соответствии с вашим гениальным замыслом,
конечность должна стоять на земле, как влитая, даже во время манипуляций с вышестоящими
суставами, имеет смысл включить атрибут Stickiness, задав его равным Sticky. Если IK Handle уже
имеет ключи, то этот атрибут игнорируется.

Если какой-нибудь сустав находится под влиянием нескольких IK-манипуляторов (вам


никто не мешает сделать их «перекрывающимися»), то с помощью атрибут Priority можно задать,
влияние которого из них будет вычисляться в первую очередь. Чем меньше значение, тем выше
приоритет вычисления.

Персонажная анимация 731


Два остальных атрибута имеют значение только для нечасто используемого алгоритма
вычисления кинематики (ikMCSolver), и мы их пока пропустим.

Алгоритмы вычисления инверсной кинематики.


Типы IK-манипуляторов. IK Solvers
В разделе IK Solvers Attributes для каждого IK Handle содержатся атрибуты, определяющие,
как работает выбранный IK-манипулятор. Дело в том, что перемещения манипулятора могут
вызывать вращения костей различным образом, в зависимости от того, по какому алгоритму
происходят эти вычисления. Этот алгоритм задается атрибутом IK Solver, а остальные атрибуты в
этом разделе определяют специфические параметры для различных алгоритмов. Рассмотрим эти
алгоритмы подробнее.

Для взрослых. Переключая атрибут IK Solver, вы можете заметить, как изменяется


имя (и тип ноды) во второй закладке в Attribute Editor. Дело в том, что все основные
атрибуты IK Solver создаются в сцене в тот момент, когда вы создаете первый
сустав скелета. Каждый из них, этих IK-солверов, обслуживает все IK Handle с
соответствующим значением атрибута IK Solver. Если вы, в силу каких то причин,
хотите создать еще один IK Solver определенного типа (например, ikRPsolver),
чтобы он обслуживал только некоторые IK Handle, вам нужно использовать MEL-
команду createNode ikRPsolver. После этого нужно указать его имя в Attribute Editor
для нужных IK Handle в качестве атрибута IK Solver

Примечание. Напомню, что «солвер» - это непереведенный «решатель», то есть


нода, ответственная за решение задачи инверсной кинематики тем или иным
способом-алгоритмом. Алгоритмы эти, очевидно, бывают разные.

Алгоритм Rotation Plane Solver


По умолчанию значение атрибута IK Solver равно ikRPSolver. Это означает, что в данном
случае используется алгоритм Rotation Plane. Суть его примерно такова.

Вычисление вращений суставов вычисляется на основе перемещений IK Handle и не зависит


от его (хэндла) поворотов (попробуйте и увидите: вращать IK Handle никто не запрещает). Для
того, чтобы определить плоскость, в которой будет происходить сгибание суставов, используются
дополнительные атрибуты IK Handle. В частности атрибут Pole Vector. Представьте себе, что вы
можете достать до собственного носа, держа локоть внизу или отведя его в сторону. Положение
IK Handle (то есть вашей кисти) будет одинаково в обоих случаях, однако плоскость сгибания
локтя будет разная. А теперь представьте себе, что из плеча торчит вектор, который задает, куда
должен смотреть локоть при сгибании. Локоть при этом должен стремиться смотреть на конец
этого вектора.

Чтобы получше разобраться с этим вектором, а заодно визуально отредактировать его,


выберите IK Handle и нажмите клавишу «t», включив Show Manipulator Tool.

732 Книга Сергея Цыпцына


Изменяя этот вектор, вы будете вращать плоскость, в которой происходит сгибание
суставов, зависящих от IK Handle.

Чтобы не выбирать каждый раз IK Handle и не переключаться в Show Manipulator Tool, было
бы разумно закрепить конец этого вектора на каком-нибудь объекте, например локаторе. Именно
для этих целей и существует Pole Vector Constraint.

Создайте локатор. Выбрав его, дополнительно выберите IK Handle, а затем выполните


операцию Constrain=>Pole Vector.

После этого конец вектора, определяющего плоскость вращения, «прилипнет» к локатору,


и вы сможете, перемещая локатор, управлять направлением сгиба.

Таким образом, перемещая сам IK Handle и сопутствующий локатор, вы можете добиться


предсказуемого поведения кинематической цепочки.

Однако вас может поджидать еще одна проблема. Это flipping, или внезапный разворот
суставов внутри кинематической цепочки. Если IK Handle, локатор и верхний сустав находятся в
одной вертикальной плоскости и вы будете перемещать IK Handle наверх, рано или поздно согнутая
конечность перевернется.

Персонажная анимация 733


Если вас это шокирует, поспешу вам сообщить, что это совершенно предсказуемо, а главное
- контролируемо. И во всем «виноват» опять-таки Pole Vector, а точнее, его направление.
Очевидно, что три точки начало (1) и конец (2) IK Handle плюс конец (3) Pole Vector -
определяют плоскость, в которой происходит сгибание суставов. Однако в этой плоскости суставы
могут согнуться либо в одну сторону, либо в противоположную (относительно линии между началом
и концом IK Handle). Если провести линию от первого до последнего сустава в цепочке IK Handle,
суставы будут сгибаться в ту сторону от этой линии, в которой находится конец вектора Pole Vector
(или, в нашем примере, Locator).

Таким образом, имея в руках конец Pole-вектора, вы можете контролировать, в какую


сторону будут сгибаться суставы, и вы всегда можете сдвинуть его так, чтобы внезапного разворота
не происходило. Надо просто анимировать его в нужные моменты, следя за тем, чтобы он не
пересекал линию между первым и последним суставом IK-цепочки.
Для дополнительного контроля над положением согнутых суставов у IK Handle имеется
дополнительный атрибут Twist. Он задается в градусах и позволяет повернуть всю цепочку
целиком.

IK-манипуляторы, использующие ikRPsolver (Rotation Plane Solver), являются рабочими


лошадками инверсной кинематики. Они, как правило, обеспечивают абсолютно предсказуемые
вращения и при этом имеют атрибуты, обеспечивающие (совместно с Pole Vector Constrain) гибкий
и мощный механизм контроля. Основные работоспособные конечности (руки, ноги) обычно (хотя
и не всегда) можно анимировать (то есть управлять) с их помощью.

734 Книга Сергея Цыпцына


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

Алгоритм Single Chain Solver


Когда требуется предельно упростить управление инверсной кинематикой и сделать его
возможным «из одного места», а не при помощи нескольких объектов, хорошим способом будет
использование ikSCsolver. Его концепция в состоит следующем.

Вычисление вращений суставов производится не только на основе перемещений IKHan-


dle, но и зависит от его поворотов. Измените для IK Handle атрибут IK Solver на ikSCsolver и
попробуйте повращать IK Handle. Теперь плоскость, в которой происходит сгибание-разгибание
суставов, полностью определяется атрибутами Rotate объекта IK Handle. Как видите, управление
становится простым до безобразия. Но за простоту приходится платить и, например, проблемы
с переворачиванием-перещелкиванием (если они возникнут, конечно) не удастся решить также
ловко, как в предыдущем случае.

Single Chain Solver удобно использовать для управления кинематическими цепочками,


состоящими из одной кости. (Кто вам сказал, что нельзя создавать IK Handle для соседних суставов?
Это как раз непостижимо удобно для управления отдельными костями.) Кроме того, для таких
IK Handle удобно создавать Point и Orient Constrain, и тогда один управляющий объект может
контролировать одновременно ориентацию нескольких цепочек. Например, один локатор может
управлять разворотом ступни (один IK Handle) и ориентацией колена (другой IK Handle). Подробнее
про использование того или иного алгоритма инверсной кинематики смотрите в нижеследующих
практических примерах.

Если два предыдущих алгоритма не имеют ограничений на количество костей, входящих


в кинематические цепочки, то следующий тип IK Handle был создан специально для конечностей
состоящих из двух костей (трех суставов).

Алгоритм Two Bone Solver


Он появился в MAYA сравнительно недавно и представляет собой еще один тип инверсной
кинематики - ik2Bsolver (2 Bone Solver). Внешне он ничем не отличается от Rotation Plane Solver и
имеет такие же атрибуты. Однако способен работать только с двумя костями. Вы, конечно, можете
задать тип ik2BSolver для IK Handle, созданного для более длинной кинематической цепочки,
однако вычисления будут производиться только для первой и последней кости в цепочке. Я так
понимаю, этот алгоритм был включен в MAYA (вместе со своим исходным кодом) специально для
экспорта персонажей в игровые движки, так как является наиболее быстрым алгоритмом среди
всех возможных солверов.

Алгоритм Multi Chain Solver


Самым сложным и, соответственно, гибким является Multi Chain Solver (ikMCsolver).
Он позволяет создавать перекрывающиеся кинематические цепочки и вычислять результат
одновременного влияния нескольких IK Handle на основе значений приоритетов и весов.
Примером использования этого алгоритма может быть персонаж, стоящий на коленях и при этом
опирающийся на руки или локти. Чтобы анимировать положение спины или таза, сохраняя контроль
над позициями рук и коленей, лучше использовать Multi Chain Solver, так как остальные алгоритмы
плохо подходят для решения данной задачи.

По умолчанию, этот IK Solver не присутствует в сцене автоматически и вам нужно создать

Персонажная анимация 735


его вручную, используя MEL-команду: createNode ikMCsolver. После этого он появится в списке
доступных алгоритмов для атрибута IK Solver для всех существующих IK Handle в текущей сцене.
Этот солвер неспроста скрыт разработчиками MAYA. Скорее всего, программисты сами не смогли
придумать ему конкретной реализации и ограничились небольшим абзацем в документации. Но
изучив этот солвер внимательнее, можно обнаружить, что он не так загадочен и бесполезен, как
на первый взгляд кажется.

Чтобы лучше понять принцип его действия, давайте абстрагируемся от самой MAYA и
представим себе структуру костей в виде дерева, с гибким стволом и ветвями. A IK Handles этого
солвера, в виде резинок, которые с привязаны к разным ветвям и одновременно тянут ветви в
разные стороны. Причем у каждой из них может быть своя упругость. Поэтому форма, в которую
согнут это деревце наши резинки, зависит от совокупности действия разных сил. Вот примерно так
же работает и ikMCsolver.

Только в отличие от дерева, конечно же, кости не гнутся, а вращаются у своего основания.
А сила натяжения каждого IK Handle задается атрибутом weight.

Очень важно помнить, что солвер во время своих расчетов учитывает все IK Handles с
одним номером приоритета (атрибут priority).

Создайте цепочку из двух костей (трех joints) и создайте два IK Handles, от первого сустава
до второго и от первого до третьего.

Так как Multi Chain Solver солвер не создается автоматически при создании костей, нужно
выполнить команду: createNode ikMCsolver.

Затем с помощью Attribute Editor у обоих IK Handles нужно выбрать тип солвера "ikMC-
solverl" в закладке IK Solver.

736 Книга Сергея Цыпцына


Перед тем, как испытать IK, поставьте ключи на перемещения на оба IK Handles и у второго
из них сделайте атрибут weight равным 100.

Такая система может напоминать работу ikRPsolver с одним IK Handle и Pole Vector, но все
же есть два отличия.

Первое, что бросается сразу в глаза - позиция последнего сустава зависит от удаленности
первого IK Handle со слабым весом. Чем дальше он удаляется от костей, особенно в противоположную
сторону от другого IK Handle, тем больше удаляется последний сустав от своей конечной цели, а
именно позиции второго IK Handle.

А второе отличие состоит в том, что солвер, перед тем как сделать новый расчет углов,
не возвращает кости в Preferred Angle (углы предпочтения). Другими словами, он делает расчет,
исходя из текущих на данный момент углов. Это означает, что даже вернув все IК Handle в исходную
позицию, мы не получим исходные углы костей. Чем больше мы дергаем наши IK Handles, тем
больше «накручиваем» углы на костях. Очень забавно, но совсем не практично.

Из этого можно сделать вывод, что использовать ikMCsolver желательно только как
вспомогательную систему. Например, с его помощью мы можем вычислить позиции суставов, к
которым с помощью Point Constraint можно прикрепить IK Handles других солверов.

От слов к делу! Рассмотрим пример применения ikMCsolver для сетапа из трех костей.
Многие сталкивались на практике с тем, что самая предсказуемая и легко управляемая система
состоит только из двух костей. Недаром в 7-ой версии MAYA разработчики добавили ikSpringSolver,
который облегчает работу с тремя и более длинными цепочками костей. Но в нашем примере нам
поможет только ikMCsolver.

Задача у нас следующая: требуется рассчитать позицию трех костей - двух коленей и таза
персонажа, который стоит на коленях. При этом, чтобы имелась возможность управлять наклоном
таза из стороны в сторону и вверх-вниз, а также поворотами влево-вправо. Колени же при этом
должны оставаться в тех местах, где находятся соответствующие локаторы.

Откройте файл MultiChainTest.ma

С нем содержится пример с тремя костями. Здесь вы не увидите никаких коленей и тем
более таза. Проявите свое воображение и представьте себе, что два локатора (синий и красный)
на плоскости задают позицию коленей, а зеленый, соответственно, таза.

Персонажная анимация 737


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

Все IK handles в сцене скрыты, и для того чтобы увидеть их, вам придется открыть Outliner
и установить их атрибуты visibility в значение 1.

Первые два IK Handle прикреплены к зеленому верхнему локатору таза обычной операцией
parent (можно использовать и Parent Constraint). Они имеют единичный вес (weight = 1), и
расстояние между ними соответствует длине второй кости.
Третий IK Handle прикреплен с помощью Point Constraint к синему локатору левого колена
и имеет большой вес (weight = 1000).

Как вы уже, видимо, догадались, третий IK Handle самый главный в этой цепочке. Он
обеспечивает достижение последним суставом позиции синего локатора.

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

Конечно же, этот солвер не безгрешен. Точнее, не абсолютно точен в своих вычислениях.
Чтобы свести к минимуму его промахи, приходиться устанавливать его атрибут tolerance на очень
малое значение, например = 0,0000001. В противном случае возможно мелкое дрожание костей при
воспроизведении анимации. К сожалению, повышение точности солвера может снизить скорость
воспроизведении анимации.

Ну, и напоследок - еще об одной особенности этого солвера. Если значение атрибута веса
главного IK Handle примерно в десять раз больше вспомогательных, то распрямление цепочки
костей будет происходить не резко, как у остальных солверов, а мягко. Конечно, при этом
последний сустав не будет полностью достигать IK-цели. Это замечательное свойство может быть
с успехом использовано для реалистичного сетапа человека и животных, особенно четвероногих,
где так важна пластичность в движениях.

Анимация длинных цепочек


Все вышеописанные алгоритмы инверсной кинематики предлагают непосредственное
управление кинематической цепочкой с помощью перемещений (или вращений) IK-манипуляторов.
Однако в случае, если цепочка состоит, например, из десяти суставов, вышеописанные способы
управления будут работать, мягко говоря, посредственно. Представьте себе, что вам нужно

738 Книга Сергея Цыпцына


анимировать чей-нибудь хвост, состоящий из пятнадцати мелких косточек или какое-нибудь не
менее гибкое, но отвратительное щупальце. Попытавшись навесить на такой хвост пяток-другой
вышеуказанных IK-манипуляторов, вы быстро придете в ярость. Но тут вам на помощь придет
совершенно замечательный способ управления длинными цепочками из костей. Он называется IK
Spline Handle. Создав интригу, я вернусь к этому чуть позже, так как столь шикарный инструмент
заслуживает отдельного разговора. А сейчас я хотел бы возвратиться к некоторым атрибутам
суставов, влияющим на действие инверсной кинематики.

Атрибуты суставов, корректирующие поведение инверсной


кинематики
Если вы создали IK Handle для трех или более костей, все они сгибаются в процессе
перемещения IK-манипулятора более-менее равномерно. Если вы хотите, чтобы один из суставов был
более «жесткий», чем остальные, или, так сказать, «несмазанный», вам следует воспользоваться
для него атрибутом Stiffness, позволяющим задать индивидуальную сопротивляемость сгибанию
по всем трем осям.

Совет. Если вы взялись редактировать жесткость одного из суставов, задайте


ее для всех суставов, входящих в кинематическую цепочку, так как вычисление
инверсной кинематики учитывает жесткость суставов друг относительно друга.
Например, в самом начале, сразу после создания скелета, можно задать значение
Stiffness равное 1 (или 100) для всех суставов . После этого можно будет изменять
его в большую или меньшую сторону для отдельных сустав в процентном
соотношении.

Если вы создаете скелет, на части которого однозначно будет навешана инверсная


кинематика, следует держать в уме следующее соображение. Если две (или более) кости немного
согнуты друг относительно друга, то созданный для них IK Handle будет отлично «знать», куда
ему следует сгибать эти кости. В случае использования манипулятора типа Rotation Plane это
реализуется в автоматическом задании значения Pole Vector непосредственно при создании
IK Handle. Поэтому старайтесь не строить совершенно прямых цепочек из костей, которые вы
собираетесь анимировать с помощью кинематики. Проще говоря, при построении скелета сгибайте
немного его руки и ноги.

Однако если вам совсем приспичило создать прямую цепочку, а затем согнуть ее, вы
можете подсказать кинематике, в какую сторону должны сгибаться кости при перемещении IK
Handle. Для этой подсказки используется атрибут Preferred Angle.

Предпочтительный угол - Preffered Angle


Проделайте простой эксперимент.
Постройте абсолютно прямую вертикальную цепочку из трех суставов.
Повесьте на нее IK Handle.
Попытайтесь согнуть кости, неистово дергая IK-манипулятор. Дышите ровно.

Персонажная анимация 739


Совершенно очевидно, что MAYA, вкупе с инверсной кинематикой, не могут сообразить,
куда сгибать абсолютно прямую цепочку.

Удалите IK Handle, выберите второй сустав, откройте Attribute Editor и введите значение
Preferred Angle Y=10.

Это означает, что предпочтительный угол для сгибания сустава определяет положительное
вращение вокруг оси Y (в данном случае абсолютная величина угла значения не имеет).
Снова навесьте IK Handle и подергайте его. Теперь кости будут сгибаться в нужном направлении.

Примечание. К сожалению, после изменения значения Preferred Angle для одного


из суставов существующий IK Handle приходится удалять. В противном случае
он начинает перекручивать локальные оси суставов, причем довольно подло и
незаметно.

Совет. Задавайте Preferred Angle перед созданием («навешиванием») инверсной


кинематики.

Если вам не хочется возиться с цифрами в клетках, можете просто предварительно


согнуть кости в нужном направлении, а потом выбрать самый верхний сустав и выполнить

740 Книга Сергея Цыпцына


операцию Skeleton=>Set Preferred Angle. MAYA при этом сама заполнит значения атрибута Pre­
ferred Angle и запомнит это положение для дальнейшего использования. Кстати, вернуться в это,
запомненное положение вы всегда можете, выбрав сустав и выполнив Skeleton=>Assume Pre­
ferred Angle.

Заметьте, что даже если кости немного согнуты перед навеской кинематики, с
помощью Preferred Angle вы может указать предпочтительное направление сгибания костей при
перемещении IK Handle.

Joint Rotation Limit Damping - мягкое торможениие


Наиболее наблюдательные умы наверняка заметят в разделе Joint Rotation Limit Damp­
ing еще двенадцать загадочных атрибутов. В теории они позволяют сделать так, чтобы сустав,
достигнув своего ограничения на вращение, не переставал внезапно вращаться, а мягко тормозился
на подходе к этому ограничению. Величина «подхода» определяется атрибутами Damp Range, a
степень торможения (от 0 до 100) - атрибутами Damp Strength. Чтобы заставить работать описанные
атрибуты, требуется изрядное терпение и аккуратность. Поэкспериментируйте самостоятельно.
Могу лишь подсказать, что для эксперимента лучше использовать цепочку из более чем двух
костей и не забыть, перво-наперво, задать ограничения на вращения. Те, кто будет обескуражен
собственными экспериментами, могут открыть сцену jointDamping.ma и усмотреть разницу в
движении двух кинематических цепочек, с одинаковой анимацией IK Handle.

Прямая и инверсная кинематика. Дело вкуса. Свобода воли


Когда я, изучая Alias Power Animator, впервые столкнулся с термином «инверсная
кинематика», то долго удивлялся: а что же такое - прямая кинематика? Сдав некогда в университете
кошмарный экзамен по теоретической механике, я придавал термину «кинематика» совершенно
иное значение, однако, в конце концов, заглянув в глубины документации обнаружил: кинематика
- это метод моделирования механики живого тела с помощью настройки и анимации скелета. Там
же я прочитал, что прямая кинематика - метод управления скелетом путем прямого вращения его
суставами. Это показалось мне настолько банальным, что я, признаться, был малость разочарован,
уж больно просто всё оказалось, для такого солидного термина.

Тем не менее, два этих вида кинематики делят между собой возможные способы анимации
скелетов. Казалось бы, области применения каждой из них довольно четко очерчены, однако
существуют некоторые нюансы. Прямая кинематика отлично подходит для анимации свободных
движений конечностей и других частей скелета (рук, шеи, челюстей). Если же конечности
ограничены какой-либо связью (ноги упираются в землю, руки на стол, лицо в тарелку), то
очевидны плюсы использования инверсной кинематики.

Однако инверсная кинематика лишает вас некоторой части свободы, предлагая


автоматические вращения конечностей, которые, возможно, не совпадают с желаемым движением.
«Докручивание» этого движения с помощью Pole Vector и других атрибутов, делает процесс
похожим на бесконечный ремонт квартиры и уводит творческий процесс в техническую сторону.
Представьте себе, что вы рисуете руку или ногу. Наверное, будете рисовать ее от плеча
к локтю и далее до кисти (или, соответственно, от бедра до колена, от колена к ступне и т.д).
Если вы обучались анимации, вам также знаком принцип движения по дуге (arc motion). Однако
инверсная кинематика делает все наоборот (на то она и инверсная): вы управляете конечностью
снизу-вверх и в каждом ключевом кадре как бы рисуете руку от кисти к плечу.

Персонажная анимация 741


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

Смешивание прямой и инверсной кинематики. История вопроса


Сначала я расскажу о том, как люди выживали в те времена, когда никакого «сблендивания
кинематик» не было и в помине. Ловкие умы могут повторить мои лаконичные объяснения на
пальцах.

Создайте «руку» из трех суставов.


Сдублируйте ее, с установками по умолчанию, а затем поверните немного каждую из двух
копий вокруг верхнего сустава.

Будем называть среднюю руку «второй», а остальные две «первой» и «третьей».


Выберите в Outliner первую, третью, а затем вторую руку за верхний сустав.
Выполните Constrain=>Point. И сразу после этого Constrain=>Orient.
Средняя рука «прилипнет» своим суставом к первым двум и повернется так, чтобы
располагаться точно посередине между остальными руками.
Теперь выберите второй сустав у первой, третьей, и второй руки. Снова выполните
Constrain=>Orient, чтобы ориентировать и вторую кость точно между соседями.

Теперь вы можете по очереди выбирать в Outliner два Orient Constrain, и меняя атрибуты,
отвечающие за веса первой и третьей руки, делать так, что вторая рука будет прилипать то к
первой, то к третьей конечности.
Теперь создайте один сустав, чуть повыше плеча.
Выберите первую, затем третью руку, а потом новый сустав.
Выполните Edit=>Parent.
Выберите самый верхний сустав и добавьте к нему новый атрибут (name=fkik, min/max=0/1,
default=0.5).
Теперь откройте окно Set Driven Key.
Загрузите наверх верхний сустав, а вниз оба констрейна типа Orient.

742 Книга Сергея Цыпцына


Сделайте так, чтобы атрибут fkik управлял изменением весов: при fkik=0 должны обнуляться
веса первой руки, а при fkik=1 в ноль обращаются веса третьей руки, а веса первой наоборот
равны единице. (Не забывайте выделять нужные атрибуты, перед тем как нажимать кнопку Key.)
Если совсем запутаетесь, откройте сцену fkikOldSchool.ma.

Теперь вам осталось навесить IK Handle на одну из управляющих рук, например, на третью.
Затем вы можете шевелить, то бишь, анимировать то первую руку (прямой кинематикой), то третью
руку (инверсной кинематикой) и переключать среднюю руку между ними, анимируя в нужный
момент атрибут fkik. Очевидно, что поверхность модели должна быть привязана к средней руке.
Это, конечно, очень примитивный пример, однако он демонстрирует основной принцип
переключения от одного типа движения к другому с помощью старых добрых констрейнов и
вездесущей технологии Set Driven Key. Несмотря на некоторую громоздкость, этот подход дает
абсолютно предсказуемый результат и отлично проверен временем.

Однако для пользователей, измученных сражениями с окном Set Driven Key и поиском
потерянных ключей, не так давно появилась возможность плавно переключаться от прямой к
инверсной кинематике, не создавая шестируких самураев.

Смешивание прямой и инверсной кинематики - современный подход


Когда вы создаете IK Handle, у него всегда есть атрибут ikBlend. По умолчанию он равен
единице. Если его обнулить, это будет означать, что этот IK Handle больше не работает, то есть
выключен (в ранних версиях MAYA этот атрибут назывался .solverEnable).
Создайте простую руку и навесьте на нее IK Handle.

Затем обнулите значение атрибута ikBlend, попробуйте подергать за IK Handle.


Бесполезно. Инверсная кинематика не работает, зато теперь можно использовать прямую
кинематику, то есть вращать суставы напрямую.

Таким образом, имеется один атрибут, переключающий управление над всеми костями
цепочки с инверсной кинематики на прямую и обратно.

В принципе этого достаточно для педантичных пользователей, так как остается только
аккуратно расставить ключи на нужные атрибуты (это, прежде всего, translate для IK Handle и
rotate для всех суставов плюс ключи для ikBlend). Но где вы видели таких пользователей среди
трехмерщиков? Поэтому, чтобы не ввергать этих детей анархии в полный хаос, был сделан
специальный пункт меню: Animate=>IK/FK Keys=>Set IK/FK Key.

Операция Set IK/FK Key. Анимация переключения кинематик

Персонажная анимация 743


Разберемся с тем, что делает эта операция, а затем посмотрим, как её использовать. Если
выбран IK Handle или хотя бы один из суставов, входящих в его кинематическую цепочку, эта
операция ставит ключ на все анимируемые атрибуты для IK Handle, включая ikBlend, а также на
ключ на атрибуты rotate для всех суставов кинематической цепочки.

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


нижеследующий порядок действий.

Взять конечность за IK Handle и поставить необходимое количество ключей на его


перемещения (и, может быть, вращения, в случае Single Chain Solver). В последнем кадре, где вы
использовали инверсную кинематику, выберите IK Handle и выполните Animate=>IK/FK Keys=>Set
IK/FK Key. Это поставит ключи не только на трансформации, но и, прежде всего, на атрибут ik­
Blend, который по умолчанию должен быть равен единице.

Перейдите в следующий кадр. Так как с этого момента должна начинаться территория
прямой кинематики, инверсную следует сразу выключить: установите ikBlend=0 и тут же поставьте
на него (и только на него!) ключ. (В этот момент документация советует выполнить Set IK/FK Key,
однако это поставит дополнительные ключи на вращения суставов, и вы получите ключевой кадр
идентичный предыдущему, то есть «замирание».)

Теперь вы можете продвигаться вперед и с удовольствием ставить анимацию с помощью


прямой кинематики, то есть анимируя углы поворота суставов.

В последнем кадре, где используется прямая кинематика, выберите IK Handle (он должен
«приехать» на место вместе с вращением костей), убедитесь, что атрибут ikBlend равен нулю и
выполните операцию Set IK/FK Key. Затем перейдите в следующий кадр, задайте ikBlend=0 и тут же
поставьте на него (опять, только на него) ключ, переключившись, таким образом, на инверсную
кинематику.

Совет. Некоторые взрослые мальчики предпочитают делать переключение не в


течение одного кадра, а гораздо быстрее. То есть вместо того, чтобы выполнив
операцию Set IK/FK Key в сотом кадре, перейти в следующий кадр, они переходят
на сотую долю кадра вперед, например в кадр 100.01 и ставят ключ на ikBlend
там.

Вроде все выглядит просто, однако есть ряд не очень положительных моментов.
Вы можете заметить, что операция Set IK/FK Key ставит ключи на все анимируемые атрибуты
IK Handle. Ключи, таким образом, плодятся в большом количестве. Однако вам нужно лишь
переключить значение атрибута ikBlend в соседних кадрах и не забыть зафиксировать положение
скелета в момент этого переключения. Поэтому вы можете вовсе не использовать операцию Set
IK/FK Key, а ставить все ключи вручную на перемещения IK Handle, вращения суставов и, конечно,
на атрибут ikBlend.
Если вы хотите «врезаться» в уже существующую инверсную кинематику с «куском»
прямой кинематики, сначала поставьте ключи на атрибуты IK Handle и ikBlend на границах этого
диапазона. Внутри этого диапазона выключите инверсную кинематику (ikBlend=0), не забудьте
поставить ключ на ikBlend и анимируйте на здоровье суставы вручную.

Переключение и смешивание FK и IK
Вы могли также заметить, что до сих пор речь шла только о переключении видов кинематики,
то есть о мгновенном переходе в соседних кадрах от одного типа управления к другому. В этом
случае все работает достаточно предсказуемо.

Несложно проверить, что если значение атрибута ikBlend будет равно, например, 0.5, на
кинематическую цепочку будут усредненно влиять и перемещения IK Handle и вращения суставов.
Поэтому если ключевые кадры, в которых атрибут ikBlend принимает значения 0 и 1, не будут

744 Книга Сергея Цыпцына


соседними, вы получите плавный переход от одной кинематики к другой. Это, конечно, удобно
в некоторых случаях, однако, в отличие от обычного смешивания типов анимации (например,
констрейнов и ключей), полностью отсутствует контроль над смешиванием вращений, чреватым
всякими перекручиваниями. Внешне все выглядит так, как будто происходит переход от одного
значения для вращений суставов, указанных в Channel Box до следующего значения. Таким
образом, используется смешивание эйлеровских углов, а об использовании кватернионов и речи
нет.

Откройте, например, файл ikFkBlendBug.ma и прокрутите, не торопясь, анимацию.


Значение атрибута ikBlend для единственного IK Handle в сцене плавно убывает от единицы
до нуля, постепенно «выключая» инверсную кинематику и переходя к прямой за 10 кадров.

Однако скелет движется совсем не так, как можно предсказать. И заставить его
переходить от инверсной кинематики к прямой адекватными методами невозможно. Поэтому
все, что я могу посоветовать - это использовать смешивание разных типов кинематики с большой
осторожностью.

Что касается данной сцены, остается применить только «метод тыка». Так как анимационной
кривой для вращения главного сустава не существует, применить эйлеровскую фильтрацию или
сменить тип интерполяции не представляется возможным. Остается лишь безнадежно обратиться
к порядку вращений. Выберите основной сустав и в Attribute Editor установите для него Rotate
Order=xzy. Убедитесь, что остальные варианты тоже существенно улучшают ситуацию. Попробуйте
объяснить происходящее.

В процессе перехода от инверсной кинематики к прямой IK Handle иногда «зависает» в


пространстве, как в только что рассмотренной сцене. Это, очевидно, связано с тем, где стоят
ключи на его перемещения. Если вы захотите вернуться обратно к инверсной кинематике, хорошо
бы этот IK Handle «пригнать» в нужное место, то есть в последний сустав кинематической цепочки.
Это можно сделать, выбрав его и выполнив Animate=>IK/FK Keys=>Move IK to FK. Можно, конечно,
воспользоваться привязкой к точкам, но это вряд ли поможет, если таких IK-манипуляторов будет
двадцать.

Операция Connect IK/FK


Как вы могли заметить, операция Set IK/FK Key применяется, когда выбран конкретный
IK Handle. Однако в управлении кинематической цепочкой могут принимать участие и другие
объекты. Например, локатор, управляющий плоскостью сгибания, через Pole Vector Constrain.
Такой локатор «ничего не знает» про атрибут ikBlend и про операцию Set IK/FK Key, однако было бы
весьма удобно, «держась» за локатор, иметь возможность включать/выключать ikBlend и ставить
на него ключи.

Персонажная анимация 745


Это можно сделать, выбрав локатор (или другой управляющий объект), а затем выбрав
IK Handle и выполнив операцию Animate=>IK/FK Keys=>Connect IK/FK. После этого у локатора
появится дополнительный атрибут ikBlend, напрямую связанный с одноименным атрибутом IK Han­
dle. Его нельзя менять вручную, однако локатор теперь присоединен к системе переключения
IK/FK и поэтому реагирует на операцию Animate=>IK/FK Keys=>Enable IK Solver соответствующим
изменением этого атрибута.

Таким образом, выбрав локатор вы можете переключаться между IK и FK и ставить ключи


на сам локатор и на атрибут ikBlend - с помощью операции Animate=>IK/FK Keys=>Set IK/FK Key.

IK Spline Solver - анимация хвостов, усов и щупалец


Как я уже упоминал, если вы попытаетесь навесить пару-другую IK-манипуляторов на
цепочку из десяти-пятнадцати костей, то быстро потеряете покой и сон. Однако такие цепочки
встречаются сплошь и рядом и управлять ими тоже как-то хочется. Конечно, можно крутить хвосты
несчастным животным или монстрам и с помощью прямой кинематики, однако для длинных и
гибких хвостов этот способ вряд ли будет оптимальным.

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

Нарисуйте цепочку из десяти коротких косточек, называя ее в соответствии с вашими


фантазиями. Я буду называть ее «хвостом».

Теперь выберите инструмент Skeleton=>IK Spline Handle Tool и привычно щелкните в первый
и последний сустав хвоста. Возникнет совершенно предсказуемый IK Handle. Однако при попытке
его подергать или повращать наиболее нетерпеливые получат обескураживающее сообщение:

Warning: Some items cannot be moved in the 3D view.

To бишь, что данный объект не предназначен для трансформаций. Именно так - не


предназначен!

Принцип действия инверсной кинематики, используемой в IK Spline Solver, заключается в


том, что вращения суставов вычисляются не на основе перемещений IK Handle, а в зависимости от
формы кривой.

Наиболее наблюдательные умы наверняка обнаружили, что после создания IK Handle в

746 Книга Сергея Цыпцына


сцене появилась новая кривая, проходящая вдоль хвоста.

Если вы будете гнуть эту кривую, форма хвоста будет соответственно изменяться. Кроме
того, если выбрать сам IK Handle, можно обнаружить на нем массу полезных атрибутов.
Это прежде всего Offset, позволяющий «протягивать» суставы вдоль кривой. Атрибут Roll
поворачивает все суставы вокруг кривой, а атрибут Twist позволяет спирально «скручивать» все
суставы от конца к началу.

Кроме того, по умолчанию вы не можете «оторвать» первый сустав от кривой (не говоря уж
об остальных). Однако выключив атрибут Root On Curve, вы сможете это сделать, получив таким
образом более «ручное» управление положением всей цепочки вдоль кривой (атрибут Offset при
этом игнорируется).

Таким образом, вы получаете действительно «гибкое» управление суставами с помощью


кривой. Форму кривой вы можете анимировать всеми известными вам способами. Первое, что
придет вам на ум, наверное, будут кластеры, и это будет совершенно адекватный выбор. Более
изысканные умы могут предпочесть Blend Shape, что в определенных случаях тоже может быть
хорошим решением.

Для автоматической анимации болтающегося по законам динамики хвоста вы можете


превратить управляющую кривую в динамическую кривую (Hair=>Make Selected Curves Dynamic) и
использовать динамику волос для анимации кривой.

Совет. Свести управление к минимуму управляющих объектов можно следующим


образом. После создания IK Spline Handle и кривой можно нарисовать вдоль этой
кривой еще одну цепочку из нескольких (трех-четырех) костей, а затем привязать
кривую к этой новой цепочке с помощью обычного скининга. Таким образом, вы
сможете управлять этой новой цепочкой с помощью прямой кинематики, кости
этой цепочки будут деформировать кривую, а кривая будет гнуть основную
многочисленную цепочку, представляющую реальный «хвост».

Немного поговорим о кривой, возникающей в ходе создания IK Spline Handle. По умолчанию,


она состоит всего из четырех контрольных точек. Однако вы можете перестроить ее с помощью
операции Rebuild Curves или указать количество сегментов в параметрах инструмента IK Spline
Handle Tool.

Персонажная анимация 747


Если снять галку Auto Simplify Curve, количество сегментов на кривой будет равно количеству
костей. Сами понимаете, что анимировать форму такой кривой будет несколько трудоемко.

Если хвост или позвоночник из чего-то «растут», то есть имеют родительский сустав или
объект, то включенная по умолчанию галка Auto Parent Curve, поместит вновь созданную кривую на
тот же уровень иерархии, чтобы хвост и управляющая кривая двигались за «родителем» вместе.
Однако глядя на то, как ловко перемещается вдоль кривой вся цепочка при изменении атрибута Off­
set, вы с большой долей вероятности захотите заняться дрессировкой пресмыкающихся, заставляя
их ползать вдоль заранее созданной кривой. Для этого вам надо снять галку Auto Create Curve и
MAYA дополнительно попросит вас выбрать кривую после щелкания в первый и последний сустав
цепочки. Этот вид анимации принципиально отличается от деформации хвостов и позвоночников
и требует в основном пристального слежения за ориентацией суставов.

Совет. Если вы будете заставлять какого-нибудь гада пресмыкаться вдоль кривой,


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

Совет. Чтобы анимировать скольжение гада вдоль кривой более привычным


способом, то есть с помощью Motion Path, используйте следующий способ:

В Option Box инструмента IK Spline Handle Tool выключите галки Root on Curve и Auto Cre­
ate Curve и включите галку Auto Create Root Axis. Это позволит вам использовать собственную
кривую и дополнительно создать пустой родительский объект для первого сустава. Создав IK Han­
dle, следует выбрать этот вспомогательный объект (он наверняка будет называться transform"!),
затем выбрать кривую и запустить этот пустой объект по пути: Animate=>Motion Paths=>Attach to
Motion Path.

Борьба с перекручиваниями - IK Spline Handle


Одной из проблем при анимации скелетов с помощью IK Spline Handle является внезапное
«прокручивание» костей вдоль продольной оси. Эта проблема сильно напоминает перекручивание
объектов при движении по пути или при использовании Aim Constraint и решается совершенно
аналогичным способом - заданием векторов слежения.

Чтобы эффективно следить и управлять ориентацией суставов во время анимации


формы кривой или во время скольжения суставов вдоль кривой, в Attribute Editor для IK Han­
dle есть специальный раздел, позволяющий корректировать вращения, полученные в результате
вычислений инверсной кинематики. Этот раздел называется Advanced Twist Control и содержит
атрибуты, практически полностью аналогичные атрибутам ноды Motion Path или Aim Constraint.

748 Книга Сергея Цыпцына


С помощью этих атрибутов можно задать направление (обычно это глобальная ось Y),
к которому суставы будут стремиться развернуться одной из своих локальных осей (обычно
это локальная ось Y для суставов). Я не буду описывать их подробно, это сделано в разделе
описывающем работу с Aim Constrain. Скажу лишь, что в целях какой-то умопомрачительной
гибкости управления, можно задавать ориентацию индивидуально для начальной и конечной
кости, а для остальных организовывать плавный переход между этими вращениями, и не как-
нибудь, а с помощью текстуры Ramp.

В заключение скажу, что при использовании IK Spline Handle, особенно внутри сложных
иерархий, вы можете случайно «припарентить» кривую к первому суставу, который находится
внутри цепочки, управляемой этой же кривой. Возникнет цикл в дереве зависимостей (подробнее
о таких циклах читайте в главе про изнанку), так как кривая управляет суставом, а сустав является
родителем для кривой. Следите внимательно, чтобы кривая находилась в иерархии никак не ниже
первого сустава.

Персонажная анимация 749


Практический пример настройки персонажа: сетап крыла
Теперь хочу представить типичный пример работы сетапщика или технического директора.
Этот материал подготовил и любезно предоставил Владимир Забелин, человек, хорошо известный
всем отечественным трехмерщикам (www.zabelinv.ru). Он приводит пример небольшого научного
исследования, коим и является типичная настройка нового персонажа. Он рассматривает
довольно сложную техническую задачу - настройку крыла птицы для крупных и средних планов,
включающую движение и деформации перьев. Вся авторская лексика и терминология сохранена
- для того, чтобы вы почувствовали «образ мысли» мастеров MAYA и учились лучше понимать
профессиональный жаргон. Итак, слово Владимиру...

750 книга Сергея Цыпцына


Настройка модели крыла

Анимация всякого рода летающих существ - не только интересная, но и не очень простая


задача. Посмотрим, в чем же сложность сетапа (настройки) крыла.

Самый «прямолинейный», если не сказать «тупой» подход - создать единую геометрию,


вставить в нее кости и попытаться пошевелить получившуюся конструкцию.

На этом пути нас ожидает несколько неприятных сюрпризов. Во-первых, такое крыло
поддается правдоподобным деформациям в очень ограниченных масштабах, и то преимущественно
в направлении «вверх-вниз».

Персонажная анимация 751


Как только мы попытаемся «сложить» крыло в продольном направлении, сразу обнаружим
очень серьезные нарушения в геометрии (перехлесты и растяжения).

Крыло слишком широкое (точнее, отношение ширины геометрии к длине управляющей


кости слишком велико), чтобы деформироваться адекватным образом. Поэтому неизбежно
использование более сложной конструкции скелета или использование дополнительных influence-
объектов.

Вторая «засада» крыло слишком тонкое. Как только мы начнем вручную редактировать
влияние костей на поверхность (веса прискиненных точек), так неизбежно столкнемся с тем, что
после редактирования веса точек верхней части поверхности будут отличаться от весов нижней
части, а значит при вертикальном «сложении» поверхности будут деформироваться немного по-
разному и, как следствие, проникать одна сквозь другую.

752 Книга Сергея Цыпцына


Можно, конечно, реализовать деформации крыла через набор blendshape'oB, но вряд
ли в таком случае мы получим достаточно гибкое управление. Да и вообще, подобное решение
будет громоздким и неэлегантным, этакий «тришкин кафтан», весь состоящий из технологических
заплаток. Но тем не менее, если мы ставим себе задачу получить всего лишь парящую где-то
далеко в небесах чайку, то «монокрыло» может быть вполне адекватно поставленной задаче. И
для реализации анимации «геометрического» крыла можно воспользоваться одним из методов
косвенного или опосредованного скиннинга (indirect skinning), основная идея которого заключается
в том, что кости скелета управляют поведением вспомогательного объекта (или объектов) или
деформера, который, в свою очередь, и определяет деформации крыла.

В качестве простейшей конструкции рассмотрим следующий пример.


Припарентим к костям крыла несколько локаторов, «погуще» в районе сустава.

С помощью Point Constraint прикрепим к каждому из локаторов по отрезку NURBS-кривой.


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

Персонажная анимация 753


Из-за того, что мы прикрепили отрезки с помощью Point constraint, они всегда остаются
параллельны одной оси.

Если теперь по этим отрезкам построить NURBS-поверхность (loft), «не убивая» историю
(history), при манипуляциях с костями поведение построенной поверхности будет ближе к
поведению крыла (конечно, такое крыло еще не слишком соответствует динамике настоящего
крыла пернатых представителей фауны и больше напоминает махолет, но все же...)

Теперь можно использовать полученную NURBS-поверхность в качестве wrap-деформера


для исходной геометрии крыла.

Вы, может, спросите: зачем? А дело в том, что Wrap-деформер позволит нам избежать
самопересечения геометрии исходного крыла при деформациях, как по ширине, так и по
толщине.

Более того, подобной конструкции крыла можно добавить несколько большую степень
правдоподобности за счет согласованных между собой вращений базовых отрезков как вправо-
влево, так и вверх-вниз. Первое позволит нам проэмулировать «растопыривание» крыльев (хотя

754 книга Сергея Цыпцына


«растопыривание» - слишком громкое слово, скорее мы получим растягивание крыла в продольном
направлении, что само по себе далеко от реального поведения перьев), второе - отставание задней
кромки крыла при маховых движениях.

Конечно, не надо вращать базовые отрезки независимо друг от друга, нужно согласовать
их вращение. Проще всего это сделать, «посадив» эти самые отрезки с помощью Driven Key на
дополнительные управляющие атрибуты.

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

Отмечу, например, что достаточно непросто будет получить гладкие деформации в районе
соединения крыла (управляемого Wrap-деформацией) и тушки тела (прискиненного к основному
скелету).

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

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

Приобретенный нами опыт, безусловно, имеет некоторые позитивные моменты, но главный


вывод - мы теперь знаем, как не надо поступать, если мы хотим решить эту задачу хорошо. В
то же самое время, ощущение, будто мы оказались у «разбитого корыта», тоже обманчиво. Мы
же только что, притом «на собственной шкуре», почувствовали справедливость главного, на мой
взгляд, принципа сетапа персонажей (под «персонажами», естественно, понимаются не только
уточки, лошади, воробьи и пчелы, но и червячные передачи, карданные валы и прочие устройства,
движение составляющих частей которых тем или иным способом должно быть согласовано друг с
другом).

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

И еще пару слов перед тем, как мы подвергнем вивисекции наше пернатое несчастье.

Сетап - лишь подготовительный, хотя и очень важный этап. Наша основная цель - это все-
таки дальнейшая анимация создаваемой конструкции, и полученный результат должен быть не
только функционален, но и удобен для дальнейшей работы. Поэтому великомученик-«сетапер»
вынужден балансировать между двумя противоречивыми условиями - ведь нужны максимальная
гибкость и минимальное число управляющих элементов.

Вполе возможно, что дойдя до этого места, вдумчивый читатель воскликнет : «А можно
еще латисы (Lattice) использовать! И нелинейные деформеры! И кластеры!» Можно. Более того,
обязательно пробуйте приходящие вам в голову идеи: ведь все, что вы читаете в книжке - лишь
изложение чужого опыта, а нужен собственный опыт, и он набирается только и исключительно путем
проб и ошибок, синяков и садин. Вполне возможно, что ваши собственные идеи окажутся более
плодотворными, чем изложенные выше или ниже. Так что экспериментируем, экспериментируем,
потом отдохнем и еще раз поэкспериментируем.

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

Персонажная анимация 755


Кожа да кости
Крыло, лишенное перьев, представляет довольно жалкое зрелище (достаточно вспомнить
несчастного цыпленка «табака»). И если проводить аналогию с рукой, то у костей крыла можно
выделить «ключицу», «плечо», «предплечье» и «кисть» со сросшимися «пальцами» (сросшиеся
пальцы, по сравнению с рукой, как раз предполагают некоторое упрощение сетапа «кожно-костной»
части крыла). Все это покрыто небольшим количеством мяса и обтянуто кожей. Прослойка мяса
невелика, кожа близко располагается к костям, поэтому прикрепление такого кожного покрова
не должно вызывать особых трудностей (Smooth Bind вполне подойдет, с небольшой коррекцией
весов)

Перья
Главная сложность перья. У настоящего крыла перья расположены в несколько
перекрывающих друг друга слоев (как на иллюстрации ниже).

Это и создает идеальный аэродинамический профиль. Но мы, для наших целей, рассмотрим
несколько более простую модель. Для нас важно, что перья вдоль крыла можно разбить на
несколько групп соответственно перья «плеча», «предплечья» и «кисти» в зависимости от того,
где именно перо крепится к коже. (Я не знаю правильных терминов, поэтому нижнюю часть пера
буду называть «основанием», верхнюю «кончиком». Желающие могут легко найти правильные
термины в соответствующих книгах о птицах.)

Основания перьев достаточно жестко закреплены возле костей, и каждое перо, на первый
взгляд, может двигаться как угодно вокруг точки крепления. Но это только на первый взгляд.
Перья взаимодействуют друг с другом так, что импульсы, которые получает основание пера,
«гасятся», усредняются влиянием соседних перьев, и в результате вся перьевая масса ведет
себя согласованно. Линия «кончиков» перьев (задняя кромка) оказывается сглаженной и, хотя и
зависит от линии оснований, но живет в основном по своим собственным законам.

Каждое перо, таким образом, испытывает два вида деформаций.

Во-первых, передняя часть каждого пера «основание» - ориентируется вдоль линии


передней кромки, «кончик» - вдоль линии задней кромки крыла. Таким образом, каждое перо
закручивается вдоль продольной оси.

Во-вторых, перо эластично и гнется вверх-вниз при маховых движениях крыльев, «кончик»
же пера в своем движении по вертикали несколько отстает от «основания».

Теперь попробуем воплотить накопленные знания в сколько-нибудь работоспособную


конструкцию.

756 Книга Сергея Цыпцына


Кстати, анекдот. В тему. Самолет на взлетной дорожке. В салоне раздается голос
стюардессы: «Уважаемые пассажиры! Экипаж нашего нового, суперсовременного
авиалайнера рад приветствовать вас на борту самолета. К вашим услугам три
бара, два ресторана, спортивный зал, беговая дорожка, плавательный бассейн,
два кинозала, аквапарк и теннисный корт. Пристегните ремни, и давайте мы
все вместе посмеемся над тем, как эта махина попытается оторваться от
земли...»

Построение крыла
Предварительный совет. Когда мы создаем цепочку костей с помощью Joint Tool,
локальная система координат внутри каждой кости по умолчанию располагается
очень удобно для дальнейшей работы. Ось X - вдоль кости, ось Y - перпендикулярно
X и в плоскости, образованной данной и следующей за ней костью, а ось 1,
естественно, перпендикулярна осям X и Y.

Если же мы после создания цепочки костей пожелаем отредактировать положение


сочленений (joints), локальные оси останутся в прежней ориентации, что отнюдь не будет
способствовать их адекватной реакции на наши дальнейшие действия.

Персонажная анимация 757


Можно, конечно, после редактирования переориентировать локальные оси каждого
сочленения с помощью операции Orient Joint, но лучше сразу строить необходимую цепочку
костей, располагая суставы (joints) в правильно выбранных местах. Можно сначала наметить
расположение сочленений либо некоторым количеством вспомогательных локаторов, либо создав
несколько «трафаретных» NURBS- кривых первого порядка с вершинами в намеченных точках, а
потом по этим шаблонам строить цепочки костей, используя функции привязки к точкам (snap to
point) или к кривой (snap to curve).

Построение «шаблона» будущего скелета

Создайте линии передней и задней кромки:

Кривая curve1 (NURBS-кривая первого порядка) - это шаблон для костей «тушки» тела,
curve2 - это кривая (NURBS-кривая 2-го или 3-го порядка), определяющая заднюю кромку (они обе
в файле wing01.ma).

Будем строить упрощенную модель крыла - всего по 3 пера на каждый сустав (итого 9
перьев), ведь для понимания процесса такого количества будет достаточно, а большее количество
перьев лишь загромоздит конструкцию, не внеся в нее ничего принципиально нового.

Для каждого пера мы будем строить отдельную цепочку костей. Построим «направляющие»
для этих перьевых «цепочек».

Построим отрезок вдоль оси X, начало которого в начале координат. Заметим, что пивот
его по построению находится в начале, и локальная ось X направлена вдоль этого отрезка.
Сделаем 8 копий этого отрезка (всего должно получиться 9 отрезков - по числу перьев). Назовем
их, например, C1, С2, СЗ....С9.

758 Книга Сергея Цыпцына


С помощью Geometry Constraint «насадим» только что созданные отрезки на шаблон
передней кромки кривую curve1. Теперь мы можем свободно двигать отрезки С1...С9 вдоль
кривой curve1:

Теперь сориентируем наши отрезки так, чтобы они пересекались с кривой curve2,
определяющей заднюю кромку крыла.

Для этого создадим девять локаторов, назвав их, например, L1, L2...L9, и с помощью того
же Geometry Constraint (или с помощью утилитки pointOnCurvelnfo) «нанижем» локаторы подряд
на кривую curve2 задней кромки крыла, как бусинки на нитку.

С помощью Aim Constraint сориентируем отрезок С1, направив его на локатор L1. Затем С2
аналогично направим на L2, СЗ на L3 и так далее.

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


отрезки С1...С9 соединяют кривые curve1 и curve2, и их точки пересечения с этими кривыми
легко контролируются. Если необходимо, мы можем подправить форму и местоположение каждой
кривой, не нарушая целостности всей конструкции.

Персонажная анимация 759


Когда все необходимые корректировки выполнены, приступим к пострению самого скелета
(файл wing02.ma)

Построение скелета
Включив привязку к точкам (snap to point), строим первую цепочку сочленений вдоль
кpивой curve1.

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


гарантированно располагаются наиболее удобным для нас образом, о чем уже
говорилось выше, за искючением первого и последнего сочленений. Проблема первого
сочленения заключается в том, что у него нет «предшественника», поэтому хоть
первая ось (X) и направлена вдоль кости, ориентация осей Y и Z неоднозначна.
Проблема последнего сочленения в том, что оно последнее и непонятно, куда,
в таком случае, должна быть направлена первая из осей (X). Но ориентация
локальный осей последнего сочленения нам будет безразлична, а вот с первым
сочленением имеет смысл быть быть поаккуратнее - оно ведь «рабочее».

760 Книга Сергея Цыпцына


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

В построенной нами цепочке первое звено (joint1) - не «рабочее». Избавимся от него. К


сожалению, нельзя просто так, за здорово живешь, «убить» (Delete) первое звено вместе с ним
уничтожится и вся остальная цепочка, поскольку сочленения образуют иерархическую структуру,
самым верхом которой является j o i n t 1.

Поэтому сначала выберем и «отпарентим» joint2 (и всю подчиненную иерархию) от joint1


- то есть выберем Edit=>Unparent. А потом смело уничтожим ненужный нам j o i n t 1 . Переименуем
оставшиеся сочленения примерно так: frontLeft1, frontLeft2, ...(файл wing04.ma).

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

Используя привязку к кривой (snap to curve) вдоль первого отрезка «перьевого шаблона»
С1, построим цепочку из трех костей (четырех сочленений), как показано на рисунке. Первые два
сочленения расположим близко друг к другу, а третье сочленение будет делить нашу цепочку
примерно пополам (это место «сгиба» пера). Самое первое сочленение - «не рабочее», оно нам

Персонажная анимация 761


нужно только для правильной ориентации локальных осей последующих костей. Поэтому первую
кость трогать не будем, а вторую и третью переименуем в а1 и b1, соответственно. Аналогично
построим еще восемь цепочек вдоль остальных восьми кривых. После переименования костей мы
получим примерно следующий результат (файл wing06.ma):

Теперь нам нужно удалить первые кости в каждой из перьевых цепочек и то, что
останется, «припарентить» к костям передней кромки крыла. Поскольку лень - великий движитель
общественного прогресса, то сэкономим немного сил, выполнив эти действия не в три (Unparent=
>Delete=>Parent), а в два этапа.

Сначала припарентим кости а1, а2, аЗ к первой фронтальной кости frontLeft1; а4, а5, а6
- ko второй frontLeft2; и, наконец, а7, а8, а9 - к третьей frontLeft3.

При таком «переприпарентивании» первые сочленения каждой из «перьевых»цепочек


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

Итак, первый, самый простой этап завершен: скелет построен и вспомогательные кривые
нам больше не нужны - их можно удалить, хотя лучше, все же, проявить осторожность и просто
спрятать (Hide). Самое время передохнуть, сохранить файл (файл wing07.ma) и расширить
сознание чашкой ароматного чая с пряником. Далее перейдем к основной задаче - приданию
нашему скелету функциональности.

762 Книга Сергея Цыпцына


Оперение крыла
Сейчас самое время «оперить» наше крыло создать девять NURBS-плоскостей, затем,
если есть желание, немного подвигать контрольные точки для придания каждому «перу» слегка
овальной формы, и, наконец, «прибиндить» (Bind to) (или «прискинить» - что лучше соответствует
терминологии нашей книги) эти, с позволения сказать, перья к скелету - по одному перу к каждой
«перьевой цепочке», используя Smooth Bind с опцией Selected Joints.

Наличие перьев на нашем скелете поможет нам лучше понимать процесс сетапа, поскольку
на узких квадратных костях скелета трудно будет разглядеть результаты нашей деятельности, а
на плоских широких «перьях» результаты сгиба и скручивания выглядят более убедительно (файл
wing08.ma).

Персонажная анимация 763


Управление крылом
Для управления передней кромкой крыла мы применим самый примитивный способ - точно
такой же, какой применяется для управления рукой.

Во-первых, назначим ikHandle на первые две кости передней кромки крыла.


Обратите внимание, что мы будем использовать ikRPSolver, чтобы иметь полный контроль над
местоположением «локтя» при сгибе передней кромки крыла.

Для реализации этого управления создадим локатор , который назовем, например, IPoleV-
ectorControl.

Поместим его в место соединения первой и второй кости передней кромки крыла, используя
все ту же привязку к точке (snap to point).

Выполним Freeze Transformation для этого локатора, чтобы обнулить значения атрибутов
translateX, translateY и translateZ.

Затем воспользуемся констрейном типа Pole Vector для ориентации направления сгиба IK
Handle передней кромки крыла (файл wing11.ma).

Теперь самое время создать контрольный элемент, управляющий работой крыла. Часто
для этой цели используют кривую, но можно обойтись и просто локатором.

764 Книга Сергея Цыпцына


Итак, создадим локатор, который назовем, например, IWingControl поместим его в место
сочленения второй и третьей кости передней кромки крыла, (там сейчас находится ikHandle1),
используя привязку к точке.

Выполним Freeze Transformation для IWingControl.

Затем с помощью Point Constaint прикрепим ikHandle1 к нашему контрольному локатору.


Убедившись, что ikHandle1 правильно реагирует перемещение контрольных локаторов IWingCon­
trol и IPoleVectorControl, можно теперь сам ikHAndle1 спрятать (Hide), чтобы он не «путался под
ногами».

Теперь займемся управлением «кистью» - третьей костью передней кромки крыла.


Естественно, хотелось бы, чтобы эта последняя кость вращалась при вращении управляющего
локатора, и такая синхронизация легко достигается согласованием вращений с помощью Orient
Constraint, однако хотелось бы сохранить нулевые значения поворотов контрольного локатора при
имеющемся взаимном расположении костей скелета, а это значит, что «напрямую» воспользоваться
им (то бишь констрейном Orient Constraint) не удастся. Мы выполним согласование вращений кости
и контрольного локатора через вспомогательный объект локатор-«посредник». Можно было бы
воспользоваться для этой цели и пустой трансформ-нодой, но мне больше нравится, когда все
элементы сетапа, даже вспомогательные, имеют какое-то «материальное воплощение».

Итак, создаем локатор-«посредник» IWingAdd.


Припарентим его к контрольному локатору IWingControl.
Затем совмещаем его положение с контрольным локатором IWingControl.
И, наконец, с помощью Orient Constaint сориентируем наш локатор-«посредник» вдоль
интересующей нас третьей кости передней кромки крыла.

В результате получается: кость и локатор ориентированы одинаково, однако связь между


ними абсолютно неправильная - сейчас кость управляет поворотом локатора-«посредника», а нам
нужно ровно наоборот (файл wing12.ma).

Поэтому разрываем связь между между локатором-«посредником» и костью, просто «убив»


в Outliner соответствующую ноду констрейна Orient Constraint.

Заблокируем (Lock) атрибут translate локатора-«посредника» в Channel Box.


С помощью констрейна Orient Constraint сориентируем третью кость по вращениям локатора
IWingAdd.

Убедившись, что крыло правильно реагирует не только на перемещение, но и на повороты


контрольного локатора IWingControl, можем спрятать наш вспомогательный локатор IWingAdd.
Итак, цель достигнута мы получили управление передней кромкой крыла. Полученный результат

Персонажная анимация 765


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

Поэтому нам придется продолжить наши изыскания - для получения согласованного


управления задней кромкой крыла.

Управление задней кромкой


Для этого построим цепочку костей вдоль задней кромки крыла, сориентируем «перьевые»
кости скелета на кости этой цепочки, а функциональность этой «заднекромочной» цепочке костей
придадим с помощью ИК-сплайна.

Итак, используя функцию привязки к точке (snap to point), выстроим цепочку костей вдоль
задней кромки крыла, переименовав сочленения соответственно в backJ, backJ_1, ..., backJ9?
(файл wins13.ma).

С помощью Aim Constraint нацелим перьевые кости а1,...,а9 на кости построенной


дополнительной цепочки backJ_1,..., backJ_9, используя в качестве Aim Vector направление вдоль
перьевой кости (локальную ось X), то есть вектор « 1 , 0 , 0 » .

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

Поэтому в качестве Up Vector выберем направление локальной оси Z, то есть <<0,0,1>>, и


направим этот самый Up Vector на объект - соседнюю кость передней кромки крыла.

Для а1, а2, аЗ целевым объектом для Up Vector будет frontLeft2, для а4, а5, а6 frontLeft3,
а для а7, а8 и а9 - frontLeft4, соответственно.

После того, как все девять «перьевых» костей а1, ..., а9 будут сориентированы указанным
образом, можно подвигать управляющий локатор крыла IWingControl, чтобы убедиться, что теперь
перья работают «почти правильно»: они ориентируются на звенья «заднекромочной» цепочки
костей, при этом плоскости перьев ориентируются вдоль костей передней кромки крыла (файл
wing14.ma).

766 Книга Сергея Цыпцына


Однако было бы естественно, чтобы перья перекручивались относительно своей продольной
оси так, чтобы передняя кромка пера ориентировалась вдоль передней кромки крыла, а задняя
кромка пера - вдоль построенной нами дополнительной «заднекромочной» цепочки. Для этого нам
нужно повернуть вторые половины перьевых скелетных цепочек b1, ..., b9 на подходящие углы.

Сделать это просто нужно воспользоваться Aim Constraint, а в качестве целевых


объектов выбрать те же кости дополнительной, «заднекромочной» скелетной цепочки, что и для
соответствующих костей а1, ..., а9.

В качестве Up Vector надо выбрать те же направления локальных осей Z <<0,0,1>>, а


вот с выбором направления самого Up Vector придется повозиться. Этим Up Vector естественно
выбрать вектор, направление которого определяется соответствующим звеном «заднекромочной»
цепочки (разность координат конца и начала соответствующей кости) но только как перевести
«кость в вектор», то есть как определить вектор направления каждой кости в мировой системе
координат?

Для определения координат выбранной точки в мировой системе координат можно,


конечно, воспользоваться MEL-командами pointPosition или xform, однако применение MEL-команд
в данной ситуации абсолютно неоправданно - с их использованием мы потеряем интерактивность
работы, поэтому придется воспользоваться несколько иными приемами.

Создадим десять дополнительных локаторов orientLO,..., orientL9 и с помощью Point Con­


straint прикрепим эти локаторы к костям backJ, backJ_1,..., backJ_9.

За счет Point Constraint созданные локаторы будут намертво прикреплены к сочленениям


костей, оставаясь при этом в исходной мировой системе координат, и атрибуты translateX, trans­
late Y, translateZ этих локаторов и будут координатами сочленений в мировой системе координат.

Персонажная анимация 767


Разность координат пары локаторов, прикрепленных к визуальному «началу» и «концу»
каждой кости, и даст нам необходимый вектор направления этой кости, который мы будем
использовать в качестве ориентации Up Vector.

Итак, командой createNode создаем ноду plusMinusAverage (по умолчанию она получит имя
plusMinusAverage1) и не забудем установить операцию Substract.

На входы этой ноды подаем координаты двух локаторов: на первый вход - координаты
«конца» (локатора orientL1), а на второй вход координаты «начала» (локатора orientL0).

Для этой цели можно воспользоваться простыми MEL-командами:

createNode plusMinusAverage;
connectAttr -f orientL1.translate plusMinusAverage1.input3D[0];
connectAttr -f orientL0.translate plusMinusAverage1.input3D[1];

Теперь осталось с помощью Aim Constrait направить кость b1 на backJ_1, выбрав в качестве
Aim Vector направление продольной локальной оси X (вектор <<1,0,0>>), в качестве Up Vector
направление локальной оси Z (вектор <<0,0,1>>), то есть World Up =«Vector», и в качестве World
Up Vector результат вычитания координат локаторов, то есть выход ноды plusMinusAverage1.

768 Книга Сергея Цыпцына


Для остальных костей (b2,...,b9) поступаем аналогично.

Потестировав полученную конструкцию, убедимся, что теперь перья не только следуют


движениям управляющего локатора, но и всегда направлены на звенья дополнительной
«заднекромочной» цепочки. Кроме того, перья при этом еще и скручиваются в соответствие с
разностью ориентации передней и задней кромок крыла (файл wing15.ma).

Персонажная анимация 769


Осталось совсем немного заставить заднюю кромку крыла реагировать на наши
манипуляции с управляющим локатором.

Для этого на всю «заднекромочную» цепочку костей навесим IК Spline Handle, постаравшись
минимизировать число контрольных точек сплайновой кривой (их должно получиться всего четыре,
и этого вполне хватит для реализации задуманного нами управления).

Точки возникшей кривой для IK Spline Handle объединяем в кластер.


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

Руководствуемся при этом общим правилом - чем ближе «к телу», тем вес меньше.

Совместим пивот созданного нами кластера с положением контрольного управляющего


локатора IWingControl.

С помощью констрейнов Point и Orient намертво прикрепим наш кластер к управляющему


крылом локатору (файл wing17.ma).

770 Книга Сергея Цыпцына


Потестируем полученный результат. В принципе основная цель достигнута: и передняя и
задняя кромкакрыладвижутсясогласованно, обе адекватнореагируютнаманипуляциисконтрольным
управляющим локатором крыла. Деформации перьев при этом вполне удовлетворительные. В
качестве последнего штриха добавим пару-тройку управляющих поведением крыла атрибутов,
которые кажутся совершенно необходимыми для комфортной работы аниматора.

Во-первых, позволим перьям «растопыриваться», то есть раздвигаться друг относительно


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

Итак, заведем дополнительный атрибут (назовем его wide) на управляющем крылом


локаторе IWingControl. Естественно, это должен атрибут типа Float, и желательно сделать его
keyable:

Возможен альтернативный способ: добавить атрибут с помощью простой MEL-команды:

addAttr -In wide - keyable true -at double IWingControl ;

Свяжем в Connection Editor этот атрибут с масштабированием вдоль локальной оси X кости BackJ:

Персонажная анимация 771


Это же можно сделать MEL-командой

connectAttr -f IWingControl.wide BackJ.scaleX;

Однако, как мы видим, при изменении атрибута wide масштабируется только кость
BackJ, а все дочерние кости «заднекромочной» цепочки остаются неизменными. Дело в том, что
у каждой кости есть специальный атрибут Segment Scale Compensate, который отвечает за то,
чтобы дочерние кости не наследовали масштабирование своих родителей, который по умолчанию
установлен в значение True.

Отожмем галку у атрибута Segment Scale Compensate для всех звеньев «заднекромочной»
цепочки и отметим, что теперь при изменении атрибута wide контрольного локатора крыла все
перья «растопыриваются» согласованно:

772 Книга Сергея Цыпцына


При wide =0.5 имеем следующую картину:

При wide=1.3:

И наконец, крыло птицы достаточно эластично, и при маховых движениях задняя кромка
гнется, отставая в своем движении от передней кромки крыла. Причем чем дальше от тела, тем
такие изгибы больше (файл wing21.ma).

Персонажная анимация 773


Каждое перо у нас управляется двумя костями - а# и b# с соответствующими номерами,
и конечно, естественно реализовать гибкость или эластичность задней кромки крыла, управляя
вращением костей b# относительно локальной оси Z (синяя окружность), однако атрибуты
вращения этих костей не свободны, они подчиняются Aim Constraint, который мы вводили (если
вы еще помните) для получения скручивающих деформаций перьев:

Как быть? Можно, конечно, воспользоваться технологией смешивания атрибутов (Blend


Attributes) для двойного управления поворотами костей b1,..., b9, но после небольшого раздумья
нетрудно найти и более простое решение.

Дело в том, что реально Aim Constraint для костей b# влияет только на вращение кости
вдоль локальной продольной оси (оси X), а вращения по остальным осям остаются нулевыми,
поскольку и кости b# и кости а# направлены на одни и те же объекты. Различия только в Up
векторах. Поэтому у дочерних (по отношению к звеньям а#) костей b# вращения по осям Y и Z
всегда будут нулевые, а значит, эти атрибуты вращения можно освободить от влияния Aim Con­
straint без ущерба для общей функциональности. Что мы и сделаем.

774 Книга Сергея Цыпцына


Выбираем все кости b1, ..., b9, в Channel Box выделяем атрибуты RotateY и RotateZ и
освобождаем их (Channels=>Break Connection)

Далее, чтобы управлять изгибом крыла, нам, естественно, понадобится еще один
дополнительный атрибут на контрольном локаторе (назовем его bend), который мы создадим
точно так же, как создавали атрибут wide, например, MEL-командой:

addAttr -In bend - keyable true -at double IWingControl ;

Поскольку есть естественное желание, чтобы изгибом всего крыла управлял один атрибут,
вы не можете напрямую связать новоявленный атрибут bend с углом поворота костей b# - кости
должны по-разному реагировать на одно и то же значение атрибута bend, а именно: чем дальше от
тела, тем поворот кости больше. Поэтому связь между атрибутом bend и углами поворота костей
мы осуществим с помощью технологии Set Driven Key.

Открываем окно Set Driven Key.

В качестве управляющего объекта (driver) выбираем IWingControl и управляющий атрибут bend.


В качестве управляемых объектов (driven) кости b1, ...,b9 и управляемый атрибут - rotateZ.

Персонажная анимация 775


Ставим всего два ключа - при значении bend=0 значение поворота для всех костей b#
равно, естественно, нулю, а при bепd=1 выставим углы поворотов вручную, руководствуясь
такими соображениями: чем дальше от тела, тем угол поворота больше, при этом линия, которую
будет образовывать задняя кромка крыла, должна быть похожа скорее не на прямую линию, а на
параболу. Впрочем, это дело вкуса...

Ну, и наконец последний, завершающий штрих - изменение Infinity для всех Driven Key
кривых открываем Graph Editor, выделив предварительно кости b#, и для всех обнаруженных
кривых изменяем значении параметра Pre- и Post Infinity с Constant на Linear (файл wing25.ma).

Ну вот и все. Основные идеи сетапа крыла изложены. Вам осталось только переварить
все прочитанное. Естественно, то крыло, которое мы построили, весьма далеко от совершенства.
Реальность, как всегда, намного сложнее. И вам придется самостоятельно изменять конструкцию,
в зависимости от конкретной задачи, но, тем не менее, надеюсь, что некое понимание устройства
крыла у вас все-таки появилось...

776 Книга Сергея Цыпцына


Перенос анимации. Навешивание ярлыков.
Animation Retargeting. Joint Labelling

Рано или поздно перед вами встанет задача переноса анимации с одного персонажа
на другой. Хочу сразу обозначить разницу между переносом анимации (Animation Mapping) и
переносом движений (Animation Retargeting). В первом случае вы переносите с одного объекта
(или персонажа) на другой именно анимацию, то есть анимационные кривые (в виде клипов)
будут перенесены с атрибутов одного персонажа на атрибуты другого. Эта технология реализуется
средствами нелинейной анимации и будет описана позже. Она полностью прозрачна и бесхитростна
и к тому же не привязана только к скелетам.

Во втором случае между персонажами, а точнее, между скелетами, переносится характер


движения. В этом случае используется специальный интеллектуальный солвер (недоступный для
редактирования), трансформирующий движение одного скелета в подходящее движение другого.
Скелеты при этом могут быть разных пропорций и даже могут иметь разное количество костей,
солвер при этом старается максимально эффективно «втиснуть» движение одного персонажа в
скелет другого. Этот процесс более интеллектуальный, чем просто перенос анимационных кривых
между атрибутами. А самая главная особенность такого переноса движения заключается в том, что
перенесенная анимация редактированию не подлежит. Да-да. Перенесенная анимация выглядит
как ключи на вращение для всех суставов в каждом кадре. То есть у вас либо получится перенести
движение, либо нет. Никаких дальнейших правок.

Итак, рассмотрим немного подробнее этот процесс. Носначалая определюсьс терминологией


и буду назвать исходным скелетом (source hierarchy) персонаж, с которого переносится движение,
а целевым (target hierarchy) - скелет, на который переносится движение.

Сразу оговорюсь, что эта технология хорошо подходит для человекообразных обезьян,
однако для четвероногих друзей, насекомых и прочих паразитов вы можете применять ее на свой
страх и риск. Еще раз напомню: она служит для переноса движения только между скелетами.

Интеллектуальный анализ двух скелетов, применяемый в этой технологии, опирается на


сравнение имен суставов (или костей, если угодно) и оценку их взаимного расположения. Но так как
имена суставов могут быть заданы совершенно произвольно (а точнее, совершенно фиксировано,
поскольку каждая студия имеет строгие правила именования суставов для своих персонажей),
заставлять пользователя переименовывать всю иерархию скелета было бы бесчеловечно. Поэтому
в MAYA появился механизм маркировки (labelling) суставов. Каждому суставу может быть присвоена
собственная текстовая метка-название (label). Эта метки используется затем для сравнения и
задания соответствия между скелетами.

Метки имеют фиксированные имена, для того, чтобы названия суставов на разных скелетах
были унифицированы. Вы можете задавать метки для суставов либо через Attribute Editor, либо
через специальное меню Skeleton=>Retargeting=>Joint Labelling, что гораздо быстрее.

Примечание. В седьмой версии MAYA существенно поменялись меню, относящиеся


к созданию меток и переносу анимации. В частности подменю Joint Labelling было
вынесено из меню Retargeting на уровень основного меню Skeleton. В него также
вошли операции для работы с метками типа Show/Hide All Labels. Приводимый
ниже пример был создан для версии MAYA 6.5, но если вы используете седьмую
версию, для вас не составит особого труда разобраться в новых названиях меню.
Единственное, что надо иметь в виду - это использование для данного примера
меток из меню Skeleton=>Joint Labelling=>Add Retargeting Labels.

Персонажная анимация 111


Сначала необходимо включить отображение меток на экране: Skeleton=>Retargeting=>Show
All Labels. Затем для выбранного сустава достаточно выбрать соответствующую метку в списке-
меню. Причем процесс задания меток обладает собственным интеллектом. Если вы выбрали сустав
бедра и выполнили для него Label Leg, автоматически будут заданы метки для нижележащих
суставов (Knee, Foot, Toe), а для выбранного сустава будет задана метка Hip. Этот интеллект
работает также для рук (Label Arm). Для других частей скелета, типа шеи (Neck), эта операция
просто задает метку только для выбранного сустава.

Если скелет, как ни странно, обладает симметрией, то правые и левые конечности


необходимо отделить друг от друга, задав для них «сторону»: Label Left или Label Right.

После того, как вы зададите метки, необходимо задать нейтральные позы для обоих
скелетов с помощью операции Skeleton=>Retargeting=>Set Neutral Pose. He путайте эти позы, с
позами возникающими автоматически при скининге (Bind Pose). Совершенно необязательно
распинать скелет, ставя его в Т-позу, при задании нейтральной позы. Наоборот, вы должны
придать обоим персонажам независимые позы, от которых будет «отсчитываться» и сравниваться
анимация. Если один персонаж это обезьяна, ее нейтральная поза наверняка будет включать в
себя согнутую спину, опущенные руки, вытянутую шею. Если вы переносите движение с обезьяны
на бравого солдата Швейка, то для него нейтральной позой может быть стойка «Смирно!».

После задания поз можно задать параметры и выполнить ключевую операцию Skeleton=>Re
targeting=>Retarget Skeleton. К этому моменту вы обязательно должны пометить один из суставов
как Root на каждом скелете. Сначала надо выбрать исходный скелет за этот сустав, затем целевой
скелет за него же и выполнить вышеуказанную операцию.

Еще немного замечаний, перед тем, как дать практический пример. Для тех суставов, чьи
метки не заданы или установлены в опцию «None», перенос движения не производится вообще.
Для остальных суставов происходит не только сравнивание имен меток, но и анализ взаимного
расположения суставов. Кроме того, для суставов, обозначенных как руки и ноги, производится
дополнительный анализ их поведения и обеспечивается сохранение некоторых характерных
особенностей движения, таких, как прилегание ног к земле. Все это делает возможным перенос

778 Книга Сергея Цыпцына


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

Разберем небольшой перенос движения.

Можете использовать свой любимый персонаж, однако если это пятирукий мутант, лучше
все-таки открыть файл retargetStart.ma.

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

Обратите внимание, что персонажи имеют не только разные пропорции, но и разное


количество суставов. Это касается бедер, шеи и, самое главное, позвоночника.

Сначала надо расставить метки на суставах. Эту рутинную работу лучше проводить на
обоих скелетах одновременно, чтобы гарантировать синхронизацию названий. Но вы можете
проделать это для каждого отморозка отдельно. Я буду просто указывать: «выберите такой-то
сустав и пометьте его как Neck», имея в виду, что вы выбираете сустав либо на обоих скелетах,
либо на одном.

Прежде всего надо включить отображение меток суставов на экране: Skeleton=>Retargetin


g=>Show All Labels. Напротив каждого сустава появится метка None.

Совет. Перед процессом расставления меток очень полезно «оторвать» меню Skel
eton=>Retargeting=>Joint Labelling, чтобы просто не сойти с ума.

Итак, первым требованием успешного переноса движения является наличие на обоих


скелетах сустава, помеченного как Root. («Помеченного» - значит имеющего метку (Label) с
именем Root).

Выберите самый верхний сустав - Root Joint. У Бивиса это сустав Bivis, у напарника - ButtHead
Теперь в меню Joint Labelling выполните Label Root.
Дальше выберите левую ногу (LeftUpLeg), выполните Label Leg.

Персонажная анимация 779


Обратите внимание, что возникли метки не только для выбранного сустава (Hip), но и
для ниже лежащей цепочки (Knee, Foot, Toe). В этом состоит «интеллектуальная» часть процесса
маркировки скелета, касающаяся рук и ног персонажа.

Чтобы отличать одну ногу от другой, обозначьте ее как левую - Label Left.
Теперь выберите правую ногу (RightUpLeg), выполните Label Leg, обозначьте как Label
Right. Выберите место, откуда растут руки (руки, а не ноги!) (Collarbone_Root), и выполните La­
bel Collar. Выберите левое плечо (LeftArm), выполните Label Arm. Стоп! Вот тут сюрприз, за счет
издержек «интеллектуальности». MAYA честно пометила выбранный сустав как Shoulder и быстро
разметила три нижележащих сустава как Elbow (локоть), Hand (рука, кисть) и Finger (палец). При
этом она совершенно не учла (да и откуда ей знать), что между локтем и кистью, был вставлен
дополнительный сустав для продольного поворота кисти.

Отредактируйте это безобразие.

Выберите дополнительный сустав, ошибочно помеченный как Hand, и выполните Label None.
Затем выберите концевой сустав, помеченный как Finger, и выполните Label Hand.

Примечание. Суставы, помеченные как None, игнорируются при переносе


анимации.

780 Книга Сергея Цыпцына


Снова выберите плечо и пометьте его как левое: Label Left.

Выберите правое плечо (Right Arm). Для того, чтобы не исправлять ошибочную разметку,
сразу пометьте его как Label Shoulder и Label Right.

Выберите правый локоть и пометьте его как Label Elbow.


Выберите концевой сустав и выполните Label Hand.

Примечание. Несмотря на то, что концевой сустав не содержит никакой анимации


и подчиненных костей, надо обязательно пометить его как Hand. Иначе перенос
анимации для рук не будет производиться вообще. MAYA должна «знать», откуда у
скелета растут руки и ноги и где они заканчиваются, чтобы корректно произвести
вычисления. Если MAYA не находит полностью помеченных рук или ног, то просто
не производит перенос движения для непомеченных конечностей.

Выберите сустав Head, отвечающий за голову и пометьте его как Label Head.
Выберите сустав Neck, отвечающий за шею и пометьте его как Label Neck. Обратите
внимание, что шея имеет разное количество суставов на первом и втором скелете.

Выберите все суставы, относящиеся к позвоночнику (Spine*), и выполните Label Spine.


Опять заметьте: у позвоночников разное количество суставов и разная степень гибкости.

Примечание. Важно выбрать все суставы, принадлежащие позвоночнику. В идеале,


это все суставы между Root и Collar. Особо проследите, чтобы сразу после Root не
оставалось суставов, отмеченных как None.

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

Примечание. Повторю сказанное раньше: процесс переноса движения - не простое


копирование анимации между одинаково помеченными суставами. Это довольно
сложные и интенсивные расчеты, усредняющие и распределяющие вращение
суставов исходного скелета среди суставов целевого персонажа.

Персонажная анимация 781


Теперь осталось задать нейтральную позу для каждого из персонажей. Можно считать, что
поза из первого кадра подходит как «нейтральная» для каждого из них.
Выберите каждый скелет за самый верхний сустав, помеченный как Root.
Выполните Skeleton=>Retargeting=>Set Neutral Pose. Заметьте, что в Attribute Editor для
каждого из скелетов появилась новая закладка.

Теперь можно выполнить собственно перенос движения.

Для этого надо сначала выбрать исходный скелет за сустав, помеченный как Root, а затем
выбрать за такой же сустав второй (целевой) скелет, на который будет переноситься движение. В
нашем случае надо выбрать сначала Bivis, а затем ButtHead.

После этого следует открыть Option Box операции Skeleton=>Retargeting=>Retarget Skel­


eton, ужаснуться от количества параметров и нажать кнопку Retarget. Как увидите, процесс
переноса движения отнюдь не мгновенное действие, что лишь подчеркивает его вычислительную
сложность.

Если вашего второго персонажа сильно «перекрячило» или согнуло вниз, нажимайте Undo
и проверяйте разметку суставов. В крайнем случае возьмите готовый файл retargetLabelled.ma,
там метки расставлены корректно.

Проверьте, как перенеслось движение. Обратите внимание на «глюки».

Во-первых, что-то случилось с правой ступней второго скелета.

Во-вторых, в первом кадре наметился явный правосторонний сколиоз.

782 Книга Сергея Цыпцына


Все это наводит на мысль, что локальные оси суставов второго скелета ориентированы
не слишком корректным образом. (Я специально подсунул вам «недочищенный» скелет, чтобы
подчеркнуть, как важно следить за начальной ориентацией суставов внутри персонажа) .

Покажите локальные оси скелета ButtHead.

Выберите его и выполните


Edit=>Select Hierarchy и Display=>Object Components=>Local Rotational Axes.

Обратите внимание, что некоторые оси, особенно в суставах позвоночника, ориентированы


довольно криво.

Вопрос в том, как вернуть все обратно и заново ориентировать оси. Малодушные (и
самые разумные пользователи) просто заново загрузят сохраненный файл retargetLabelled.ma.
Однако мы легких путей не ищем, а потому убьем всю анимацию второго персонажа и вернемся в

Персонажная анимация 783


нейтральную позу.

Снова выберите ButtHead и выполните Edit=>5elect Hierarchy, а затем Edit=>Delete By


Type=>Channels. Все ключи должны исчезнуть с временной линейки.

Теперь просто выполните Skeleton=>Retargeting=>Go To Neutral Pose.

Затем выполните Skeleton=>Orient Joint (с установками по умолчанию).


MAYA весело поприветствует вас сообщениями типа:

// Warning: Skipping Spine: It has non-zero rotations. //


// Warning: Skipping Spinel: It has non-zero rotations. //
// Warning: Skipping Spine2: It has non-zero rotations. //

Это означает, что данная операция не может быть использована для суставов с ненулевыми
вращениями. Чтобы обойти это ограничение, а заодно вычистить все вращения и получить
«стерильный» скелет, откройте Option Box операции Modify=>Freeze Transformation и включите
галку Joint Orient, а затем нажмите кнопку Freeze Transform.

Снова выполните Skeleton=>Orient Joint.


Все локальные оси должны развернуться должным образом.

Теперь можно повторить попытку переноса движения. Выберите первый и второй скелеты.
Выполните Skeleton=>Retargeting=>Set Neutral Pose (ведь мы основательно «прочистили» второй
скелет), а затем Skeleton=>Retargeting=>Retarget Skeleton.

784 Книга Сергея Цыпцына


Теперь со ступней все в порядке, но сколиоз остался. Это связано с тем, что позвоночники
двух персонажей имеют разное количество суставов и, кроме того, изогнуты в разные стороны.
Как следствие, ориентация некоторых суставов позвоночника (например, последнего) у каждого
скелета своя. Вы может побороться с этим самостоятельно, но на будущее помните несколько
моментов.
Чем более похожи скелеты, тем успешнее перенос движения.
Нейтральные позы также должны быть хотя бы топологически похожи. Если один скелет
стоит прямо, то второй в своей нейтральной позе не должен быть завязан в узел.
Анимация переносится только с одного скелета. Поэтому если ваш исходный персонаж
управляется с помощью нескольких скелетов, то вам придется выбрать только один из них и
переносить движение только с него.
Перенесенная анимация - «голая», прямая кинематика с ключами в каждом кадре.
Инверсная кинематика не переносится ни при каких условиях, даже если вы обвешаете целевой
скелет IК-манипуляторами.
Аккуратная разметка суставов первый залог успеха. Все радикальные перекручивания
или сгибания на 90 градусов, как правило, вызваны пропущенной меткой для сустава позвоночника
или потерянной «рукой».
Следите за сообщениями в процессе переноса движения. Иногда они указывают на то, что
вы забыли пометить важный сустав или обозначить правую или левую сторону конечности.
По умолчанию движение переносится в предположении о том, что ноги стоят на земле, а
руки не закреплены и свободно болтаются в воздухе.

Поэтому в Option Box операции Retarget Skeleton для вычисления движения нижних
конечностей (Lower Body) по умолчанию используется опция Scaled Foot Placement, обеспечивающая
то, что расстояние от бедер до ступней (Hip to Foot) будет пропорционально сохраняться на втором
скелете (вы можете сами определить, какое расстояние использовать для сохранения пропорций
в движении ног, задав значение параметра Lower Body Scale).
Если персонаж выполняет какие-то специфические движения ногами, например прыгает
по камням через ручей, необходимо, чтобы ноги попадали в конкретные места (абсолютные
позиции). В этом случае можно использовать опцию Absolute Foot Placement.
Если руки не закреплены, для переноса движения верхних конечностей (Upper Body) лучше
использовать опцию Joint Rotations Only. Если же руки опираются на что-то или совсем уж сильно
отличаются по размеру для обоих скелетов, можно воспользоваться опцией Scaled Hand Place­
ment. Если персонаж что-то держит в руках, лучше использовать вариант Maintain Hand Distance,
сохраняющий пропорции в расстоянии от рук до туловища.
На этом можно закончить разговор о мануальной терапии, то есть о скелетах и суставах, и
перейти к дерматологической теме - скинингу.

Персонажная анимация 785


Полнотельная кинематика: Full Body IK

В седьмой версии MAYA появился еще один вид инверсной кинематики. Этот способ
управления персонажем появился в результате покупки компанией Alias компании Kaydara,
имевшей наиболее продвинутые, на тот момент, решения в области инверсной кинематики,
нелинейной анимации и управления скелетом.
Этот вид управления персонажем, возможно, придется по вкусу если не большинству,
то значительному количеству майских пользователей, измученно навешивающих сонмы IK-
манипуляторов и управляющих локаторов на своих иезуитски-сложных персонажей.

Идея подкупающе проста и привлекательна. Берется уже построенный скелет и на него


одним махом навешивается полная система управления персонажем под названием Full Body IK.
При этом создаются манипуляторы для рук, ног, бедер и других частей тела, дергая за которые вы
можете управлять скелетом наподобие марионетки: потянув за одну руку вбок, вы согнете персонаж
в пояснице, потащив руку вниз, вы заставите персонажа согнуть колени и т.д. Таким образом, все
манипуляторы оказываются связанными между собой и персонаж ведет себя «интеллектуально»,
как единое целое, сгибаясь и двигаясь «привычным» образом.

Впрочем, лучше сразу несколько раз увидеть, чем один раз услышать или прочитать.
Откройте новую сцену и выполните 5keleton=>Full Body IK=>Get FBIK Example.
Из открывшегося окна Visor с парой примеров перетащите и бросьте средней кнопкой
мыши человекоподобного персонажа прямо в панель камеры.

Теперь отключите в камере отображение суставов (костей) Show=>Joints и полюбуйтесь на


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

786 Книга Сергея Цыпцына


Очевидное применение Full Body IK предполагает последовательное выставление персонажа
в различные позы и постановку на них ключей. Так как управление таким персонажем отнюдь
не просто набор IK-манипуляторов, для постановки ключей на позы персонажа предназначена
специальная операция Animate=>Set Full Body IK Keys. Я поговорю о ней подробнее немного позже,
а сейчас попробуем разобраться, как устроена система Full Body IK и что необходимо сделать с
уже построенным скелетом, чтобы навесить на него эту систему управления.

Подготовка скелета к использованию Full Body IK


В отличие от создания обычных IK Handle, когда требуется просто наличие соответствующих
частей скелета, система Full Body IK требует специальной подготовки скелета к дальнейшему
использованию.

Внешне это выглядит так: вы создали скелет и просите MAYA создать для него систему
управления человекообразным или четырехлапым персонажем (эти варианты указываются в Op­
tion Box операции Add Full Body IK). Однако MAYA ничего не знает про то, где, по вашему мнению,
у персонажа находится голова, а где хвост, где руки, а где ноги. MAYA видит ваш скелет как
сборище костей с именами j o i n t 1 , joint2..., как-то соединенных между собой. Поэтому самым
главным условием успешного создания системы управления Full Body IK является корректное
поименование частей тела вашего скелета. После того, как разные кости будут иметь строго
определенные имена, MAYA сможет создать нужные манипуляторы для рук, ног, головы и других
частей тела. Любые неточности в названиях костей будут приводить к ошибкам и некорректной
работе системы Full Body IK.

Персонажная анимация 787


Итак, вы должны «подсказать» MAYA, где у вашего скелета находятся определенные части
тела. Это можно сделать двумя способами.

1. Можно просто назвать суставы определенным образом, дав им имена в соответствии с


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

2. Можно создать для суставов метки (labels), рассмотренные выше в разделе про перенос
анимации. Эти метки, создаваемые через меню Skeleton=>Joint Labelling=>Add FBIK Labels,
позволяют дать суставам «дополнительные» и строго фиксированные имена.

Далее, я буду говорить про «имена» или «названия» суставов, имея в виду, что это могут
быть как реальные имена, так и метки.

Все суставы (или кости) персонажа можно разделить на несколько типов.

Прежде всего это базовые суставы. Для успешного создания системы управления Full Body
IK необходимо дать названия некоторому базовому набору суставов (и, как следствие, создать
его). Если базовые суставы не будут иметь нужные названия, система Full Body IK просто не будет
создана.

Базовые суставы называются в MAYA так: Hips (pelvis or root, копчик или основание
позвоночника), Spine (позвонки), Head (top of neck, голова), UpLeg (бедра), Leg (knees, колени),
Foot (ankles, ступни), Arm (shoulders, плечи), ForeArm (elbows, локти), and Hand (wrists, запястья).
В скобках приведены «человеческие» названия для суставов.

Вращательные суставы не имеют анатомических аналогов и создаются для симуляции


продольных вращений некоторых костей, например между локтем и кистью. Сюда входят Arm-
Roll (между плечом и локтем), ForeArmRoll (между локтем и кистью), UpLegRoll (между бедром и
коленом), and LegRoll (между коленом и стопой).

Примечание. Как нетрудно заметить, в меню Joint Labelling не существует меток


с суффиксом Roll. Поэтому вращательные суставы должны иметь то же имя, что
и вышестоящий сустав, то есть сустав между локтем и кистью должен быть
помечен как Elbow.

Примечание. Проще всего уяснить безумные правила поименования, исследуя уже


готовые примеры. Не забывайте про Skeleton=>Full Body IK=>Get FBIK Example.

Вспомогательные суставы позволяют создать дополнительные манипуляторы для


управления более «мелкими» частями тела, такими как пальцы, шея, ключицы. Сюда же входят
вспомогательные косточки для управления работой кисти и стопы (InHand/lnFoot, FingerBase/Toe-
Base).

Следует заметить, что если вы назвали сустав каким-то «своим» образом (например,
«tail» или «хвост» или «joint4096»), этот сустав не будет управляться системой Full Body IK и,
как следствие, просто не будет вращаться при работе с манипуляторами. Тоже самое касается
«непоименованных» суставов, имеющих метки «None». Такие суставы система Full Body IK просто
игнорирует.

Правила, по которым именуются суставы, однозначно определены и достаточно подробно


описаны в документации. Эти правила формулируются отдельно для каждого метода именования
суставов: для непосредственных имен и для меток. Нет смысла перерисовывать всю эту таблицу в
книгу, поэтому я с неким облегчением просто отошлю вас в документацию:

788 Книга Сергея Цыпцына


Примечание. Пытливые умы наверняка попытаются найти смысл существования
двух способов поименования суставов (метки и имена) и выяснить разницу между
системами Full Body IK, созданными на основе того или другого метода. Разница
действительно есть.

Во-первых, не существует меток типа inHand и inFoot, обозначающих вспомогательные


кости в кисти или ступне (полный список отсутствующих меток можно посмотреть в документации
в вышеупомянутой таблице, там, где в столбце FBIK joint labels стоят прочерки), поэтому если вы
хотите, чтобы MAYA управляла такими костями с помощью Full Body IK, вам следует использовать
метод прямого переименования костей.

Во-вторых, при именовании позвонков с помощью меток вы можете давать им только


одинаковые названия, типа Spine, в то время как реальные имена суставов могут содержать цифры,
например Spinel Spine9. Поэтому во втором случае для MAYA несколько проще «разобраться» с
позвоночником в процессе создания системы Full Body IK.

Создание системы управления Full Body IK


После того, как вы дали базовым (и, может быть, даже вспомогательным) суставам имена
или метки в соответствии с документацией, вы можете выбрать ваш скелет за самую верхнюю
кость и выполнить операцию Skeleton=>Full Body IK=>Add Full Body IK.

Если вам не лень, откройте файл fbikLabelled.ma, выберите скелет за самый верхний
сустав ButtHead и откройте Option Box операции Add Full Body IK.

Убедитесь, что выбран метод идентификации суставов по меткам (Identify Joints=By Label)
и коль скоро скелет явно прямоходящий, то надо выбрать Posture=Biped.

Персонажная анимация 789


Если вы нажмете на кнопку Apply, то MAYA выразительно выругается на то, что не может
найти сустав, помеченный как «левое колено» (Left Knee), а коль скоро колено это один из
базовых суставов, то никакой системы Full Body IK не будет создано.

Выберите левое колено и пометьте его с помощью Skeleton=>Joint Labelling=>Add FBIK La­
bel как Knee и затем как Left.

Снова нажмите кнопку Apply.

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


Самые внимательные умы, наверняка заметили замечание, появившееся в Script Editor
после создания манипуляторов:

// Warning: Skeleton arms are not aligned with the x-axis. //

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

Перед навешиванием Full Body IK всегда проверяйте следующие условия:

1. Скелет должен быть хотя бы приблизительно стоять в Т-позе.


2. Лицо (нос) должно смотреть вдоль оси Z (в положительном направлении).
3. Ноги должны быть выпрямлены.
4. Руки также должны быть прямыми, ладони смотрят вниз, а большие пальцы (если таковые
имеются) направлены вдоль оси X.

В случае, если ваш персонаж еще не встал на две ноги и продолжает бегать на четырех
лапах, требования будут следующие:

1. Морда должна глядеть вдоль оси Z (в положительном направлении).


2. Лапы должны вытянуты вниз, причем пальцы (когти, копыта, ласты) также должны смотреть
вниз, как будто бедное животное подвесили в воздухе.
3. Особо длинная шея также должна быть вытянута в положительном направлении оси Z.
4. Хвост может болтаться как угодно. Для него не предусмотрено никакого управления.

Сохраните сцену для дальнейшего использования как fbikCreated.ma

Если отключить отображение суставов в камере, можно увидеть все созданные

790 Книга Сергея Цыпцына


манипуляторы. Эти манипуляторы называются иногда эффекторами, так как имеют тип ноды hik-
Effector.

Примечание. Hik расшифровывается как Human Inverse Kinematics.

Подергав за некоторые из них, например, за локоть, вы можете заметить, что работают они
похоже на обычные IK Handle, то есть могут даже отрываться от своего сустава, если перемещения
слишком велики. Однако сдвинув немного соседний манипулятор, вы увидите, что оторвавшийся
эффектор прилипает обратно к суставу.

Полный список эффекторов, вкупе с соответствующей схемой их расположения, можно


найти в документации.

Вы также можете заметить, что некоторые эффекторы ведут себя по разному. Мало того,
что они имеют разную форму (кубики, шарики), они еще и по-разному реагируют на перемещения
соседних частей тела. Некоторые остаются на месте, а некоторые послушно следуют за скелетом.
Об этом стоит поговорить подробнее.

Примечание. Вы можете подстраивать размер эффекторов просто меняя из


масштаб с помощью инструмента Scale (не обязательно одинаково по всем
направлениям). Также можно воспользоваться атрибутом Radius, который есть
у каждого эффектора.

Пиннинг, или прикалывание


Эффекторы, имеющие форму сферы, являются «свободными» или «неприбитыми» (un­
pinned). Они никак не закреплены и двигаются вслед за остальными частями тела.

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


столе, имеет смысл «прибить» или «приколоть» (pin) соответствующие эффекторы. Сделать это
можно, изменив значение атрибута Pinning для нужного эффектора.

Если вы хотите закрепить только позиции, оставив возможность для вращения в


закрепленном суставе, то установите Pinning=pinTranslate. Эффектор примет форму кубика и
перестанет перемещаться вслед за скелетом, проворачиваясь в месте закрепления.

Если же вы хотите запретить и «проворачивание», например, для ног на земле, то

Персонажная анимация 791


установите Pinning=pinAU.

Случай Pinning=pinRotate позволяет организовать параллельно-поступательное движение


всех суставов, лежащих ниже соответствующего эффектора. Поэкспериментируйте с плечом.

Примечание. Для удобства экспериментов отключите в Attribute Editor функцию


List=>Auto Load Selected Attributes. Затем меняйте значения для Pinning для одного
эффектора, неистово дергая за остальные.

Анимация с помощью эффекторов.


Внутреннее устройство Full Body IK
В принципе дальнейший процесс выглядит довольно радужно. Вы берете ваш
интеллектуальный скелет как марионетку, устанавливаете его в нужную позу, меняя, если надо
значения для Pinning, затем ставите ключ на весь скелет или только на его часть и двигаетесь
дальше. Причем самая шикарная новость заключается в том, что вы можете управлять скелетом как
с помощью эффекторов, так и просто сгибая нужные суставы, то есть у вас в руках одновременно
и прямая и инверсная кинематика.

На этом можно было бы и закончить. Однако одна деталь не даст пытливым умам спокойно
спать - почему для постановки ключей на FBIK-скелет нужна специальная операция, да еще и со
своими параметрами.

Действительно, для того, чтобы ставить ключи на персонаж с Full Body IK нельзя
использовать ни операцию Set Key, ни функцию Auto Key. Для этого существует специальная
операция Animate=>Set Full Body IK Key.
Прежде, чем говорить о ее параметрах, я бы хотел остановиться подробнее на внутреннем
устройстве системы Full Body IK.

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

Основной скелет (тот, который виден на экране) называется в майской терминологии input
skeleton. Я буду продолжать называть его основным, подчеркивая, что именно он используется

792 Книга Сергея Цыпцына


для конечной анимации персонажа и скининга.

Вы можете показать служебный FK Skeleton, выбрав любой эффектор и выполнив


Skeleton=>Full Body IK=> Show FBIK FK Skeleton. Он отображается темно-синим цветом.

Примечание. Чтобы лучше видеть разницу между основным и вспомогательным


FK-скелетом измените значение атрибута Radius для всех суставов последнего.

Когда вы ставите ключ (точнее, ключи) на ваш персонаж (или его часть, об этом позже) с
помощью операции Set Full Body IK Keys, то все ключи ставятся, во-первых, на эффекторы, а во-
вторых, на суставы вспомогательного FK-скелета. На суставы основного скелета никаких ключей
на ставится!

Еще раз повторюсь: на основном скелете никаких ключей не появляется, все ключи
создаются для набора эффекторов и вспомогательного FK-скелета.

Отсюда следует, что анимация основного скелета является как бы усреднением


(«сблендиванием») инверсной кинематики (анимация эффекторов) и прямой кинематики (движение
FK-скелета). Ситуация полностью аналогичная смешиванию прямой и инверсной кинематики (FKIK
Blending), описанному выше.

Давайте разберемся сначала, кто отвечает за смешивание прямой и инверсной кинематики


и как этим можно управлять.

Загрузите заново сцену fbikCreated.ma

Выберите центральный эффектор в районе седалища и включите отображение


вспомогательного FK-скелета: Skeleton=>Full Body IK=> Show FBIK FK Skeleton

Если вы уже в первом кадре, откройте Option Box операции Animate=>Set Full Body IK Keys
и установите параметры по умолчанию

Персонажная анимация 793


Нажмите Apply, поставив тем самым ключи на все эффекторы и суставы вспомогательного
FK-скелета.

Встаньте в десятый кадр и посадите персонаж на корточки, опустив центральный эффектор.


Снова нажмите Apply.

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

Таким образом, когда вы интерактивно управляете своим персонажем, дергая за


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

Однако когда проигрывается анимация, то в промежуточных (неключевых) кадрах


кинематические решения для основного скелета (инверсная кинематика) и FK-скелета (прямая
кинематика) могут совершенно обоснованно не совпадать.
Примечание. Представьте себе руку из двух костей и обычный IK Handle на ней.
Если вы согнете руку с помощью IK Handle, например, за десять кадров (поставив
два ключа на IK Handle), а затем запомните значения углов для суставов в первом и
десятом кадре и сделаете анимацию такой же руки с помощью прямой кинематики,
то увидите, что хотя положения костей совпадают в первом и десятом кадре,
промежуточное движение совершенно разное.

794 Книга Сергея Цыпцына


Поэтому когда вы ставите ключи на персонаж, в некотором кадре вы должны определиться,
будет ли ваш скелет следовать за решением инверсной кинематики (грубо говоря, за эффекторами)
или он будет двигаться за прямой кинематикой (за FK-скелетом). У вас есть возможность сделать
этот выбор в Option Box операции Set Full Body IK Keys.

Параметр Reach keying mode отвечает за «тип» устанавливаемых ключей в данном кадре.
Если выбран тип IK Key, то кости, управляемые выбранным эффектором, будут двигаться после
этого ключа вслед за решением инверсной кинематики, а если выбран тип FK Key, то эти кости
будут следовать за FK-скелетом.

Грубое правило постановки и выбора типа ключей такое: после задания позы и перед
установкой ключа следует выбрать те эффекторы, чьи суставы должны оставаться на месте и
после этого поставить ключ типа IK Key. Это гарантирует, что между соседними ключами нужные
суставы не будут проскальзывать или дрожать. (Заметьте, я пока ничего не говорю про параметр
Keying Mode, полагая, что он установлен в Аll.)

Технически вся эта чехарда с типами ключей устроена следующим образом. У каждого
эффектора есть два атрибута: Reach Translation и Reach Rotation, на которые документация (и
я в дальнейшем) часто ссылается как на один атрибут Reach. Так вот, когда этот (эти) атрибут
равен единице, то кости (суставы), управляемые этим эффектором, строго следуют за инверсной
кинематикой, определяемой положением этого эффектора (это практический полный аналог
атрибута ikBlend для обычных IK Handle). Если атрибут Reach равен нулю, то кости, управляемые
им, начинают следовать правилам прямой кинематики, игнорируя положение эффектора и
двигаясь вслед за FK-скелетом.

По умолчанию, у вновь созданного Full Body IK персонажа атрибуты Reach равны единице
для рук (HandEff), ног (FootEff) и бедер (HipEff), (для handEff атрибут Reach Rotate равен нулю),
так как эти части тела обычно управляются с помощью эффекторов, то есть с помощью инверсной
кинематики. Для остальных эффекторов атрибут Reach равен нулю, так как, например, голову или
шею проще анимировать прямой кинематикой.

Еще раз уточню, что атрибут Reach определяет, как будут двигаться кости (соответствующие
эффектору) между ключевыми кадрами. Если, например Reach будет равен 0.5, то между
ключевыми кадрами кости основного скелета будут где-то посередине между решением инверсной
кинематики и FK-скелетом.

Примечание. Вас может немного смутить, что во время анимации эффекторы


«уезжают» от своих суставов. Да, меня это тоже смущает. Однако если вы
остановите анимацию и легонько дернете за любой эффектор, то скелеты
и эффекторы мгновенно синхронизируются. Просто не обращайте на это
внимания.

Так вот, когда вы выбираете эффектор(ы) и ставите на него ключ типа IK Key, то для него
(них) атрибут Reach устанавливается в единицу и на него (них) ставится ключ - с тангенсом типа
Stepped Next. Это происходит только для выбранных эффекторов - и не верьте документации,
утверждающей, что «all other effectors' Reach values are set to 0»! Атрибуты Reach для остальных
невыбранных эффекторов остаются нетронутыми.

Если же вы ставите на выбранные эффекторы ключ типа FK Key, то для них атрибут
Reach устанавливается в ноль и на него ставится ключ {с тангенсом типа Stepped). Это опять же
происходит только для выбранных эффекторов.

Примечание. Тангенс типа Stepped Next определяет, что если в данном кадре

Персонажная анимация 795


атрибут Reach равен нулю, то в следующем кадре (и даже между кадрами) значение
этого атрибута будет определяться следующим ключевым кадром. Тангенс типа
Stepped, наоборот, определяет, что значение атрибута будет неизменным вплоть
до следующего ключевого кадра. Таким образом, если вы поставили сначала IK Key,
а потом FK Key, то значение атрибута Reach «соскочит» в ноль, как только вы
уйдете из первого ключевого кадра. Это избавляет вас от необходимости ставить
ключи на все эффекторы в тех кадрах, где вы работаете только с конкретными
частями тела. Если вы поставите третий ключ снова типа IK Key, то между
вторым и третьим ключевыми кадрами атрибут Reach будет также равен нулю,
так во втором ключевом кадре тип тангенса равен Stepped, в первом и третьем
- Stepped Next.

Таким образом, если за ключом типа IK Key следует ключ типа FK Key, то кости выбранного
эффектора начинают работать в режиме прямой кинематики сразу же после первого IК-ключа.
Если за ключом типа FK Key следует ключ типа IK Key, то кости выбранного эффектора продолжают
работать в режиме прямой кинематики вплоть до достижения этого IK-ключа. Это удобно, так
как позволяет фиксировать и отрывать конечности в нужный момент времени, не заботясь о
дополнительных ключах в соседних кадрах.

Параметр Keying Mode=All определяет, что в дополнение к ключам на атрибут Reach для
выбранных эффекторов, ставятся ключи на перемещения и вращения всех эффекторов и на
перемещения, вращения и масштаб всех суставов FK-скелета. Существует возможность также
ставить эти ключи только на определенные части тела (Keying Mode=Body Part), относящиеся к
выбранным эффекторам. То есть для выбранного эффектора ключи ставятся только на некоторый
набор эффекторов и костей FK-скелета, относящихся к текущей части тела.

Соответствие между частями тела и входящими в них эффекторами и костями определяется


следующим образом.

Части тела FK-скелет Эффекторы


Hips Hips HipsEff
Spine Spine SpineEff
Spine1-Spine9 NeckEff
Head Neck HeadEff
Neck1-Neck9
Head
Anns Shoulder (clavicle) AnnEff
Arm (shoulder) ForeAmiEfT
UpArmRoll (upper arm roll) HandEff
Fore Aim (elbow) FingerBaseEff
ForeArmRoll (lower arm roll)
Hand (wrist)
FingerBase
Legs UpLeg (hips) UpLegEff
UpLegRoll (upper leg roll) LegEff
Leg (knee) FootEff
LegRoll (lower leg roll) ToeBaseEff
Foot (ankle)
ToeBase (ball of foot)

796 Книга Сергея Цыпцына


Если Keying Mode=Selected, то, соответственно, ключи на трансформации ставятся только
на выбранный эффектор.

Еще раз повторюсь, что параметр Keying Mode определяет, на какие эффекторы будут
ставиться ключи на перемещение и вращение (и масштаб для FK-скелета). Он не никак не влияет
на постановку ключей на атрибут Reach, производимую только для выбранных эффекторов в
соответствии со значением Reach Keying Mode.

Откройте заново файл fbikCreated.ma.

Выберите оба эффектора для ног и поставьте ключ типа IK Key (при этом Keing Mode=AU).
Перейдите в двадцатый кадр и снова поставьте такой же ключ (пользуясь Option Box операции Set
Full Body IK Keys).

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

Персонаж должен приседать, а его ноги должны оставаться на земле.

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

Примечание. Сменить тип устанавливаемого ключа можно разными способами.


Прежде всего это Option Box операции Set Full Body IK Keys. Также существует
горячие клавиши Alt-1, Alt-2, Alt-3, переключающие режим Reach Keying Mode. Ho
удобнее всего пользоваться Marking Menu, выпадающим по нажатию правой кнопки
мыши при выбранном эффекторе.

В этом случае вы увидите, что ноги персонажа проваливаются под землю между двадцатым
и тридцатым кадром. Последите за изменением атрибутов Reach для эффекторов ног, перемещаясь
от кадра к кадру. После двадцатого кадра Reach становится равным нулю и это означает, что
суставы, управляемые эффекторами ног двигаются по законам прямой кинематики, то есть вслед
за FK-скелетом (который вы всегда можете включить для отображения на экране).

Персонажная анимация 797


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

Совет. Если вы хотите подредактировать движение между ключевыми кадрами,


вы можете использовать Keying Mode=Body Part и Reach Keying Mode=Simple. Это
зафиксирует позиции и вращения эффекторов и суставов, но никак не повлияет на
атрибут Reach.

Примечание. Забегая немного вперед, могу добавить, что при создания системы
Full Body IK дополнительно создается персонаж (character) и некоторое количество
«подперсонажей» (subcharacters) для каждой части тела. Эти объекты нелинейной
анимации создаются для хранения и манипулирования ключами, поставленными на
эффекторы и суставы. Вы можете заметить, что при выборе любого эффектора
на таймлайне появляется соответствующий ему subcharacter.

Это происходит вследствие того, что в меню Skeleton=>Full Body IK по умолчанию включена
опция Body Part Autoload.

798 Книга Сергея Цыпцына


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

Примечание. Имейте в виду один неприятный глюк. После того как вы загрузите
или создадите скелет с Full Body IK, при выделении любого объекта отключается
активный Character Set. Это от того, что происходит автоматическое
переключение Character Set для нового Full Body IK, но при этом нарушается выбор
обычных сетов. Для того, чтобы можно было работать с обычными сетами,
нужно отключить меню "Body Part Autoload".

Проблемы синхронизации. Немного о грустном


Как уже упоминалось выше, при анимации с помощью Full Body IK ключи в каждом кадре
ставятся как на эффекторах, так и на соответствующих им суставах FK-скелета. Пока вы ставите
ключи, трудно что-нибудь испортить, однако как только вы соберетесь редактировать или удалять
ключи с вашего персонажа, вас поджидает некоторое количество ловушек и опасностей.

Во-первых, если вы выберете какой-нибудь эффектор и по привычке откроете старый добрый


Graph Editor, то увидите там анимационные кривые и ключи только для выбранного эффектора. Вы
не увидите там ключей для соответствующих этому эффектору костей FK-скелета.

Справедливо и обратное: выбрав, например, колено на FK-скелете (который надо


предварительно показать на экране), вы не увидите в Graph Editor ключей для эффектора,
управляющего ногой.

Очевидно, что удалив или сдвинув эти ключи вы успешно рассинхронизируете инверсную и
прямую кинематику (рассинхронизируете в ключевых кадрах, в промежуточных кадрах кинематики
и так рассинхронизированы). Эффекторы будут двигаться по-своему, а FK-скелет - по-своему.
Поэтому постарайтесь держаться подальше от Graph Editor. Если вам уж очень невтерпеж, можете
открыть его, посмотреть на кривые, вздохнуть и закрыть его - от греха подальше. Самые смелые
могут поменять тип тангенсов, не трогая позиции ключей.

Персонажная анимация 799


Удаляйте и редактируйте ключи с помощью TimeLine. По нажатию правой кнопки мыши там
появляется новое меню, для удаления ключей с персонажей, содержащих Full Body IK.

С помощью этого меню выбранные на TimeLine ключи удаляются как с эффекторов, так и
с суставов FK-скелета, обеспечивая необходимую синхронизацию.

Во-вторых, вы должны помнить, что если включена опция Body Part Autoload, то на Time-
Line отображаются ключи не только для выбранного эффектора, но и для всех эффекторов и
суставов, входящих в соответствующую часть тела. Это может иногда служить причиной путаницы
и появления «лишних» ключей.

В-третьих, если опция Body Part Autoload выключена и вы ставите ключи на выбранные
эффекторы с помощью Keying Mode=Selected (или с помощью правой кнопки мыши и меню Key
Selected), на TimeLine появляются ключи только для выбранного эффектора. Следовательно, если
вы начнете их редактировать на TimeLine, то быстро нарушите вышеупомянутую синхронизацию.
Помните об этом и следите за тем, какие ключи отображаются на TimeLine в каждый момент
времени.

Двойной пивот. Secondary Controller


При анимации некоторых частей тела иногда возникает задача иметь для одного
управляющего объекта два центра вращения. Типичный пример - анимация стопы, когда при
ходьбе стопа вращается то вокруг пятки, то вокруг пальцев. Раньше эта задача решалась с помощью
разных трюков: дополнительных группировок, констрейнов и пр. В системе управления Full Body
IK эта возможность предусмотрена изначально. Вы можете добавить к любому эффектору, скажем
так, дополнительный пивот, за который можно двигать и вращать выбранный эффектор.

Возьмем надоевший персонаж из файла fbikCreated.ma.

Выберите эффектор для левой ступни (LeftFootEff) и не забудьте выполнить Skeleton=>Full


Body IK=>Go to Stance Pose.

Затем выполните Skeleton=>Full Body IK=>Add Secondary Controller.


Появившийся эффектор оттащите назад и вниз на место пятки, уменьшите, если надо, а
затем выполните Skeleton=>Full Body IK=>Activate Secondary Effector.

800 Книга Сергея Цыпцына


Попробуйте повращать ступню за новый контроллер. Если вы хотите поправить положение
дополнительного эффектора относительно ступни, выполните Change Secondary Effector Placement
и передвиньте его в нужное место. Не забудьте снова выполнить Activate Secondary Effector, чтобы
выйти из режима редактирования положения эффектора (это напоминает режим редактирования
пивота).

Снова выберите эффектор для левой ступни (LeftFootEff) и выполните Add Secondary Con­
troller.

Новый эффектор оттащите вперед и вниз на место сгиба пальцев, уменьшите его, если
надо, а затем выполните Skeleton=>Full Body IK=>Activate Secondary Effector.

Теперь вы можете вращать ступню сразу за три пивота. При анимации не забудьте выбирать
нужный эффектор и ставить на него ключи типа IK Key, чтобы избегать проскальзывания в точке
вращения (дополнительные эффекторы также имеют атрибуты Reach и на них распространяются
принципы выбора Reach Keying Mode).

Жесткий контакт с землей


В системе Full Body IK предусмотрена возможность отслеживания контакта рук и ног
персонажа с землей (или с полом, если угодно). По умолчанию плоскость земли располагается
на уровне Y=0 и визуально совпадает с горизонтальной сеткой на экране. Также по умолчанию
персонаж не реагирует на контакт с землей, пока вы не включите необходимые атрибуты.

Все эти атрибуты располагаются на центральном эффекторе, а точнее на ноде hikFloorCon-


tactMarker, появляющейся в Channel Box и Attribute Editor при выборе центрального эффектора.

Удобнее работать с атрибутами для контакта в Attribute Editor, так как там они появляются
уже сгруппированными по разделам для работы с отдельными видами контактов с землей: для
рук, для ног, для пальцев.

Персонажная анимация 801


«Освободите» персонажу ноги, выключив для эффекторов ног закрепление в пространстве:
Pinning=unpinned

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


что никакого контакта с землей не происходит.

Перейдите в закладку hikFloorContactMarker в Attribute Editor и включите в разделе Feet to


Floor Contact Attributes атрибут Feet Contact (контакт для ног).

Снова перемещайте персонаж вверх и вниз, убедитесь, что ноги успешно упираются в
землю.

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


Для тех конечностей, у которых Pinning=pinAll, эффекторы просто будут останавливаться на уровне
земли, если вы попытаетесь вручную опустить их ниже соответствующей плоскости.

Если вам нужна дополнительная индивидуальная плоскость контакта для любого эффектора,
вы можете создать ее, просто выбрав нужный эффектор, и выполнить операцию Skeleton=>Full
Body IK=>Add Contact Plane.

802 Книга Сергея Цыпцына


Таким образом, вы можете, например, отслеживать контакт рук со столом или ног с
пересеченной местностью. Такую плоскость, к сожалению, нельзя вращать, а можно лишь
перемещать (и анимировать) по вертикали.

Коль скоро наш персонаж не имеет пальцев, вы можете загрузить готовый


пример, воспользовавшись операцией Get FBIK Example... Выбрав центральный эффектор,
поэкспериментируйте с различными атрибутами для контакта рук и пальцев с землей.

Некоторые комментарии к системе Full Body IK


Некоторые начитанные умы, осведомленные о невыносимой крутости пакетов Motion Builder
и FILMBOX, наверняка заподозрят, что вышеизложенные сведения не покрывают все возможности
системы Full Body IK, унаследованной от компании Kaydara. И будут правы. Действительно,
чтобы описать все многочисленные настройки этой системы придется перевести немало страниц
документации и превратить эту главу в перечисление атрибутов и соответствующих им свойств.
Сознательно избегая этого, я лишь укажу путь для дальнейших исследований этой мощной
системы.

Если вы выберете любой эффектор, то увидите в Attribute Editor дополнительную закладку


hikHandle. Надо сказать, что название ноды не сильно удачное, так как в отличие от IK Handle нода
hikHandle соответствует не выбранному эффектору, а всей системе Full Body IK, управляющей
персонажем. То есть выбирая любой эффектор, вы будете видеть в Attribute Editor одну и ту
же закладку hikHandle, соответствующую одной ноде (атрибуты самого эффектора находятся,
очевидно, в закладке hikEffector).

Таким образом, нода hikHandle отвечает за настройку поведения всей системы Full
Body IK для выбранного персонажа. Далее вам остается вооружиться описанием этой ноды из
документации, терпением и, если надо, словарем и разобраться с атрибутами данной ноды. Скажу
лишь, что если некоторые атрибуты заблокированы, то в разделе Pull надо включить опцию Expert
Mode для совсем уж взрослых мальчиков, чтобы получить доступ ко всем секретным атрибутам.

Персонажная анимация 803


А теперь немного комментариев для тех, на кого знакомство с системой Full Body IK
произвело, возможно, слишком сильное впечатление. Иными словами, чуть-чуть о недостатках
этого мощного инструмента.

Во-первых, «закоренелые» пользователи MAYA будут, без сомнения, удручены


вышеупомянутыми ограничениями на редактирования анимационных кривых в Graph Editor. A
также невозможностью использовать старую добрую операцию Set Key и режим AutoKey. С точки
зрения совместимости на уровне пользователей, новая технология несколько ограниченна.
Следует заметить также, режим AutoKey помогает автоматически синхронизировать эффекторы
Full Body IK, когда идет подстройка одного из них в Graph Editor. Таким образом те, кто любят
контролировать анимационные кривые, будут сильно разочарованы. Например, из-за того, что
скрыт FK-скелет, и все общение происходит через управляющие эффекторы, и, очевидно, данная
концепция не подразумевает работу традиционным способом.

Во-вторых, вся система достаточно сложна и громоздка для аниматоров. Всегда существует
большая вероятность того, что стоит что-нибудь забыть переключить или недоглядеть, и FBIK
поведет себя непредсказуемым образом. Например, можно сильно потянуть одну конечность так,
что фиксация остальных с поверхностью земли будет неполной, и если после этого поставить
ключи, то при прохождении через этот кадр, будет "дребезг" в позиции ступней.

В-третьих, в седьмой версии отсутствует удобный интерфейс по выбору и редактированию


свойств эффекторов, как это сделано в Motion Builder или в скрипте Миши Бажуткина (http://www.
geocities.com/bazhutkin/selector1.html)

804 Книга Сергея Цыпцына


Я надеюсь, что скоро такой интерфейс появится в стандартной поставке MAYA, а пока могу
порекомендовать к использованию следующий скрипт господина Takayuki Kondo (http://www.
mars.dti.ne.jp/-takayuki/yuki.files/mel/FBIK_CharacterControl.zip)

В-четвертых, в системе не реализована "мягкая IK". При достижении экстремальных поз,


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

Пытливые умы, конечно, обнаружили, что при создании системы Full Body IK в сцене
появляются новые сущности (не путать с существами). Их можно обнаружить в Outliner или
Channel Box в виде объекта fbikCharacter и множества подобъектов, чьи названия начинаются
с подчеркивания, типа _Legs. Все это так называемые Characters, относящиеся к понятиям и
технологиям нелинейной анимации. К этим понятиям мы сейчас и перейдем. Те кому не терпится
перейти к дерматологической тематике и заняться скинингом, могут проскочить эту тему и перейти
к «шкурному» вопросу.

Нелинейная анимация: Non-linear Animation


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

Персонажная анимация 805


только удобные инструменты, но и забавные термины.

Дело в том, что основной инструмент нелинейной анимации в MAYA называется Trax Edi­
tor (сокращение от Tracks). Благодаря гибкости русского языка и неоднозначности трактовки
большинства словоформ, использующих корень «трах», название этого инструмента приобрело на
традиционном майском жаргоне дополнительное очарование.

Что же лежит в основе понятия «нелинейная анимация»? Начнем разбираться от простого


к сложному.

Представьте, что у вас есть персонаж, состоящий из некоторого количества объектов,


например, из четырех IK Handle для рук и ног, и еще шести управляющих локаторов для головы,
спины и других частей тела. Если вы поставили персонажа в некоторую позу и собираетесь ее
зафиксировать, то перед тем как поставить ключ, вы должны выбрать все десять управляющих
объектов (или часть из них), проверить, какие атрибуты будут анимироваться и выполнить
операцию Set Key. Перейдя к следующей позе, вы опять должны не забыть выбрать нужные
объекты и поставить ключ на нужные атрибуты. Представьте, что для одного объекта вам надо
анимировать атрибуты translate, а для другого offset. Оцените количество движений мышью для
совместной анимации десяти управляющих объектов.

Рано или поздно вам (или кому-то еще) захочется объединить все необходимые атрибуты
для анимации конкретного персонажа в некоторый набор атрибутов, и далее иметь дело только
с этим набором, с облегчением забыв о том, каким объектам эти атрибуты принадлежат. Таким
образом, мы выходим на понятие обобщенного «Персонажа», представляющего из себя набор
атрибутов от различных объектов. Таким образом, мы поднимаемся с уровня «объекты-атрибуты»,
на следующий уровень абстракции, используя вполне человеческое и нетехническое понятие
«Персонаж», как набор атрибутов, собранных вместе и необходимых для управления и анимации
любой системой объектов. Такой «Персонаж» - уже не объект, а некое абстрактное понятие,
имеющее, впрочем, вполне конкретную реализацию в MAYA.

Обобщенный «Персонаж». Character Set


Проделайте небольшое упражнение.

Откройте файл grassNLA.ma (эту модель предоставил Стаc Глазов).


В нем находится что-то вроде травинки с анимированным скелетом, управляемым, в свою
очередь, с помощью IK Splane Handle, который содержит кривую, деформируемую кластерами.
Финальная анимация определяется движением шести кластеров, за выбором которых приходится
все время следить во время постановки анимации.

Выберите все шесть кластеров, а затем в Channel Box выберите все атрибуты translate.
Откройте Option Box операции Character=>Create Character Set.
Назовите персонажа Grass и установите lnclude=From Channel Box.

Нажмите кнопку Create Character Set и поглядите в Outliner. Там появится новая сущность

806 Книга Сергея Цыпцына


под названием Grass, которую можно выбрать и увидеть, что в Channel Box появятся все атрибуты
translate для всех кластеров.

Эта сущность и есть обобщенный «Персонаж», о котором говорилось выше. Теперь вы


можете анимировать травинку как единое целое, не заботясь о том, каким объектам принадлежат
атрибуты из Channel Box.

Примечание. Участник сцены с именем Grass не является геометрическим объектом!


Это просто набор атрибутов. Взрослые мальчики быстро увидят, что тип ноды
для Grass это character. Замечу, что character - специальный вид объектов типа
objectSet, которые могут включать в себя списки объектов, их компонент или
атрибутов.

Примечание. Предвижу, что перевод понятия Character как «персонаж» будет


постоянно путаться с обычным словом «персонаж», применяемым к трехмерным
персонажам, состоящим из поверхностей, костей и пр. Поэтому я, как обычно,
постараюсь не переводить понятие character, подчеркивая его абстрактную
сущность. Я надеюсь, что слова «выберите только что созданный character» уже
никого не будут шокировать, и во всяком случае никто не подумает, будто дано
указание выбрать реальный скелет персонажа в сцене. Впрочем, когда речь пойдет
о работе с клипами, я буду позволять себе употреблять русский перевод в нужном
контексте.

Таким образом, вы имеете набор атрибутов для анимации под названием Grass. Этот набор
можно дополнять или изменять с помощью операций Add to Character/Remove From Character. Для
этого достаточно выбрать нужные атрибуты в Channel Box.

Например, вы хотите анимировать также скручивание травинки.


Выберите ikHandel1, а затем отметьте в Channel Box атрибут twist.
Выполните операцию Character=> Add to Character. Среди атрибутов из набора Grass
появится также ikHandle1.twist.

«Но позвольте!» - воскликнут пытливые умы. «Ведь у операции Add to Character Set
отсутствует Option Box. Откуда тогда MAYA узнала о том, в какой набор character надо добавить
новый атрибут? Ведь таких наборов в сцене может быть много.»

Ответ следующий: MAYA добавила атрибут в текущий character. Если посмотреть в правую
часть Timeline, можно заметить небольшой элемент интерфейса для выбора текущего character в
сцене.

Персонажная анимация 807


За что же отвечает текущий character? Самое главное его предназначение состоит в том,
что каждый раз, когда вы нажимаете клавишу «s» или соответственно выполняете операцию Set
Key (с параметрами по умолчанию), то ключи ставятся на все атрибуты текущего character.

Примечание. Если текущий character не выбран (None), ключи ставятся, как обычно,
на выбранный объект.

Таким образом, вам не надо даже заботиться о выборе объектов и следует только помнить,
какой character является текущим. Это устрашающе экономит время аниматора.

Подперсонажи - SubCharacters
В травинкой все более-менее просто, однако у некоторых персонажей бывают руки и даже,
что удивительно, ноги. И часто бывает нужно поставить ключи только на атрибуты объектов,
управляющих ногами или руками, и не хочется ставить ключи на все атрибуты, входящие в char­
acter.

В этом случае следует заранее продумать структуру персонажа и определить, какие


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

Все атрибуты, входящие в character, можно разбить на подгруппы, образующие


иерархическую структуру.

Например, выберите в Outliner недавно созданный character Grass.


В Channel Box выделите три атрибута cluster6Handle.tx, cluster6Handle.ty, cluster6Handle.
tz. Убедитесь, глядя на Timeline, что выбран character Grass.

Откройте Option Box операции Create Subcharacter Set и установите Subcharacter Set
Attributes=From Channel Box.

Назовите «подперсонаж» как Top и нажмите кнопку Create Subcharacter Set.

Теперь исследуйте структуру character Grass в Outliner и на Timeline.

808 Книга Сергея Цыпцына


Как видите, три выбранных атрибута переместились в subcharacter Top.

Теперь вы можете добавлять новые атрибуты либо в основной character Grass, либо в
subcharacter Top, в зависимости от того, какой из них является текущим.

Деление на «подперсонажи» очень похоже на иерархическое разбиение на группы.


Каждый атрибут может входить только в одну подгруппу (подперсонаж) и не может принадлежать
одновременно двум подперсонажам.

Если текущим является «верхний» или «основной» персонаж (character), то при выполнении
операции Set Key ключи ставятся на все атрибуты этого персонажа и все атрибуты всех его
подперсонажей (subcharacters). Если текущим является какой-нибудь подперсонаж (subcharacter),
то ключи ставятся на все его атрибуты и атрибуты входящих в него «подподперсонажей» (subchar­
acters).

Примечание. Вы можете редактировать структуру character и subcharacter


пользуясь редактором Relationship Editor в режиме Character Editing. В него вы
можете попасть через пункт меню Character=>Set Current Character Set=>Character
Sets... или из меню на Timeline.

Позы и клипы
Продолжим философские рассуждения. Коль скоро весьма удобно рассматривать
обобщенный «Персонаж» как список атрибутов, то вполне «по-человечески» будет назвать «Позой»
зафиксированный набор значений этих атрибутов. В самом деле, одной позе соответствует вполне
конкретный набор значений атрибутов, а другой позе - другой набор значений.

Теперь мысленно возьмем две позы и представим движение персонажа из одной позы в
другую. Адекватно будет назвать такое движение (кусок анимации) как «Клип». Таким образом,

Персонажная анимация 809


всю анимацию можно представить себе как набор «Клипов», то есть движений от одной позы
к другой. Представьте теперь, что такие «Клипы» можно разрезать (создавая новые «Позы») и
склеивать, комбинируя анимацию наподобие монтажа в программе Adobe Premiere (или более
приходящейся вам по вкусу). Отсюда и произошло название «нелинейная» анимация - по аналогии
с нелинейным монтажем.

Пытливые умы, склонные к абстрактному мышлению, могут поразмышлять также над


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

Таким образом, мы как бы «отдираем» клипы и позы от самих персонажей и храним их


отдельно, как самостоятельные объекты, при необходимости «наваливая» ихто на один, то на другой
персонаж. Это позволяет создавать библиотеки клипов (или библиотеки движений) и использовать
их многократно. Уровень абстракции при таком подходе поднимается невыносимо высоко и мы
оперирует такими понятиям, как «некоторый персонаж выполняет некоторую последовательность
клипов». При этом клипы и персонаж являются независимыми друг от друга объектами. Если вас
подавляет такой уровень абстракции, представляйте себе клипы как набор анимационных кривых,
не привязанных к конкретному объекту. Такие кривые можно хранить отдельно и накладывать на
объекты по мере необходимости, по аналогии с назначением материалов на поверхности.

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

Все эти блага цивилизации и называются нелинейной анимацией.

Примечание. Возникает вполне резонный вопрос: когда использовать прелести


нелинейной анимации, а когда работать «по старинке»? Вы уже, наверное,
понимаете, что использование данной технологии требует некоторого
времени на подготовку: создание персонажа, определение клипов и поз и т.д.
Поэтому применение этого подхода имеет смысл, когда анимация, во-первых,
сложная, во-вторых, ее много, в третьих, когда она может быть использована
несколько раз (например, зациклена), в-четвертых, когда требуется глобальное
редактирование анимации (растяжение, изменение темпа, смешивание и т.д.).
Нелинейную анимацию можно также определить как «многоразовую анимациию».
Здесь же следует отметить, что описание нелинейной анимации находится в
главе про персонажку по чистой случайности. Эта технология никак не привязана
к костям, скелетам, кинематике и прочим ужасам. Клипы и персонажи могут
быть определены для абсолютно произвольного набора объектов, а ваш персонаж
может быть облаком или книжкой.

Работа с Trax Editor


Посмотрим теперь, как все это реализовано в MAYA. Надо сказать, что для освоения
идеологии нелинейной анимации требуется изрядное терпение, так как при этом необходимо
изучить довольно непростой инструмент под названием Trax Editor.

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

810 Книга Сергея Цыпцына


Создание и редактирование клипов
Откройте файл duckNLA.ma. (Данную сцену предоставил Стаc Глазов, а я ее изрядно
испортил.)

В сцене уже есть character под названием duck. И даже присутствует некоторая анимация,
сделанная с помощью постановки ключей на все атрибуты персонажа. Утка совершает один цикл
плавательных движений.

Откройте Window=>Animation Editors=>Trax Editor. Дальше придется работать в основном с ним.

Совет. Настройте три панели, в одной из которых будет Outliner, в другой -


камера, а в третьей Trax Editor. Справа удобно поставить Attribute Editor.

Чтобы увидеть клипы, соответствующие некоторому персонажу, надо загрузить этот


персонаж в Trax Editor.

Выберите character duck в Outliner и выполните в меню Trax Editor операцию List=> Load
Selected Character. Появится синяя полоска duck, под которой пока нет ни одного клипа.

Примечание. Можно включить в меню Trax Editor опцию List=>Auto Load Selected
Character.

Итак, коль скоро персонаж уже имеет некоторую анимацию, создадим из этой анимации
клип. Выполните в меню Trax Editor операцию Create=>Clip с параметрами по умолчанию.

Примечание. В Trax Editor действуют те же сочетания клавиши Alt и кнопок мыши


для навигации, что и в панели камеры.

Любители монтажных программ, наверное, сразу набросятся на клип и начнут неистово


стучать по нему мышкой, следуя своим старым привычкам.

Действительно, клип можно перемещать по TimeLine вправо-влево, при этом смещается


вся анимация.

Клип можно растягивать-сжимать за правый (левый) нижний угол. При этом вся анимация

Персонажная анимация 811


растягивается (замедляется) или сжимается (ускоряется).

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

Примечание. Если два раза щелкнуть по цифрам в углах клипа, то можно вбивать
значения вручную прямо «на клипе».

Пытливые умы, пропитанные идеологией MAYA наверняка заподозрят, что в результате этих
операций меняются атрибуты некоторого объекта и будут, безусловно, правы. Клип это объект
сцены со своими атрибутами, что прекрасно видно в Attribute Editor.

Вышеупомянутые манипуляции с клипом изменяют атрибуты Start Frame, Scale, Source


Start/End. А вот как визуально добраться до Cycle и Hold?

Для этого надо нажать Shift и вновь потаскать клип за углы. Форма курсора поможет
сообразить, за что отвечают разные углы.

Задайте в Attribute Editor значение Post Cycle=2. Это вызовет повторение клипа еще два раза.
Никто не мешает вам после этого, менять Scale для клипа, циклы будут также масштабироваться.
Атрибут Hold отвечает за удержание последнего кадра клипа в виде «стоп-кадра» в течение нужного
количества времени. Если после клипа нет других клипов, это, очевидно, не имеет смысла.

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

Сохраните сцену как duckNLAclip1.ma

Изнанка клипов
Любители экстремального монтажа знают, что есть два вида видео-материала: исходный
материал (полученный захватом с камеры и лежащий на диске в определенном месте) и рабочий
материал, представленный на временной линейке монтажной программы. Все манипуляции
(склейки, переходы, подрезки) производятся над рабочим материалом, а исходный материал, как
лежал одним куском (несколькими кусками) на диске, так и лежит, и никто его, как правило, не
трогает.

Точно также анимационный клип в MAYA состоит из двух частей. Первый часть - это
исходный клип (source clip), невидимый в Trax Editor, а вторая часть - регулярный(нормальный)
клип (regular clip), который как раз и лежит в рабочей области Trax Editor.

Когда вы выполняете операцию Create Clip, все анимационные кривые «отдираются» от


вашего персонажа (character) и копируются в исходный клип. Таким образом, исходный клип - это
просто набор анимационных кривых. Далее, создается копия исходного клипа в виде регулярного
клипа. Говоря по-майски, создается instance исходного клипа. Эта копия помещается, по
умолчанию, в Trax Editor, и ее (копию) вы можете тянуть, резать, удалять, зацикливать, при этом
исходный клип (и, следовательно, исходные анимационные кривые) остается нетронутым,: вы
издеваетесь только над копией.

812 Книга Сергея Цыпцына


Однако, если вы доберетесь до исходного клипа и отредактируете его анимационные
кривые, эти изменения сразу отразятся на регулярном клипе, ведь он является копией (а точнее,
«инстансированием») исходного клипа.

Примечание. Регулярные клипы иногда называются в документации плановыми


(scheduled) клипами.

Примечание. После создания клипа все ключи, по умолчанию, будут удалены с Time-
Line и «перейдут» в исходный клип. А персонаж готов к постановке новых ключей
и созданию новых клипов.

Один исходный клип может иметь много регулярных копий. Если вы копируете регулярный
клип с помощью операции Duplicate (из меню Trax Editor), то по умолчанию создается новый
регулярный клип, у которого тот же самый «исходник». Если вы удаляете регулярный клип из
Trax Editor, то с исходным клипом ничего не происходит, он остается жив-здоров. Вы всего лишь
удаляете его копию.

Итак, регулярные клипы вы видите и редактируете вТгах Editor. А где искать исходные клипы?
Для них определены специальные закладки в окне Visor, куда можно попасть непосредственно из
Trax Editor с помощью меню File=>Visor...
В закладке Character Clips находятся все исходные клипы, соответствующие существующим
персонажам. Есть еще закладка Unused Clips, куда попадают «бесхозные» клипы, например, при
импорте их из внешних файлов.

Если вы заглянете в Outliner и снимете цензурную галку Display=>DAG Objects Only, то


увидите, что в сцене присутствуют два клипа: исходный (clip1 Source) и регулярный (clipl).

Вы можете перетащить clip1Source средней кнопкой мыши из Visor или Outliner и бросить
его на свободное место в Trax Editor. После этого вы немедленно получите еще одну копию
исходного клипа в виде регулярного клипа в Trax Editor.

Удалите полученный таким образом клип из Trax Editor, при этом исходный клип останется
неизменным (правда, может изменить при этом свое имя).

Персонажная анимация 813


Таким образом, в основном вы будете работать с регулярными клипами в Trax Editor,
обращаясь в Visor только по мере необходимости.

Следует, однако, постоянно помнить, что у каждого регулярного клипа есть «исходник».
Например, при выполнении операций Edit=>Trim Before/After, просто происходит изменение
атрибутов Source Start/End для регулярного клипа. А вот операция Split, разделяющая один
регулярный клип на два клипа, порождает два новых регулярных клипа и, по умолчанию, оставляет
один исходный клип. (Не пытайтесь «засплитить» зацикленный клип, это невозможно. Установите
сначала Post Cycle=0.) Однако в Option Box операции Split вы можете выбрать опцию Delete Original
Source, после чего будут возникать два новых регулярных клипа и два новых исходных клипа.

Примечание. В Option Box операции Create=>Clip входит опция Put Clip in Visor Only/
Put Clip in Trax Editor and Visor. Она как раз и определяет, создавать ли только
исходный клип, помещаемый в Visor, или также создавать регулярный клип и
показывать его в Trax Editor.

Импортирование клипов

Вернемся, однако, к нашей монтажной утке. Если вы вконец уморили ее своими


экпериментами над клипом, то просто загрузите файл duckNLAclip1.ma. Если утка, тем не менее,
жива, просто установите для клипа Post Cycle=2, оставив остальные значение без изменений.
Примечание. Далее я буду говорить «клип», имея в виду «регулярный клип». И только когда дело
дойдет до исходного клипа, я буду употреблять слово «исходный».

Судя по тому, что клип самостоятельный объект сцены, его наверняка можно
экспортировать в виде отдельного файла и позже импортировать обратно, имея, таким образом,
библиотеку клипов, не привязанных к конкретной сцене. Вопрос о том, как «приклеить» клип,
созданный для слона, к персонажу типа «моська», я оставлю на попозже, я предположу, что вы
в состоянии поставить ключи на супер-утку и создать еще пару клипов. Более того, вы наверняка
способны выбрать эти клипы и экспортировать их на диск с помощью операции File=>Export Clip.
А вот о том, как эти клипы импортировать обратно, следует поговорить подробнее.

Выберите duck в Outliner или на TimeLine (это важно) и выполните File=>lmport Clip to
Character. Выберите в папке Clips файла run.ma и нажмите Import.

В Trax Editor появится новый клип с бегущей уткой. В зависимости от того, в каком кадре
вы находились, он появится либо после первого клипа, либо над ним. Оттащите его так, чтобы он
был слева от первого «плывущего» клипа.

«Поелозьте» по времени, чтобы убедиться, что клип «приехал» в сцену в целости и


сохранности.Теперь поместите новый клип справа от первого клипа и снова проверьте его
пригодность.

814 Книга Сергея Цыпцына


Очевидно, что движение утки теперь несколько другое и прямо скажем не совсем
корректное. Проблемы с лапами очевидны.

Очевидно также и то, что на работу данного клипа каким-то образом влияет, клип
находящийся перед ним. Вопрос в том, каким образом?

Абсолютные и относительные клипы и каналы


Если первый и второй клипы стоят не вплотную к друг другу, после окончания первого клипа
утка остается в некоторой позе, соответствующей последнему кадру первого клипа. Очевидно, что
второй клип может учитывать эту позу или игнорировать ее, просто «прогоняя» утку через свои
анимационные кривые. В последнем случае клип называется «абсолютным» (absolute). И в этом
случае никого влияния все предыдущие клипы и позы на такой клип не оказывают.

Однако часто бывает так, что очередное движение должно начинаться с учетом последней
позы персонажа. Например, вы сделали в начале координат клип, отвечающий за прыжок вперед,
а затем клип, отвечающий за прыжок на месте, и теперь, расположив клипы друг за другом, вы,
естественно ожидаете, что после первого прыжка, персонаж подпрыгнет на месте приземления,
однако в случае, если второй клип будет абсолютным, то второй прыжок будет происходит в
начале координат, где был создан клип, то есть персонаж, прыгнув вперед, тут же сместится назад
и там скакнет на месте. Так что в этом случае хотелось бы сделать клип «относительным» (rela­
tive), чтобы к анимации клипа добавлялась еще последняя поза предыдущего клипа. Более строго
говоря, для «относительного» клипа к значениям анимационных кривых добавляются последние
значения анимированных атрибутов из предыдущего клипа.

Персонажная анимация 815


В третьей версии MAYA, где впервые появилась нелинейная анимации, клипы могли быть
либо относительными, либо абсолютными. Целиком. Однако очень быстро стало понятно, что
хочется задавать «относительность» не для клипа целиком, а для отдельных каналов (атрибут),
входящих в состав клипа (а точнее, персонажа). Например, в предыдущем примере, с прыжками,
хотелось бы, чтобы перемещения центра персонажа и ног были относительными и «накапливались»,
а вот вращения рук (при условии использования прямой кинематики для рук), спины, шеи и
вращающихся частей были абсолютными. Иначе вращения могут начать «накапливаться» при
зацикливании клипов и постепенно приводить к большим значениям углов и даже к ошибкам в
случае небольших несовпадений значений вращений в начале и в конце клипа.

Теперь свойство «относительности» или «абсолютности» применяется не только к клипам,


но и ко всем анимационным каналам (атрибутам) внутри клипа. «Абсолютным клипом» называется
клип, у которого все каналы абсолютные. Ситуация с относительным клипом несколько более
запутанная, но об этом позже. Посмотрим, где это все спрятано в майском интерфейсе.

Выберите второй («бегущий») клип и нажмите правую кнопку мыши над ним. Появится
основное рабочее меню для работы с клипами. В нем собраны основные операции из меню Тгах
Editor, применимые к клипам.

Выберите в этом меню операцию Edit=>Clip Channel Offset.

Однако не произойдет ровным счетом ничего. На самом деле должен появиться At­
tribute Editor для выбранного клипа, который и так открыт. Таким образом MAYA говорит вам
(довольно ненавязчиво, надо сказать), что в Attribute Editor надо открыть раздел Channel Offsets и
отредактировать там свойства анимационных каналов.

Откройте в Attribute Editor раздел Channel Offsets и поглядите, как MAYA расставила
свойства Absolute/Relative для импортированного клипа.

Примечание. Здесь следует заметить, что ноль скоро при экспорте клипа в
отдельный файл, сохраняется только «исходный» клип, то информация об
атрибутах Channel Offset просто теряется (эти атрибуты есть только у
регулярных клипов, у исходных они отсутствуют, проверьте сами). Поэтому при
импорте клипа (равно как и при его создании) MAYA проявляет некий «интеллект»
при расстановке свойств Absolute/Relative для нового регулярного клипа.

816 Книга Сергея Цыпцына


Все каналы вращений установлены как абсолютные. Остальные каналы (translate, scale)
также являются абсолютными кроме root.tranlsate, rightLeglK.translate, leftLeglK.translate.
Последние принадлежат к объектам, находящимся на верхнем уровне иерархии (у которых нет
родительских объектов), поэтому MAYA по умолчанию выставляет свойство relative для каналов
таких объектов (кроме rotation) .

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

Установите свойство absolute для всех каналов rightLeglK и LeftLeglK.

Проблемы с растяжением лап должны исчезнуть.

Сохраните файл как duckNLAClip2.ma

Персонажная анимация 817


Склеивание и смешивание клипов
Посмотрим теперь как можно гладко состыковать клипы. Если второй клип просто
располагается справа от первого, то утка внезапно перескакивает из последней позы первого
клипа в первую позу второго клипа. Попробуем сделать этот переход более мягким.

Если «надвинуть» второй клип на первый (попутно возникнет вторая монтажная дорожка),
то возникнет эффект «суммирования» клипов, когда значения соответстующих каналов просто
суммируются и возникает просто «двойная» анимация. Для корректировки анимации это, может
быть, и хорошо, однако сейчас задача состоит в том, чтобы сделать мягкий переход от одного
клипа к другому.

Отодвиньте второй клип правее, затем выберите первый клип, нажмите Shift и выберите
второй клип.

Создайте переход (blend) между выбранными клипами: Create=>Blend.

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

Выберите в Trax Editor зеленую стрелку, чтобы посмотреть на этот переход повнимательнее.
Это тоже отдельный объект. Как и у любого объекта, у перехода обнаруживаются некоторые
атрибуты в Attribute Editor.

818 Книга Сергея Цыпцына


Первый атрибут Weight отвечает за степень смешивания клипов. Интуитивно понятно, что
в начале перехода больший вес имеет первый клип, а в конце второй. Графически это можно
увидеть в Graph Editor (в который можно быстро попасть из Trax Editor с помощью меню View=>Graph
Anim Curves).

По умолчанию анимационная кривая распределения веса клипов относительно перехода


представляет собой прямую линию в диапазоне от нуля до единицы по обеим осям. Пусть вас
не смущает диапазон от нуля до единицы по горизонтали, это нормализованная (относительная)
длина самого перехода, а не диапазон в кадрах или секундах. Поэтому в Attribute Editor, как
правило, показывается Weight=1, хотя было бы адекватно ожидать там пересчитанного значения
Weight в зависимости от текущего времени. Вы можете редактировать эту кривую перехода, делая,
например, «мягкие»тангенсы в конце или в начале. Помните, что значение Weight=0 отвечает за
полное игнорирование второго клипа, значение Weight=0.5 - за усредненное смешивание клипов,
а значение Weight=1 за полное влияние второго клипа. И также помните, что горизонтальный
диапазон - это длина перехода.

Второй атрибут, Rotation Blend, требует более подробных комментариев.


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

Персонажная анимация 819


другое, когда такая махина как персонаж, состоящая их десятка-другого атрибутов, должна
плавно перейти из одно позы в другую. Основную опасность хранят в себе атрибуты отвечающие
за вращение и об этом уже подробно говорилось выше, в разделе про эйлеровские углы,
интерполяцию вращений, кватернионы и прочие ужасы. Сейчас же я еще раз напомню, что вам
может казаться, будто в при переходе из одной позы в другую персонаж лишь немного приподнял
руки, а на деле значения для вращений костей в многочисленных суставах могут различаться на
сотни градусов для этих поз или клипов (тем более, если вы импортировали клип, не проверенный
антивирусной программой). Если линейно проинтерполировать значения вращений, то вместо
того, чтобы поднять руки, персонаж начнет неистово ими махать по кругу.

Поэтому для переходов между клипами по умолчанию значение Rotation Blend установлено
как Quaternion Short, что означает максимально короткую траекторию вращающихся объектов в
пространстве при переходе от позы к позе. Про остальные значения просто пока забудьте.
Еще раз повторюсь, что когда вы вручную контролируете вращение объекта и ставите на него
ключи, наблюдая за значениями вращений, то вы примерно чувствуете, как он будет двигаться.
Однако работая с позами и клипами, вы как правило, не уточняете, какие именно значения для
вращений многочисленных суставов установлены в конце одного клипа, а какие в конце другого.
Сейчас утка, закончив плыть, делает искусственное переходное движение лапами между
плаванием и бегом, а затем начинает бежать. Однако хотелось бы, чтобы утка начинала бежать
еще в воде, постепенно переходя от плавания к бегу. То есть хочется получит не переходный
взмах, а смешанное движение, включающее в себя и плавание и бег.

Для этого передвиньте второй клип под первый, расположив его «внахлест».

Теперь утка начинает бежать, еще не закончив плыть. Постарайтесь почувствовать, а


точнее понять, разницу с вариантом, когда клипы пересекались, но переход еще не был создан.
После создания перехода, на участке пересечения клипов, их анимационные кривые суммируются
с весами, определяемыми вышерассмотренной кривой. Без перехода, пересекающиеся клипы
просто абсолютно суммируются. Начало перехода в данном случае совпадает с началом пересечения
клипов, а не с концом первого клипа.

Установите для второго клипа в Attribute Editor значение Post Cycle=4 и сохраните сцену
как duckNLAClip3.ma

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

Немного тонкостей, или еще раз об абсолютных клипах


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

Выбрать второй клип (это важно), нажать над ним правую кнопку мыши и выполнить Enable
Clip, сняв соответствующий флажок и заблокировав тем самым работу второго клипа.

Примечание. Заблокировать работу всех клипов на одной дорожке (track) можно,


нажав кнопку Mute слева от начала дорожки.

820 Книга Сергея Цыпцына


Выберите теперь первый клип и установите в Attribute Editor значение Post Cycle=20.

Встаньте в двадцать пятый кадр, являющийся последним кадром зацикленного клипа.


Перейдите в следующий кадр. Левое крыло утки немного резко вернется в первый кадр следующего
цикла клипа.

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

Проведите эксперимент. Нажмите в Attribute Editor кнопку All Relative в разделе Channels
Offsets.

Теперь крыло утки не будет возвращаться назад при переходе от 25-го к 26-му кадру,
а будет начинать новый цикл из текущего положения. Казалось бы, что все неплохо, однако
прокрутите анимацию до пятисотого кадра и посмотрите на «распнутую» утку.

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

Если вашей первой мыслью будет исправить это несовпадение и поставить ключи так,
чтобы конец и начало клипа совпадали, то это не очень хорошая мысль. Чтобы движение было
по-настоящему зацикленным, нужно чтобы в последний кадр отличался от первого на «один шаг
цикла», иначе при зацикливании, будут возникать два одинаковых кадра, стоящих рядом, и это
будет давать небольшую паузу в движении, хорошо различимую глазом.

Персонажная анимация 821


Так что давайте вернем ситуацию обратно, а заодно уличим MAYA в некоторых
неточностях.

Если клип выбран, нажмите правую кнопку мыши над ним, и выполните переключение
Relative Clip, сняв флажок и сделав тем самым клип абсолютным.

Проверьте, что все каналы клипа в разделе Channels Offset стали абсолютными, и утка
теперь не растопыривает крылья.

А теперь нажмите правую кнопку мыши над клипом, и снова выполните переключение
Relative Clip, включив флажок и сделав тем самым клип «относительным». И сразу загляните
в Attribute Editor. Посмотрите в Channels Offset, где творится некоторая чехарда: все каналы
вращений остались абсолютными, а остальные каналы стали относительными. Это в понимании
MAYA называется «относительным» клипом.

822 Книга Сергея Цыпцына


Примечание. Самые взрослые мальчики залезут в Script Editor и увидят замечание
типа:
clipSchedule -ci 0 -absolute 0 duckScheduler1;
// Warning: line 1: The -abs and -abr flags are now obsolete.
Please use -aa, -ar, -ra or -da instead //
To есть MAYA сама выполняет свои же устаревшие команды!
Поэтому мой совет будет следующим: не пользуйтесь контекстным меню, для
изменения свойств абсолютностиIотносительности для каналов. Используйте
Attribute Editor. Тем более, что если вы еще раз нажмете правую кнопку мыши
над клипом, то увидите, что пункт Relative Clip вообще пропал и вместо него
красуется надпись Edit Clip Channel Offsetes...

Нажмите BAttribute Editor кнопку Restore Defaults (и не забудьте посмотреть, что произойдет
с каналами), чтобы вернуться к исходной ситуации.

Редактирование анимационных кривых для клипа


Как вы можете заметить, персонаж duck не имеет никаких ключей. Все анимационные
кривые «зашиты» в клипы. (Конечно, внутрь клипов они не «спрятаны», но их связи вы можете
исследовать с помощью Hypergraph).

Тем не менее, добраться до анимационных кривых довольно несложно и также несложно


их отредактировать.

Все, что нужно сделать - это выбрать клип и открыть Graph Editor.
Выберите первый клип и выполните в Trax Editor операцию View=>Graph Anim Curves
Это всего лишь откроет Graph Editor для выбранного клипа.

Пытливые умы могут тут же задаться вопросами если регулярный клип является копией
исходного, то чьи анимационные кривые мы видим в Graph Editor? Являются ли они копией других
кривых или существуют в одном экземпляре?

Ответ следующий - для каждого исходного клипа существует один экземпляр анимационных
кривых. Все регулярные клипы, созданные на основе этого исходного клипа, используют эти же
кривые, никаких копий кривых не создается.

Персонажная анимация 823


Обратите внимание на любопытную деталь. Если сейчас вы выберете исходный клип Clip-
1Source (например, нажав над клипом правую кнопку мыши и выполнив Select Source Clip), то
увидите в Graph Editor те же самые анимационные кривые. Однако начинаться они будут не с
первого, а с нулевого кадра!

Если вы сдвинете или сожмете (отредактировав Scale) регулярный clip1, то в Graph Editor
для него анимационные кривые также сдвинутся или сожмутся (надо только «обновить» Graph
Editor, выбрав что-нибудь, а затем снова выбрав clipl). В то же время анимационные кривые для
исходного клипа clipl Source останутся неизменными.

Однако, все это одни и те же анимационные кривые, просто для регулярных клипов они
показываются в Graph Editor с учетом положения и масштаба клипов, а для исходных клипов они
всегда отображаются в исходном масштабе и с нулевого кадра.

Если вы «испортили» c l i p l , верните его на место (Start Frame=1, Scale=1) и снова покажите
его анимационные кривые.

Выберите в левой панели Graph Editor каналы с именами типа shoulder, отвечающие за
движение крыла.

Очевидно, что крыло начинает двигаться с пятого кадра, вызывая некоторую паузу в начале
клипа. Отредактируем это.

Выберите крайние левые ключи всех анимационных кривых.


В первом поле Stats на полке Graph Editor введите 1 вместо 5.

824 Книга Сергея Цыпцына


Не забудьте также разыскать в Graph Editor каналы shoulder_r.Translate (они находятся
немного ниже) и проделать с ними то же самое.

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

Сохраните сцену как duckNLAClip4.ma

Временная активизация ключей


Есть и другой способ редактирования исходной анимации. Он является более рискованным
и предназначен для редактирования ключей не в Graph Editor, а непосредственно на экране и на
TimeLine.

Выберите clipl и выполните Modify=>Activate/Deactivate Keys. (Можно сделать это по


правой кнопке мыши.)

Ничего не произошло. Однако если выбрать в Outliner персонаж Duck, вы увидите, что на
TimeLine появились исходные ключи для первого клипа. А клип стал сиреневым, что означает,
что его ключи временно «активизированы» и что после редактирования анимации надо не забыть
вернуть клип в нормальное состояние.

Перейдите в пятый кадр и выберите сустав под название head.

Наклоните немного голову утки, покрутив сустав вокруг оси Z.

Занеся руку над клавишей «s», посмотрите в правую часть TimeLine. Похоже там, в поле
выбора текущего персонажа, стоит No Character Set.

Перед постановкой ключей на любые части тела, обязательно сделайте персонаж текущим!!
Иначе позднее вы можете очень сильно запутаться в ключах и позах.

Персонажная анимация 825


Сделайте текущим персонаж duck.

Теперь поставьте ключ на сустав для головы, а точнее на весь персонаж.


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

Выберите клип и деактивизируйте ключи, выполнив снова Modify=> Activate /Deactivate Keys.

Корректирующая анимация. Ключи поверх клипов


Одним из преимуществ нелинейной анимации является возможность «наслаивать» одну
анимацию поверх другой, создавая дополнительные «уровни» анимации, предназначенные для
корректировки существующей анимации. Такой подход позволяет разделить всю анимацию на
«слои», каждый из которых отвечает за свой тип движения. В общем, по аналогии с проходами
(pass) рендеринга, отдельно просчитывающими тени, блики, отражения и пр.

Убедитесь, что ключи не активизированы, то есть что клип имеет здоровый светло-синий
цвет и персонаж duck не имеет ключей на TimeLine.

Посмотрим, что будет, если мы начнем ставить ключи поверх клипа, не активируя ключи
Встаньте в первый кадр. Убедитесь, что на TimeLine текущим персонажем является duck.
Нажмите клавишу «s», ставя ключ на уже имеющуюся позу.

Если утка вдруг резко «улетела» из кадра, не пугайтесь: это «шутки» нелинейной анимации.
Просто сместитесь в любой кадр и вернитесь обратно в первый.
Встаньте в двадцать пятый кадр. И снова поставьте ключ клавишей «s».
Теперь встаньте в тринадцатый кадр.
Выберите сустав root и опустите утку немного вниз.
Поставьте ключ и проиграйте анимацию. Утка должна притонуть и всплыть в течение клипа.
Таким образом, вы создали еще один слой анимации, отвечающий за вертикальное движение
утки. Чтобы зациклить это движение и синхронизировать его с остальной анимацией, создадим из
этих трех ключей клип.

Выполните в Trax Editor операцию Create Clip. Для созданного клипа (clip2), установите
Post Cycle=2. Теперь утка циклически покачивается на волнах.

Подобным способом вы может создавать сколько угодно слоев «корректирующей»


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

Сохраните сцену как duckNLAClip5.ma

826 Книга Сергея Цыпцына


Монтаж анимации
Теперь потренируйтесь в монтаже анимации.
Выберите персонаж duck и импортируйте в сцену следующие клипы: fly.ma (postCycle=2),
flyAhead.ma (Post Cycle=4), flyDown.ma.

Расположите их на временной линейке друг за другом. Сделайте между ними переходы


(Create Blend), поэкспериментируйте с перекрытием клипов.

Затем выберите clipl и сделайте его копию: Edit Duplicate.


Расположите копию справа от клипа downFly и также сделайте между ними переход.

Осталось разобраться с лапами. На некоторых участках лапы ведут себя немного


вызывающе. Это связано с тем, что MAYA установила для них при импорте, по умолчанию, опцию
Channel Offsets=Relative.

Выберите клип fly, и в Attribute Editor установите для лап Channel Offsets=Absolute.

Затем, нажимая Shift, выберите все остальные импортированные клипы и выполните


операцию Edit=>Copy Channel Offsets. Это скопирует установки для Channel Offsets с первого
выбранного клипа на все остальные.

Сохраните сцену как duckNLAClip6.ma

Персонажная анимация 827


Слияние и запекание клипов
Предположим вы собираетесь запустить вашу утку по пути, чтобы она не только неистово
махала крыльями и лапами, но и передвигалась по какой-то траектории. Для этого достаточно
сгруппировать сустав root и группы leftLeglK и rightLeglK в одну группу и запустить ее по пути.
Однако вы можете захотеть перед этим «зафиксировать» полученную с таким трудом нелинейную
анимацию и превратить ее в один длинный клип, с которым будет дальше удобнее работать
(например, одним махом изменять длину анимации). А может, вы даже захотите избавиться от
клипов и персонажей и оставить только традиционную ключевую анимацию на объектах сцены.
Выберите в Trax Editor все клипы и переходы.

Выполните команду Edit=>Merge.

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

Сохраните сцену как duckNLAClip7.ma

Посмотрим теперь на анимационные кривые полученного клипа.


Выберите клип и активизируйте его ключи: Modify=>Activate/Deactivate Keys.
Выберите персонаж duck и посмотрите на TimeLine. Вы увидите, что при «слиянии»
(merge) клипов в один клип, происходит проставление ключей в каждом кадре. Следовательно,
анимационные кривые полученного крипа редактированию уже не подлежат, вы можете
оперировать только с клипом как единым целым.

Если вы захотите избавиться от клипа, а заодно и от персонажа, чтобы вернуться к


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

Деформация времени. Retiming


Если вы в ярости уже удалили и клип и персонаж, вернитесь к тому моменту, когда «слитый»
клип еще жив (duckNLAClip7.ma). Рассмотрим кратко один вопрос, связанный с нелинейным
искажением времени.

Дело в том, что при помощи атрибута Scale вы меняете темп всего клипа целиком. Однако
иногда возникают ситуации, когда нужно «подрулить» скорость выполнения только части клипа.
Например, сделать скорость посадки на воду чуть помедленнее или сделать так, чтобы утка
плыла, постепенно ускоряясь. Конечно, если у вас есть исходные клипы, это можно сделать для
каждого из них поотдельности, но зачастую бывает так, что анимацию надо «подогнать» целиком
под некоторый заданный темп или соответствующему безумному, утреннему замыслу режиссера.
Еще одной очевидной задачей являет разворачивание анимации вспять.

В этом случае используется технология деформации времени (Time Warp).


Выберите клип, полученный с помощью операции Merge.
Выполните операцию Enable Time Warp.
В Attribute Editor появится доступная галка Enable Time Warp, а на самом клипе (только
если снять с него выделение) появится зеленая полоска, сигнализирующая о том, что для клипа
создана и активизирована анимационная кривая, управляющая скоростью исполнения клипа.
Самый простой способ увидеть эту кривую - выбрать клип, показать его анимационные
кривые и в списке каналов в Graph Editor выбрать последний из них (Time Warp), а затем нажать
клавишу «f».

828 Книга Сергея Цыпцына


Значения 100 по обеим осям в Graph Editor означают проценты от длины клипа. Их можно
трактовать так: по горизонтали откладывается текущее значение времени в терминах процентного
расстояния от начала клипа, график анимационной кривой показывает, какой участок исходного
клипа будет выполняться в этот момент. Например, чтобы «развернуть» клип вспять, надо просто
изменить наклон кривой, чтобы она двигалась сверху вниз, а не снизу вверх.

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


только не выходить за диапазон (0,100).

Вес клипов
Пытливые умы конечно давно приметили в Attribute Editor атрибут Weight и соседний с
ним атрибут Weight Style. Эти атрибуты отвечают за «интенсивность», или «громкость» клипа.
Попробуйте, например, в последнем примере установить для клипа Weight=0.1, и вы увидите, что
утка станет шевелить конечностями в десять раз менее интенсивно.

Вы можете рассматривать клип как кубик, а атрибут Weight как высоту этого кубика, то есть
вертикальный размер его анимационных кривых. Уменьшая Weight вы «сжимаете» вертикально
анимационные кривые -то бишь уменьшаете «громкость» анимации. Атрибут Weight Style
определяет, где находится pivot такого «сжатия»: на минимуме анимационных кривых или в нуле
(вариант Absolute From Start означает, что относительно нуля сжимаются только «абсолютные»
каналы). Конечно, можно не только сжимать (глушить), но и растягивать клипы, получая эффекты
преувеличения анимации. (Вам наверняка понравится вариант Weight=0.1, Weight Style=From
Zero)

Примечание. С помощью контекстного меню вы можете даже создать анимационную


кривую, распределяющую вес клипа вдоль длины клипа. Эта операция называется
Create Weight Curve.

Персонажная анимация 829


Некоторые комментарии на нелинейную тему
Вышеприведенный материал не покрывает всех возможностей Trax Editor и прелестей
нелинейной анимации. Прокомментирую вкратце некоторые дополнительные понятия и
операции.

Поза выделена в Trax Editor как отдельный объект, однако вы можете рассматривать ее
как клип длиною в один кадр и работать с нею при помощи тех же самых инструментов. Одним из
применений именно поз может быть создание персонажа для атрибутов Blend Shapes и дальнейшее
выстраивание мимики в виде набора поз. Имейте в виду, что созданная поза появляется только в
Visor и ее надо вытаскивать оттуда в Trax Editor вручную.

Сравнительно новое и довольно изящное нововведение возможность создавать клипы для


персонажей, чьи атрибуты анимированы с помощью expression и констрейнов (Create=>Expression
Clip). По умолчанию длина таких клипов при создании устанавливается равной диапазону, заданному
на TimeLine. Однако очевидно, что позже вы можете менять атрибут Source End для такого клипа
как угодно. Такие клипы можно смешивать с другими клипами, ставить поверх них ключи, резать
и пр. При зацикливании таких клипов, помните про Channel Offsets, поскольку «относительные»
каналы могут давать интересные эффекты «накопления» процедурной анимации.

Если вы импортируете в сцену звуковой файл, то сразу увидите его в Trax Editor. Сразу
скажу, что со звуковыми клипами в Trax Editor нельзя делать ничего вообще. Только двигать
вправо-влево. Как могут заметить пытливые умы, это даже не настоящие клипы, а просто ноды типа
audio, видимые в Trax Editor. При расположении звуковых клипов друг под другом, проигрываться
будет только верхний клип, его и можно услышать. Чтобы услышать другие звуковые клипы,
присутствующие в Trax Editor, надо обязательно включить в контекстном меню на TimeLine опцию
Use Trax Sounds. Кроме того, надо не забыть в общих установках для анимации установить Playback
Speed=Realtime.

Рано или поздно (лучше поздно) перед вами встанет задача переноса анимации с одного
персонажа на другого. Технически это делается обычно следующим образом: в сцене должны
быть два персонажа, и хотя бы на одном из них должна быть анимация в виде клипов. Вы
выбираете нужный клип с одного персонажа и выполняете в Trax Editor операцию Edit=>Copy.
Заглянув в Option Box команды Paste, вы можете увидеть несколько способов (Paste Method), с
помощью которых MAYA может «приделать» анимационные кривые от одного персонажа к другому.
В тех случаях, когда персонажи идентичны, вполне может подойти метод определения нужных
атрибутов по имени или по структуре иерархии. Однако, в тех случаях, когда нет уверенности
в том, что абсолютно все атрибуты двух персонажей имеют идентичные имена и совпадающие

830 Книга Сергея Цыпцына


номера внутри персонажа, самый надежный способ - это Character Mapping. С помощью окна,
открывающегося при выполнении File=>Character Mapper, можно задать однозначное соответствие
между атрибутами двух персонажей вручную.

Тут стоит заметить, что с появлением технологии Animation Retargeting возник


альтернативный путь переноса анимации с одного персонажа на другой. Не могу пока сказать,
какой из двух методов предпочтительнее, однако могу заметить, что с помощью операции Retar­
get Skeleton вы можете переносить анимацию со скелета на скелет вне зависимости от того, есть
ли на оригинальном персонаже клипы или нет, то есть без привязки к нелинейной анимации.
Однако следует помнить, что получившиеся анимационные кривые в результате переноса
анимации, будут «забейканы»(backed), то есть ключи на них будут стоять в каждом кадре. Такая
перенесенная анимация редактированию подлежит плохо, так что если вы хотите с ней что-то
делать в дальнейшем, этот метод вам не подойдет.

Практические замечания относительно нелинейной анимации


В этом разделе я попросил Мишу Бажуткина поделиться опытом использования нелинейной
анимации. Его замечания помогут вам сэкономить некоторое количество времени при решении
проблем и распутыванию «косяков», а практические советы будут, с моей точки зрения,
безоговорочно суперполезны. Этот материал состоит из двух частей. В первой идет речь о том,
в каких случаях удобно использовать возможности клипов и нелинейной анимации, а во второй
- когда во время работы появляются проблемы и как с ними нужно бороться.

С тех пор, как в MAYA появилось понятие Персонажа (Character Set), многие сетапщики и
аниматоры с большим энтузиазмом восприняли эту технологию и стали создавать эти Character
Set еще до стадии анимации, как бы «укомплектовывая» его по полной программе различными
«примочками». Но потом появились проблемы - на деле оказалось не все так радужно и красиво.
Тем не менее, эта технология заслуживает большого внимания. И зная подводные камни, можно
извлечь из нее много полезного.

Обратите внимание на то, что, начиная с версии 6.0, в MAYA был значительно изменен
механизм работы клипов и самого Trax Editor. Эти изменения настолько значительны, что некоторые
сцены, сделанные в версии MAYA 5.0 с использованием клипов, могут некорректно открываться в
старших версиях MAYA.

Character Set - что может быть плохого при его использовании?

Trax Editor абсолютно бесполезен, если ваши анимированные атрибуты не находятся в


Character Set. Ведь вы сможете создавать клипы только после того, как они окажутся там. Теперь
представим себе следующую ситуацию, когда вы готовите персонажа для последующего этапа
анимации. Причем предположим, что технологический процесс требует, чтобы персонаж был
включен в сцену как Reference. И перед вами встает вопрос: в какой момент создавать Character
Set - в файле с персонажем или в сцене после импорта (Reference) персонажа? Мой совет - делайте
это после импорта. Если вас беспокоит, что эта процедура будет непростой (из-за большого числа
объектов, входящих в состав Character Set, или по каким другим причинам), сделайте на этот случай
небольшой скрипт для автоматизации этого процесса. Или создайте Quick Select Set - в большинстве
случаев этого вполне достаточно для того, чтобы аниматор мог выбрать и работать с Character Set
в анимационной сцене. Почему же я не рекомендую заранее, до анимации, подготовить Character
Set? Дело в том, что в момент, когда происходит «связывание» анимационных «кривых» с нодой
клипа, MAYA руководствуется не именами этих анимационных нод, а всего лишь их порядковым
номером. Этот номер они получают в процессе создания клипа. Пока ничего страшного нет. Но,
допустим, вы решили несколько модернизировать персонажа и добавить несколько новых атрибутов
для его управления. И здесь тоже нет ничего страшного. Проблемы начнутся в тот момент, когда
вы захотите удалить часть атрибутов - а вы обязательно захотите этого, рано или поздно... После
этого «редактирования» перестроится и весь Character Set, в который они входили. Далее, когда
вы откроете сцену, где анимация персонажа размещалась в клипе, произойдет путаница в связях
между анимационными кривыми и клипом. Иными словами, то, что раньше вращало голову, теперь

Персонажная анимация 831


будет вращать таз. И это в лучшем случае. Путаются не только каналы (атрибуты), но и объекты.
Страшнее всего то, восстановить этот порядок бывает просто невозможно из-за того, что после
некоторых операций с клипом (например, Merge) анимационным кривым могут быть присвоены
имена, никак не привязанные по смыслу к соответствующим им атрибутам. А вот если Character
Set был создан в этой же сцене после импорта персонажа, этой путаницы уже не будет, так как
формирование Character Set идет по обычной схеме, соответствующей анимации. Для того, чтобы
быть объективным, я провел небольшой тест в разных версиях MAYA, от 5.0 до 6.5, и обнаружил,
что этой проблемы частично нет, начиная с версии 6.0. Если из Character Set (файла Reference)
были частично удалены одни атрибуты и добавлены новые, при открытии сцены, новым атрибутам
может добавиться анимация от старых атрибутов. Тем не менее, это лишь свидетельствует, что
технология не застрахована от таких случаев на все сто процентов.

Клипы
Клип в MAYA - это, по сути, контейнер, содержащий какое-либо движение. Поза - это тоже
клип, только без движения. Аниматор может превратить обычные ключи в клип, и наоборот, клип
в ключи. Но помимо этого, в клипе есть дополнительные параметры, которые помогают аниматору
оперировать ими. Например, с какого кадра он будет воспроизводиться в сцене (Start Frame).
Также у него есть и другие, не менее важные, хотя, на первый взгляд, незаметные атрибуты.
Например, атрибуты Source Start и Source End, показывающие, с какого и по какой именно кадр
будет воспроизводиться анимация из анимационных кривых, содержащихся в клипе. Именно они
определяют базовую длину клипа.

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


использовать Trax Editor для тех случаев, когда имеется какой-то большой «кусок» анимации (да
простят меня аниматоры за это словечко). Например, в нем подряд идут разные по характеру
движения. При проигрывании этой анимации может возникнуть ощущение, что оно неритмично
и какие-то части выглядят вяло по отношению к другим. В этом случае имеет смысл создать из
этой анимации клип и разрезать его в тех местах, где меняется характер движения (Edit => Split).
Далее, меняя скорость каждого из этих мини-клипов, можно добиться общего ровного ритма.
После этого, если есть необходимость, можно склеить эти клипы с помощью операции Merge (Edit
=> Merge). Полученный клип будет содержать уже отредактированную анимацию.

При этом хочется обратить внимание на тот факт, что операция Merge изменяет исходные
анимационные кривые клипов. Появляются ключи в каждом кадре клипа, как и при операции Bake
Channel в Graph Editor. И в анимационных кривых, входящих в этот клип, имеются дополнительные
ключи в тех кадрах, где исходный клип был разрезан операцией Split. Эти ключи стоят рядом с
оригинальными ключами, повремени примерно на одну десятую долю секунды. Иногда имеет смысл
их «подчищать». Автоматически это можно сделать операцией Bake Simulation (Edit=>Keys=>Bake
Simulation), после того, как клип был активирован (меню Trax Editor: Modify => Activate /Deactivate
Keys).

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

Absolute и Relative
В отличие от клипов, с которыми многие имели дело в программах для видеомонтажа,
в MAYA клипы содержат информацию о движении объектов в пространстве. И это значит, что
при склейке разных клипов могут появиться вопросы типа: как быть, если движение в клипах
происходило в разных местах сцены, а хочется, чтобы вместо однокадрового скачка, движение
органично продолжилось с последней позы первого клипа? Для этого в клип были введены
дополнительные параметры Absolute и Relative, которые частично помогают решить эту проблему.
Absolute - режим, при котором значение ключа внутри клипа трактуется как абсолютное, то есть

832 Книга Сергея Цыпцына


как оно было записано, так и будет воспроизведено. Его противоположность - режим Relative,
при котором значения всей анимационной кривой клипа смещается (отсюда и название параметра
Channel Offset), но так, чтобы значение первого ключа этого клипа было равным последнему
значению впереди стоящего клипа. Если этот клип первый, не имеет значения, какой это режим,
Absolute или Relative.

В MAYA 6.5 этот подход стал более продвинутым, в результате того, что разработчики
сделали возможным устанавливать этот параметр не только на весь клип, но и на каждый его
канал по отдельности. Теперь во многих случаях нет необходимости прибегать к Subcharacter Set,
чтобы более тонко регулировать эти правила для каналов. Для того, чтобы облегчить работу по
настройке этих параметров в разных, но однотипных клипах, в меню Тгах появилось функция Сору
Channel Offset, которая позволяет быстро скопировать установки первого выбранного клипа на все
последующие.

Blend
Начиная с версии MAYA6.0, значительно расширились возможности функции Blend, которая
стала позволять делать не только плавные переходы между концом и началом двух клипов, а
также микшировать их движения с нужным количеством кадров, просто подставляя их один под
другой. Это сделало Тгах Editor достаточно мощным редактором нелинейной анимации, и во многих
случаях уже нет такой острой необходимости прибегать к услугам других пакетов, таких как Motion
Builder. К сожалению, до сих пор в MAYA нет штатного инструмента для автоматической подгонки
двух аналогичных поз из разных клипов, перед тем, как сделать Blend между ними. Частично эту
проблему могут решить инструмент Redirect, технология Motion Wrap, а также собственноручно
написанные скрипты.

Например, стало очень просто создавать цикл походки на основе данных Motion Capture.
Для этого нужно поместить анимацию походки в клип, выбрать ключевую позу, с которой будет
начинаться и заканчиваться цикл, но так, чтобы в походке она появлялась хотя бы три раза, то
есть персонаж сделал бы четыре шага. Можно и больше, если позволяют записанные данные.
Основная идея - сделать линейный Blend в течение двух шагов так, чтобы в начале и в конце этого
мы «пришли» к одной и той же позе.

Для этого сделаем копию этого клипа (Edit =>Duplicate).

Подрежем в первый клип так, чтобы в нем остались третий и четвертый шаг, а в другом - первый
и второй шаги (Edit=>Trim Before и Trim After).

Подставим в Тгах Editor один клип под другой и, выделив оба клипа, сделаем Blend (Edit=>Blend).
Очень важно, чтобы Blend был линейным. Если он будет другого типа, то персонаж «поплывет», то
есть его таз не будет стабилизирован относительно одной точки, как на беговой дорожке. Также
важно, чтобы все каналы нижнего клипа были в режиме Absolute.

Для этого нужно выделить клип, зайти в Attribute Editor и в закладке Channel Offset нажать
кнопку All Absolute. Если все сделано правильно, мы получим зацикленное движение. Если у вас
получатся какие-либо скачки в позах, при возращении в первый кадр, значит, вы где-то ошиблись
в кадрах при подрезании клипов. Чтобы проверить это, убедитесь, что цифры в верхнем левом
углу верхнего клипа и в верхнем правом углу нижнего клипа совпадают.

Для того, чтобы персонаж не проскальзывал на одном месте, а двигался вперед, можно
использовать технологию Motion Wrap.

Персонажная анимация 833


Motion Wrap
После того, как анимация «попадает» в клип, анимационные каналы персонажа очищаются,
и это дает возможность создавать новую анимацию поверх уже имеющейся. Если на персонаж
ставить ключи одновременно с активным клипом, MAYA сохраняет в ключах не абсолютное
значение, показанное в Channel Box, а разницу между ним и значением из клипа. Иными
словами, эта анимация просто суммируется с анимацией клипа. Это дает возможность аниматору
недеструктивно редактировать уже существующую анимацию «послойно».

Основное применение эта технология находит во время правки данных с Motion Capture,
микшировании клипов (например, для создания циклов походки), а также при создании новых
вариантов ранее анимированного движения. Полученную анимацию можно также превратить в клип
и получить новое движение. Клипы, расположенные в Trax Editor один под другим, автоматически
складываются в режиме Add.

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

Основное правило при создании Motion Wrap анимации - это предварительно поставить два
ключа: в кадре, с которого начинается правка, и там, где она заканчивается. Главное - чтобы в
этих кадрах позы персонажа устраивали аниматора. Если все было сделано правильно, значения
этих ключей должны быть нулевыми, если, конечно, вы не преследуете других целей, таких,
как общее смещение анимации (offset) . Тангенсы этих крайних ключей лучше делать типа Flat,
чтобы Motion Wrap был незаметен для зрителя. Далее аниматор ставит ключи в нужных кадрах,
поправляя позы персонажа, там, где считает это целесообразным.

В этом случае нужно быть внимательным, чтобы во время работы с Motion Wrap режим
Auto Key не был включен, то есть все изменения в позах вы должны подтверждать («ключевать»)
стандартным образом, нажимая клавишу «s» (Set Key).

В предыдущем примере с циклом походки аниматор должен поставить ключ на корневую


кость и на локаторы, отвечающие за перемещение - в начальном кадре, где начинается «варпинг»,
и в последнем, где он заканчивается. Потом надо сдвинуть персонаж вперед на такое расстояние,
которое он реально проходит за два шага, и снова поставить ключ.

Time Warp
Те, кто работал в программах для композитинга, часто пользуются функцией Time Remap­
ping, чтобы нелинейно управлять скоростью воспроизведения видеоклипов. Очень здорово, что
для клипов в MAYA имеются такие же возможности, только под названием Time Warp. Для клипа
создается дополнительная кривая, которая показывает, в процентном соотношении к общей длине
клипа, какой именно кадр этого клипа должен быть воспроизведен. При включении этого режима
изначально кривая в Graph Editor представляет собой линейный график (два ключа от 0 до 100
по двум осям). Далее аниматор, редактируя ее, может по своему усмотрению изменять скорость
воспроизведения на различных участках клипа. Только будьте внимательны: пересчет позы
персонажа не интерактивен, то есть после очередной правки Time Warp кривой, нужно подвигать
мышью по Time Line, чтобы проанализировать происходящее. Конечно, это не всегда удобно и
не интерактивно. Но самое интересное то, что такую кривую необязательно создавать в MAYA, a
можно импортировать из программы композитинга, например из программы After Effects .

834 Книга Сергея Цыпцына


Нестандартное использование клипов.
Движение по пути, или Macro Driven Key
Клипы также можно использовать и не по их прямому назначению. Я уже ранее сравнивал
их с анимационным контейнером. Развивая эту тему, могу предложить еще одну технологию.
Предположим, у вас есть персонаж, которым вы хотите управлять процедурным методом,
например, с помощью динамики. Вам для этого, собственно, нужен клип с циклом походки, а также
информацию о направлении движения, длину пройденного пути и положение в пространстве.
Клип даст нам возможность регулировать скорость воспроизведения цикла походки в зависимости
от пройденного расстояния.

Но сначала его нужно подготовить для этого.


Создадим из него этакий Macro Driven Key.
Зациклим кривые цикла походки. Для этого нужно выделить кривые клипа в Graph Editor
и вызывать Curves=>Post Infinity =>Cycle.

Проверьте это следующим образом. Поставьте значение атрибута клипа Source End на много
больше, чем там было, и проиграйте анимацию. Если все сделано правильно, при прохождении
кадра, где раньше клип заканчивался, не должно быть никаких скачков. Если таковые имеются,
значит это неправильный цикл. Также для «чистоты» воспроизведения желательно сделать всем
кривым вращения операцию Euler Filter, чтобы при попадании в межкадровое пространство не
было никаких «глюков» с вращением.

Еще одно условие - персонаж должен «шевелиться» на одном месте. И у него должен
иметься такой локатор (или группа), двигая который, мы могли бы передвигать его по сцене.
На этом локаторе создадим дополнительный атрибут (тип Float) для управления фазой
движения цикла.
Свяжем его (в Connection Editor ) с атрибутами клипа - Source Start и Source End. В этот
момент клип в Trax Editor должен сократиться до одного кадра. Это нормально, за исключением
того, что теперь стало трудней искать его там и выделять.

Проверим работу нового атрибута (кстати, я его назвал phase), изменяя его значения -
персонаж должен зашевелиться.

Теперь добавим на контрольный локатор еще один атрибут (path, тоже типа Float) для
преобразования пройденного расстояния персонажем в текущую фазу цикла. Преобразование
можно делать простым выражением (expression) типа: phase = path / 1.15. Можете также
использовать Set Driven Key, особенно если эта зависимость нелинейная.

Собственно, теперь настроенного таким образом персонажа можно запустить по сцене,


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

Данную технику можно использовать также для анимации толпы. Мой коллега, программист
Дмитрий Робустов, для нужд нашей студии написал плагин, который, используя фазы клипа
персонажа, меняет позу персонажа уже во время рендеринга в RenderMan. Это позволяет
существенно оптимизировать процесс передачи данных на рендер и ускорить сам процесс просчета
толпы. Но замечу: это только один из многочисленных вариантов технологий анимации толпы. Как
правило, в каждой студии, он чем-то отличается от других.

Перенос анимации и поз из одной сцены в другие

Одно из главных достоинств клипов - возможность на их основе создавать библиотеку


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

Персонажная анимация 835


Причин, по которым это происходит, может быть несколько: например, при создании
Character Set поменялся порядок атрибутов (аниматор выбирал объекты в другом порядке), или
изменилось число атрибутов, или у персонажа изменился префикс, если он был импортирован в
сцену.

Например, клип был экспортирован в отдельный файл с персонажа с префиксом «man:»,


а затем был перенесен на персонаж с префиксом «man1:».

Для того, чтобы «помочь» пользователям в таких ситуациях корректно перенести клип
на Character Set, в MAYA существует несколько режимов вставки клипов: по имени атрибута, по
порядку, по имени ноды и «карте» (Character Map) персонажа. Последний режим разработан
специально для тех случаев, когда названия атрибутов, между которыми происходит копирование
анимации, различны. То есть теоретически можно обмениваться анимацией между персонажами
разного типа. Недостаток этого режима - необходимость создавать так называемую «карту»,
в которой просто расписаны соответствия между атрибутами двух персонажей. Что-то типа:
«человек.левая_рука -> птица.левое_крыло» (пишу на русском, чтобы было понятнее).

Для персонажей, у которых таких атрибутов (каналов) может быть больше сотни,
составление подобной карты может превратиться в рутину. Остальные режимы вставки клипа на
Character Set в вышеописанных ситуациях дают «сбои».

Для того, чтобы помочь себе и каждый раз не мучиться с подобными проблемами, я стал
создавать, помимо персонажа, еще и Quick Select Set, куда входили все объекты, участвующие в
анимации. И перед тем, как создавать Character Set, я выделял эти объекты в алфавитном порядке
с помощью написанного скрипта, пользуясь информацией ранее созданного Quick Select Set. Дело
в том, что стандартный способ выделения, вызываемый из меню Edit=>Quick Select Sets, дает
разный порядок выделения в разных сценах, и это также создает проблему с переносом клипов.

Вот самые важные строки этого скрипта:

string $list[] = sets -q SquickSelectSet';


$list = sort $list';
select -r $list;

Переменная SquickSelectSet содержит имя нужного Quick Select Set. A MEL-команда sort
производит сортировку объектов этого сета в алфавитном порядке. После того, как ваши Character
Sets будут созданы по этой схеме, вы можете переносить клипы в режиме «по порядку атрибутов»
(By Attribute Order) в окне Paste Clip Options (меню Trax Editor, Edit=>Paste). Единственное, чего
не может предусмотреть этот способ, так это изменений в самом Quick Select Set или в атрибутах
объектов, входящих в него.

Некоренные переходы между клипами


Бывают ситуации, когда нужно «плавно» склеить две позы, или позу с клипом, или конец
одного клипа с началом другого. Для таких случаев в Trax Editor есть инструмент Blend. В последних
версиях MAYA у него появился режим Quaternion, который помогает избежать неправильных
переходов при вращении между начальной и конечной позами. Дело в том, что стандартный Blend
(режим Linear) работает без учета специфики эйлеровского (Euler) вращения, когда каждая ось
вращения «блендится» без учета вращения остальных, и это приводит порой к довольно странным
переходам. Задача же режима Quaternion заключается в том, чтобы сделать переход максимально
простым - по кратчайшему пути. Но, увы, даже это порой дает сбои. И тогда на помощь приходит
проверенный способ - Euler Filter (эйлеровский фильтр) из меню Curves в Graph Editor. Но для
того, чтобы до него добраться, нужно пройти следующий путь.

Для начала мы просто сделаем операцию Merge в Trax Editor, выделив два нужных клипа.
Затем вызовем меню правой кнопкой мыши на полученном клипе, активируем его ключи, выбрав

836 Книга Сергея Цыпцына


меню Activate Keys. Клип должен окраситься другим цветом (в разных версиях MAYA этот цвет
разный, не говоря уже о тех «бойцах», которые заменяют цвета разработчиков на собственные).
Выделив клип, нужно открыть Graph Editor и в нем найти и удалить те ключи, что находятся в
диапазоне перехода.
Также нужно поправить тангенсы ключей крайних поз: для случая Ease In Out это будет тип
Flat. Выделив все каналы, чтобы не мучиться с конкретным выделением каналов вращения, надо
вызвать в Graph Editor меню Curves=>Euler Filter.

В ранних версиях MAYA можно было делать операцию Merge только для участка с переходом
между клипами, созданного операцией Blend. К сожалению, теперь этот фокус не проходит, а
после операции Merge оригинальные ключи в полученном клипе «засоряются» дополнительными,
как после операции Bake Channel.

Как вариант, можно активировать ключи клипа с движением, и после этого поставить в
позу персонаж в нужном кадре, используя возможности окна Visor, вызвать меню правой кнопкой
мыши на позе - Apply Pose. Когда персонаж встанет в эту позу, ее можно «закрепить» ключами и
проделать операцию Euler Filter. Есть и другие способы, поэтому каждый из вас может найти свой
путь, «субъективно оптимальный» в каждом конкретном случае.

«Шкурный вопрос»: скининг персонажей


Разобравшись с настройкой персонажей и безумным управлением скелетами с помощью
конструктора из хэндлов, констрейнов и прочих «запчастей» (наиболее малодушные уже, наверное,
оседлали систему Full Body IK, ведь так?), вы конечно зададитесь вопросом: «А мясо где?». Иными
словами, какой толк от скелета, если на нем нет самого персонажа во плоти? Даже если вы
делаете фильм ужасов с участием лучших скелетов мира, все равно вам придется изготовить
модели костей и «насадить» их на «майские кости», ведь объекты типа joint не рендерятся сами
по себе.
Заметьте, что настройка управления скелетом (сетап) и привязывание модели (поверхности)
к скелету (скининг) - две разные и почти независимые задачи. Система управления персонажем
может включать в себя четыре, пять (хоть десять) различных скелетов и дополнительных костей,
однако в этой системе должен быть один скелет, к которому будет привязана «кожа». Самый
традиционный пример - три скелета для одного персонажа: один скелет управляется с помощью
IK, другой - с помощью FK, а третий всегда находится «посередине» между первыми двумя. Вот
к этому третьему, «пассивному» скелету и крепится «кожа». Заметьте также, что для скининга
совершенно все равно, как управляется скелет, к которому производится привязка. «Прискиненная»
поверхность деформируется в зависимости от положения суставов, и ей все равно, каким образом
эти суставы управляются.

Итак, скининг - это привязывание деформируемого объекта к костям скелета.


«Деформируемым» объектом может быть любая поверхность, кривая или решетка Lattice, то есть
любой объект, у которого есть компоненты-точки (частицы не в счет!). После привязки (bind) кости
скелета становятся деформерами для привязанной (bound) поверхности. Вы можете воспринимать
кости, как «большие кластеры», если вам это поможет.

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


Согнутые кости вызывают сокращения мышц, а мышцы, в свою очередь, вызывают деформации
кожи. Однако в компьютерной графике до сих пор преобладает «прямой» подход, когда кости
напрямую влияют на поверхность модели. Следует, тем не менее, сказать, что в последнее
время стали появляться «полуавтоматические» мускульные решения в виде различных плагинов
и отдельных пакетов. Эти решения как раз исповедуют «анатомический» подход, передающий
деформации от костей к коже через мышцы. Также следует добавить, что в MAYA имеются довольно
гибкие средства для настройки мышечных деформации в дополнение к традиционному прямому
скинингу (или даже как альтернатива ему).

Иногда эти средства называют «непрямым» скинингом (indirect skinning). Представьте


себе, что вы назначили на часть тела (например, на бедро) сетку Lattice в качестве деформера.

Персонажная анимация 837


А потом привязали этот деформер к соответствующим костям скелета. Получится, что кости гнут
сетку Lattice, а сетка деформирует бедро. Другой пример непрямого скининга заключается в
использовании Wrap-деформера. Предположим у вас есть две модели одного персонажа с разным
разрешением. Вы можете привязать к скелету модель с низким разрешением, а потом использовать
эту прискиненную модель как Wrap-деформер для модели высокого разрешения. Кости будут гнуть
низкополигональную модель, а та, в свою очередь, будет деформировать высокополигональную.
Преимущество такого подхода состоит в том, что настроить скининг на низкополигональной модели
гораздо проще и быстрее.

Кроме того, к непрямому скинингу можно отнести механизм Influence Objects (или, как
говорят майщики, «инфлюенсы», то есть влияющие объекты). Когда, в дополнение к скинингу,
на поверхность модели могут также влиять своей формой дополнительные объекты. Именно так
делаются мышечные деформации. К этому мы еще вернемся. А сейчас, чтобы «потрогать руками»
скининг, сделайте простое упражнение.

Создание скининга
Откройте файл skinLeg.ma. В нем содержится часть тела и кусочек скелета.
Выберите поверхность и верхний сустав Leg.
Выполните Skin=>Bind Skin=>Smooth Bind.
Выберите группу LGroup (для этого есть специальный «хендл») и пошевелите ногой. Как
видите, нога гнется с помощью костей (можете также выбирать подгруппы внутри LGroup и вращать
соответствующие части ноги).

У большинства населения планеты тут же неизбежно возникнут вопросы: почему мы


воспользовались методом Smooth Bind и зачем существует на свете метод Rigid Bind?

Рискуя шокировать «майскую» общественность, я не буду рассказывать ничего конкретного


про метод Rigid Skin. Он морально устарел и используется относительно (если не сказать,
абсолютно) редко. Я опросил значительную часть «сетапщиков», и они лишь подтвердили этот
факт. (Не исключаю, правда, что где-нибудь, конечно же, существуют фэн-клубы Rigid Skin, и
потому заранее прошу их не подавать на меня в суд.)

838 Книга Сергея Цыпцына


Методы мягкого и жесткого скининга
Теперь попробую рассказать про оба метода «на пальцах», прежде чем окончательно
забыть Rigid Bind. Глядя на то, как кости деформируют поверхность, попробуйте представить себе
простейший алгоритм, по которому они это делают (если вы слишком просвещены, сделайте вид,
что забыли все известные алгоритмы). Первое, что приходит на ум -каждая кость тащит за собой
«свои» вершины. То есть все вершины прискиненной поверхности разбиваются на эксклюзивные
наборы (сеты), каждый из которых находится под влиянием «своей» кости, то есть перемещается
вслед за ней. Это и есть алгоритм Rigid Bind! Он прост, вычислительно легок, но результат его
работы довольно средний. Ведь возникают многочисленные самопересечения и заломы в тех
местах, где вершины, «ведомые» соседними костями, начинают проникать друг сквозь друга.
Попробуйте снова открыть файл skinLeg.ma и привязать поверхность к скелету методом Rigid Bind.
Согните ногу и полюбуйтесь на результат.

Для корректировки этих проблем существует множество «подпорок» типа флексоров (Flex­
ors) и разных ухищрений. Конечно, веса вершин, на которые влияет та или иная кость, можно
редактировать и сами вершины можно переносить «от одной кости к другой» с помощью Edit Mem­
bership Tool, однако тот факт, что каждая вершина может находиться под влиянием только одной
кости, является самым существенным ограничением технологии Rigid Bind. Возможно этот метод
может быть эффективен в том случае, когда к костям привязывают не поверхности, а решетки
Lattice, так как редактирование весов небольшого количества вершин решетки не будет сложной
задачей. Однако на этой оптимистической ноте я и закончу с методом Rigid Bind.

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


после привязки скелета к поверхности методом Smooth Bind на каждую вершину поверхности
влияют ВСЕ кости скелета!! Только с разными весами.

Действительно, на вершины под коленкой соседние кости влияют «согласованно», то есть


эти вершины перемещаются под влиянием обеих костей.

Разумно предположить, что чем дальше кость от данной вершины, тем меньше эта кость на
нее влияет. Разумно также предположить, что рассчитывать влияние всех костей на все вершины
довольно долго, поэтому проще ограничить число костей, одновременно влияющих на каждую
вершину некоторым числом: например, 5.

Персонажная анимация 839


Таким образом на вершины «под коленкой» влияют сразу пять костей, однако «реально»
влияют только две ближайшие кости. «Реально» - это значит, что веса этих двух костей значительно
больше весов влияния остальных костей. В этом нетрудно убедиться, выбрав несколько вершин в
месте сгиба и открыв Component Editor. Там в закладке Smooth Skins будут показаны веса пяти (!)
костей, влияющих на выбранные вершины.

Обратите внимание на то, что веса остальных костей, хотя и маленькие, но ненулевые,
то есть существует влияние пяточной кости на место сгиба под коленкой! Это побочный эффект
«интеллектуальности» метода Smooth Bind. Конечно, при выполнении операции Smooth Bind
можно подобрать параметр Dropoff Rate, влияющий на то, как далеко может влиять кость на
близлежащие вершины, однако застраховаться от появления маленьких весов (влияния пятки на
колено) заранее невозможно. Для «вычищения» таких маленьких зловредных весов была даже
придумана специальная операция Skin=>Edit Smooth Skin=>Prune Small Weights (prune=урезать),
удаляющая все веса меньше указанного в Option Box со всех вершин поверхности (или только с
выбранных вершин).

Примечание. Я все время говорю (и буду говорить) о привязке поверхности, однако


вы должны помнить: привязать к костям можно не только поверхность, но и
кривую и Lattice. Были бы вершины.

Примечание. Как вы уже заметили, в этом разделе я все время говорю «кости»
и очень редко «суставы». Дело в том, что в процессе привязки принимаются во
внимание именно «кости», то есть прямые линии между соседними суставами.
Расстояние до вершин рассчитывается до ближайшей кости (линии), а не до
ближайшего сустава (точки). Помните, однако, что с точки зрения объектов в
сцене «кости» и «суставы» - одно и то же. Я также буду все время перемешивать
термины «привязка», «привязывать» и «скининг», «прискинить». Все это одно и
то же.

Параметры операции Smooth Bind

Поэкспериментируем, чтобы лучше понять суть метода Smooth Bind.


Снова откройте файл skinLeg.ma.
Выберите поверхность и верхнюю кость.
Откройте Option Box операции Skin=>Bind Skin=>Smooth Bind.

840 Книга Сергея Цыпцына


Параметр Bind to особых экспериментов не требует: либо вы привязываете поверхность
только к выбранным костям (Selected Joints), либо ко всему скелету целиком (Joint Hierarchy),
даже если вы выбрали одну из промежуточных костей. Вариант Object Hierarchy позволяет сделать
привязку поверхности не только к костям, но и к иерархии из локаторов или пустых групп (в этой
иерархии не должно быть деформируемых объектов).

Параметр Bind Method вам вряд ли придется когда-нибудь менять. Значение по умолчанию
Closest In Hierarchy задает, что в процессе привязки будет учитываться положение каждой кости
в иерархии скелета. К примеру, несмотря на то, что кость левой пятки расположена очень близко
к поверхности правой пятки, она не будет влиять на нее после привязки, так как находится очень
далеко в иерархии скелета от кости правой пятки, которая является ближайшей к поверхности
правой пятки. Аналогично, если рука в момент привязки окажется около бедра, кости руки не
будут влиять на бедро, так как в иерархии скелета они находятся далеко от костей бедра. Значение
Closest Distance определяет игнорирование иерархии скелета и задает привязку только на основе
пространственной близости костей к вершинам.

Поэкспериментируйте с параметром Dropoff Rate. Задайте его равным 0.1 и нажмите Apply. Теперь
выберите несколько вершин под коленом и откройте Component Editor.

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

Выберите поверхность и «отвяжите» ногу от костей с помощью операции Skin=>Detach Skin.


Если нога была согнута, поверхность тут же распрямится. Пытливые умы, конечно, не могли не
заметить в Option Box операции Detach Skin опцию Delete History, благодаря которой происходит
удаление деформаций с поверхности.

Если выбрать вариант Bake History, нога останется, очевидно, в деформированном


положении, после того как кости «отвяжутся» от поверхности.

Опция Keep History может быть полезна, если вы хотите отвязать кости, не удаляя,
однако, информацию о весах (еще точнее, не удаляя ноду skinCluster). Это имеет смысл, когда вы
хотите добавить пару костей с скелету и привязать его обратно к поверхности с сохранением уже
настроенных весов.

Персонажная анимация 841


Разогните кости и снова привяжите ногу к костям, задав при этом Dropoff Rate=10.
Выберите снова вершины под коленом и откройте Component Editor.

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

В случае ноги этот вариант явно предпочтительнее, кроме того форма сгиба стала более
«резкой», поэтому имеет смысл увеличивать Dropoff Rate для «острогнущихся» конечностей.

Кроме того, очевидно, что в большинстве случаев хватит влияния только двух костей
на ближайшие точки, а остальные кости могут только вносить путаницу. Поэтому имеет смысл
задавать в Option Box значение Max lnfluences=2. Если понадобится, позже вы можете добавить
влияние дополнительных костей на нужные участки поверхности, редактируя скининг. Для этого
надо либо заранее выключить галку Maintain Max Influences в Option Box, либо позже снять ее
в Attribute Editor для ноды skinCluster, чтобы MAYA не пыталась ограничивать влияние только
фиксированным количеством костей.

Педантичные умы могут отвязать кости и, задав Max lnfluences=2, привязать их обратно, а
далее убедиться, что на любые вершины влияют только две кости.

После того, как вы создали привязку, резонно задуматься об ее редактировании.


Однако перед тем, как переходить к способам редактирования, сделаю несколько технических
замечаний.

Нормализация весов
Как хорошо видно в Component Editor в колонке Total, MAYA удерживает равным единице
суммарный вес костей, влияющих на каждую вершину. Если вы вручную (или в результате раскраски
весов) увеличите для какой-нибудь вершины вес одной кости, веса остальных автоматически
уменьшатся (в соответствии с расстоянием до этих костей).

В принципе это вполне разумное ограничение, позволяющее избегать сильного разброса в


значениях весов костей. Однако если вам для каких-то личных целей и экспериментов захочется
снять это ограничение, вы можете сделать это, разыскав в Attribute Editor ноду skinCluster и
отключив галку Normalize Weights. Этого же можно добиться с помощью соответствующих команд
в меню Skin=>Edit Smooth Skin.

842 Книга Сергея Цыпцына


Нода skinCluster и tweak
Если для каждого деформера существует «своя» нода, отвечающая за деформации
именно этого типа, то для скининга такой нодой является skinCluster. Эта нода создается всегда
и кроме того, что хранит в себе все веса всех костей для всех точек, имеет еще массу полезных
атрибутов. Например, вы можете поменять максимальное количество одновременно влияющих
на вершины костей с помощью атрибута Max Influences. Те, кто без отвращения умеет ковыряться
во внутренностях MAYA, смогут разглядеть в Hypergraph, что skinCluster является полноценным
деформером, так как находится в дереве зависимостей между оригинальной формой объекта
(ShapeOrig) и результирующей формой.

На выходе skinCluster - атрибут outputGeometry, содержащий описание деформированной


геометрии и подключенный к атрибуту create (для NURBS) или inMesh (для полигонов). Как и для
всех деформеров, вместе с skinCluster всегда создается нода tweak - для того, чтобы корректно
обрабатывать ручное редактирование прискиненной геометрии. Подробнее про ноду tweak
вы можете прочитать в главе про изнанку MAYA. Здесь лишь намечу, что, как следует из Hy­
pergraph, нода tweak располагается в истории ПЕРЕД нодой skinCluster, поэтому если вы будете
тянуть за вершины уже прискиненной и согнутой поверхности, точки будут перемещаться не в том
направлении, куда вы их тянете, ведь после ваших перемещений на вершины еще накладывается
деформация. Вы, конечно, можете поменять порядок деформаций (то есть поменять местами
tweak и skinCluster), однако я не советую вам этого делать: результат конечной деформации будет
непредсказуем.

А советую подумать над следующим трюком. Согнув конечность, вы можете исправить


возникшие «косяки», просто потаскав поверхность за вершины. Однако, разогнув конечность
обратно, хочется, чтобы результат такого редактирования обнулился. В этом случае может помочь
вездесущая функция Set Driven Key. Можно создать зависимость между углом сгиба костей и
атрибутом envelope для ноды tweak. В разогнутом положении envelope должен быть равен нулю,
а в согнутом - единице.

Поза привязки: Bind Pose


Пытливые умы конечно заметили, что для выбранных костей привязанного скелета в At­
tribute Editor появляется нода bindPose. Когда MAYA делает привязку поверхности к костям, она
сохраняет информацию о том, в какой позе была сделана привязка. Это поза используется как
«точка отсчета» для вычисления деформаций. Вы всегда можете вернуться в эту позу с помощью
операции Skin=>Go to Bind Pose (или MAYA может вас попросить об этом для выполнения некоторых

Персонажная анимация 843


операций). Однако если на костях персонажа уже находятся элементы управления типа IK Handle
или expression, они будут препятствовать такому вращению костей, a MAYA будет вас приветствовать
сообщениями типа:

// Warning: file: С:/Program Files/Alias/Maya7.0/scripts/others/gotoBindPose.mel line 45: Could not


reach pose on Left_Hip rotate. //
// Warning: file: C:/Program Files/Alias/Maya7.0/scripts/others/gotoBindPose.mel line 45: Could not
reach pose on Left_Knee rotate. //
// Warning: file: C:/Program Files/Alias/Maya7.0/scripts/others/gotoBindPose.mel line 45: Could not
reach pose on Left_Ankle rotate. //
// Warning: file: C:/Program Files/Alias/Maya7.0/scripts/others/gotoBindPose.mel line 45: Skipped
pose on locatorl due to new parent. Parent when pose was saved was world. //
// --To ensure pose is correct below this joint, add an extra transform above this joint, restore
the old parent or manually position the joint to the correct bindPose.

// To disable IK, constraints, and expressions, you can use the Modify->DisableNodes menu.

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


отключить все препятствующие вращению костей объекты и после этого повторить попытку встать
в Bind Pose.

Отключить мешающие объекты одним махом можно с помощью меню Modify=>Evaluate


Nodes=>lgnore All/Evaluate All. После этого операция Go to Bind Pose теоретически должна работать
без проблем.

Редактирование скининга. Paint Skin Weights Tool


Наивно думать, что у вас получиться с первого раза прискинить свою модель к скелету.
Очевидно, что придется как-то редактировать получившийся после первоначальной привязки
результат. Инструментов редактирования скининга может быть несколько.

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

Во-вторых, есть MEL-команда skinPercent, которую мы не будем рассматривать.

В-третьих, можно добавить к поверхности модели так называемые «инфлюенсы», о которых


речь пойдет чуть позже.

Ну, и, наконец, в-четвертых, это инструмент Paint Skin Weights Tool, позволяющих красить
поверхность модели весами выбранных костей. О нем и пойдет речь сейчас.

Я думаю, многие аналитические умы, едва речь пошла о весах, сразу задумались о
возможности рисовать этими весами вдоль поверхности. Действительно инструмент Paint Skin
Weights Tool подобен всем остальным «рисовальным» инструментам. Его отличительная особенность
- необходимость сначала указать кость, а затем рисовать карту влияния именно этой кости.

Итак, откройте все же уже поднадоевший вам файл skinL.eg.ma и привяжите поверхность
к скелету со следующими параметрами: Maxlnfluences=2, Dropoff Rate=5, Maintain Max
lnfluences=On.

Согните ногу в колене. Так как мы задали довольно высокий Dropoff Rate, то граница
влияния соседних костей довольно «резкая» под коленкой.

844 Книга Сергея Цыпцына


Сгиб под коленом почти идеален, однако для тех случаев, когда хочется немного
«расправить», займемся раскраской весов.

Теперь выберите поверхность и возьмите в руки инструмент редактирования скининга


Skin=>Edit Smooth Skin=> Paint Skin Weights Tool.

He забудьте открыть Tool Settings для этого инструмента и нажать в нем кнопку Reset Tool.
В разделе Influence находится список костей, влияющих на выбранную поверхность. Щелкая по
названиям костей, вы можете видеть области их влияния.

Чтобы немного примять верхнюю часть икры, мы не будем уменьшать влияние кости Left_
Knee, а будем увеличивать влияние вышестоящей кости LeftJHip.

Выберите в списке Influence кость Left_Hip.

Задайте Paint Operation=Add, а значение Value=0.05.

Покрасьте область непосредственно под коленкой со стороны икры.

Персонажная анимация 845


Таким образом мы будем добавляем значение 0.05 веса кости LeftJHip в области под
кисточкой. В соответствии с принципом нормализации, MAYA одновременно вычитает в этой области
значение 0.05 из веса нижней кости Left_Knee. Поэтому влияние нижней кости уменьшается.
Теперь выберите Paint Operation=Smooth и покрасьте всю отредактированную область.

Совет. Всегда «разравнивайте» только что сделанные изменения с помощью


операции Smooth. Исключение составляют заливка черным или белым цветом.

Если вы хотите уменьшать текущее значение веса, задавайте Paint Operation=Scale, a Val-
ue=0.95. Если нужно совсем избавиться от влияния кости на некоторый участок (это часто случается
в области подмышек), то следует установить Paint Operation=Replace, Value=0 и покрасить этот
участок в черный цвет.

Совет. Если вы совсем «расколбасили» свою модель безумной раскраской весов,


вы всегда можете вернуться к начальной расстановке весов с помощью операции
Skin=>Edit Smooth Skin=>Reset Weights to Default. Бывает удобно выложить эту
операцию на полку.

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

Иногда бывает нужно «заморозить» или зафиксировать раскраску весов для выбранной
кости. Для этого предназначена кнопка Toggle Hold Weights On Selected. Нажав ее, вы гарантируете,
что черно-белая карта весов для выбранной кости не будет изменяться при покраске областей
влияния соседних костей.

Фиксируя карту влияния какой-нибудь кости с помощью кнопки Toggle Hold Weights On
Selected, следует, однако, помнить, что тем самым вы накладываете ограничение на изменение
области влияния для других костей. Если на раскрашиваемую область влияют три кости, то
заморозив карту весов для одной из них, вы будете перераспределять веса между оставшимися
двумя.

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

В самом деле, выберите в списке Influence кость Left_Hip и нажмите кнопку Hold Weights
On Selected.

Теперь выберите в списке кость Left_Knee и попробуйте покрасить белым цветом (Paint
Operation=Replace, a Value=1) область выше колена.

846 Книга Сергея Цыпцына


Несмотря на то, что поверхность исправно красится в белый цвет, никакого изменения
формы не происходит. Более того, выбрав в списке какую-нибудь другую кость и вернувшись обратно
к Left_Knee, вы увидите, что все изменения будут потеряны. И это совершенно предсказуемо,
ведь область выше колена находится в основном под влиянием кости Left_Hip, чья карта влияния
«заморожена».

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

Совет. Часто бывает удобнее прямо на экране, а не в списке выбрать кости, чье
влияние хочется покрасить. Для этого надо просто нажать над нужной костью
правую кнопку мыши и выбрать в контекстном меню Paint Weights.

Если же во время рисования щелкнуть в окне средней кнопкой мыши, вы попадете в


режим «временного вращения». Появится вращательный манипулятор над той костью, которая
была выбрана в списке. Далее вы можете крутить эту кость опять же средней кнопкой мыши и
даже перемещаться по иерархии скелета стрелками вверх и вниз. Для того, чтобы вернуться в
режим покраски, достаточно щелкнуть левой кнопкой мыши над поверхностью.

Добившись приемлемого результата, сохраните сцену как skinLegPainted.ma.

Объекты влияния: Influences


Кости скелета могут быть не единственными объектами влияния на поверхность модели. В
принципе все деформеры, назначенные на модель до или после скининга, могут рассматриваться
как объекты влияния, однако, в соответствии с майской традицией, таким образом обычно
называют объекты, добавленные к скинингу уже после привязки с помощью операции Add Influ­
ence.

Идея следующая: вы берете поверхность, кривую или локатор и назначаете ее как объект
влияния («инфлюенс») для уже прискиненной поверхности. После этого все перемещения и даже
деформации объекта влияния будут влиять на модель. Внешне это ничем не отличается от Wrap
Deformer, с тем исключением, что после этого можно красить веса влияния не только костей, но и
назначенного объекта влияния.

Откройте только что сохраненную сцену skinLegPainted.ma.

Теперь импортируйте в нее же файл skinMuscle.ma. В сцене появится сплайновая сфера.


Если ее выбрать, то можно обнаружить, что в ее истории находится деформация типа BlendShape,
превращающая сферу в подобие сокращающейся мышцы.

Переместите сферу внутрь бедра.

Выбрав сферу, выберите также сустав LeftJHip и выполните операцию Edit=>Parent, чтобы
сфера «прикрепилась» к бедру и двигалась вместе с ним.

Совет. Используйте режим Shading=>X-Ray.

Откройте окно Set Driven Key.

Персонажная анимация 847


В верхнюю часть загрузите кость Left_Knee, а в нижнюю ноду blendShape1 (чтобы сделать
это, надо выбрать сферу, затем в Attribute Editor открыть закладку blendShapel, потом нажать в
нижней часть Attribute Editor кнопку Select, и к конце концов нажать кнопку Load Driven в окне Set
Driven Key).

Управляющий атрибут будет Left_Knee.rotateZ, а управляемый blendShape1.Muscle1,


чтобы сгибание в колене вызывало деформацию сферы.
Нажмите кнопку Key, пока нога не согнута.
Теперь согните ногу, потянув за IK Handle.

Выберите в окошке Set Driven Key ноду blendShapel и установите в Attribute Editor для нее
Muscle1=1.

Нажмите кнопку Key снова при согнутой ноге и деформированной мышце.


Теперь вы имеете подобие мышцы, деформирующейся в процессе сгибания ноги.

848 Книга Сергея Цыпцына


Осталось сделать так, чтобы мышца влияла на поверхность ноги.
Прежде всего, лучше будет вернуться в Bind Pose, это можно сделать, просто вернув IK
Handle в нулевое положение.

Выберите поверхность ноги, а затем мышцу (порядок важен) и откройте Option Box операции
Skin=>Edit Smooth Skin=>Add Influence.

Установите Dropoff=5. Более высокие значения задают область влияния с резкими


границами, более низкие размытую и более широкую область влияния.

Галка Use Geometry по умолчанию включена и означает, что добавляемая к скинингу мышца
будет влиять на поверхность ноги не только своими трансформациями, но и деформациями, то
есть изменениями формы.

Опция Lock Weight может быть полезна в том случае, если вы долго мучились с настройкой
скининга и теперь не хотите потерять тщательно нарисованные области влияния всех костей. Надо
понимать, что добавляя объект влияния, мы «втискиваем» его в уже имеющееся распределение
весов. Если нажать галку Lock Weights, то новый инфлюенс будет добавлен с нулевым влиянием, и
его веса будут заморожены, до тех пор пока вы не отожмете кнопку Toggle Hold Weights On Selected
в инструменте Paint Skin Weights Tool.

Оставьте галку Lock Weights выключенной и нажмите кнопку Add.

Сфера добавилась как объект влияния, в чем можно убедиться, выбрав ее и обнаружив у

Персонажная анимация 849


нее в истории ноду skinCluster1.

Однако никакого влияния она, похоже, не оказывает. Впрочем, если сферу немного
помасштабировать, станет ясно, что влияние все-таки есть, но только вследствие трансформаций
- а вот деформации, вызванные сгибанием ноги, не оказывают никакого влияния. В чем же дело,
ведь мы специально оставили галку Use Geometry включенной?!
Оказывается, надо включить еще одну, секретную галку.
Разыщите в Attribute Editor закладку skinClusterl и включите там опцию Use Components.
После этого все объекты влияния будут передавать поверхности также свои деформации.

Примечание. Никто не запретит вам добавлять инфлюенсы в произвольной позе, а


не только в Bind Pose. Однако будьте внимательны: могут появиться неожиданные
деформации в момент добавления объекта влияния, вызванные тем, что согнутая
конечность уже имеет деформации, вызванные костями, а добавление инфлюенса
по умолчанию перераспределяет веса в области его влияния. В этих случаях имеет
смысл использовать вариант Lock Weights.

Теперь, когда вы сгибаете ногу, все деформации сокращающейся мышцы передаются на


бедро. Однако если внимательно приглядеться, можно увидеть, что форма сгиба под коленом
пришла в полную негодность. Это результат того, что к скинингу добавился довольно большой
объект влияния со своим распределением весов, которые потеснили веса уже настроенных костей.
Вызвав инструмент Paint Skin Weights Tool, вы всегда можете увидеть объект влияния в списке In­
fluence и отредактировать его область влияния.

Практический совет: Перед тем, как настраивать скининг, добавьте к нему


все уже готовые объекты влияния и лишь потом настраивайте все области
распределения весов. Ниже будут приведены и остальные практические советы
от Миши Бажуткина.

850 Книга Сергея Цыпцына


Назначение и использование объектов влияния.
Некоторые анатомические и философские аспекты
мышечных деформаций.
Конечно, первое, что приходит в голову по поводу объектов влияния, это использование
их в качестве симуляции мышечных деформаций. Как вы понимаете, приведенный пример с
использованием Blend Shapes не исчерпывает все возможные трюки. Объекты влияния могут
просто масштабироваться или перемещаться «под кожей», могут быть деформированы не только
морфингом и т.д.

Кроме того, объекты влияния могут быть использованы не только для «вспучивания»
поверхности в нужных местах. Используя кривые как инфлюенсы, вы можете делать складки кожи
или подобие крупных морщин.

Еще одно применение инфлюенсов - предотвращение ненужных «заломов», или


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

Объекты влияния не являются единственным лекарством. Вы можете использовать


кластеры, решетки Lattice и все остальные деформеры, чтобы добиваться нужных эффектов при
сгибании костей. Вам следует только позаботиться о том, чтобы закрепить деформер на скелете,
например, с помощью операции parent. Как правило, функция Set Driven Key позволяет задать все
необходимые зависимости между сгибанием костей и атрибутами деформера, чтобы добиться
автоматических деформаций.

Конечно, главный недостаток такого подхода - отсутствие анатомически правильного


набора мышц и их влияния на поверхность кожи. Можно, конечно, попытаться симулировать
основные мышцы, как было описано выше, но, как вы понимаете, такое решение с парой сотен
объектов влияния будет, мягко говоря, громоздким и тяжело настраиваемым. В этой связи разумно
ожидать, что уже существуют (или вот-вот появятся) соответствующие плагины, скрывающие
внутри себя всю «анатомическую кухню» и предоставляющие удобный интерфейс для работы с
мышечными информациями, а также адекватную производительность.

На данный момент могу отметить наиболее известные мускульные решения.

Это прежде всего Comet Muscle System (http://www.cometdigital.com/cMuscleSystem.


php). Его отличительная особенность - возможность конвертировать уже настроенный скининг с
майскими объектами влияния в систему управления мышцами, используемую самим плагином.
Это позволяет не «выбрасывать» уже настроенные персонажи.

Еще одно решение - это Muscle TK (http://www.cgtoolkit.com/muscletk.htm), оно


отличающееся очень резвой производительностью и остроумным интерфейсом.

Здесь же следует отметить отечественную разработку LifeStudio:Head (http://www.life-


mi.com), использующую «мускульный» подход для анимации лица. Анатомический правильный
набор макромускулов позволяет реалистично управлять мимикой, объединять мускулы в группы,
задавать области влияния мускулов.

Персонажная анимация 851


Копирование весов
Изрядно помучившись с раскрашиванием весов для правой руки или ноги персонажа,
вы рано или поздно задумаетесь о том, нельзя ли скопировать уже отредактированные области
влияния с одной стороны персонажа на другую. Тем более после того, как вы обнаружите, что
опция симметричного рисования (Reflection Paint) для данного инструмента отсутствует (и по
вполне понятным причинам - ведь кость влияния может быть выбрана только одна).

Для этих целей существует специальная операция Skin=>Edit Smooth Skin=>Mirror Skin
Weights. Она позволяет скопировать веса вершин с одной стороны поверхности на другую. Если
«кожа» персонажа состоит из нескольких поверхностей, копирование может быть произведено
с одной поверхности на другую, надо их выбрать в нужном порядке. Можно также симметрично
скопировать веса только выбранных вершин.

Следует понимать, что зеркальное копирование весов производится без всякого анализа
топологии поверхности: MAYA просто ищет в пространстве точки, симметричные относительно
выбранной в Option Box плоскости, и копирует их веса в выбранном направлении. Однако анализ
топологии скелета все же производится. Поэтому перед зеркальным копированием вы должны
позаботиться о том, чтобы ваш персонаж находился в симметричной позе и чтобы его скелет тоже
был симметричен относительно нужных плоскостей.

Но если можно скопировать веса с одной части персонажа на другую, то можно и копировать
их между персонажами. Для этого есть операция Skin=>Edit Smooth Skin=> Copy Skin Weights.
Очевидно, что эта операция будет хорошо работать только для весьма похожих персонажей.

Во-первых, скелеты таких персонажей должны иметь одинаковую иерархию. Конечно,


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

Во-вторых, персонажи должны быть примерно одинакового размера, ведь копирование


весов производится примерно так: для каждой исходной вершины в пространстве ищется
ближайшая вершина на той поверхности, куда переносятся веса.

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


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

В-четвертых, совершенно очевидно, что персонажи во время копирования должны стоять


в одинаковых позах.

Копирование весов позволяет экономить массу времени при настройке скининга. Многие
энтузиасты и технические директора пишут собственные скрипты для копирования, перемещения,
сохранения и восстановления весов вершин.

Сохрание и восстановление весов


Предположим, вы приблизительно настроили скининг, а теперь вы хотите отредактировать
его более подробно, но желаете сохранить текущую настройку как некоторый шаблон, к которому
можно вернуться позже. Можно, конечно, сохранить сцену и потом загружать ее снова. Однако
существует альтернативная возможность «сдирать» скининг и сохранять его на диске. Как нетрудно
заметить, распределение весов описывается черно-белыми картами, которые теоретически
можно сохранить на диске вместе с именами костей. Именно для этого предназначены капризные
операции Import/Export Skin Weights. Они позволяют сохранять и читать веса скининга с диска.

852 Книга Сергея Цыпцына


Очевидно, что таким образом можно переносить веса между совершенно разными по
размеру и пропорциям персонажами, которые стоят, к тому же, в разных позах. Скининг будет
переноситься при этом в виде текстур. Ниже я приведу пример использования этой возможности.
Главное ограничение данного подхода в том, что поверхности персонажей должны иметь
абсолютно одинаковый UV-Mapping, а для двух разных персонажей является чудовищно сильным
ограничением. Но в противном случае текстуры лягут в разные места поверхности, и перенос
весов будет некорректным.

Изучение чужих персонажей


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

Настройка скининга дело еще более индивидуальное. Кому-то нравятся объекты влияния,
кто-то предпочитает Sculp Deformer для мышц, а кто-то все делает с помощью tweaks и Blend
Shapes.

Бывает полезно взглянуть на чужих персонажей, чтобы выработать свой собственный


стиль. В Интернете есть достаточное количество уроков и примеров, однако я попросил Владимира
Панкратова, директора студии Пиастро (www.piastro.ru), предоставить для этой книжки какую-
нибудь коммерческую модель с настроенным скинингом, чтобы вы могли потерзать ее в домашних
условиях. Вот она:

Откройте файл trollSkin.ma.

Вокруг тролля расставлены пять хэндлов (один напротив пуза), чтобы удобнее было
выбирать нужные кости для тестирования скининга. Так как вся кинематическая «обвязка» с
тролля снята, гнуть его следует с помощью прямой кинематики, то есть вращая кости.

Погните тролля за руки (или за лапы?). Обратите внимание, что к костям прикреплены все
пять поверхностей из группы geometry.

В районе бицепсов находятся инфлюенсы - сферы, размер которых меняется через Set
Driven Key в зависимости от сгиба в локтях.

Персонажная анимация 853


Там же находятся два деформера типа Sculp. Причем влияют они не на руку (лапу), а на
щитки на предплечье. Это сделано для того, чтобы при сгибе в локтях, щитки не проникали сразу
в поверхность бицепсов, а деформировались при этом. Можете изменить размер этих деформеров
и усилить этот эффект.

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

Вопрос о том, как крепятся кольца на груди и спине, не касается скинига, поэтому вы
можете исследовать его самостоятельно, это довольно остроумное решение.

Вы наверняка захотите потренироваться в настройке скининга на таком красавце, однако,


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

Выберите поверхность тела (body_osnova) и выполните операцию Export Skin Weights. MAYA
попросит вас ввести имя нового файла. Задайте, например, skinBody и нажмите кнопку Export.

Появится предупреждение о том, что на диск будут записаны 99 текстур. Лучше будет
согласиться, после чего все эти текстуры довольно неторопливо запишутся на диск.

Примечание. Экспортируются веса только выбранных поверхностей. Если вы


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

Теперь вы можете выбрать поверхность тела и выполнить операцию Reset Weights to De­
fault, чтобы вернуться к скинингу по умолчанию. Это займет некоторое время.

Повращайте плечи и убедитесь, что скининг «сильно изменился». После этого попробуйте
с помощью инструмента Paint Skin Weights Tool настроить веса. В какой-то момент вам наверняка
захочется взглянуть на оригинальные веса. Вы можете это сделать, импортировав их обратно.

854 Книга Сергея Цыпцына


Выберите снова поверхность тела и выполните операцию Import Skin Weights.
Укажите файл bodySkin.weightMap и нажмите кнопку Import.
Насладитесь завораживающим процессом восстановления весов.

Внимание! Перед процессом импорта весов необходимо выйти из контекста инструмента


Paint Skin Weights Tool, иначе вы получите сообщение об ошибке.

Обратите внимание, что вместе с файлом skinBody.weightMap создается целая папка с


именем skinBody в которой, собственно, и хранятся черно-белые карты. А сам файл является
текстовым, его можно с любопытством почитать.

Примечание. Импортируются веса только для выбранных поверхностей. Если вы


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

Если вы решите полностью отодрать персонаж от скелета, в Option Box операции Detach
Skin выберите опцию Bake History, чтобы оставить все поверхности в текущем положении. Не
забудьте перед этим встать в Bind Pose и выбрать все поверхности из группы geometry.

Практические замечания по скинингу персонажей


Далее некоторые практические комментарии и некоторое количество советов начинающим
сетапщикам и таксидермистам - от Михаила Бажуткина.

1. Так как конечные суставы (например, на пальцах) не несут смысловой нагрузки в


процессе скининга, имеет смысл исключать их из набора костей, используемого для привязки.
По этой и по другим причинам для экономии времени во время настройки персонажа, создайте
Quick Select Set, в котором будут только кости, участвующие в скининге. Назовите его, например,
bindSet.

2. Тогда, для того, чтобы привязать модель к костям, вы можете выделять кости через
меню Edit => Quick Select Set => bindSet, а затем выбирать поверхность. При этом в окне Option Box
для операции Smooth Bind нужно установить значение Bind to=Selected Joints. Как следствие, нет
необходимости включать параметр Remove Unused Influences. К тому же, из-за того, что некоторые

Персонажная анимация 855


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

3. Не спешите раскрашивать веса костей после того, как вы совершили привязку операцией
Smooth Bind. На данном этапе имеет смысл сделать несколько тестов, которые вам ответят на
вопросы о том, правильно ли расставлены позиции суставов, и оптимальны ли были параметры
операции Smooth Bind. Ведь от того, насколько хорошо они были изначально подобраны для
вашей модели, в дальнейшем зависит количество часов, проведенных вами перед компьютером.
В своей работе я за основу тестов, как правило, беру пальцы рук персонажа, потому что их кости
самые маленькие. И подгоняя значение параметра Dropoff Rate (в окне Smooth Bind Options), я
смотрю, как при сгибании этих костей между ними распределяются веса. Чем меньше значение
Dropoff Rate, тем шире зона совместного влияния соседних костей, и в результате - неправильный
сгиб поверхности. Практика показывает, что проще изначально сделать границы влияния костей
контрастными (с помощью большого Dropoff Rate), а потом, если необходимо, сделать операцию
Smooth в Paint Skin Weights Tool. To же самое касается параметра Max Influences, которому для
базовой привязки, как правило, лучше давать значение 2, чтобы в области суставов смешивались
веса только двух костей. Более сложные взаимодействия костей (от трех и выше) лучше делать
вручную, раскрашивая их в Paint Skin Weights Tool. Исключением могут быть персонажи с длинными
цепочками костей, такие, как змеи, рыбы и другие твари с длинными шеями и хвостами.

4. Если вы готовите своего персонажа не для «игрового движка», не советую включать


параметр Maintain Max Influences. При включении этого параметра MAYA будет автоматически
обнулять малые веса костей так, чтобы влияющих костей для каждой вершины геометрии в сумме
было не более, чем указано параметром Max Influences. На практике во время рисования весов
возможны неприятные «перескоки» весов и геометрии, если модель в это время не стоит в Bind
Pose. При этом будет трудно добиться желаемого результата (а порой и невозможно). Если вы
боретесь за «чистоту» скининга, лучше после окончания редактирования весов применить операцию
Skin=>Edit Smooth Bind=>Prune Small Weights, которая обнулит малые веса костей. Этот параметр
(Maintain Max Influences) необходим в игровой индустрии, из-за того, что некоторые «движки» для
оптимизации имеют ограничение на количество костей (например, до трех), влияющих на каждую
вершину геометрии.

5. Если в процессе скининга, у вас появится необходимость добавить еще одну кость,
используйте операцию Skin=>Edit Smooth Skin=>Add Influence. В окне Option Box для операции Add
Influence выставьте Use Geometry=Off, Lock Weights = On, a Default Weight = 0. Это необходимо
для того, чтобы веса других костей не пострадали после добавления новой кости. Тоже самое
касается геометрического «инфлюенса», только в этом случае нужно включить опцию Use Geome­
try. Параметр Dropoff и Polygon Smoothness можно настраивать после того, как вы добавили объект
в скин-деформер. Для того, чтобы после такого добавления начать редактировать скининг, нужно
вызвать Paint Skin Weights Tool и в списке костей найти добавленную кость или инфлюенс-объект
(как правило, если список отсортирован по принципу «By Hierarchy», этот объект будет в конце
списка и в конце его имени будет в скобках пометка Hold). Затем, выделив его в списке, нажать на
кнопку Toggle Hold Weights On Selected, находящуюся под списком костей. Это снимет блокировку
весов выбранной кости или объекта, и можно будет их редактировать. Будьте внимательны, когда
вы добавляете геометрический инфлюенс-объект, не забудьте включить параметр Use Components
в атрибутах скин-деформера (skinCluster). Если он будет выключен, то, как бы вы ни «колбасили»
форму инфлюенс-объекта, вы не увидите никакой реакции со стороны деформера. Деформер
будет реагировать только на трансформации инфлюенса.

6. Как правило, после того как вы уже имеете прискиненную поверхность, нужно
отредактировать веса костей и, может быть, инфлюенса. И это можно сделать не только в Paint
Skin Weights Tool. Если выделить кость, участвующую в скининге, и открыть Attribute Editor, то там
можно увидеть внизу новую закладку Smooth Skin Parameters.

856 Книга Сергея Цыпцына


Для костей там будет параметр Dropoff, а для геометрического инфлюенса еще и параметры
NURBS Samples (если это NURBS-объект) или Smoothness (если объект полигональный). Обратите
внимание, что это не атрибуты объекта, а альтернативный инструмент редактирования весов и
параметров скин-деформера. После изменения этих параметров нужно нажимать кнопку Update
Weights. Мне представляется, что наибольшая ценность этой закладки как раз в том, что можно
менять параметры геометрического инфлюенса. Только для того, чтобы не сбились веса, так
тщательно нарисованные вашей рукой, нужно включить галку Hold Weights. Все дело в том, что
веса инфлюенса и его параметр (например, Smoothness или NURBS Samples) - это не одно и тоже.
Вес определяет зону, где поверхность подчиняется геометрическому инфлюенсу, а не костям, а
параметр - это характеристика того, как инфлюенс действует на поверхность, по аналогии с Wrap-
деформером. Ведь геометрический инфлюенс - это тот же Wrap-деформер, только включенный в
скининиг, с возможностью распределения его зоны влияния среди других костей.

7. А для того, чтобы добавить в скининг не одну, а сразу несколько костей, я использую
другой способ. Хитрость этого метода в том, что он использует одну уникальную способность
скин-деформера - временно отключаться, оставаясь при этом в истории объекта. Для этого все
новые кости надо добавить в наш ранее созданный bindSet. Затем надо выбрать прискиненную
поверхность и выполнить Skin=>Detach Skin с параметром History = Keep History (для того, чтобы
не потерять скин-деформер (skinCluster) с уже отредактироваными весами - это тот самый,
волшебный параметр, котрый был заявлен еще в документации к MAYA версии 4.5, а заработал
лишь в версии 5.0). Затем выбираем Edit=>Quick Select Sets=>bindSet, поверхность и Skin=>Bind
Skin=>Smooth Bind, с тем же параметром Bind to=Selected Joints. Тогда мы получим поверхность,
которая будет прискинена и к «старым» и «новым» костям. Причем новые кости «приедут» в наш
скининг с нулевыми весами, а веса «старых» костей не пострадают после этой операции.

8. Для того, чтобы было удобно настраивать веса скининга и одновременно тестировать
его, рекомендую использовать следующий прием. Поставьте ключи в нулевом кадре на все ваши
контрольные объекты, управляющие персонажем, и тем самым зафиксируейте базовую позу
персонажа. В последующих кадрах вы выставляете своего персонажа в другие позы, при которых
удобно проверять работу скининга, например, когда согнуты рука и нога, повернуты голова и шея.
И в процессе рисования весов вы просто двигаете мышью по Timeline между ключевыми позами,
не выходя из инструмента Paint Skin Weights Tool. Попробуйте, это действительно удобно!

9. При раскраске скининга я обычно пользуюсь режимом Replace со значением 1,


периодически изменяя параметр Opacity. Так, на мой взгляд, получается быстрее и меньше
«грязи» в весах на граничных областях, где смешиваются веса нескольких костей. Но если
рисовать вес со значением 0, вы рискуете тем, что в весах могут накопиться непредсказуемые
погрешности. Ведь при уменьшении веса выбранной кости, веса остальных костей, даже с очень
малым влиянием, автоматически увеличиваются. Это происходит из-за того, что в MAYA введен
механизм нормализации, который автоматически корректирует веса так, чтобы их сумма для
каждой вершины геометрии была равна единице. Поэтому лучше рисовать веса со значением 1,
меняя только значения Opacity. Чем меньше это значение, тем качественнее можно проработать
скининг. Использование планшета только приветствуется, потому что в этом случае прозрачность
кисти регулирует не только параметр Opacity, но и сила давления на перо. А для уменьшения веса
кости, лучше выбрать соседнюю кость и увеличить ее влияние.

10. Для чего нужны режимы Add и Scale при редактировании весов в Paint Skin Weights Tool?
Add прибавляет данное значение (Value) к имеющемуся весу выбранной кости, a Scale умножает
на него. Внимательные умы могут заметить, что, добавляя и умножая вес, можно легко выйти за
единичный или нулевой (максимальный и минимальный) диапазоны. Но так как есть параметр-
ограничитель Min/Max Value, можно не боятся этого и использовать эти режимы совместно с
режимом Replace. Есть случай, когда имеет смысл на время выйти из нормального (от 0 до 1)
диапазона. Правда, это уже относится к cluster-деформеру. Бывают в практике случаи, когда нужно
инвертировать вес кластера, то есть то, что было 0, превратить в 1, а то, что было 1 - в 0. В этом
случае можно обойтись средствами Paint Attributes Tool. Для начала мы установим значения Min
Value=-1 и Value= - 1 , выставим режим Scale и нажмем кнопку Flood. Эта операция умножит все веса
кластера на - 1 . Не пугайтесь того, что поверхность стала вся черной, это не от того, что все веса
обнулились, а от того, что они перешли в диапазон от -1 до 0. Вторичное нажатие на Flood может
вернуть веса в исходное значение. (А для пытливых умов в закладке Display имеется возможность

Персонажная анимация 857


изменять диапазон отображаемых весов.) Итак, теперь нам осталось сдвинуть вправо на единицу
инвертированные веса. Для этого поставим Value = 1, режим - в Add и снова нажмем Flood. Теперь
влияние кластера на геометрию стало противоположным исходному значению.

11. Многие пользователи сталкиваются с проблемой, когда при попытке привязать к


костям еще одну поверхность, программа выдает следующую ошибку:

Error: Skin on jointX was bound at a different pose. Go to the bindPose to attach new skins.

Эта операция невозможна, потому что скелет должен находиться в той же позе, что при
предыдущей привязке. Дело в том, что MAYA во время операции Smooth Bind создает ноду bind­
Pose для того, чтобы запомнить и сохранить позу привязки (Bind Pose), и в дальнейшем, при
повторении операции привязки, она проверяет текущую позу на соответствие уже запомненной.
Поэтому необходимо возвратить скелет в уже существующую позу для привязки. Если у вас не
была сохранена эта поза (в виде ключей на управляющих объектах или в виде позы в Visor), можно
воспользоваться командой Skin=>Go to Bind Pose. Но иногда MAYA «упирается» и отказывается это
сделать! Я не буду останавливаться на вопросе «почему?», а лучше расскажу, как поступить в этом
случае. Есть в MAYA MEL-команда dagPose, которая поможет нам сделать «reset» bind-позы, то есть
сделать Bind Pose из текущей позы. В некоторых случаях это даже нужно делать. Например, когда
вы привязываете тело к скелету в позе «звезды» (так лучше делать для облегчения настроек всех
сгибов), а обувь в позе, когда ноги стоят на «земле», носками вперед. Перед тем, как запустить
команду, нужно выбрать все те кости, для которых она будет выполняться. А вот, собственно, ее
формат:

dagPose -reset -name bindPosel;

Обратите внимание на то, что имя bindPose-ноды (в конце команды) может меняться: bindPose2,
bindPose3 и т.д. Это происходит потому, что MAYA создает новую bindPose-ноду всякий раз, когда
вы привязываете геометрию к разным скелетным «цепочкам», или в случае изменения в уже
существующей цепочке, например, при добавлении новых костей в имеющийся скелет.

Дополнительные кости и раскладывание вращения на сгиб и


скручивание для корректного скининга
Так исторически сложилось, что в результате некоторых автоматизируемых действий в
MAYA мы получаем сложное вращение суставов сразу по трем осям. К этим действиям относятся
решение IK солвера и результат работы Orient, Aim и Parent Constraints. Всем хорошо известно, что
при создании простого IK руки мы получаем сразу два таких сустава: предплечье и запястье. Именно
в этих местах скининг ведет себя наиболее омерзительно, скручивая поверхность персонажа в
точку.

Правильным решением этой проблемы будет разбиение сложного «ball»-вращения на два


простых. А именно, на направляющее (aim) и скручивающее (twist). Это даст нам возможность,
во-первых, сделать более корректный скининг, а во-вторых, использовать полученный
«скручивающий» twist-угол для последующего использования в деформациях персонажа. Ведь
такие проблемы встречаются не только в руках и ногах, но в позвоночнике, длинной шее и прочих
костных цепочках.

Причем абсолютно неправильно пытаться разделить вращение путем соединения отдельных


атрибутов rotate с соответствующими атрибутами других объектов типа кубиков на запястьях, как
описано в некоторых методиках. Потому что внутренняя математика MAYA временами выдает такие
углы, которые не поддаются такому простому разделению. Что, в свою очередь, приводит к еще
худшим последствиям.

Откройте файл conversion_ball_rotation_01.ma.

В этом примере вращение двух костей aim_joint и twist J o i n t будет согласовано с вращением

858 Книга Сергея Цыпцына


кости ball_joint зеленого цвета.

Чтобы было нагляднее демонстрировать пример, кость b a l l j o i n t анимирована от первого


до 25-го кадра, так, чтобы ее вращение было сразу по трем осям.

Для того, чтобы повернуть кость aim_joint без учета twist-вращения, так чтобы ее
направление совпало с направлением кости b a l l j o i n t , мы воспользуемся Aim Constraint. В качестве
«цели» выступит сустав targetjoint.

Итак, выделяем targetjoint и aim_joint и вызываем Option Box операции Constraints=> Aim
из раздела Animation.

Так как у нас кости были построены вдоль оси Y, в параметрах указываем Aim Vector = 0, 1,
О и Up Vector = 0, 0, 1. Если вы ошиблись со значениями параметров при создании Constraint - не
страшно, их можно всегда исправить после, с помощью Attribute Editor.

Затем выберите кости b a l l j o i n t и t w i s t j o i n t , и вызовите Constraint => Orient. Этот Con­


straint согласует ориентацию этих костей.

Переключите порядок вращения в кости t w i s t j o i n t с XYZ на XZY, если хотите, чтобы twist-
угол рассчитывался в «человеческих» единицах (в диапазоне от -180 до 180 градусов). Порядок
вращения нужно выбирать таким, чтобы ось, по которой, собственно, будет происходить вращение,

Персонажная анимация 859


была последней. В нашем случае, это ось Y. Это поможет Orient Constraint при вычислении
ориентации сделать оптимальное решение.

Например, для MAYA, угол по оси Y, равный значению 272 и 88 - одно и тоже, только вот
первая цифра, уж поверьте, никак не понравится ни одному сетапщику в мире. Если не изменить
порядок вращения кости, при переходе через значение -90 градусов, может возникнуть «щелчок» в
прискиненной геометрии, если этот угол был использован в сетапе для вычисления twist-поворота
и последующих деформаций.

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

Посмотрите на рисунки. Как видите, даже цифры при сложении поворотов двух костей
отличаются от значений исходной ball j o i n t . Хотя ориентация конечных костей идентична! Можете
легко проверить это, прицепив в первом кадре к balLjoint и twist_joint два одинаковых куба и
проиграв анимацию.

В файле additional_arm_joints.mb в качестве более сложного примера продемонстрирован


один из вариантов этой технологии для корректировки skin-деформации.

Дополнительные кости внутри геометрии. Обратите внимание на то, что в случае с


запястьем, у Aim Constraint атрибут World Up Type переключен в режим Object Rotation Up для
того, чтобы привязать Up-вектор к ориентации кисти руки. Для этого в атрибут World Up Object
нужно прописать имя этой кости. Это служит подобием якоря для Aim Constraint, и, таким образом,
между кистью руки и дополнительной костью нет twist-вращения, что соответствует анатомии.
Само twist-вращение распределяется между дополнительными костями от локтя до запястья.

Но полученный twist-угол может использоваться не только для вращении костей. Также


вы можете его использовать для управления скручиванием в деформерах Twist и Wire, которые
в некоторых случаях могут более успешно заменить Skin-деформер, особенно для cartoon-
персонажей.

Для корректировки skin-деформации в локтях (а также в коленях и на сгибах пальцев)


я рекомендую построить дополнительную кость и с помощью Orient Constraint привязать ее
ориентацию к двум соседним костям, чтобы она всегда была развернута между ними. Эта кость
будет подправлять область сгиба, если для нее толково настроить веса. К ней можно добавить еще
одну кость, которую можно двигать, вращать и масштабировать относительно поворота первой,

860 Книга Сергея Цыпцына


для более тонких манипуляций.

Совет. Не забудьте переключить параметр interpType в Orient Constraint в значение


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

В заключение хочется добавить, что для разделения сложных вращений можно, при
желании, воспользоваться вместо Aim и Orient Constraint работой ikSCsolver. Пытливые умы в
качестве разминки могут проделать эту работу сами.

Анимация 861
MEL
или MAYA Embedded Language
Заранее предупреждаю: эстетствующие умы, имеющие аллергию на слова
«программирование» и «скрипты», могут с отвращением и ужасом пропустить эту главу без ущерба
для дальнейшего чтения. В последующих главах я не буду злоупотреблять многостраничными
скриптами, отсылая читателя к этой главе. Так что решение спрятаться от MEL лежит целиком на
вашей личной совести. Могу сказать лишь одно: если избегать MEL во всех его проявлениях, то
рано или поздно это скажется на производительности и эффективности вашей работы. Кроме того
вы лишаете себя возможности небрежно блеснуть перед коллегами модной фразой типа «я это
делаю полностью процедурно, с помощью MEL».

В принципе, можно обходиться без знания и использования MEL в своей работе, особенно
если ваши служебные или домашние обязанности сводятся к выдаче двух минут анимации в день
или моделированию заданного количества элементов интерьера. Но подумайте о том, что рано
или поздно вам это сильно надоест, и в этот момент знание MEL может вам сильно пригодиться в
поиске новой работы или смене характера 3D-деятельности.

Про что эта глава


Кроме того, не спешите пугаться и разбегаться, кто куда. Я и не собираюсь в одной
главе давать полное описание языка программирования с полным разбором синтаксиса и типов
данных.

Во-первых, для этого есть специальные, неплохие книжки (например, «MAYA: полное
руководство по программированию» Дэвида Гоулда; текст там дельный, перевод - на совести
издательства).

Во-вторых, в одной главе это невозможно сделать.

В-третьих, я просто собираюсь порассуждать здесь на тему о том, как бы я (или кто-то
другой, более скромный) осваивал язык MEL, только-только познакомившись с MAYA. На примере
таких рассуждений я намереваюсь описать логику использования и основные правила работы с
MEL, но уж никак не полный синтаксис этого языка и все существующие в нем функции.

Как и в предыдущих главах, освоив логику использования, вы легко расширите собственную


сферу применения MEL, просто читая описание новых функций и текст чужих скриптов.

Боюсь, правда, что вам не удастся использовать эту главу как справочное пособие по MEL.
Ее можно лишь прочитать с начала до конца (опуская наиболее жуткие, не лезущие в голову вещи)
и попытаться вникнуть в суть использования MEL. Ведь, как вы сами знаете, наилучшее справочное
пособие - в документации.

Что такое MEL?


Так что же это за зверь, про которого все так много говорят? Как следует из дословного
перевода этой аббревиатуры, это встроенный (embedded) в MAYA язык программирования для
выполнения различных спецзаданий.

Какого рода спецзадания выполняются с помощью MEL? В рекламно-популярной литературе


обычно пишут: «позволяет расширить функциональность MAYA за счет добавления новых функций».
Но это - лишь часть работы, выполняемой MEL.

Во-первых, вся интерфейсная часть MAYA - ее, так сказать, витрина - написана на MEL
и поэтому может быть дополнена новыми меню, окнами, кнопками. Соответственно, интерфейс
MAYA может быть улучшен, изменен или обезображен до неузнаваемости. Вы можете писать свои
окошки для выполнения вами же запрограммированных действий или встраиваться в стандартные
меню MAYA, чувствуя себя агрессивным хакером. MEL позволяет делать и то и другое.

Пример из прошлого. В первой версии MAYA не было никаких операций, связанных

Анимация 865
с выравниванием и привязкой объектов друг к другу (snap & align). Мои друзья, только что
перешедшие с другого пакета на MAYA, были в шоке от такой аскетичности и горестно молили
о помощи. Запрограммировать выравнивание объектов было делом нехитрым, а вот в качестве
интерфейса для написанного скрипта я сделал копию окошка из другого пакета, повторяющую все
кнопочки и педальки соответствующего инструмента.

Но чтобы у потрясенных пользователей не возникло дезориентации в 3D-пространстве, пришлось


внести небольшие отличия в интерфейс, а то поначалу они не могли понять, в каком же пакете
работают. Скрипт этот безнадежно устарел и являет собой образец наивного программирования
пользователя, только начавшего осваивать MAYA. Однако в целях образования или из чистого
любопытства вы можете скачать его с
http: / /www.highend3d.com/files/dl.3d?group=melscripts&file_loc=ali-v0.9-. mel&file_id=778
или найти на компакт-диске, прилагаемом к этой книге.

Во-вторых, наиболее часто MEL используется для создания коротких «макросов», то есть
запоминания последовательности действий для последующего многократного воспроизведения
ее. Эту последовательность действий гордо называют скриптом (а не «макро») и назначают обычно
на горячую клавишу или на кнопку на полке. В отличие от макро в других программах, эти скрипты
для MAYA обычно подвергаются активному редактированию, их передают по наследству, а иногда
даже продают, за небольшие деньги.

В-третьих, иногда требуется выполнить действия, не предусмотренные в интерфейсе MAYA


(например, поменять вес контрольных вершин на кривой), но, тем не менее, присутствующие
среди стандартных возможностей пакета.

В-четвертых, если некоторая функция или алгоритм в MAYA отсутствует, его можно
запрограммировать на MEL и действительно получить то самое расширение функциональности
MAYA, о котором так часто говорят рекламные листовки. Примером может служить анимация
аттрактора Лоренца с помощью expression или паровоз с квадратными колесами (www. zabelin.
ru).

В-пятых, MEL позволяет легко читать и записывать данные в произвольных текстовых


форматах с помощью соответствующих функций чтения и записи. Это решает задачу обмена
информацией с другими пакетами и работы с числовыми данными, полученными в результате
расчетов в специализированных программах.

В-шестых, MEL используется для процедурного моделирования, то есть создания кривых и


поверхностей не с помощью рук и мыши, а с помощью головы и запрограммированных формул. В
результате создаются объекты с некоторыми параметрами, определяющие форму объекта целиком
- так называемые процедурные примитивы. Примером может служит изготовление футбольных
мячей, циклоид и других «красивых» поверхностей и кривых

866 Книга Сергея Цыпцына


В-седьмых, про процедурную анимацию писать бессмысленно и банально. Одно лишь
присутствие и использование expressions в MAYA оправдывает существование MEL в составе
программы.

В-восьмых, сделать что-нибудь серьезное с частицами без применения expressions и,


как следствие, без использования MEL, как правило, невозможно. Таким образом, в области
спецэффектов знать MEL - это не просто преимущество, а уже необходимое требование.

В-девятых, MEL- это любимое развлечение (а нетолько рабочий инструмент) всех технических
директоров. Можно даже сказать: для них это основное средство творческого самовыражения (и
в самом деле, нужно ведь давать возможность посамовыражаться и техдиректорам, а не только
эстетам-художникам или заносчивым аниматорам).

В-десятых, список применений MEL можно продолжать еще очень долго, начиная с задач
обслуживания рендеринга и заканчивая запуском «Фотошопа» из-под MAYA.

Есть скрипт!
Как представители других конфессий часто ссылаются на наличие у них плагинов
с различной дополнительной функциональностью, так и майские пользователи с завидной
регулярностью произносят сакральную фразу: «Есть такой скрипт!», отвечая на вопрос, а есть ли
в MAYA та или иная операция.
Действительно, MAYA представляет из себя центральное приложение, обросшее массой
дополнительных скриптов.
Дело в том, что в отличие от плагинов, требующих, во-первых, времени, во-вторых,
квалификации, в-третьих, сильной мотивации (как правило, коммерческой или производственной)
для их написания, скрипты могут быть написаны молниеносно, в том числе для решения
сиюминутной задачи, о которой можно забыть после ее решения.
Соответственно, задачи, которые решаются с помощью скриптов, могут быть как весьма
универсальные, так и узкоспециализированные, интересующие довольно ограниченный круг
пользователей. Поэтому, как правило, можно найти скрипты-решения практически на все (в том
числе, довольно экзотические) случаи жизни.
Такая архитектура и такое положение дел, с моей точки зрения - довольно удачный
компромисс между мощностью, гибкостью и удобством программы. Ведь если включить в MAYA все
это огромное количество довольно полезных (и бесплатных) скриптов, написанных пользователями
за несколько лет существования MAYA, этой программой просто невозможно будет пользоваться
- из-за обилия мелких, узконаправленных функций и операций, в которых может потеряться
основная логика пакета.
Поэтому если вам вдруг не хватает какой-то возможности в MAYA, с большой долей
вероятности уже существует скрипт, решающий вашу проблему. Первым делом надо залезть в
Интернет в поисках такого решения, а еще лучше - позвонить приятелям, которые наверняка уже
разыскали и скачали его.

MEL-ресурсы
Наиболее удачное, опять же с моей точки зрения, хранилище скриптов для MAYA,
содержащее категоризацию по функциональности, находится на сайте www.highend3d.com.
Также не стоит забывать про сайт производителя MAYA: www.alias.com.
Один из лучших ресурсов с точки зрения обучения и понимания MEL создал уважаемый
человеком по имени Brian Ewert. Его сайт (http://www.ewertb.com/) содержит не только примеры
полезных скриптов, но и подробный список вопросов и ответов, касающихся наиболее часто
возникающих проблем при работе с MEL. Кроме того, если у вас возник вопрос типа: «А как бы мне
сделать вот это на MEL?», вы наверняка найдет ответ на его отличном англоязычном сайте.
Некоторое количество ссылок на полезные ресурсы, касающиеся MEL-программирования,

MEL, или MAYA Embedded Language 867


можно найти на http://www.learning-maya.com/ - однако часть из них довольно давно не
обновлялась. Впрочем, MEL не претерпел особых изменений в своей природе, и с момента выхода
первой версии MAYA количество MEL-команд лишь удвоилось...

Освоение MEL. Как все начинается


Начинается все с окна Script Editor, когда начинающий пользователь, преодолев свой
первобытный ужас перед словом «программирование», жмет на кнопочку с горизонтальной
полоской в правом нижнем углу экрана.
Там он наблюдает, какие команды MAYA выполняет в ответ на его неуклюжие действия.
Потом, набравшись наглости, пользователь пытается скопировать эти команды из верхней части
окна Script Editor в нижнюю и даже выполнять их. Продравшись сквозь вереницу сообщений
об ошибке, пользователь затем пытается изменять скопированные команды и даже выполнять
их целыми пачками. С этого момента его можно причислять к числу скриптописателей, ибо
дальнейшее его совершенствование как супер-программиста сводится к чтению документации по
командам и текста чужих скриптов.
Это, кстати, наиболее правильный, наглядный и адекватный способ овладения MEL.
Преимущество такого подхода в мгновенной интерактивности и абсолютной наглядности. Если
пользователь выполнил команду sphere, он получит сферу на экране, а если выполнил move 0 5 0,
выделенный объект тут же скакнет в точку 0 5 0.
При чтении лекций и даже при письменном изложении материала я всегда стараюсь придерживаться
этакого «любопытствующего» подхода, чтобы MEL не показался начинающим «майщикам» чем-то
абстрактным, оторванным от жизни.

Лирическое отступление. MEL - полноценный язык программирования. При этом он -


стопроцентно процедурный язык. С тех пор, как в мир ворвался язык C++, законодателем мод стал
не процедурный, а объектно-ориентированный подход. С точки зрения оптимизации производства
программных продуктов и разработки больших систем это, несомненно, оптимальный подход.
Но человек с нормальной психикой ориентирован на «процедурный» образ жизни и мысли, то
есть на совершение некоторых последовательностей действий и на созерцание результата этих
действий, и потому для него объектно-ориентированный подход кажется не сильно естественным
и даже довольно затруднительным для освоения. Трудно представлять свои действия как
манипуляции с некоторыми данными, которые вызывают изменения в окружающей среде. Это уже
смахивает на эзотерику. Я, как математик по образованию, всегда был нацелен на алгоритм, то
есть на последовательность действий, решающих задачу, или иначе говоря на процедуру решения
проблемы. Изготовление компьютерной графики тоже являет собой образец чисто процедурных
действий, типа: моделируем, деформируем, ставим ключи, назначаем материал и т.д. Поэтому,
на мой взгляд, абсолютно процедурный MEL на самом деле довольно прост в освоении. Кроме
того, чтение чужих скриптов как последовательности инструкций выполняемых в MAYA, также
облегчает изучение и применение MELa нормальными людьми, а не одними оголтелыми
программистами. (Я, кстати, в прошлой жизни тоже был одним из них.) Я также думаю, что в силу
процедурности мышления нормальных людей основной постулат MAYA о том, что любой объект
- это набор атрибутов, определяющих его свойства, со скрипом воспринимается начинающими
пользователями, поскольку этот постулат как раз отличается явной объектно-ориентированной
направленностью.

Суть этой моей сентенции такова: MEL - вполне «человеческий» язык программирования.
Даешь старый добрый процедурный подход!

Примечание. Технический критик, в лице Алексея, был просто взбешен и ошарашен


этими моими радикальными, пусть и лирическими заявлениями. Мне с трудом
удалось его успокоить. Однако я почел за лучшее все же вычеркнуть свои нападки
на Visual Basic...

MAYA API

868 Книга Сергея Цыпцына


Несмотря на вышеприведенное эмоциональное заявление, замечу также, что в этой книге
вы не найдете никакой информации про использование MAYA API и написание плагинов для MAYA
на языке C++. Почему?

Во-первых, я не люблю язык C++. Так получилось...

Во-вторых, если рассказывать об этом, предполагая, что пользователь книги не


программист, придется рассказывать об основах языка C++, об иерархиях классов, о полиморфизме
и прочих вещах, на которые у меня и без того аллергия (см. также первую причину). Это будет
нерациональное и неполезное для здоровья расходование книжного пространства. Если же
предположить, что пользователи книги все как один программисты, их можно смело отослать
к прекрасной документации и примерам из базовой поставки MAYA, этого им должно хватить с
головой. Кроме того, разговора с безумными программистами на их же языке на страницах книги
не всякий вытерпит. Перегреется...

Повторю: вы должны иметь очень сильную производственную или коммерческую


мотивацию, чтобы начать писать плагины для MAYA. Дело это непростое, занудное и хлопотное.
Размер кода на C++ чудовищен (как обычно), а сам код нечитабелен для нормального человека.
Если вам все же не терпится, начните с написания своего деформера, путем изменения примеров
из MAYA SDK. Вышеупомянутая книжка Дэвида Гоулда может также помочь, однако всем, у кого нет
хотя бы минимального опыта программирования на C++, будет очень тяжко.

MEL для программистов - но на С

Если вы не программист, переходите к следующему разделу («Не для программистов. Как


примерно все происходит»). Для остальных замечу: MEL более всего похож на С или на Perl.
Язык MEL интерпретируемый, поэтому код на MEL будет выполняться, как правило, одинаково на
всех платформах, на которых запускается MAYA, за исключением команд работы с операционной
системой.

В отличие от С, все переменные здесь начинаются со знака доллара: например, $х=5.


Тип float соответствует типу double на языке С. Тип char отсутствует, но тип string оперирует
со строками как с простыми переменными, а не с массивами. Обратиться к элементу строки по
индексу нельзя, а можно только с помощью нужной функции.
Массивы и матрицы присутствуют и не требуют выделения памяти, в силу отсутствия
необходимости компиляции.

Массивы массивов объявлять нельзя. Структуры отсутствуют.

Есть спецтип vector, как вариант массива из трех float, над которым определены векторные
операции. Типы описывать не обязательно. Как обычно, объявление по первому присваиванию
служит источником неприятностей.

Контрольные конструкции - типа {}, if-else, for, while, break, switch, continue и другие - такие же,
как в С.

Оператора goto нет в принципе. А иногда хочется.

Есть также операции работы с файлами типа fopen, fread, fwrite, fprint, хорошо работающие
с текстовыми данными.

Вместо printf в MEL надо писать print!

Есть возможность объявлять и вызывать процедуры с аргументами и без.

Наиболее непривычен вариант вызова функций не в виде имени и списка аргументов


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

MEL, или MAYA Embedded Language 869


То есть вместо

setAttr("pCube1.tx", 10);

можно написать

setAttr pCube1.tx 10;

При этом, если нужно «поймать» возвращаемое функцией значение, необходимо


использовать спецкавычки.

Например, вместо

int $х = size($array);

можно написать

int $x = 'size $array';

Обилие встроенных команд-функций, с огромным количеством аргументов-флагов, делает


такую «строковую» запись удобнее.

Вместо

string $control =

attrFieldSliderGrp("-l","mag","-min", 0,"-max", 1,"-w",400);

удобнее написать:

string $control =
attrFieldSliderGrp -I "magnitude" -min 0 -max 1 -w 400';
Такой стиль вызова команд иногда называется императивным - в противовес традиционному
функциональному.

Не для программистов. Как примерно все происходит.


Откройте Script Editor. Создайте сплайновую сферу.

Убедитесь в том, что MAYA напечатала в верхней части Script Editor команду:

sphere -p 0 0 0 -ах 0 1 0 -ssw 0 -esw 360 -r 1 -d 3 -ut 0 -tol 0.01 -s 8 -nsp 4 -ch 1;

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

Вторая часть, ядро MAYA, скрывается позади интерфейса, и если вам еще не исполнилось
семи лет, представьте себе, что оно (ядро) сидит в системном блоке, а интерфейс - в мониторе
компьютера.

Когда пользователь своими непрямыми руками что-то делает через интерфейс (например,
двигает сферу за манипулятор Move Tool) происходит примерно такая цепочка действий:
Интерфейс MAYA преобразует судорожные движения рук пользователя в команду move с нужными
параметрами и передает эту MEL-команду ядру MAYA. Ядро MAYA «ловит» эту команду, пересчитывает
матрицы трансформаций, запоминает новое положение сферы и «кричит» интерфейсу MAYA:
«Готово! Перерисуй экран!». Интерфейс просто обновляет экран в соответствии с новым

870 Книга Сергея Цыпцына


положением сферы, а пользователь гордится своим гениальными перемещением объекта.
Если не верите, передвиньте сферу по вертикали - и вы тут же убедитесь, что в Script Edi­
tor появилась команда типа

move -r 0 4.539716 0 ;

Интерфейс ее и отсылает ядру, чтобы оно реально передвинуло сферу в новое положение,
посчитало все, что нужно, и сообщило, где теперь сфера находится - чтобы именно там интерфейс
ее и нарисовал.

Отсюда следует два вывода.

Вывод первый. Все, что делается через интерфейс MAYA, можно повторить с помощью MEL-
команд.

Вывод второй. В помощью MEL-команд можно сделать гораздо больше, чем через интерфейс
MAYA. Надо только их знать.

Совет. Сохраните любую сцену, как файл с расширением .та и откройте его в
любом текстовом редакторе. Вы увидите, что MAYA сохраняет собственные сцены
как последовательность MEL-команд, выполнение которых приводит к созданию
сцены. Такая открытость и возможность в любой момент выполнять любые
MEL-команды делает MAYA абсолютно открытой и драматически расширяемой
системой.

Немного MEL-команд. Работа с документацией


На сегодняшний день число MEL-команд перевалило за тысячу сто, поэтому попытка
запомнить их все приводит, как правило, к переполнению памяти у пользователя и потере им
данных, так что гораздо проще воспользоваться документацией, где эти команды аккуратно
разложены и в алфавитном порядке и по категориям. В главном меню Help есть отдельный пункт
MEL Command Reference. Такой же пункт есть в меню Help в Script Editor.

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

Структура MEL-команд
Следует сразу оговориться, что условно язык MEL состоит как бы из двух частей.

Первая - это конструкции языка программирования типа if-else, for, while, break, switch,
continue, такие, что позволяют складывать числа, организовывать циклы, условные переходы и
управлять последовательностью выполнения команд.

Вторая огромная часть - это собственно сами MEL-команды, которые выполняют конкретные
действия в MAYA, а не только складывают и умножают числа.

Основные конструкции языка я разберу чуть позже, а сейчас остановлюсь на внешнем виде
MEL-команд.

Каждая команда имеет примерно одинаковую структуру, состоящую из имени команды


(например, move), флагов-параметров (-r) и некоторых значений (0 5.6 0):

move -r 0 5.6 0;

MEL, или MAYA Embedded Language 871


В самом конце команды может указываться имя объекта, к которому эта команда применяется,
move -r 0 5.6 0 pCubel;

Если имя объекта не указано, команда применяется к выбранным объектам (если она, конечно,
работает с объектами).

Флаги (аргументы, модифицирующие действие команды по умолчанию) могут появляться после


имени команды в произвольном порядке. Некоторые флаги требуют значений для себя, и тогда
после имени флага (начинающегося с «-» ) указываются значения флага, которые могут быть чем
угодно - числом, строкой, тройкой чисел и проч.

sphere -р 0 0 0 -ах 0 1 0 -ssw 0 -esw 360 -r 1 -d 3 -ut 0 -tol 0.01 -s 8 -nsp 4 -ch 1;

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

sphere -pivot 0 0 0 -axis 0 1 0 -startSweep 0 -endSweep 360 -radius 1 -degree 3 -useTolerance 0 -toler­
ance 0.01 -sections 8 -spans 4 -constructionHistory 1;

Если флаг не указан, используется поведение команды по умолчанию (точнее, значения


флага по умолчанию). Если, например, просто выполнить команду

sphere;

то возникнет сфера, лежащая на боку, так как значение флага -axis по умолчанию равно 1 0 0.
Именно это значение будет использовано, если флаг -axis не указан явно в команде.

Впрочем, если слова «флаги» или «аргументы» начинают вас пугать, перейдем к
практическому примеру, на котором разберем, как можно случайным образом изменять свойства
(то есть атрибуты) большого количества выделенных объектов с помощью MEL.

Особенности работы в Script Editor


Для начала напомню про особенности работы в Script Editor.
Нижняя часть Script Editor cлyжит для ввода, редактирования и отладки последовательностей
команд. Команды вводятся как обычный текст и выполняются нажатием на серую кнопку Enter
справа на цифровой клавиатуре (или Ctrl+Enter, для владельцев супер-ноутбуков). Чтобы выполнить
только часть набранных команд, необходимо предварительно выделить их левой кнопкой мыши,
а затем нажать серую кнопку Enter. Можно также перетаскивать мышью выделенный текст из
верхней части Script Editor в нижнюю часть.

Я настойчиво советую выполнять любые команды, всегда выделяя их в нижней части Script
Editor и нажимая серую клавишу Enter, чтобы команды не пропадали из окна.

Совет. Если в нижней панели Script Editor трижды щелкнуть по тексту, строка
выделится целиком.

Совет. Горячие клавиши копирования (Ctrl-C) и вставки (Ctrl-V) работают, как


в большинстве текстовых редакторов. Перетаскивание выделенного текста с
нажатой клавишей Ctrl также работает.

Совет. Те, кто не хочет сломать глаза на микроскопическом шрифте Script Editor,
могут нажать Ctrl и покрутить колесо мыши в нижней панели.

872 Книга Сергея Цыпцына


Совет. Если вы хотите изменить шрифт в Script Editor, вам придется сделать
следующий трюк. Откройте WordPad или Word, скопируйте кусок текста с
нужным шрифтом, вставьте его в Script Editor через меню Edit=>Paste (причем
Ctrl-V вставит только текст, но без шрифта). Или сделайте Drag'n'Drop куска
текста из Word в Script Editor.

Хороший совет. Если вы не хотите мучиться с предыдущими советами и


собираетесь проводить некоторое время в обнимку со Script Editor, установите
себе Mel Studio Pro (http://www.disimation.com/). Это не программа - это мечта
MEL-программиста...

Применение MEL для работы со списком выделенных объектов


Дальнейшее изложение будет строиться следующим образом. Для решения поставленных
задач я буду вводить новые команды и конструкции языка. Чтобы объяснить их назначение и
особенности использования, мне придется делать теоретические отступления, после чего
возвращаться к продолжению решения практической задачи. Таким образом, эту главу нельзя
рассматривать как справочник по MEL, ибо вспомнить, в каком месте рассказывалось о нужной
команде, будет довольно сложно. Попытайтесь просто следить за ходом рассуждений и в
самостоятельной работе применять похожую логику.

Довольно часто возникает задача задавать различные свойства сразу некоторому


немаленькому числу выбранных объектов. Например, вы построили город (или хотя бы деревню),
а теперь хотите выбрать домишки и быстро развернуть их случайным образом в горизонтальной
плоскости. Или задать им всем разный размер по высоте. Вы можете также захотеть назначить
им различные цвета и другие свойства. В общем, задача сводится к работе со списком выбранных
объектов и заданию различных значений для некоторых атрибутов этих объектов. Вручную вам бы
пришлось методом интенсивного тыка перебирать все объекты и вбивать цифры в клеточки или
неистово дергать за манипуляторы. Посмотрим, как решать подобные задачи с помощью MEL.

Создайте полигональный куб.

Поднимите его на 0.5 по оси Y и опустите его пивот в начало координат, чтобы пивот лежал
на нижней грани куба.

Откройте Option Box операции Duplicate и сделайте девять копий куба со смещением на
единицу по оси X.

Выберите десять полученных кубов и сделайте девять копий выделения со смещением на


единицу по оси Z.

MEL, или MAYA Embedded Language 873


В результате получится горизонтальная сетка 10x10 из ста кубиков. Если вам лень делать
такую работу, откройте файл cubeGrid.ma.

Выберите все объекты. Если мы хотим задать им случайный размер, то очевидно следует
пробежаться по списку выбранных объектов и задать различные значения для атрибута scaleY.
Как же получить список выбранных объектов? Для работы со списками объектов в сцене есть
команда Is.

Для справки. В среде Unix команда Is выполняет функции команды dir для Windows/DOS,
то есть выдает список файлов. Is - это аскетическое сокращение от list.

Если вы выполните команду Is в Script Editor1 , то получите в верхней части огромный


список всех объектов в сцене, например:

1 Напоминаю: в дальнейшем выражение «выполнить команду в Script Editor»


будет означать «набрать текст команды, выделить его и нажать серую клавишу
Enter»! - Примечание автора.
874 Книга Сергея Цыпцына
Is;

// Result: time1 renderPartition renderGlobalsListl defaultLightList1 defaultShaderListl postProcess-


Listl defaultRenderUtilityList1 lightList1 defaultTextureList1 lambert1 particleCloud1 initialShading-
Group initialParticleSE initialMateriallnfo shaderGlowl dofl defaultRenderGlobals defaultRenderQual-
ity defaultResolution defaultLightSet defaultObjectSet hardwareRenderGlobals characterPartition
defaultHardwareRenderGlobals ikSystem hyperGraphlnfo hyperGraphLayout globalCacheControl dyn-
Controller1 strokeGlobals UghtLinker1 persp perspShape top topShape front frontShape side sideShape
layersFilter objectTypeFilter68 renderLayersFilter objectTypeFilter69 renderingSetsFilter objectType-
Filter70 relationshipPaneHLeftAttrFilter relationshipPanel1RightAttrFilter layerManager defaultLayer
renderLayerManager defaultRenderLayer globalRender polyCubel pCubel pCubeShapel pCube2 pCube-
Shape2 pCube3 pCubeShape3 pCube4 pCubeShape4 pCube5 pCubeShape5 рCube6 pCubeShape6 pCube7
pCubeShape7 pCube8 pCubeShape8 pCube9 pCubeShape9

pCube97 pCubeShape97 pCube98 pCubeShape98 pCube99 pCubeShape99 pCubelOO pCubeShape100 ui-


ConfigurationScriptNode sceneConfigurationScriptNode //

Если почитать документацию к команде Is, выяснится, что у нее есть масса флагов, позволяющих
выдавать списки объектов только определенного вида, в том числе только выбранные объекты.
Выполните команду Is -sl и убедитесь, что в верхней панели появился список только что выбранных
кубов.

Is -si;

// Result: pCubel pCube2 pCube3 pCube4 pCube5 рСиЬеб . . .

Теперь надо этот список как-то «поймать», то есть сохранить для дальнейшей работы.
Выполните команду:

$list = 'ls -sl';

а затем команду

print $list;

и убедитесь, что команда print напечатает список выбранных объектов, сохраненный в переменной
Slist.

Точка с запятой в конце каждой команды обязательна, она отделяет одну команду от
другой. В принципе несколько команд можно писать в одной строке, разделяя их точкой с запятой
друг от друга, однако на первых порах я настоятельно советую писать в каждой строке одну
команду и не забывать про точку с запятой в конце строки. Пробелы можно ставить и в начале и
в середине строки «для красоты», они просто игнорируются. (Только не надо их вставлять внутри
имени команд или флагов!..)

Если хорошо понимаете, что такое переменные, и представляете себе, что они бывают
разных типов, пропускайте следующий раздел и переходите к работе с циклом («Работа с циклом.
Перебор объектов в списке»). Если же вы изрядно нервничаете и слова «переменная», а, тем
более, «массив», вас сильно пугают, переходите к следующему разделу.

Переменные и типы данных


Немного отвлечемся от кубиков.
Строка

$list = 'ls -sl'

MEL, или MAYA Embedded Language 875


объявляет новую переменную и присваивает ей значение, равное результату, возвращаемому
командой Is.

Переменные в MEL используются для временного хранения данных (или информации). Вы


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

Команды

$text= "Hello World!";


$х=1.5;

объявляют переменные разных типов, то есть в памяти заводятся ячейки разного размера под
строку ($text) и под число ($х).

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

$N=100;
$pi=3.1415926;

заводят две числовые переменные разных типов.

Примечание. Имеется небольшая путаница со словом «команды». Иногда я, как и


все, использую их для обозначения строчек кода на MEL, а иногда для обозначения
собственно MEL-команд. Надеюсь, что контекст изложения позволит отделять
их по смыслу друг от друга.

До сих пор я приводил примеры объявления переменных по первому присваиванию, когда


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

Взрослые мальчики, однако, объявляют переменные явным образом, перед началом их


использования. Команды

int $quantity;
float $expo;
string $text20;

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

Примечание. Обычно пустые переменные инициализируются нулями, но уповать


на это не стоит, лучше присвоить им значение явным образом.

Можно также сразу объявлять переменные и присваивать им значения одной командой.

int $quantity=10;
float $expo=1.56782;
string $text20= "Start of message";

Как вы уже догадались, напечатать значение переменной можно с помощью команды print.

876 Книга Сергея Цыпцына


С ее помощью вы можете поставить эксперименты на преобразование типов, то есть узнать, что
будет, если в переменную типа string (строка) засунуть (присвоить) целое число, и наоборот, если
числовой переменной попытаться присвоить строку.

Массивы
Какого же типа получается переменная, объявленная в результате команды

$list = 'ls -sl'

Если вы думаете, что это строка, причем очень длинная, то вы ошибаетесь. Хотя бы потому, что
команда

print $list;

печатает не длинную строку, а столбец из коротких строк.


Для любопытных умов существует чрезвычайно полезная команда whatls, которая позволяет
получить информацию о том, чем является строка, заданная по имени.

Например, whatls "print"; выдает результат Command, заявляя о том, что print - это
встроенная команда. Выполните

whatls "$list";

Полученный результат

// Result: string[] variable //

позволяет сделать вывод, что кроме простых переменных типа string, существуют составные
переменные типа string[], то есть массивы строк.

Одна переменная такого типа может содержать сразу несколько строк:

string $array[] = {"First", "Second", "Zero"};

Обращаться к элементам такого массива можно по индексу, то есть по номеру внутри массива,
например

print $array[0];
print $list[21];

Примечание. Индекс первого элемента в массиве всегда равен нулю, то есть


нумерация начинается с нуля. Массивы также бывают не только строковые, но и
числовые, типа int[] и float[].

Таким образом после выполнения команды

$list = 'ls -sl'

переменная $list неявно (по первому присваиванию) была объявлена как массив строк, и этот
массив был заполнен именами выбранных объектов.

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

string $list[] = 'Is -sl';

MEL, или MAYA Embedded Language 877


Это будет классическим объявлением переменной типа массива строк с одновременным
присваиванием ему результата выполнения команды Is.

Вы должны понимать, что выражение $list[] может использоваться только при объявлении
переменной типа массив. Если последнюю команду разбить на объявление и на присваивание, это
будет выглядеть следующим образом.

string $list[];
$list = ' l s - s l ' ;

Обратите внимание, что во второй строке используется $list без скобок, так как массив строк
присваивается самой переменной.

Если вся эта жуткая теория про типы данных и переменных вас чудовищно устрашила,
не переживайте. Переходите к следующему разделу и воспринимайте только что описанную
команду как стандартное заклинание, которое позволяет получить и сохранить список выделенных
объектов.
Работа с объектами и атрибутами

Вам уже, наверное, осточертела навязчивая парадигма о том, что любой объект
представляет собой просто набор атрибутов, определяющих его свойства и качество жизни.
Однако я с маниакальным упорством буду возвращаться к ней снова и снова. На этот раз, чтобы
напомнить, что у любого атрибута есть, как правило, короткое и длинное имя, а вот полное имя
атрибута состоит из имени объекта и названия атрибута, например pCubel.tx или pCubel.trans-
lateX. Название атрибута всегда отделяется от имени объекта точкой, такая запись однозначно
определяет значение конкретного атрибута у конкретного объекта. Вы можете использовать как
короткие имена атрибутов, так и длинные, главное - не забывайте правильно писать маленькие и
большие буквы в именах объектов и атрибутов (MAYA чувствительна к регистру символов).

Полный путь к объекту или атрибуту


Если вы создадите в новой сцене полигональный куб, затем сгруппируете его с самим собой
(Ctrl-g), продублируете (Ctrl-g) и немного сдвинете его, то при выборе на экране получившихся
кубиков вы будете получать в Script Editor следующие команды:

select -r group2 | pCube1 ;


select -r group1 | pCube1 ;

Очевидно, что при копировании групп MAYA оставляет без изменений «начинку» иерархии и
дает новое имя только самой верхней группе, в то время как объекты, входящие внутрь иерархии,
имеют одинаковые имена. Точно так же, как в разных папках на диске могут быть файлы с
одинаковыми именами.

Когда вы работаете с иерархиями на MEL, важно помнить об этом и использовать полные


имена объектов, включающие как имя, так и «путь» к объекту. «Путь» в данном случае - это строка
с именами всех родительских объектов, разделенных вертикальной чертой.

Если в этой сцене дать команду

select -r pCube1 ;

MAYA выдаст сообщение об ошибке

// Error: More than one object matches name: pCubel //

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

878 книга Сергея Цыпцына


То же самое происходит и при работе с атрибутами. При попытке изменить атрибут объекта
с использованием короткого имени вы получите сообщение:

setAttr "pCubel.translateX" 3;
// Error: Not enough data was provided. The last 0 items will be skipped. //

Любопытно, но если вы зададите количество числовых значений для изменяемого атрибута


равным количеству объектов с данным коротким именем, то команда setAttr отработает без
ошибок:

setAttr "pCubel.translateY" 5 5 ;

Кстати, если объект не находится в иерархии, то его полное имя содержит просто одну
дополнительную вертикальную черту, обозначающую, что объект пригруппирован к мировому
пространству, например: | pTorus1. В общем случае эту черту можно не писать.
Чаще всего одинаковые имена возникают при дублировании групп (иерархий), и это
вполне разумно, когда у вас есть, например, набор персонажей, и у каждого из них конечности
называются одинаковыми, «человеческими» именами, типа «left_hand» или «right_foot». Однако
иногда хочется избежать появления одинаковых имен в сцене (например, для экспорта в другие
программы). Для этого в Option Box операции Duplicate существует галка Assign Unique Name to
Child Node.

Как правило, MAYA сама отслеживает формирование нужных имен и путей, в частности, при
работе с командой 'Is -sl', однако в некоторых случаях необходимо помнить о наличии одинаковых
имен объектов в сцене.

Работа с циклом. Перебор объектов в списке


Коль скоро переменная $list содержит список выбранных объектов, самое время
пробежаться по этому списку и что-нибудь с этими объектами сделать. Если сказать обычными
словами, получится примерно так: «для каждого элемента в списке сделать что-нибудь».

На языке MEL это же означает цикл, который выглядит следующим образом:

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
print $item;
}

В данном случае нам понадобилась одна простая переменная типа string (строка) с именем
$item, чтобы «засовывать» в нее очередной элемент в списке в процессе перебора всех элементов
в цикле. Как видите, на MEL это звучит почти как на английском.

Фигурная скобка открывает тело цикла, то есть набор команд, которые будут выполняться
в цикле (их может быть хоть двести). Вторая скобка закрывает цикл и после нее могут идти
команды, уже не выполняющиеся в цикле. Такой интеллектуальный цикл сам посчитает, сколько
элементов в массиве $list, и выполнится ровно это число раз. Причем на каждом повторении цикла
в переменную $item будет попадать следующий элемент списка.

Если вы напечатали все символы правильно, MAYA напишет длинную строку, состоящую из
напечатанных друг за другом имен выбранных объектов:

pCubelpCube2pCube3pCube4pCube5pCube6pCube7pCube8pCube9pCube...

MEL, или MAYA Embedded Language 879


Примечание. Размер списка или любого другого массива вы можете узнать с
помощью команды size. Например:
$N=size($list);
// Result: 2650 //

Теперь самое время вместо команды print сделать какие-нибудь интеллектуальные


манипуляции над каждым выбранным объектом, например, изменить ему размер по вертикали,
то есть атрибут scaleY. Вы, естественно, заметили, что если в Channel Box вручную вбить значение
для любого атрибута, MAYA откликнется на это в Script Editor командой типа

setAttr "pCube23.scaleY" 1.4;

Соответственно, вместо "pCube23.scaleY" хочется подставить что-то типа $item.scaleY, a


вместо 1.4 какое-нибудь случайное число.

Однако MAYA не сможет понять запись $item.scaleY , так как реального геометрического
объекта с именем $item не существует. Но коль скоро мы знаем, что в переменной $item находится
строка, равная имени очередного объекта в списке, мы можем сконструировать строку типа
"pCube23.scaleY" следующим образом
$item + ".scaleY"
Пытливые умы наверняка догадаются, что операция суммирования для строк всего лишь
склеивает две строки в одну (другие операции для строк просто не определены).

Теперь мы можем переписать наш цикл так

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
setAttr ($item+".scaleY") (rand(0,2));
}

Если вы не сделали ни одной ошибки и выполнили вышеприведенные строки, то кубики на


экране должны стать разных размеров.

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

setAttr ($item+".scaleY") (rand(0,2));

Она является образцом создания полного имени атрибута, включающего в себя имя объекта.
Функция rand(0,2) возвращает, в данном случае, значение от нуля до двух. (Дополнительные
скобки вокруг нее означают «посчитать выражение в скобках и выдать его наружу в виде числа».

880 Книга Сергея Цыпцына


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

string $list[] = 'Is -sl';


string $item;
for($item in $list)
[
setAttr ($item+".scaleY") (rand(3,7));
}

Скобки и кавычки
Примечание. Те, кто имеют хоть небольшой опыт программирования или
увлекаются чтением чужих программ, без сомнения будут смущены наличием двух
способов вызывать функции-команды. На MEL можно вызвать функцию при помощи
традиционных скобок

$x=rand(1.1, 2.5);

или «императивным» способом, с помощью спецкавычек, «ловящих» результат выполнения


команды и «отдающих» его наружу:

$x='rand 1.1 2.5';

Нет никаких рекомендаций по использованию того или иного стиля. Это дело вкуса, а
результат вызова команд будет идентичным. Дело в том, что довольно неудобно использовать
традиционные скобки для вызова чисто MEL-овских команд типа sphere с огромным количеством
флагов

sphere("-p", 0, 0, 0, "-ах", 0, 1, 0, "-ssw", 0, "-esw", 360, "-r", 1, " - d " , 3, "-s", 8, "-nsp", 4, "-ch",
1);

string $l[] = ls("-sl", " c a m " ) ;

Гораздо удобнее использовать «строчный» стиль:

sphere -p 0 0 0 -ах 0 1 0 -ssw 0 -esw 360 -r 1 -d 3 -s 8 -nsp 4 -ch 1;


string $l[] = Is -sl -cam';

Однако, традиционные функции типа rand, noise или sin по привычке удобно вызывать с
помощью аргументов в скобках, поэтому я обычно смешиваю стили в своих программах. Если вы

MEL, или MAYA Embedded Language 881


хотите придерживаться MEL-овского стиля, можете переписать наш цикл как

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
setAttr ($item+".scaleY") 'rand 3 7';
}

Комментарии
Иногда удобно комментировать свои действия в самом скрипте. Для этого используются
комментарии. Как только MAYA встречает в какой-нибудь строке скрипта две косые черты «//»,
она игнорирует всё, что написано после них и до конца строки. Если две косые черты стоят в
начале строки, эта строка игнорируется, и вы можете писать в этой строке что угодно: полезные
замечания или всяческие глупости.

Добавление вращения
Если все кубы выбраны, вы всегда можете вернуть их в исходный размер просто задав в
Channel Box значение scaleY=1.

Добавьте пару строк в наш мощный скрипт для добавления случайных размеров по осям X и Z.

string $list[] = 'Is -sl'';


string $item;
for($item in $list)
{
setAttr ($item+".scaleY") (rand(3,7));
setAttr ($item+".scaleX") (rand(0.3,0.8));
setAttr ($item+".scaleZ") (rand(0.3,0.8)j;
}

Теперь боковые размеры всех кубов случайным образом задаются в диапазоне от 0.3 до 0.8.

Добавим вращения нашим урбанистическим объектам. Вставьте еще одну строку в тело цикла:

string $list[] = 'Is -sl';


string $item;

882 Книга Сергея Цыпцына


for($item in $list)
{
setAttr ($item+".scaleY") (rand(3,7));
setAttr ($item+".scaleX") (rand(0.3,0.8));
setAttr ($item+".scaleZ") (rand(0.3,0.8));

setAttr ($item+".rotateY") (rand(-30,30));


}

Объекты повернутся на случайный угол вокруг вертикали в диапазоне от -30 до 30.

Далее вы можете продолжать издеваться над полученным «микрорайоном» в соответствии


с вашими архитектурными пристрастиями. Помните, что Undo работает даже для выполняемых
скриптов.

Чтобы, например, немного подвигать объекты в горизонтальной плоскости, добавьте еще


одну строку:

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
setAttr ($item+".scaleY") (rand(3,7));
setAttr ($item+".scaleX") (rand(0.3,0.8));
setAttr ($item+".scaleZ") (rand(0.3,0.8));

setAttr ($item+".rotateY") (rand(-30,30));

move -r (rand(-0.5,0.5)) 0 (rand(-0.5,0.5)) $item;


}

Пустые строки вставлены здесь для удобства чтения, MAYA же их просто игнорирует.
Так как команда setAttr задает абсолютные значения атрибутов, пришлось использовать команду
move с флагом -r, чтобы задать смещение относительно текущей позиции объектов. Пытливые
умы, конечно, сразу заметят, что весь скрипт можно было бы переписать в более компактной и
даже более понятной форме:

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
scale (rand(0.3,0.8)) (rand(3,7)) (rand(0.3,0.8)) $item;
rotate 0 (rand(-30,30)) 0 $item;

MEL, или MAYA Embedded Language 883


move -r (rand(-0.5,0.5)) 0 (rand(-0.5,0.5)) $item;
}

Здесь сразу понятно, что с помощью команд move, rotate, scale трансформируется
очередной объект в списке, имя которого содержится в переменной $item. Но если бы я сразу
написал такой простой скрипт, как бы я тогда рассказал про составление имени произвольного
атрибута с помощью склеивания строк типа: ($item+".scaleY")?!

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

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

string $list[] = 'Is -sl';


string $item;
for($item in $list)
{
....

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

Создание Noise Deformer


Разберем теперь, как еще можно использовать вышеполученный универсальный скрипт для
работы с выделенными объектами. Оказывается, он легко адаптируется для работы с выделенными
компонентами.

Создайте в новой сцене сплайновую сферу.

Задайте для нее в Channel Box: sections=30, spans=30.


Выделите часть контрольных вершин, например с левого края.

В Script Editor отредактируйте предыдущий скрипт, убрав из него команды scale и rotate
(какой смысл вращать вершины?) и добавив перемещение по вертикали:

string $list[] = 'Is -sl';


string $item;

884 Книга Сергея Цыпцына


for($item in $list)
{
move -r (rand(-0.1,0.1)) (rand(-0.1,0.1)) (rand(-0.1,0.1)) $item;
}

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

Однако вершины сдвинутся как-то странно, целыми группами. Нажмите Undo. Выделите
снова часть вершин и загляните в Script Editor. Там должна появиться команда типа:

select-r nurbs5phere1.cv[4][13:16] nurbsSphere1.cv[5:6][12:17] nurbsSphere1.cv[6][18] nurbsSpherel.


cv[7][11:18] nurbsSpherel.CV[8][10:19] nurbsSpherel .cv[9] [9:19] nurbsSpherel.cv[10:25][8:19] nurb­
sSpherel.cv[26][9:18] nurbsSpherel.cv[27][9] ;

Очевидно, что MAYA формирует список выделенных вершин, группируя их в «кучки» по


степени близости друг к другу.

Если выделить и выполнить команду Is -si, она выдаст в точности этот же список и,
следовательно, наш цикл будет случайным образом двигать целые «кучки» вершин.

Выбирать их по одной, нажимая Shift - это, естественно, не вариант. Но, к счастью, у


команды Is есть флаг, который возвращает список выбранных объектов (или компонент) в «длинной»
форме, где каждая компонента перечислена индивидуально. Подправьте первую строчку скрипта,
добавив в команду Is флаг -fl.

string $list[] = 'Is -sl - f l ' ;


string $item;
for($item in $list)
{
move -r (rand(-0.1,0.1)) (rand(-0.1,0.1)) (rand(-0.1,0.1)) $item;
}

Теперь цикл пробегает по каждой выделенной вершине и сдвигает ее немного.

MEL, или MAYA Embedded Language 885


Undo no прежнему работает. Возможно некоторым настойчивым умам захочется изменять величину
смещения, а редактировать каждый раз шесть цифр довольно утомительно. Для этого проще
создать простую переменную типа float.

float $d=0.05;
string $list[] = 'Is -sl - f l ' ;
string $item;
for($item in $list)
[
move -r (rand(-$d,$d)) (rand(-$d,$d)) (rand(-$d,$d)) $item;
}
Таким образом, с минимальными исправлениями универсальный скрипт для работы
с выделенными объектами превращается в подобие noise deformer, и он модифицирует форму
объекта случайным образом. Этот скрипт будет работать с выделенными вершинами не только на
сплайновых поверхностях, но и на кривых, полигональных сетках и даже на решетках типа Lattice,
причем вы можете одновременно выбирать компоненты разных объектов и запускать скрипт на
выполнение.

Затащите его на полку и не забудьте сделать: File=>$ave Preferences.

Примечание. Флаг -fl никак не влияет на вид списка в случае, когда выбраны
объекты, а не компоненты, так что можете использовать его всегда, для
универсальности.

Если вы измените для сферы количество sections/spans до 50, то есть радикально увеличите
количество вершин, а затем выберете все вершины и запустите деформер-скрипт, его выполнение
займет ощутимое время.

886 Книга Сергея Цыпцына


Граница применимости MEL
Вышеприведенный пример очень четко обозначает границу применимости MEL. Так
как команды языка выполняются ядром MAYA, а не самой операционной системой (технически
говоря, MEL - интерпретируемый язык), в случае интенсивных или сложных вычислений его
производительность невысока. Он предназначен для автоматизации, а не для сложных расчетов.
И в тот момент, когда его производительности вам начнет не хватать, вам придется задуматься об
освоении MAYA API и работе с MAYA SDK.

Кроме того, если вы захотите написать полноценный деформер, так чтобы деформация
поверхности имела Construction History, то есть ноду, в которой можно задавать величину
деформации, вам никуда уже не деться от C++ и от MAYA API. С помощью скриптов нельзя задавать
операции, имеющие Construction History, можно лишь выполнить последовательность действий,
нажать Undo, изменить значения переменных и выполнить скрипт снова. Это принципиальный
момент.

Процедурное моделирование
Разберем далее, как можно использовать MEL-команды для моделирования, то есть для
построения геометрии с помощью формул. А заодно разберем еще одну конструкцию цикла и
применение условных переходов.

Начнем с наивного использования метода пристального взгляда.


В новой сцене нарисуйте кривую любым способом.
Загляните в Script Editor и найдите там последнюю команду, напечатанную в верхней части
окна. Она выглядит примерно так:

curve -d 3 -р 9.116545 0 11.562727 -р 1.740198 0 7.561535 -р -2.160891 0 2.562245 -р 0.675565 0 -


1.455057 -р 7.176817 0 -0.665676 -k 0 -k 0 -k 0 -k 1 -k 2 -k 2 -k 2 ;

Суда по всему, флаг d задает степень кривой, а флаги -р определяют координаты


контрольных вершин кривой. Остальные флаги нас пока не интересуют.

Наберите и выполните команду

curve -р 0 0 0;

После этого в начале координат (в точке 0 0 0) возникнет кривая, состоящая из одной (!)
точки. Вы можете убедиться в этом, выбрав ее и исследовав в Attribute Editor.
Очевидно, что если выполнить команду:

curve -р 0 0 0 -р 0 1 0 -р 1 1 0 -р 1 0 0;

то возникнет сегмент кривой третьего порядка (значение флага d по умолчанию равно трем).
Однако идея состоит в том, чтобы поставив одну точку, добавлять к ней новые вершины в
цикле, добиваясь «выращивания» кривой по некоторой формуле.

Методом тыка попробуем выяснить, какие команды и флаги для этого нужны.
Коль скоро среди операций моделирования есть инструмент добавления точек к кривой, выберите
любую кривую, а затем выполните Edit Curves=>Add Points Tool.

Добавьте несколько точек к кривой, скашивая глаз на Script Editor и отслеживая, какие
команды появляются в нем при каждом новом щелчке.

MEL, или MAYA Embedded Language 887


Каждой новой точке соответствует примерно следующая команда:

curve -os -а -р 0.477587 0.511006 0 curve2 ;

Ключевым моментом являет наличие флага а, переводящего команду curve из режима


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

Пытливые умы наверняка уже исследовали описание команды curve в документации.


Наличие флага -os говорит о том, что координаты точек задаются в локальном пространстве
объекта (object space), то есть кривой.

Удалите все кривые в сцене.


Попробуем поставить точку и добавить к ней еще три вершины:

curve -р 0 0 0 -n "myCurve";
curve -p 0 1 0 -a "myCurve";
curve -p 1 1 0 -a "myCurve";
curve -p 1 0 0 -a "myCurve";

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

Дело за малым: осталось вместо трех последних команд написать цикл, добавляющий
заданное количество вершин к первой точке.

Такой цикл, выполняющийся нужное количество раз, немного отличается по синтаксису от


цикла for-in, описанного в предыдущем выше.

Напишите и выполните следующий код:

curve -р 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$i+1)
{
curve -p (rand(0,2)) (rand(0,2)) 0 -a "myCurve";
}

Возникнет хаотическая кривая, состоящая из ста и одной вершины. Напомню, что функция
rand возвращает новое случайное число при каждом вызове.

888 Книга Сергея Цыпцына


Нам понадобилась простая переменная $i, типа целое число, называемая обычно счетчиком
цикла. Работу такого цикла можно описать примерно следующим образом.

Перед началом выполнения счетчику цикла присваивается нулевое значение ($i=0), затем
проверяется условие цикла ($i<100), и если оно не выполняется, цикл прекращает исполняться.
В противном же случае выполняются команды из тела цикла. После каждого выполнения одного
оборота цикла, выполняется операция увеличения счетчика ($i=$i+1), затем снова проверяется
условие цикла ($i<100) и все продолжается до тех пор, пока условие цикла перестанет
выполняться.

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

Приведенная стандартная конструкция позволяет выполнить набор команд нужное


количество раз. В данном случае сто раз выполняется команда добавления новой вершины к
существующей кривой myCurve.

Рисовать хаотические кривые в пространстве, конечно, забавно, однако попробуем


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

Счетчик цикла изменяется в цикле от нуля до ста. Если его разделить на десять, то это
число очевидно будет изменяться от нуля до десяти.

Удалите все кривые.


Пишем построитель графиков.

curve -р 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$i+1)
{
float $x=$i/10.0;
float $y=sin($i/10.0);
curve -p ($x) ($y) 0 -a "myCurve";
}

Теперь в цикле сто раз будут вычисляться новые значения для переменных $х и $у,
основанные на растущем счетчике цикла. Эти значения будут добавляться как координаты новой
вершины к кривой myCurve. В результате получается график функции синус (sin).

MEL, или MAYA Embedded Language 889


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

float $x=$i/10;

то результат выполнения программы будут весьма загадочным.

Несмотря на то, что переменная $х объявлена как float, она, очевидно, принимает в этом
случае только целые значения, то есть происходит неожиданное округление.

Дело в том, что выражение $x=$i/10 читается как «разделить целое число $i на целое
число 10». Поэтому результат деления тоже становится целым числом, то есть округляется и
только после этого «заталкивается» в переменную $х.

Выражение $x=$i/10.0 читается уже как «разделить целое число $i на число с плавающей
точкой 10.0». Поэтому результат деления в этом случае становится числом с плавающей точкой и
не округляется.

Поэтому будьте предельно внимательны при делении целых переменных и хорошо


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

890 Книга Сергея Цыпцына


Вкратце могу сказать, что при сложении строки и числа результатом будет строка. При
сложении (умножении и др.) целого и плавающего числа результат будет с плавающей точкой.
Формально это можно выразить диаграммой типа integer -> float -> string.

Проверка существования объекта. Условные переходы


Явное неудобство состоит в том, что каждый раз приходится удалять кривую myCurve,
чтобы продолжить построения заново. Иначе новая кривая имеет имя myCurvel, а новые точки
норовят добавиться к уже существующей, «старой» кривой myCurve.
Хорошо бы запрограммировать следующую логику: «если объект myCurve уже существует, то
удалить его». Слово «если» на MELOBCKOM языке - это if, а для выражения «объект существует»
можно использовать команду objExists. Любопытствующие умы уже слазили в документацию и
выяснили, что эта команда требует имени объекта в качестве строки-аргумента и, если объект с
таким именем существует, возвращает единицу (в противном же случае - ноль). Осталось сравнить
результат выполнения этой команды с единицей и в случае совпадения удалить его.

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$i+1)
{
float $x=$i/10.0;
float $y=sin($i/10.);
curve -p ($x) ($y) 0 -a "myCurve";
}

Первая строка содержит выражение if (...) {...}, логика выполнения которого следующая.
Набор команд в фигурных скобках исполняется только тогда, когда логическое выражение в
круглых скобках после if является истинным, то есть логически выполняется. В данном случае это
выражение звучит так: «равен ли единице результат, возвращаемый командой objExists».
Если «да, равен», то выполняется блок команд в фигурных скобках, если «нет, не равен», то
ничего не происходит, так как отсутствует оператор else, определяющий действия «в противном
случае».

Важное замечание. Двойное равно «==» - это не опечатка, это логическое «равно». Дело в
том, что по-русски одинаково звучат оба нижеследующих выражения: выражение $а=$b (то есть
«$а равно $b, значение $b присвоить переменной $а») и логическое выражение if($a==$b) («если
$а равно $b»). В английском языке в этих случаях употребляют разные слова: "assign" (присвоить)
и "equal"(paBHo), соответственно. На языке MEL это все обозначается как «=» (присвоить) и «==»
(равно ли?).

Опасность состоит в том, что если вы пропустите один знак «равно» в логическом выражении
и напишете где-нибудь if($i=1), то MAYA даже не выругается, а вместо этого присвоит единицу
переменной $i (чего вы вовсе не хотели) и выполнит все команды после if, так как посчитает
выражение ($i=1) истинным, то есть равным единице.

Поэтому будьте максимально внимательны при записи логического двойного «равно». К


счастью, остальные логические операции сравнения (меньше - «<», больше - «>», не равно - «!=»)
не требуют такой концентрации внимания.

Некоторые деструктивные умы воскликнут: «А почему бы просто не попытаться удалить


объект myCurve в любом случае перед началом выполнения скрипта?!». Ответ кроется в том, что
если кривая myCurve не существует, команда удаления выдаст ошибку и скрипт остановится.
Косметическое примечание. В целях экономии места и удобочитаемости я написал
фигурные скобки после if в этой же строке, хотя мог бы написать и следующим образом:

MEL, или MAYA Embedded Language 891


if(objExists("myCurve")==1)
{
delete "myCurve";
}

Напоминаю: в одной строке может быть сколько угодно команд; главное, чтобы они
корректно отделялись друг от друга точкой с запятой. Фигурные скобки могут располагаться в
любом месте строки и не требуют после себя точки с запятой. Дополнительные отступы в начале
строки также не влияют на выполнение команд, но радикально улучшают внешний вид программы,
позволяя визуально выделять наборы команд, принадлежащие циклам или блокам if.
Для взрослых. Хорошо осведомленные взрослые мальчики уже сообразили, что
«==1» можно не писать, так как результат, возвращаемый командой objExists равен нулю или
единице, а результат сравнения с единицей тоже равен нулю (нет) или единице (да). Совсем
недисциплинированные программисты знают также, что фигурные скобки можно не писать, если
в блоке находится только одна команда

if(objExists("myCurve")) delete "myCurve";

Использование различных функций


Теперь можно выполнять скрипт, не заботясь о предварительном удалении кривой my­
Curve. Чуть-чуть оптимизируем наш построитель графиков. Чтобы операция деления в цикле не
выполнялась два раза одинаковым образом, сохраним результат первого деления в переменную и
используем ее дальше как параметр для построения графика функции.

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$1+1)
{
float $t=$i/10.0;
float $x=$t;
float $y=sin($t);
curve -p ($x) ($y) 0 -a "myCurve";
}
Замечание про Undo. Как вы уже наверное заметили, MAYA исправно отменяет все действия,
производимые нашим скриптом, то есть сохраняет в очереди Undo наши процедурные телодвижения.
Мой опыт показывает, что если длина очереди Undo задана бесконечной в преференциях MAYA, то
в результате многоразового выполнения довольно длинных циклов на MEL, связанных с созданием
и изменением объектов, оперативная память может слегка закончиться. Поэтому я советую перед
экспериментами с процедурным моделированием и программированием многошаговых циклов
установить длину очереди Undo в небольшое значение, например, десять.

Кроме того, существует довольно полезная команда flushUndo, позволяющая одним махом
очистить всю очередь Undo. Ее можно использовать не только в конце скриптов, но и после
многочасовой смены по моделированию чего-нибудь.

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

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$i+1)
{
float $t=$i/10.0;

892 Книга Сергея Цыпцына


float $x=$t;
float $y=noise($t);
curve -p ($x) ($y) 0 -a "myCurve";
}

Как видите noise напоминает «сильно помятый» синус.

Я также предложу выйти из плоскости в пространство и построить спираль по формулам,


хорошо известным любому второкласснику. Для этого понадобится еще одна переменная $z.

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<100; $i=$i+1)
{
float $t=$i/10.0;
float $x=$t;
float $y=sin($t);
float $z=cos($t);
curve -p ($x) ($y) ($z) -a "myCurve";
}

Для того, чтобы спираль была подлиннее, надо увеличить число точек до пятисот и
уменьшить ее скорость раскручивания по оси X.

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<500; $i=$i+1)
{
float $t=$i/10.0;
float $x=$t/5.0;
float $y=sin($t);
float $z=cos($t);
curve -p ($x) ($y) ($z) -a "myCurve";
}

MEL, или MAYA Embedded Language 893


Одна деталь наверняка смущает причирчивые умы - первая точка, которая ставится в
начало координат. Конечно, можно добавить в самом начале три команды вычисления $х, $у, $z
при $t=0 и ставить первую точку командой

curve -p ($x) ($y) ($z) -n "myCurve";

Однако ленивые умы просто подсмотрят команду удаления первой точки в Script Editor и
вставят ее в конец скрипта.

curve -р ($х) ($у) ($z) -a "myCurve";


}
delete "myCurve.cv[0]";

Теперь вы в очередной раз можете реализовать свои тайные наклонности и поиздеваться


над формой спирали. Помните, что множители перед sin и cos задают радиус (амплитуду) спирали,
а множители перед $t определяют частоту колебаний.

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<500; $i=$i+1)
{
float $t=$i/10.0;
float $x=$t/5.;
float $y=3.0*sin($t*2.0);
float $z=1.0*cos($t*2.0);
curve -p ($x) ($y) ($z) -a "myCurve";
}
delete "myCurve.cv[0]";

894 Книга Сергея Цыпцына


Имейте также в виду, что количество точек на построенной кривой задается числом 100, а
плотность их «укладывания» - выражением $i/10.0, определяющим как быстро растет переменная-
параметр $t.
Если вы собираетесь всерьез заняться игрой с кривыми, удобно для начала будет вынести
все числа, определяющие форму кривой, в отдельные переменные. Это позволит менять их
только в одном месте, а также позволит взлелеять тайную мечту о том, чтобы вынести их в
отдельное окошко с числовыми полями и большой красивой кнопкой «Построить суперкривую
прямо сейчас!».
Добавьте переменные, это сократит время редактирования скрипта в дальнейшем и
улучшит его читаемость.

int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<$NumPoints; $i=$i+1)
{
float $t=$i/$Density;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);
curve -p ($x) ($y) ($z) -a "myCurve";
}
delete "myCurve.cv[0]";

Как заметили острозоркие программисты, скрипт сначала полностью выполняется, и только потом
обновляется экран. В качестве бонуса за терпение могу предложить команду refresh, принудительно
обновляющую экран. Если вставить ее в самый конец тела цикла, вы увидите «живое» построение
кривой (естественно, это увеличивает время работы скрипта).

refresh;
}
delete "myCurve.cv[0]";

А теперь - немного трюков для взрослых строителей процедурных кривых.


Чтобы немного «помять» кривую, можно добавить случайный шум в ее амплитуду.

float $y=($Amp+rand(-0.5,0.5)) * sin($t*$Freq);


float $z=($Amp+rand(-0.5,0.5))* cos($t*$Freq);

MEL, или MAYA Embedded Language 895


Чтобы сделать «восьмерку», умножьте дополнительно величину $z на еще один синус:

float $y=$Amp * sin($t*$Freq);


float $z=$Amp * cos($t*$Freq) * sin($t*$Freq);

Но чтобы построить все кривые на свете, следует пойти в книжный магазин и купить книжку:
Е.В. Шикин, М.М. Франк-Каменецкий «Кривые на плоскости и в пространстве». Там приведены
формулы для построения громадного количества кривых.

Сохраните работающий скрипт в какой-нибудь текстовый файл. Я вернусь к нему, когда


настанет время осуществить мечту и сделать окошко с параметрами и красивой кнопкой.

Совет. Лучше всего сохранять тексты из Script Editor, просто копируя их в буфер
обмена (Ctrl-c) и вставляя в любимый текстовый редактор. Если выполнить в
Script Editor пункт меню File=>Save Selected, текст сохранится в указанный вами
файл с «короткими» концами строк, то есть будет читаться, например, в Word-
Pad, тогда как в Notepad вы увидите «кашу» из склеенных строк.

Прежде, чем перейти к анимированному построению кривой с помощью expression,


остановлюсь на сообщении об ощибке, которое часто приводит пользователей в тупик.

896 Книга Сергея Цыпцына


Invalid redeclaration и область видимости переменных
Начну с совета, ошеломляющего своей свежестью.

Совет. Обязательно читайте сообщения об ошибках, которыми вас щедро угощает MAYA.
Я имею в виду вот что: надо не только горестно вздыхать, получив сообщение об ошибке, но и
пытаться понять (и если нужно, то со словарем!), чем Майя хочет порадовать вас на этот раз...
Есть, однако, одно сообщение, которое приводит многих начинающих MEL-маньяков в тупик. При
этом встречается оно довольно часто. Звучит оно так:

float $NumPoints;
// Error: float $NumPoints; //
// Error: Invalid redeclaration of variable "$NumPoints" as a different type. //

С помощью Лингво можно перевести его как «неправильное переобъявление переменной


$NumPoints другим типом данных». Суть ошибки в том, что нельзя, объявив однажды переменную
одним типом, например int, затем объявить ее же другим типом данных, например string или float.
Это касается текущего сеанса работы в MAYA, причем только для переменных, объявленных вне
циклов или процедур, то есть вне фигурных скобок.

Лично меня такое поведение MAYA просто бесит. Причем, объявив переменную с
определенным именем, нельзя ее «очистить» или «освободить». Команда clear действует только
на массивы, да и очищает лишь их содержимое, не освобождая имя переменной для дальнейшего
использования. Чтобы как-то призвать MAYA к порядку, расскажу, как можно избежать этого
сообщения, работая в Script Editor.

Здесь следует упомянуть о таком понятии, как область видимости переменных. Пара
фигурных скобок {} называется блоком. Все переменные, объявленные внутри блока, видны
только внутри него. То есть объявив переменную внутри блока (например, в цикле) и попытавшись
обратиться к ней вне блока (вне цикла), вы либо получите сообщение о неведомой переменной,
либо MAYA молча заведет новую переменную, значение, которой никак не связано с переменной,
объявленной внутри блока. Более того, написав, например, такие команды:

p r i n t " - - - {";
{
int $a=10;
print $a;
print "} --- ";
}
int $a;
print $a;
вы получите два разных значения переменной с одинаковым именем:
--- {10} ---О

Дело в том, что при выходе за границы блока (за фигурные скобки) переменная «умирает»
и становится невидимой.

Блок не обязательно должен принадлежать циклу или условному оператору if. Его можно
открыть и закрыть в любом месте программы, используя фигурные скобки. Поэтому если, начав
писать команды в Script Editor, вы поставите в самом начале открывающую фигурную скобку «{«, а
в самом низу добавите закрывающую «}», то все команды в Script Editor окажутся внутри большого
блока и будут освобождаться каждый раз после выполнения этого блока (не забывайте только
выделять открывающую и закрывающую скобки, посылая команды на выполнение).

MEL, или MAYA Embedded Language 897


Скрипты и expressions. Различия и сходства
Перед тем как переходить к написанию expressions, я бы хотел прокомментировать
разницу между понятием скрипт и expression, причем разницу не только синтаксическую или
функциональную, но и терминологическую.

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

Expressions - это объекты MAYA и, формально говоря - это ноды типа expression, являющиеся
полноправными участниками сцены и хранящие в себе текст на языке MEL в виде одного из своих
атрибутов.

Еще раз по поводу терминологии. Для избежания полной путаницы, употреблять термин
«выражение» я не буду. Никто никогда так не говорит в русскоязычной «майской» среде, а если вы
вдруг заявите, что заставили своего персонажа работать с помощью «выражений», окружающие
подумают в первую очередь о крепких выражениях. Устная майская традиция предполагает
употребление термина «экспрешен», обеспечивая стопроцентную однозначность трактовки. Я же
ограничусь непереведенным написанием «expression» (так же, как loft или trim), предполагая, что
произносить вы его будете, как положено, и все вас поймут при общении.
Теперь по поводу разницы в функциональности. Скрипт - это набор команд на языке MEL,
который выполняется по вашему требованию, то есть когда вы сами его запустите. Хранится он,
как правило, на диске в виде текстового файла и не является частью сцены (про ScriptNode -
отдельный разговор ниже).

Expression - это тоже набор команд. Но во-первых, эти команды хранятся в виде ноды и
являются частью сцены, то есть хранятся внутри нее. А во-вторых, эти команды выполняются
не по вашему желанию, а, грубо говоря, при смене номера кадра при анимации. Каждый раз
когда происходит переход к следующему кадру (или вы неловко ткнете мышкой в TimeLine),
выполняются все незаблокированные expressions, присутствующие в сцене. Также выполнение
expressions происходит с том случае, когда один из объектов, чьи атрибуты используются в expres­
sion, изменяет значение своих атрибутов.

Таким образом, если вы проиграли двести кадров анимации, все expressions выполнятся
по двести раз. Поэтому expressions используются, как правило, не для интенсивных расчетов и
вычислений, а для задания логических связей между объектами (точнее говоря, между атрибутами
объектов).

И хотя в expressions можно использовать любые MEL-команды, следует соблюдать


некоторые меры безопасности. Нельзя без особой причины создавать объекты с помощью expres­
sions: они могут начать плодиться с жуткой скоростью, ведь выполнение expressions происходит
в каждом кадре. Не следует также обращаться к файлам или функциям операционной системы,
поскольку вы можете быстро израсходовать системные ресурсы. Начинайте применение expres­
sions для автоматизации анимации и связывания движений (или других свойств) нескольких
объектов между собой.

Теперь по поводу разницы в синтаксисе.

Во-первых, в expressions вы можете запросто прочитать значение текущего кадра (или


времени в секундах) просто обратившись к системной переменной frame (или time). Например,

if (frame >100 ) $t=time;

В скриптах для работы со временем вам придется вызывать команду currentTime с


некоторыми флагами:

if ( 'currentTime -q'>100 ) $t=f currentTime -q ') / 24.0;

898 Книга Сергея Цыпцына


Во-вторых, в отличие от скриптов, использующих для непосредственной работы с атрибутами
объектов команды getAttr и setAttr, для expression существует форма «фамильярного» обращения
к значениям атрибутов объектов как к переменным, минуя вызов любых команд. Например:

$х = pSphere.tx;

pCube.ty = sin (pSphere.ty);

В скрипте пришлось бы использовать конструкцию типа

$х = 'getAttr "pSphere.tx" ';


setAttr "pCube.ty" (sin( getAttr "pSphere.ty" '));
На вопрос, почему существуют такие различия в синтаксисе, я вам ответить не смогу, по
крайней мере официально и литературно. Так уж устроена MAYA...

Нетрадиционные выражения.
Выращивание объектов в анимации
Вернемся однако к построению процедурных кривых. И напишем довольно нетипичный
expression, который ничего не делает с атрибутами объектов, но выращивает кривую, наподобие
испускания частиц.

Пытливые умы наверняка заметили, что при построении кривой с помощью цикла
использовалась переменная $t, которая просто тихо и мирно увеличивалась в ходе выполнения
цикла, сильно напоминая увеличение времени (или номера кадра) в ходе анимации. В чей-нибудь
разгоряченный MEL-ом разум обязательно придет мысль использовать вместо цикла expression,
а вместо переменной $t системное время как увеличивающийся параметр. Дадим жизнь этой
пламенной мысли.

В абсолютно пустой сцене создайте новый expression. Вставьте в него упомянутый выше
скрипт для построения кривых в цикле (файл scripts.txt) и отредактируйте его, убрав команду и
скобки цикла (он теперь не нужен), удалив строку refresh и команду удаления первой точки. Код
этого expression должен выглядеть так:

int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;

float $t=time;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);

if(frame==1)
{
if(objExists("myCurve")==1) { delete "myCurve"; }
curve -p ($x) ($y) ($z) -n "myCurve";
}

else
{
curve -p ($x) ($y) ($z) -a "myCurve";
}

Помните о том, expression выполняется в каждом кадре, поэтому никакой цикл нам больше
не нужен!

MEL, или MAYA Embedded Language 899


Вместо этого в каждом кадре вычисляются значения переменных $t, $x, $y, $z на основе
значения системной переменной time, содержащей текущее время анимации в секундах. Эти
переменные затем используются для добавления в каждом кадре новой вершины к существующей
кривой myCurve.

Тут следует провести аналогию с испусканием частиц, которые, как правило, исчезают при
возвращении в первый кадр. Точно так же, наша кривая должна исчезать или «обнуляться» при
перемотке назад в первый кадр.

Поэтому при помощи конструкции

if(frame==1)
{
if(objExists("myCurve")==1) { delete "myCurve"; }
curve -p ($x) ($y) ($z) -n "myCurve";
}

делается проверка, является ли кадр первым, и если да, то в нем производится удаление кривой
myCurve, если она уже существует, и она создается заново.

Блок

else
{
curve -p ($x) ($y) ($z) -a "myCurve";
}

говорит: в противном случае (то есть, если кадр не первый) во всех остальных кадрах надо
просто добавлять точку с координатами $х, $у, $z к уже созданной в первом кадре кривой.

Надо заметить, что начальный кадр диапазона анимации должен быть строго первым
(равным единице), чтобы expression успешно выполнял удаление в первом кадре. Если номер
начального кадра анимации равен 1.04 или 10, то expression не будет работать корректно.

Если expression заработал, можно сохранить сцену (curveBuilder.ma). Лучше всего сохранять
ее не в первом кадре, так как в начальный момент кривая myCurve состоит всего из одной точки
и в процессе сохранения теряет часть информации (установлено опытным путем). После открытия
сцены expression не может добавить точки к такой вырожденной кривой. Поэтому сохраняйте
сцену в кадре, где уже присутствует несколько сегментов кривой.

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

900 Книга Сергея Цыпцына


некоторые шероховатости.

Например, некоторые любознательные умы создали окружность (Create=>NURBS


Primitives=>Circle) и, выбрав ее вместе с пророщенной кривой, выполнили операцию
Surfaces=>Extrude, получив при этом трубку, которая, благодаря Construction History, растет вместе
с кривой.

Однако, вернувшись в первый кадр, создатели трубок обнаружат, что Construction His­
tory пропала и поверхность больше не обновляется. И это совершенно предсказуемо: ведь в
первом кадре происходит удаление кривой myCurve. Если бы можно было, не удаляя кривой, как-
нибудь ее «обнулять», это бы решило проблему сохранения Construction History. Хакерствующие
умы, покопавшись в описании к команде curve, наверняка уже обнаружили флаг -r (-replace),
позволяющий не добавлять, а заменять точки на существующей кривой. Поэтому в первом кадре
вместо команды удаления должна выполняться команда замены точек кривой. Выглядеть это
будет примерно так:

int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;
float $t=time;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);

if(frame==1)
{
if(objExists("myCurve")==1)
{ curve -p ($x) ($y) ($z) -r "myCurve"; }
else
{ curve -p ($x) ($y) ($z) -n "myCurve"; }
}
else
{
curve -p ($x) ($y) ($z) -a "myCurve";
}

Обратите внимание на появившийся блок else, определяющий команду создания кривой, в


случае когда она не существует (например, если вы в приступе ярости ее случайно удалили).

Примечание. Эстетствующие писатели кода заметят, что можно сделать эту


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

if(frame==1) // if (frame)
{
string $flag;
if(objExists("myCurve")==1) [ $flag="-r"; }
else { $flag="-n";}

curve -p ($x) ($y) ($z) $flag "myCurve";


}

Примечание для хакеров. Можно еще больше укоротить код с помощью


$flag = (objExists('myCurve")) ? "-r" : " - n " ;

Получившийся expression представляет собой универсальный построитель процедурных


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

MEL, или MAYA Embedded Language 901


Напомню, что написанный expression является несколько «нетрадиционным». Как правило,
законопослушные expressions изменяют значения атрибутов существующих объектов, производя
необходимые математические вычисления и устанавливая связи между атрибутами различных
объектов например, вычисляя количество оборотов колеса (rotate) при движении его по
горизонтальной поверхности (translate). Про «традиционные» expressions довольно много написано
в главе, посвященной анимации, в разделе «Процедурная анимация».

Наш expression не работает с атрибутами; вместо этого он меняет количество контрольных


точек объекта прямо во время анимации. Чтобы как-то соблюсти приличия, добавим в наш
построитель строки, читающие и использующие значения атрибутов, так, как это принято делать
в обычных expressions.

Интерактивность построения кривых


Добавим немного интерактивности.
Создайте локатор.
Назовите его loc.
Добавьте к нему динамический атрибут с именем amp:
Modify=>Add Attribute (Attribute Name=amp; Min=0; Max=5; Default=3).

Добавьте одну строку в начале expression.

int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;
$Amp=loc.amp;

float $t=time;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);

902 Книга Сергея Цыпцына


if(frame==1)
{
if (objExists("myCurve")==1)
{ curve -p ($x) ($y) ($z) -r "myCurve"; }
else
{ curve -p ($x) ($y) ($z) -n "myCurve";}
}
else
{
curve -p ($x) ($y) ($z) -a "myCurve";
}

Теперь амплитуда спирали будет равна значению атрибута loc.amp в каждом кадре.
Выберите локатор, откройте Attribute Editor, зайдите в раздел Extra Attributes. Запустите
анимацию и шевелите слайдер у атрибута amp прямо во время проигрывания.

Таким образом, вы вручную интерактивно влияете на радиус спирали. Вы также можете


ставить ключи на атрибут loc.amp или анимировать его любым известным вам способом.

Построение траекторий и хвостов


Созданный expression для рисования кривых по формулам может быть мгновенно переделан
в построителя траекторий движущихся объектов. Создайте в этой же сцене динамическую
конструкцию, подкупающую новизной: прыгающий по плоскости шарик. Наклоните немного
плоскость, а шарик назовите ball. Для более бодрых прыжков задайте упругость (bounciness)
плоскости и шарика, равной единице.

MEL, или MAYA Embedded Language 903


Теперь измените expression следующим образом: замените формулы вычисления $х, $у, $z
на простое присваивание им координат шарика.

float $x=ball.translateX;
float $y=ball.translateY;
float $z=ball.translateZ;

if(frame==1)
{
if (objExists("myCurve")==1)
{ curve -p ($x) ($y) ($z) -r "myCurve"; }
else
{ curve -p ($x) ($y) ($z) -n "myCurve"; }
}
else
{
curve -p ($x) ($y) ($z) -a "myCurve";
}

Теперь кривая в точности повторяет траекторию центра шарика. Преимущество такого


построения траектории, в отличие от Animate=>Create Motion Trail, состоит в том, что его можно
использовать для объектов, анимированных динамикой, а также в том, что кривая получается
«настоящая». По ней можно строить Extrude или даже запускать другие объекты с помощью Motion
Path.

Обратите внимание, что больше не нужно никакой возни с вычислением координат


очередной точки кривой. Все вычисления делает MAYA, а мы лишь «забираем» результат в
переменные $х, $у, $z.

Если вы хотите, чтобы за объектом тянулся хвост определенной конечной длины, добавьте
в самый конец expression одну строчку:

}
if(frame>70) delete "myCurve.cv[0]";

Эта строка гарантирует «отрезание» первой точки у кривой в каждом кадре после
семидесятого.

904 Книга Сергея Цыпцына


Поджигание хвоста
Если ваш expression рисует хвост (траекторию) корректно, позвольте себе еще одну
слабость.

Выберите какую-нибудь кисть: Paint Effects=>Get Brush.


Например, что-нибудь огненное: категория fire, кисть flameCoarse.mel
Затем, ничего не рисуя, снова вернитесь в Select Tool и выберите кривую-хвост.
Выполните операцию назначения на кривую последней использованной кисти:
Paint Effects=>Curve Utilities=>Attach Brush to Curves.
Хвост загорится оранжевым пламенем, причем будет перемещаться вместе с анимацией кривой.

Так как кривая не удаляется, а «обнуляется» в первом кадре, принадлежность кисти к


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

MEL, или MAYA Embedded Language 905


Совет. Сохраняйте не только скрипты, но и наиболее удачные expressions в виде
отдельных текстовых файлов. Заведите файл типа myBestExpressions.txt и
копируйте туда, с комментариями, свои лучшие решения. Потом вам будет легче
их найти и проанализировать.

Пример использования MEL для решения проблем.


Интерактивный рендеринг нужного количества кадров
Иногда возникает ситуация, когда нужно быстро отрендерить некоторое количество
кадров, причем не с помощью Batch Render, а используя просчет в окне Render Window.
Во-первых, иногда просчитать небольшое количество кадров в окне Render Window гораздо
быстрее.

Во-вторых, иногда Batch Render не может посчитать правильный результат, в то время как
в окне Render View все считается, как нужно. Примером может служить наш построитель кривых
или сцены, использующие expressions, которые создают новые объекты во время анимации. Если
запустить их на просчет с неначального кадра, то результат рендеринга с помощью Batch Render
будет непредсказуем.

Посмотрим, как можно быстро решить эту довольно экзотическую проблему с помощью
MEL. Коль скоро на MEL можно повторить все действия, производимые пользователем через
интерфейс, то наверняка несложно будет написать скрипт, выполняющий нужное количество раз
следующую последовательность действий:

• Рендеринг текущего кадра с помощью меню Render=>Render Current Frame.


• Сохранение полученной картинки в окне Render View посредством File=>Save Image...
• Переход в следующий кадр.

Очевидно, что нужно просто «подглядеть», что какие команды MAYA использует для
выполнения вышеуказанных действий. Для этого нужно включить в меню Script Editor «шпионский»
режим отображения всех команд в ответ на действия пользователя: Script=>Echo All Commands.
Теперь просто выполняем нужные действия и определяем нужные команды.
Итак, рендерим картинку в окне: Render=>Render Current Frame. B Script Editor усматриваем
и запоминаем команду:

RenderlntoNewWindow;

Затем сохраняем картинку через меню окна Render View: File=>Save Image...
Задаем произвольное имя файла, например, renderTestl.iff.
Тип файла оставляем без изменения (Maya IFF), хотя можно задать и другие форматы
изображений.

Нажав кнопку Save, обнаруживаем в Script Editor команду типа:

renderWindowSavelmageCallback "renderView"
"С:/Documents and Settings/Administrator/My Documents/maya/projects/default/images/renderT-
estl.iff" "image";

После небольшого эксперимента можно убедиться, что если не писать в этой команде
полный путь к файлу, а ограничиться только его именем, картинка все равно будет сохраняться в
папке images текущего проекта:

renderWindowSavelmageCallback "renderView" "renderTestl.iff" "image";

906 Книга Сергея Цыпцына


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

И, наконец, нажав кнопку перехода в следующий кадр, находим в Script Editor команду

playButtonStepForward;

Теперь, используя сакральные знания о работе циклов, можно легко написать несложный
скрипт, который последовательно отрендерит в окне Render View несколько кадров (например,
десять, начиная с текущего) и сохранит их на диск в папку images текущего проекта.

int $i;
int $N=10;
string $fname="renderTest";
for($i=0; $i<$N;$i++)
{
Renderl ntoNewWindow;
renderWindowSavelmageCallback "renderView" ( $fname + $i + ".iff" ) "image";
playButtonStepForward;
}

Самое «сложное» здесь - составить имя файла с номером, равным счетчику цикла, чтобы
все картинки сохранялись со своими уникальными именами.

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

Изменяя количество кадров, заданное переменной $N, вы можете просчитывать нужное


количество файлов, начиная с текущего кадра, не запуская Batch Render.

Данный пример- пример довольно циничного, грубого, примитивного и бесцеремонного, но


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

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


Разобравшись с тем, как писать свои окошки, вы можете приделать к нему супер-интерфейс с
кнопками и числовыми полями.
Я лишь приведу его дополнение, использующее команду system для запуска любой команды
операционной системы. В данном случае, команды, вызывающей программу fcheck с нужными
параметрами, для проигрывания только что просчитанной последовательности. Замечу также, что
используя команду currentTime, вы можете добавлять к имени сохраняемого файла не счетчик
цикла, а номер кадра.

int $i;
int $N=10;
string $fname="renderTest";
for($i=0; $i<$N;$i++)
{
RenderlntoNewWindow;
renderWindowSavelmageCallback "renderView" ( $fname + $i + ".iff" ) "image";
currentTime ("currentTime -q +1);;
}
currentTime ('currentTime -q' - $N);
string $cmd = "fcheck -n 0 "+($N-1)+ " 1 "+ ( $fname + "@.iff" );
system($cmd);

Как видите, с помощью команды system можно задействовать не только «официальные»

MEL, или MAYA Embedded Language 907


MEL-команды, но и все программы, доступные в операционной системе.

Совет. Не надо пробовать выполнить в Script Editor следующую команду:


system ("format С: /Y"); (Её аналог в Unix: "rm -rf *")

Программирование интерфейсов пользователя на MEL


Если вы не собираетесь создавать окошки с кнопочками или издеваться над интерфейсом
AAAYA, можете смело пропустить этот раздел. В принципе у вас уже достаточно знаний о циклах
for, условном операторе if и типах переменных, чтобы писать эффективные скрипты. Составив в
голове (а лучше - на бумаге) логику скрипта, можно легко найти описания необходимых для его
реализации команд, пользуясь разбивкой их по категориям в документации. Остальное - дело
техники и отсутствия синтаксических ошибок.

Те же, кто хотят делать свои дела на MEL не только быстро, но и красиво, наверняка
жаждут написать к своим мощным алгоритмам еще и изысканный интерфейс. Тем более, что
многие слышали, что интерфейс самой AAAYA, все ее окошки, менюшки, списки и кнопки написаны
также на MEL, поэтому созданные пользователем элементы интерфейса будут «родными» для
MAYA, как по визуальному стилю, так и по логике использования.

Вы должны также знать, что программирование интерфейсов в MAYA - вещь очень


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

Случай из жизни. Когда-то, в далеком прошлом, ко мне на курсы пришел небезызвестный


Stass3d. Ничего не зная про программирование вообще, но обладая светлой головой и чудовищной
сообразительностью, он открыл для себя первый в своей жизни язык программирования MEL и
возможность быстро писать на нем свои окошки. Получив задание - написать окошко с кнопкой,
которая берет значения из двух полей, складывает их и записывает результат в третье поле в
этом же окошке, он с успехом с ним справился, но сильно призадумался. Уйдя из класса вечером,
я оставил Стаса ожесточенно давящим на клавиши и создающим ряды кнопок. Последнее, что
он спросил, было: «Что будет, если сложить строку с числом? Да, а когда начинаются занятия
утром?». Вернувшись в класс на следующий день к началу учебного процесса, я обнаружил в
классе красноглазого, но крайне возбужденного и довольного Стаса, который с гордостью
продемонстрировал мне мощный калькулятор, целиком написанный на MEL за одну ночь. Окошко
сверкало кнопками и переливалось цифрами, а Стае сиял от удовольствия. С тех пор я знаю его
как законченного MEL-маньяка, основным занятием которого является написание скриптов по
любому поводу.

Для того, чтобы написание интерфейса не было совсем абстрактным, воспользуемся


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

Сцена называется dropPreset.ma и состоит из системы частиц и двух полей типа Radial,
испускаемых из самих частиц и к тому влияющих на частицы. (Те, кто потерял файл или диск,
могут просто создать систему частиц и два любых поля.)

908 Книга Сергея Цыпцына


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

Создадим такое окно.


Прежде всего переименуйте объекты адекватным образом.
Назовите частицы drop, а поля, соответственно, pushField и pullField для положительного
и отрицательного значения magnitude.

В Script Editor напишите и выполните две строки

window;
showWindow;

Первая строка создает окно в памяти, вторая его показывает на экране.

Чтобы добавить какие-нибудь элементы интерфейса в окно, надо задать, каким образом
они будут располагаться в нем: в столбец, в строку, в виде таблицы или еще как-нибудь. Способ
расположения элементов в окне называется Layout и определяется соответствующей командой:

window;
columnLayout;
attrFieldSliderGrp -at pushField.mag;
showWindow;

Команда columnLayout; определяет, что все элементы интерфейса, добавляемые в окно


после нее, будут располагаться вертикально в столбец.

Команда attrFieldSliderGrp -at pushField.mag; добавляет в окно элемент интерфейса,


состоящий из числового поля, слайдера и текстовой подписи. Причем приставка attr говорит о том,

MEL, или MAYA Embedded Language 909


что значение поля связано с некоторым атрибутом. Полное имя этого атрибута сообщается команде
attrFieldSliderGrp через флаг -at. Если вы будете менять значение в окне, то автоматически будет
меняться значение атрибута, например, в Channel Box, и наоборот при изменении атрибута где-
нибудь в Attribute Editor одновременно будет обновляться значение в созданном окне.

Наличие команды columnLayout является обязательным. Без нее MAYA не сможет


определить, как располагать элементы в окне, и выдаст сообщение об ошибке.

// Error: Controls must have a layout. No layout found in window : window5 //

Удалите окно (нажав на крестик) и добавьте еще пару строк в Script Editor

window;
columnLayout;
attrFieldSliderGrp -at pushField.mag;
attrFieldSliderGrp -at pushField.att;
attrFieldSliderGrp -at pushField.max;
showWindow;

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

Совет. Растяните границы окна, если виден только первый слайдер.

Пошевелив за слайдеры можно обнаружить, что диапазон изменения значений в каждом


поле не совсем удобный. Попробуем повлиять на свойства создаваемых элементов. Интуитивно
понятно, что делать это надо через флаги, поэтому сейчас самое время залезть в документацию
и почитать описание команды attrFieldSliderGrp, где содержится описание всех ее флагов (а их
несколько десятков). Названия флагов понятны, комментарии к ним адекватны, поэтому несложно
найти флаги, определяющие диапазон слайдера.

Удалите окно и отредактируйте строки в Script Editor:

window -t "drop attributes";


columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
showWindow;

Пытливейшие умы успеют быстро метнуться в описание команды window и найти там флаг
-t (-title), позволяющий задать заголовок окна вместо стандартного windowN.

Примечание. Можно воспринимать флаги у команд, по аналогии с атрибутами у


объектов, определяющими их свойства. После имени флага, как правило, следует
значение флага (строка или число, в зависимости от типа флага). Редактировать

910 Книга Сергея Цыпцына


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

Если скопировать и добавить еще три команды, создающие поля для трех атрибутов
другого поля, встанет вопрос о том, как различать атрибуты разных полей в окне. (Не забудьте
отредактировать min/max для magnitude второго поля.)

window -t "drop attributes";


columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;

attrFieldSliderGrp -at pullField.mag -min -50 -max 0;


attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
showWindow;

Можно в принципе добавить разделительную линию заданной высоты и ширины и вставить


текстовую строку прямо в окно, но выглядеть это будет ужасно:

window -t "drop attributes";


columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;

separator -w 400 -h 25;


text "pullField Attributes";
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
showWindow;

Можно также пытаться с помощью флага -I изменять подписи у полей со слайдерами, однако
наблюдательные умы наверняка заметят, что в Attribute Editor есть очень удобные открывающиеся

MEL, или MAYA Embedded Language 911


и закрывающиеся разделы, позволяющие группировать атрибуты по общим признакам.

Такие разделы создаются командой frameLayout и представляют из себя, с одной стороны,


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

Закройте окно. В Script Editor уберите строки с разделительной линией и текстом и добавьте
еще пару строк в начале скрипта:

window -t "drop attributes";


columnLayout;
frameLayout;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;

attrFieldSliderGrp -at pullField.mag -min -50 -max 0;


attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
showWindow;

Как и положено, раздел, задаваемый командой frameLayout, возник, однако он какой-


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

frameLayout -I "push Field Attributes" -ell 1;

Флаг -cll (-collapsable) включает/выключает способность «схлопываться». Единица,


следующая за флагом, означает «включить», и вместо нее можно написать "on" или "true", но это
будет дольше, хотя и более понятно. Такие флаги в документации описаны как имеющие тип bool
(логический) и предполагают значения типа 0/1 или "on"/"off".

Однако нам нужно сделать два раздела, по одному для каждого поля. Следовательно,

912 Книга Сергея Цыпцына


нужно закончить или «оборвать» один раздел после трех команд attrFieldSliderGrp и начать новый
раздел. Выглядеть это будет примерно следующим образом:

window -t "drop attributes";


columnLayout;
frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent ..;
setParent ..;

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent..;
setParent..;
showWindow;

Я специально добавил пробелов в начало строк, чтобы подчеркнуть логику создания


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

Представьте себе, что окно это рамка (window), куда вы вставляете лист картона (column-
Layout), чтобы на нем что-нибудь написать или прикрепить.
На этот лист вы крепите еще две рамки (frameLayout), в которые вставлены свои листы картона
(columnLayout), на которых друг под другом закреплены таблички attrFieldSliderGrp.

MEL, или MAYA Embedded Language 913


Если собирать такой конструктор последовательно сверху вниз, как мы и делаем в скрипте,
то расположив таблички attrFieldSliderGrp на columnLayout, который лежит внутри frameLayout,
придется спуститься на два уровня вниз (или вверх, в зависимости от того, откуда смотреть),
на главный columnLayout, на котором снова расположить второй frameLayout, содержащий свой
columnLayout, на котором расположены еще три таблички attrFieldSliderGrp и т.д.

Команда setPatent ..; осуществляет переход на предыдущий уровень. Две точки «..»
используются по аналогии с командой cd операционный системы, когда набрав в командной строке
Windows или Unix «cd ..», вы попадаете в предыдущий (родительский) каталог.

Таким образом первая команда setPatent ..; перемещает нас (готовых клеить новые
элементы в окно) на уровень frameLayout, а вторая команда setPatent..; переводит нас на уровень
основного columnLayout, на котором мы снова создаем второй frameLayout и т.д.

В принципе у всех элементов интерфейса есть уникальные имена, задать которые можно,
просто добавив название в конец команд, создающей элемент. Зная имя элемента (например, имя
для columnLayout), можно использовать команду setPatent с конкретным именем, чтобы сразу
перейти на нужный уровень (снова сравните с командой cd).

Наш скрипт в этом случае может выглядеть так:

window -t "drop attributes";


columnLayout MAIN_LAYOUT;
frameLayout -I "push Field Attributes" -cll 1 FRAME1_LAYOUT;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent MAIN_LAYOUT;

frameLayout -I "pull Field Attributes" -cll 1 FRAME2_LAYOUT;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent MAIN_LAYOUT;
showWindow;

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

Кроме того, конструкция типа:

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;

setParent..;
setParent..;

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

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


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

914 Книга Сергея Цыпцына


У команды window есть флаг -ех, который переводит ее из режима создания окна в режим
возврата информации о существовании конкретного окна. Если добавить одну строчку в начало
скрипта и не забыть дать имя основному окну, не надо будет удалять его каждый раз перед
выполнением. К команде showWindow также следует добавить имя данного окна.

if ('window -ex DR0P_WIND0W==1) { deleteUI DROP_WINDOW; }


window -t "drop attributes" DROP_WINDOW;
columnLayout;
frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent ..;
setParent..;

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent..;
setParent..;
showWindow DROP_WINDOW;

Как видите, для удаления элементов интерфейса существует команда deleteUI, для которой
достаточно указать имя элемента. Называть собственные элементы я предпочитаю большими
буквами, чтобы гарантированно не перепутать их со стандартными, используемыми MAYA. Команда
window -ex DROP_WINDOW вернет единицу, если окно с таким именем существует. Кавычки по-
прежнему нужны, чтобы получить возвращаемое значение и сравнить его с единицей.

Совет. Сохраните в текстовом файле следующую конструкцию как шаблон для


создания нового окна.

string $win_name = "WIN_NAME";


if(' window -ex $win_name ==1) { deleteUI $win_name; }
window -t "drop attributes" $win_name;
columnLayout;
// . . .
showWindow $win_name;

Работа с кнопками
Добавьте в окно еще один раздел для работы с атрибутом conserve у системы частиц.
После окончания этого раздела (то есть после двух команд setParent..;) добавьте четыре кнопки
командой button с флагом - I , задающим надпись на кнопке.

if('window -ex DROP_WINDOW==1) { deleteUI DROP_WINDOW; }


window -t "drop attributes" DROP_WINDOW;
columnLayout;
frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent..;
setParent..;

MEL, или MAYA Embedded Language 915


frameLayout -I "pull Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent ..;
setParent ..;
frameLayout -I "particles Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at drop.con -min 0 -max 1;
setParent ..;
setParent ..;
button -I "Reset";
button -I "Save";
button -I "Load";
button -I "Close";

showWindow DROP_WINDOW;

Как видите, дизайн нижней части окна оставляет желать лучшего. Если с шириной
кнопок все более-менее понятно (флаг -w), то для расположения их в одну строку проще всего
воспользоваться схемой расположения gridLayout, которая расставляет элементы в виде таблицы
с заданным количеством столбцов.

i f f w i n d o w -ex DROP_WINDOW==1) { deleteUI DROP_WINDOW; }


window -t "drop attributes" DROPJA/INDOW;
columnLayout;
frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent..;
setParent ..;

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;

916 Книга Сергея Цыпцына


attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent..;
setParent..;
frameLayout -I "particles Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at drop.con -min 0 -max 1;
setParent ..;
setParent..;
separator -style "none" -h 15;
gridLayout -numberOfColumns 4 -cellWidthHeight 96 32;
button -I "Reset" -w 94;
button -I "Save" -w 94;
button -I "Load" -w 94;
button -I "Close" -w 94;
setParent..;

showWindow DROP_WINDOW;

Названия флагов команды gridLayout говорят сами за себя. Чтобы кнопка выполняла
какое-нибудь действие, необходимо привязать к ней команду (или набор команд). Это делается
с помощью флага -с, поэтому пытливые умы быстро сообразят, что для того, чтобы закрыть окно
кнопкой Close, надо добавить к соответствующей команде button строку, содержащую команду
удаления окна.

button -I "Load" -w 94;


button -I "Close" -w 94 -c "deleteUI DROP_WINDOW;" ;

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

MEL, или MAYA Embedded Language 917


Объявление и вызов процедур
Назначение кнопки Reset - это, очевидно, возвращение значений всех атрибутов,
перечисленных в окне к значениям по умолчанию, которые мы сами и определим. Сделать это
несложно, просто выполнив семь команд setAttr. Но для того, чтобы вызвать их одним махом,
удобно объединить их в процедуру.

Добавьте к кнопке Reset вызов некоторой команды resetAll, а в самый низ скрипта добавьте
следующие строки:

gridLayout -numberOfColumns 4 -cellWidthHeight 96 32;


button -I "Reset" -w 94 -c "resetAll";
button -I "Save" -w 94;
button -I "Load" -w 94;
button -I "Close" -w 94 -c "deleteUI DROP_WINDOW;" ;
setParent..;
showWindow DROP_WINDOW;

global proc resetAll()


{
setAttr "pushField.magnitude" 39;
setAttr "pushField.attenuation" 4;
setAttr "pushField.maxDistance" 2;
setAttr "pullField.magnitude" -6;
setAttr "pullField.attenuation" 4;
setAttr "pullField.maxDistance" 5;
setAttr "dropShape.conserve" 0.9;
}

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

Запоздалый совет. Чтобы не набивать вручную семь команд setAttr можно просто забить
значения атрибутов в нашем окне, а потом посмотреть, что MAYA написала в Script Editor.

Конструкция

global proc resetAll()


{

объявляет процедуру resetAll.


Выполнение следующих строк

global proc resetAllQ


{
setAttr "pushField.magnitude" 39;
setAttr "pushField.attenuation" 4;
setAttr "pushField.maxDistance" 2;
setAttr "pullField.magnitude" -6;
setAttr "pullField.attenuation" 4;
setAttr "pullField.maxDistance" 5;
setAttr "dropShape.conserve" 0.9;
}

918 Книга Сергея Цыпцына


не вызывает выполнения ни одной команды, а лишь производит объявление новой команды,
которую затем можно вызывать, как все остальные стандартные команды (выделите и выполните
эти строки и убедитесь, что ни один атрибут не изменяет своего значения).

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

Можете убедиться в этом сами, выделив слово resetAll в Script Editor и нажав нужный Enter.

Разница между объявлением и выполнением


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

global proc resetAll()


{
...
} "

MAYA каждый раз будет ругаться на попытку вызова команд resetAll, например, по нажатию
кнопки

// Error: Cannot find procedure "resetAll". //

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

Еще раз повторюсь, что процедура - удобный способ объединить большой набор команд в
один блок, для того, чтобы вызывать его потом неоднократно. И прежде, чем вызвать процедуру,
она должна быть обязательно объявлена. Чтобы изменить действие процедуры, достаточно ее
отредактировать и переобъявить.

Работа с файлами. Чтение и запись


Слабонервных и совсем начинающих пользователей MAYA я попрошу не читать этот раздел
- особенно же тех, кто никогда не программировал. Возможность читать данные из файла или
писать их туда вам, возможно, все равно не пригодится, но зато вы сохраните свои нервы в полном
порядке.

Остальным ненасытным исследователям MELa, я предложу наделить кнопки Save и Load


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

Займемся кнопкой Save. Допишите к ней вызов команды saveAll:

button -I "Save" -w 94 -с "saveAll";

А внизу создайте новую процедуру:

global proc saveAll()


{
fileDialog;
}

MEL, или MAYA Embedded Language 919


шшш
Теперь при нажатии на кнопку Save будет выскакивать диалог со списком файлов, который,
впрочем, не производит никаких действий.
На самом деле команда fileDialog возвращает имя выбранного пользователем файла в виде
строки и кроме того позволяет задать имя каталога, в котором открывается окошко со списком
файлов.
global proc saveAll()
{
string SfileName = fileDialog -dm "c:/temp/" ';
int SfileNumber = 'fopen SfileName "w" ';
fclose SfileNumber;
}

Обратите внимание, что косые черты в имени папки - прямые, как в Unix, а не обратные,
как в Windows. Это важно.

Команда fopen открывает файл с указанным в качестве первого аргумента именем. Второй
аргумент («w») определяет, что файл открывается для записи, то есть что все его содержимое
при открытии стирается. Причем команда fopen возвращает уникальный номер только что
открытого файла, на который будут ссылаться все дальнейшие команды чтения-записи в файл.
Для любопытствующих умов замечу, что операционная система работает не с текстовыми именами
файлов, а с их номерами (каналами), поэтому при открытии файла для работы ему присваивается
уникальный номер, возвращаемый командой fopen.

Команда fclose просто закрывает файл с указанным номером (а не именем). Файлы


положено закрывать после работы с ними.

Представляйте себе мысленно открытие файла в скрипте как открытие нового документа
в MS Word или Notepad.

Между командами fopen и fclose можно вставить необходимые строки, производящие


запись значений атрибутов в открытый файл.

Если на экран значения переменных можно вывести командой print, то в файл их можно
напечатать командой fprint

global proc saveAll()


{
string $fileName = fileDialog -dm "c:/temp/" *;
int $fileNumber = "fopen $fileName "w" ';
float $value;
$value = 'getAttr "pushField.magnitude" ';
fprint $fileNumber $value;
$value = 'getAttr "pushField.attenuation" ';
fprint $fileNumber $value;
$value = 'getAttr "pushField.maxDistance" ';
fprint $fileNumber $value;
$value = getAttr "pullField.magnitude" ';
fprint $fileNumber $value;
$value = 'getAttr "pullField.attenuation" ';
fprint $fileNumber $value;
$value = 'getAttr "pullField.maxDistance" ';
fprint $fileNumber $value;
$value = 'getAttr "drop$hape.conserve" ';
fprint $fileNumber $value;
fclose $fileNumber;
}

920 Книга Сергея Цыпцына


Теперь, чтобы записать значения атрибутов на диск, нужно выбрать существующий
файл на диске (желательно пустой или ненужный) и нажать кнопку Open в файловом диалоге.
Ограничением команды fileDialog является то, что при задании вручную имени несуществующего
файла она возвращает пустую строку и файл не открывается для работы с ним. Как решить эту
проблему, я расскажу чуть позже, в разделе для взрослых.

Если наша кнопка Save отработала без ошибок, то есть выдала список файлов, в котором
вы указали файл для записи и нажали Open, можете открыть указанный вами файл и обнаружить,
что MAYA напечатала туда все значения атрибутов друг за другом, в одну строку, как в общем-то и
следовало ожидать.

3942-6450.9

Осталось напечатать после каждого значения «перевод каретки», то есть перейти на следующую
строку в файле. Это можно сделать, напечатав специальный невидимый символ, обозначаемый
как «\п», который просто переводит курсор на следующую строку (когда работаете с командой
print, представляйте, что печатаете на клавиатуре, и когда нужно нажать Enter, используете
выражение print «\n»). Чтобы не добавлять дополнительную команду frpint «\n», просто прибавим
этот спецсимвол к печатаемому значению атрибута. В результате получится строка, состоящая из
цифр и спецсимвола, которая будет печататься в файл.

global proc saveAll()


{
string $fileName = "fileDialog -dm "c:/temp/" ';
int $fileNumber = fopen $fileName "w" ';
float $value;
$value = 'getAttr "pushField.magnitude" ';
fprint $fileNumber ($value+"\n");
$value = getAttr "pushField.attenuation" ';
fprint $fileNumber ($value+"\n");
$value = getAttr "pushField.maxDistance" ';
fprint $fileNumber ($value+"\n");
$value = 'getAttr "pullField.magnitude" ';
fprint $fileNumber ($value+"\n");
$value = 'getAttr "pullField.attenuation" ';
fprint $fileNumber ($value+"\n");
$value = 'getAttr "pullField.maxDistance" ';
fprint $fileNumber ($value+"\n");
$value = getAttr "drop$hape.conserve" ';
fprint $fileNumber ($value+"\n");
fclose $fileNumber;
}

Если теперь вы откроете файл с сохраненными атрибутами, например, в редакторе Word-


Pad, то увидите, что все в порядке и все значения располагаются в отдельных строках.

MEL, или MAYA Embedded Language 921


Однако если вы надумаете открыть его в NotePad или MS Word, то увидите странные значки
вместо окончаний строк.

Объяснение сути этой проблемы, честно говоря, совершенно не касаемо MAYA, а относится
к операционной системе Windows (и DOS). Приведу лишь решение проблемы. При записи в файл
для перевода строки надо добавлять два спецсимвола «\r\n», то есть вот так:

$value = 'getAttr "pushField.magnitude" ';


fprint $fileNumber ($value+"\r\n");

Любители компактного кода быстро сообразят, что можно выкинуть одно присвоение и
запихнуть команду getAttr прямо внутрь команды fprint.

global proc saveAll()


{
string $fileName = fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "w" ';
fprint $fileNumber ('getAttr "pushField.magnitude" '+"\r\n");
fprint $fileNumber ("getAttr "pushField.attenuation" '+"\r\n");
fprint $fileNumber ("getAttr "pushField.maxDistance" '+"\r\n");
fprint $fileNumber (getAttr "pullField.magnitude" '+"\r\n");
fprint $fileNumber (getAttr "pullField.attenuation" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.maxDistance" '+"\r\n");
fprint $fileNumber (getAttr "drop$hape.conserve" '+"\r\n");
fclose $fileNumber;
}

Прежде чем перейти к программированию кнопки Load и написания процедуры чтения


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

Спецсимволы. Косые и обратные черты. Кавычки в кавычках


Для того, чтобы печатать разные непечатные символы командами print или fprint, в языке
MEL используются спецсимволы.

Как вы уже знаете, спецсимвол «\n», встречающийся внутри строки, переводит печать на
новую строку:

print "Hello \n, World!";


Hello
, World!

Спецсимвол «\t», печатает табуляцию:

print "Hello \t\t\t\t, World!";


Hello , World!

Если вам надо поместить внутрь строки символ двойной кавычки, это тоже делается через
обратную косую черту перед знаком кавычки, ведь просто поставив кавычку внутри строки, вы
просто закончите строку и получите сообщение об ошибке. Таким образом «V», тоже является

922 Книга Сергея Цыпцына


спецсимволом.

print "Hello , \"World!\" ";


Hello , "World!"

Пытливые умы наверняка догадаются, что для того, чтобы напечатать или запихнуть внутрь
строки обратную косую черту, надо перед ней поставить еще одну обратную косую черту, иначе
MAYA будет пытаться трактовать символ, следующий за одиночной косой чертой, как спецсимвол.
Двойная обратная косая черта трактуется как одиночная.

print "Hello , WWorldlW ";


Hello , \World!\

Совет. Будьте предельно внимательны при написании строк, содержащих путь к


файлу или имя папки. Либо пишите обычные косые черты типа «С:/temp/» либо
двойные обратные: «c:\\temp\\».

Если после обратной косой черты стоит любой другой символ, кроме n, r, t, \ или ", то он
не трактуется как спецсимвол и печатается без изменений, а косая черта при этом опускается.

print "c:\temp\fromPC\disk8\NewFolder\system\network\driveC\docs";
с: empfromPCdisk8NewFoldersystemetworkdriveCdocs

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

string $text = "Very very \


long text";

Для взрослых: использование команды fileBrowserDialog

На платформе Windows MAYA имеет продвинутую команду fileBrowserDialog, позволяющую


более гибко работать со списками файлов и папок и осуществлять выбор файлов для дальнейшей
работы.

Процедуру saveAll придется разбить на две процедуры, так как fileBrowserDialog требует
объявления дополнительной процедуры, которая вызывается при нажатии на кнопку в окне
файлового диалога. Выглядеть это будет так:

global proc saveAll()


{
fileBrowserDialog -m 1 -fc "saveAttr" -an "Save_Attr" -ft "text";
}

global proc saveAttr( string $fileName , string $fileType)


{
/ / n o fileDialog here
int $fileNumber = 'fopen $fileName "w" ';
fprint $fileNumber f g e t A t t r "pushField.magnitude" '+"\r\n");
fprint $fileNumber f g e t A t t r "pushField.attenuation" '+"\r\n");
fprint $fileNumber f g e t A t t r "pushField. maxDistance" '+"\r\n");
fprint $fileNumber f g e t A t t r "pullField. magnitude" '+"\r\n");
fprint $fileNumber f g e t A t t r "pullField.attenuation" '+"\r\n");
fprint $fileNumber f g e t A t t r "pullField.maxDistance" '+"\r\n");
fprint $fileNumber f g e t A t t r "drop$hape.conserve" '+"\r\n");
fclose $fileNumber;
}

MEL, или MAYA Embedded Language 923


Обратите внимание, что в команде fileBrowserDialog задается в виде строки имя процедуры
saveAttr, которая будет вызываться при нажатии кнопки Save_Attr в окне файлового диалога.

Пытливейшие из умов сообразят, что команду fileBrowserDialog можно «повесить» прямо


на кнопку Save в нашем основном окне и избежать, тем самым, написания лишней процедуры
saveAll.

button -I "Save" -w 94
-с "fileBrowserDialog -m 1 -fc \"saveAttr\" -an \"Save_Attr\" -ft \"text\";";

Чтение данных из файла


После написания процедуры сохранения данных на диск не составит никакого труда
скопировать и переделать ее для чтения значений атрибутов из файла.
Не забудьте дописать вызов команды loadAll для кнопки Load:

button -I "Load" -w 94 -с "loadAll";

А внизу создайте новую процедуру, скопировав и переименовав старую процедуру


saveAll:

global proc loadAll()


{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "r" ';

fclose $fileNumber;
}

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

Чтение из файла осуществляется обычно построчно. Поэтому алгоритм будет следующий:


прочесть строку из файла, преобразовать ее в число и присвоить это число атрибуту командой
setAttr.

global proc loadAll()


{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "r" ';
float $value;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "dropShape.conserve" $value ;

924 Книга Сергея Цыпцына


fclose $fileNumber;
}

Обратите внимание, что в строке типа

$value = ' fgetline $fileNumber' ;

в правой части происходит чтение строки из файла, которая преобразуется в число оператором
присваивания «=», так как слева от него стоит переменная типа float.

Команда fgetline читает строку из файла, номер которого указан в качестве аргумента,
и переводит курсор на следующую строку, так что следующий вызов fgetline будет читать новую
строку.

Для взрослых. Проверить достижение конца файла можно командой eof , а возвратиться к
его началу командой rewind.

Любители запихать все в одну строку могут скомпрессировать наш код в следующую
процедуру:

global proc loadAll()


{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "r" ';

setAttr "pushField.magnitude" (floatf fgetline $fileNumber')) ;


setAttr "pushField.attenuation" (floatf fgetline $fileNumber')) ;
setAttr "pushField.maxDistance" (floatf fgetline $fileNumber')) ;
setAttr "pullField.magnitude" (floatf fgetline $fileNumber')) ;
setAttr "pullField.attenuation" (floatf fgetline $fileNumber')) ;
setAttr "pullField.maxDistance" (floatf fgetline $fileNumber')) ;
setAttr "dropShape.conserve" (floatf fgetline $fileNumber')) ;
fclose $fileNumber;
}

Оформление скрипта в виде процедуры. Вызов его с диска


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

Держать такое огромное количество строк в Script Editor, естественно, неудобно. Можно,
конечно, выделить весь нужный текст в Script Editor и забросить его на полку (shelf) одним
движением мыши. Однако мы поступим более традиционным способом. Оформим весь наш скрипт,
рисующий окно, в виде процедуры и будем вызывать его по имени этой процедуры.

Допишите в самом начале скрипта объявление новой процедуры dropAttrWindow, а после


команды showWindow DROP_WINDOW; не забудьте поставить закрывающую фигурную скобку. Не
скупитесь на комментарии, которые облегчат чтение кода другим пользователям или вам самим
через десять лет. Результат нашего многодневного труда выглядит следующим образом.

global proc dropAttrWindow()


{
i f f window -ex DROP_WINDOW'==1) { deleteUI DROP_WINDOW; }
window -t "drop attributes" DROP_WINDOW;
columnLayout;

MEL, или MAYA Embedded Language 925


frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at pushField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent..;
setParent..;

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent..;
setParent..;
frameLayout -I "pull Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at drop.con -min 0 -max 1;
setParent..;
setParent..;
separator -style "none" -h 15;
gridLayout -numberOfColumns 4 -ccllWidthHeight 96 32;
button -I "Reset" -w 94 -c "resetAll";
button -I "Save" -w 94 -c "saveAll";
button -I "Load" -w 94 -c "loadAll";
button -I "Close" -w 94 -c "deleteUI DROP_WINDOW;" ;
setParent..;

showWindow DROP_WINDOW;
} // end of dropAttrWindow procedure
//////////////////////////////////////////////////////////
global proc resetAll()
{
setAttr "pushField.magnitude" 39;
setAttr "pushField.attenuation" 4;
setAttr "pushField.maxDistance" 2;
setAttr "pullField. magnitude" -6;
setAttr "pullField.attenuation" 4;
setAttr "pullField.maxDistance" 5;
setAttr "dropShape.conserve" 0.9;
}
//////////////////////////////////////////////////////////
global proc saveAll()
{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "w" ';
fprint $fileNumber ('getAttr "pushField.magnitude" '+"\r\n");
fprint $fileNumber ('getAttr "pushField.attenuation" "+"\r\n");
fprint $fileNumber ("getAttr "pushField.maxDistance" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.magnitude" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.attenuation" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.maxDistance" '+"\r\n");
fprint $fileNumber ('getAttr "dropShape.conserve" '+"\r\n");
fclose $fileNumber;
}
//////////////////////////////////////////////////////////
global proc loadAll()
{
string $fileName = 'fileDialog -dm "c:/temp/" ';

926 Книга Сергея Цыпцына


int $fileNumber = 'fopen $fileName "r" ';
float $value;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField. magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "dropShape.conserve" $value ;
fclose $fileNumber;
}

Если теперь выделить и выполнить приведенный выше код, то ничего, очевидно, на экране
не появится. Произойдет лишь объявление четырех процедур, после чего MAYA будет знать об их
существовании и при попытке их вызвать будет бодро их выполнять. А вызвать любую процедуру
можно по имени. Теперь достаточно набрать в Script Editor строку dropAttrWindow, выделить ее и
выполнить, как тут же на экране появится окно с атрибутами.

Однако, как заметят проницательные умы, это будет работать пока мы не выйдем из MAYA.
Если зайти в MAYA заново, на попытку вызвать команду dropAttrWindow вы получите сообщение об
ошибке:

dropAttrWindow;
// Error: Cannot find procedure "dropAttrWindow". //

Для того, чтобы все заработало, надо снова провести объявление процедур, то есть
загрузить в Script Editor предварительно сохраненный код, описывающий все процедуры, и
выполнить его.

Однако вы, наверное, слышали, что если сохранить текст скрипта в определенном месте
с определенным именем, он будет доступен для MAYA всегда. По крайней мере, так поступают с
файлами скриптов, скачанными из Интернета.

Сохраните вышеприведенный текст, описывающий четыре процедуры, в виде текстового


файла с именем dropAttrWindow. mel. Поместите его в папку scripts, которая находится в директории
с именем maya, где MAYA хранит все свои установки. Если вы не меняли при помощи переменной
окружения расположение этой папки на диске, то обычно это:
X:\Documents and Settings\UserName\My Documents\maya\scripts
Подробнее про сохранение установок MAYA на диске и расположение папок с этими
установками на диске читайте в главе про интерфейс.

Примечание. В папке тауа вы можете обнаружить две директории с именем scripts.


Одну непосредственно в папке тауа, а другую (или другие) в подпапке maya\N.N (где
N.N - это номер версии MAYA). Вы можете сохранять свои (или чужие) скрипты в
любой из этих папок, но имейте в виду, что скрипты сохраненные в папке тауа\
N.N\scripts будут доступны только в MAYA версии N.N (если у вас установлено
несколько версий MAYA).

MEL, или MAYA Embedded Language 927


Имя файла (dropAttrWindow.mel) должно в точности совпадать с именем процедуры,
создающей окно на экране (а расширение должно быть в точности .mel).

Если вы сделали все корректно, можете выйти из MAYA, затем зайти обратно, открыть
файл с частицами (dropPreset.ma) и выполнить в Script Editor команду dropAttrWindow. При этом
появится до боли знакомое окно с атрибутами.

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

Порядок вызова и расположение пользовательских и стандартных


скриптов. Что происходит при вызове MEL-команды
Сведения, изложенные в этом разделе, являются ключевыми для понимания механизма
работы скриптов. Постарайтесь вникнуть в суть действий, происходящих после попытки выполнить
ту или иную команду на MEL.

Итак, вы, предположим, открыли MAYA, набрали в Script Editor некоторую команду
(например, dropAttrWindow) и попытались ее выполнить.

MAYA производит следующие действия.

1. Сначала MAYA проверяет, не объявлена ли уже процедура с таким именем. То есть не


выполнял ли пользователь недавно строки типа

global proc dropAttrWindow( )


{

i
И если объявление процедуры с таким именем будет найдено в памяти, эта процедура будет
немедленно выполнена.

2. Если процедура с таким именем до сих пор не была объявлена, MAYA проверяет, не
является ли эта команда стандартной майской командой типа print или Is. Если да, то понятно, что
происходит.

3. Если имя команды, которую упрямо хочет выполнить пользователь, не является


стандартной майской командой, то MAYA думает, что это наверное вызов скрипта, хранящегося на
диске, и начинает искать файл с именем dropAttrWindow.mel (то есть «имя_введенной_команды.
mel» ) в нужном месте на диске.

928 Книга Сергея Цыпцына


Где же это «нужное место»?! Их несколько. И все они просматриваются в определенном
порядке.
4. Прежде всего, просматриваются пользовательские папки scripts, находящиеся в
папке maya (X:\Documents and Settings\UserName\My Documents\maya\scripts), своей для каждого
пользователя. Если файл с именем dropAttrWindow.mel найден там, то он открывается в памяти
и выполняется, то есть происходит объявление всех содержащихся в нем глобальных процедур.
После чего найденная процедура dropAttrWindow просто выполняется. А объявление процедуры
(что важно!), остается в памяти MAYA.

5. Если файла с именем dropAttrWindow.mel в пользовательских папках scripts не найдено,


тогда просматриваются родные майские папки в директории
X:\Program Files\Alias\MayaN.N\scripts
на предмет присутствия там нужного файла.

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

Можно сделать некоторое количество выводов на основе изложенной информации.

Как запускать скрипты, скачанные из Интернета


Как правило, вы скачиваете скрипт в виде файла с расширением .mel, например su­
perscript, mel. Если инструкция по запуску файла отсутствует, то прежде всего надо положить
этот файл в вашу директорию maya/scripts (и ни в коем случае не в стандартную майскую), а
затем попробовать набрать в Script Editor команду superscript. Как правило, это сработает в 90%
случаев.

Иногда выполняемая команда требует аргументов при запуске, например «superscript 1»,
и в этом случае либо выдается подсказка (если скрипт грамотно написан), либо надо открывать
текст скрипта и искать там описание процедуры global proc superScript( . . . ), и разбираться, как
она устроена, и что ей требуется указать в качестве входных аргументов.

Если в файле superscript.mel отсутствует описание процедуры superscript, совпадающей


по имени с названием файла, значит вы скачали не тот файл. Удалите его и не мучайтесь.

Примечание. Здесь и далее я буду ссылаться на вашу (или пользовательскую)


папку scripts, имея в виду ту самую папку, которая лежит в директории тауа,
содержащей в себе все настройки и установки MAYA. Как правило, эта директория
располагается в каталоге My Documents, если вы работаете под Windows, или, в
ином случае, в вашей домашней (home) директории.

Что такое Source Script


Если вы сохранили свои (или чужие) процедуры в каком нибудь-файле, то запускаете скрипт,
выполняя команду, совпадающую по имени с названием файла, и все прекрасно работает. До тех
пор, пока вы не откроете файл и не внесете туда гениальные изменения радикально улучшающие
работу скрипта. Сохранив файл, вы обнаружите, что MAYA выполняет прежнюю версию скрипта,
так как она была загружена в память с диска при первом вызове скрипта и благополучно там
находится.

Чтобы загрузить изменения, только что сделанные в файле, не перезапуская MAYA, надо
принудительно выполнить скрипт из файла. Эта операция называется Source Script и находится в
меню File окна Script Editor. Все команды из указанного фала просто выполняются, поэтому если в
файле находятся только объявления процедур, они обновляются в памяти, а если набор команд,
то эти команды выполняются.

MEL, или MAYA Embedded Language 929


Можно представить, на пальцах, действие операции Source Script как мгновенное открытие
текста скрипта в нижней части Script Editor, выполнение его и удаление текста.

Совет. Если вы пишете скрипты с помощью какого-нибудь текстового редактора,


то для операции Source Script имеет смысл сделать кнопку на полке или горячую
клавишу, обновляющую или выполняющую ваш скрипт из файла. Соответствующая
команда может выглядеть примерно так.
source "C:/Work/scripts/myScript.mel";

Script Node, или expression по вызову


Иногда возникает задача сохранения набора команд, то есть скрипта, вместе со сценой,
а не в виде отдельного независимого файла. Скрипт, над которым мы только что трудились,
создающий окно с атрибутами для конкретных объектов из конкретной сцены, являет собой
пример такого набора команд, который хочется хранить в сцене, а не таскать за собой с машины
на машину.

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

Чтобы сохранить набор команд вместе со сценой, надо создать объект типа Script Node.
Это делается при помощи Expression Editor.

Загрузите сцену с частицами (dropPreset.ma).


Откройте Expression Editor и в меню Select Filter выберите By Script Node Name.
В окне появится интерфейс, очень напоминающий создание expression, однако слово script
напоминает о том, что мы на грани создания объекта Script Node.

В текстовое поле следует просто вписать набор команд и нажать кнопку Create.
При этом писать следует именно скрипт, а не expression. To есть фамильярности типа
$x=pCube1.tx недопустимы.

В нашем примере, в принципе, достаточно вписать сюда одну команду:

dropAttrWindow;

930 Книга Сергея Цыпцына


которая будет благополучно вызывать процедуру создания окна, сохраненную на диске в файле
dropAttrWindow.mel. Но тогда придется вместе со сценой таскать еще и этот файл, что рано или
поздно приведет к путанице.

Поэтому проще и удобнее скопировать в поле Script: все содержимое файла dropAttrWin­
dow.mel и дополнить его в конце вызовом команды dropAttrWindow:

global proc dropAttrWindow()


{
i f ( ' window -ex DROP_WINDOW'==1) { deleteUI DROP_WINDOW; }
window -t "drop attributes" DROP_WINDOW;
columnLayout;
frameLayout -I "push Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at pushField.mag -min 0 -max 50;
attrFieldSliderGrp -at push Field, att -min 0 -max 4 ;
attrFieldSliderGrp -at pushField.max -min 0 -max 10 ;
setParent..;
setParent..;

frameLayout -I "pull Field Attributes" -cll 1;


columnLayout;
attrFieldSliderGrp -at pullField.mag -min -50 -max 0;
attrFieldSliderGrp -at pullField.att -min 0 -max 4 ;
attrFieldSliderGrp -at pullField.max -min 0 -max 10 ;
setParent..;
setParent..;
frameLayout -I "pull Field Attributes" -cll 1;
columnLayout;
attrFieldSliderGrp -at drop.con -min 0 -max 1;
setParent..;
setParent..;
separator -style "none" -h 15;
gridLayout -numberOfColumns 4 -ccllWidthHeight 96 32;
button -I "Reset" -w 94 -c "resetAll";
button -I "Save" -w 94 -c "saveAll";
button -I "Load" -w 94 -c "loadAll";
button -I "Close" -w 94 -c "deleteUI DROP_WINDOW;" ;setParent ..;

showWindow DROP_WINDOW;
}
//////////////////////////////////////////////////////////
global proc resetAll()
{
setAttr "pushField.magnitude" 39;
setAttr "pushField.attenuation" 4;
setAttr "pushField.maxDistance" 2;
setAttr "pullField.magnitude" -6;
setAttr "pullField.attenuation" 4;
setAttr "pullField.maxDistance" 5;
setAttr "dropShape.conserve" 0.9;
}
//////////////////////////////////////////////////////////
global proc saveAll()
{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = 'fopen $fileName "w" ';
fprint $fileNumber (getAttr "pushField.magnitude" '+"\r\n");
fprint $fileNumber ('getAttr "pushField.attenuation" '+"\r\n");

MEL, или MAYA Embedded Language 931


fprint $fileNumber ("getAttr "pushField.maxDistance" '+"\r\n");
fprint $fileNumber (getAttr "pullField.magnitude" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.attenuation" '+"\r\n");
fprint $fileNumber ('getAttr "pullField.maxDistance" '+"\r\n");
fprint $fileNumber ('getAttr "dropShape.conserve" '+"\r\n");
fclose $fileNumber;
}
//////////////////////////////////////////////////////////
global proc loadAll()
{
string $fileName = 'fileDialog -dm "c:/temp/" ';
int $fileNumber = fopen $fileName "r" ';
float $value;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pushField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.magnitude" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.attenuation" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "pullField.maxDistance" $value ;
$value = ' fgetline $fileNumber' ;
setAttr "dropShape.conserve" $value ;
fclose $fileNumber;
}
// вызов процедуры dropAttrWindow в конце Script Node
dropAttrWindow;

После этого следует немедленно нажать кнопку Create и получить новый объект типа Script
Node с именем scriptl.

932 Книга Сергея Цыпцына


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

Протестировать созданный объект-скрипт можно нажав кнопку Test Script. Если вы


скопировали все правильно, должно выскочить окошко с атрибутами.

Осталось решить, когда созданный объект Script Node будет выполняться. Пока он просто
сохранился в недрах сцены и выполняется только по нашему требованию при нажатии на кнопку
Test Script. В отличие от expressions, он не будет выполняться при смене кадра, если только мы
его об этом не попросим.

Чтобы задать, когда созданный объект-скрипт будет выполняться, выберите в списке Ex­
ecute On: пункт GUI Open/Close.

Это означает, что скрипт будет выполняться каждый раз при открытии (или закрытии)
сцены в MAYA.

Опция Script: = Before означает выполнение при открытии сцены.

Остальные пункты в списке Execute On: позволяют выполнять Script Node при открытии
сцены не только в интерфейсе MAYA, но и при постановке на рендеринг. Опция Time Changed
превращает такой скрипт в банальный expression, выполняющийся каждый раз при смене кадра.
Сейчас нужно обязательно сохранить сцену, ведь мы создали новый объект!

Сохраните сцену как dropPresetScriptNode.ma.

Создайте новую сцену, а затем откройте только сохраненный файл с частицами.

При открытии сцены будет выскакивать окошко для работы с атрибутами.

MEL, или MAYA Embedded Language 933


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

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

Интерфейс для рисования процедурных кривых

Если вы уже устали от рисования окошек, пропускайте этот раздел и двигайтесь в сторону
изменения стандартных майских скриптов. А я бы хотел остановиться на вопросе создания окошек,
содержащих не слайдеры, связанные с атрибутами объектов, а просто числовые поля, значения
которых можно использовать для последующих построений или вычислений.

Напомню, что вначале главы нами был написан скрипт, рисующий спираль или другую
процедурную кривую по заданной формуле.

int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $x$peed=5.0;

if(objExists("myCurve")==1) { delete "myCurve"; }


curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<$NumPoints; $i=$i+1)
{
float $t=$i/$Density;
float $x=$t/$x$peed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);
curve -p ($x) ($y) ($z) -a "myCurve";
}
delete "myCurve.cv[0]";

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

Чтобы избежать удаления первой точки на кривой последней командой


delete "myCurve.cv[0]"; сделаем в цикле проверку того, что если $i равно 0, то следует поставить
первую точку на новую кривую, а в противном случае добавить точку к уже существующей.

global proc curveBuilderProc()


{
int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;
if(objExists("myCurve")==1) { delete "myCurve"; }
// curve -p 0 0 0 -n "myCurve";
int $i;
for($i=0; $i<$NumPoints; $i=$i+1)
{
float $t=$i/$Density;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);

934 Книга Сергея Цыпцына


float $z=$Amp * cos($t*$Freq);
if($i==0) { curve -p ($x) ($y) ($z) -n "myCurve";}
else [ curve -p ($x) ($y) ($z) -a "myCurve"; }
}
// delete "myCurve.cv[0]";
}

Выполните эти строчки, чтобы объявить процедуру curveBuilderProc в памяти.


Напомню, что переменные $Атр и $Freq задают в данном случае радиус и частоту
вращения спирали. Общее количество точек определяется переменной $NumPoints, их плотность
укладывания (а следовательно, и общая длина кривой) - переменной $Density, а скорость роста
кривой вдоль оси X - переменной $xSpeed (на самом деле увеличение $xSpeed задает замедление
роста вдоль оси X, так как я перепутал знаки «делить» и «умножить»).
Я не ввожу таких понятий, как количество витков или шаг спирали, так как во-первых,
эта кривая будет оставаться спиралью лишь до тех пор, пока вы не поменяете формулу, а у
произвольной кривой может и не быть витков или шагов. Во-вторых - это не принципиально.
В-третьих, вычисление количества витков, потребует введения в формулы числа "пи", рассказ о
котором никак не входит в мои планы.
Создадим теперь окно, в котором будут числовые поля для задания значений вышеуказанных
переменных и большая кнопка «Построить кривую».
Воспользуемся опять заготовкой для создания окна с проверкой его наличия в памяти,
благополучно сохраненной запасливыми умами.

string $win_name = "CURVE_BUILDER";


if('window -ex $win_name ==1) { deleteUI $win_name; }
window -t "Curve Builder" $win_name;
columnLayout;
intSliderGrp -I "Num Points" -field 1 -value 500;
floatSliderGrp -I "Amplitude" -field 1 -value 3.0;
floatSliderGrp -I "Frequency" -field 1 -value 2.0;
floatSliderGrp -I "Density" -field 1 -value 10.0;
floatSliderGrp -I "X Speed" -field 1 -value 5.0;
separator-style "none" -h 15;
gridLayout -numberOfColumns 2 -ccllWidthHeight 192 32;
button -I "Build Curve" -w 188 -c "curveBuilderProc";
button -I "Close" -w 188 с ("deleteUI "+$win_name);
showWindow $win_name;

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

У этих команд есть очевидный флаг value, позволяющий установить или прочитать
значение поля. В режиме создания через этот флаг задаются значения, задаваемые при появлении
окна. Две кнопки внизу окна ничем не отличаются от изученных ранее. Очевидно, что первая из
них вызывает команду-процедуру построения кривой curveBuilder.

MEL, или MAYA Embedded Language 935


Теперь настало время изменить процедуру curveBuilder так, чтобы перед построением
кривой происходило считывание значений числовых полей в окне, и эти значения присваивались
уже имеющимся переменным $NumPoints, $Amp и др.

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

Режимы команд построения элементов интерфейса


До сих пор мы использовали команды построения интерфейса в режиме создания, то есть
добавляли новые элементы в уже созданное окно. И лишь при проверке существования окна в
памяти, мы использовали флаг -ex (-exists) для команды window, переводящий ее в режим запроса
(или режим получения информации).

Оказывается, абсолютно все команды построения элементов интерфейса (а не только


команда window) имеют три режима работы.

Второй режим (после режима создания) называется режимом запроса и позволяет


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

Примечание. Я повторно настаиваю на драматическом сходстве между


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

Для элементов интерфейса нет команды типа getAttrUI или getFlagUI, все гораздо проще
(а может, сложнее).

Для того, чтобы получить значение флага (определяющего, например, ширину кнопки),
надо после команды, используемой для создания кнопки, добавить флаг -q (-quiery). После чего
указать флаг, значение которого мы хотим получить (например, -w) и, естественно, имя элемента
интерфейса. Команда получения ширины кнопки выглядит примерно так:

$wid = 'button -q -w BUT_CLOSE';

Совершенно очевидно, что надо позаботиться при создании некоторых элементов, чтобы
у них были конкретные названия. Это можно сделать в режиме создания, просто добавив в самом
конце команды имя элемента.

button -I "Close" -w 188 -с ("deleteUI "+$win_name) BUT_CLOSE;


$wid = 'button -q -w BUT_CLOSE';

Абсолютно аналогично используется третий режим, режим редактирования значений


флагов, с помощью которого вы можете изменять свойства уже созданных элементов интерфейса.
Достаточно использовать после имени команды флаг -е (-edit), затем указать имя флага и
обязательно новое значение флага, после чего указать также имя элемента, свойство которого
редактируется.

button -I "Close" -w 188 -с ("deleteUI "+$win_name) BUT_CLOSE;


button -e -I "Close and Exit" BUT_CLOSE;

Если флаги -q или -е в команде работы с элементами интерфейса отсутствуют, то по умолчанию


команда используется в режиме создания нового элемента.

936 Книга Сергея Цыпцына


Примечание. Использование флагов -q и -е сильно напоминает работу с командами
getAttr и setAttr для запроса или редактирования атрибутов объектов.

Имена элементов интерфейса


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

string $win_name = "CURVE_BUILDER";


if('window -ex $win_name '==1) { deleteUI $win_name;}
window -t "Curve Builder" $win_name;
columnLayout;
intSliderGrp -I "Num Points" -field 1 -value 500 -min 4 -max 5000 NUMP;
floatSliderGrp -I "Amplitude" -field 1 -value 3.0 -min 0 -max 10 AMP;
floatSliderGrp -I "Frequency" -field 1 -value 2.0 -min 0 -max 10 FREQ;
floatSliderGrp -I "Density" -field 1 -value 10.0 -min 0.01 -max 100 DENS;
floatSliderGrp -I "X Speed" -field 1 -value 5.0 -min 0.01 -max 50 XSPEED;
separator -style "none" -h 15;
gridLayout -numberOfColumns 2 -ccllWidthHeight 192 32;
button -I "Build Curve" -w 188 -c "curveBuilderProc ";
button -I "Close" -w 188 -c ("deleteUI "+$win_name);
showWindow $win_name;

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


чтобы не перепутать их с уже имеющимися элементами.

Для взрослых. Более профессиональный подход заключается в использовании того имени,


которое MAYA сама дает создаваемому элементу. Это имя всегда возвращается командой в режиме
создания элемента. Его можно запомнить в переменную (возможно, глобальную) и использовать
позже:

$iname = 'intSliderGrp -I "Num Points" -f 1 -value 500 -min 4 -max 5000';


// Result: CURVE_BUILDER|columnLayout2|gridLayout3|intSliderGrp1 //

Если вышеприведенные команды создают окно без ошибок, то дело за малым - переделать
незначительно процедуру построения кривой. Очевидно, что надо просто прочитать значения
числовых полей из окна и «засунуть» их в нужные переменные.

global proc curveBuilderProc()


{
int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;
$NumPoints = 'intSliderGrp -q -value NUMP';
$Amp = floatSliderGrp -q -valueAMP";
$Freq = floatSliderGrp -q -value FREQ';
$Density = floatSliderGrp -q -value DENS';
$xSpeed = 'floatSliderGrp -q -value XSPEED';
if(objExists("myCurve")==1) { delete "myCurve"; }
int $i;
for($i=0; $i<$NumPoints; $i=$i+1)
{
float $t=$i/$Density;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);

MEL, или MAYA Embedded Language 937


if ($i==0) { curve -p ($x) ($y) ($z) -n "myCurve";}
else { curve -p ($x) ($y) ($z) -a "myCurve"; }
}
}

Чтобы прочитать значения числовых полей, надо обратиться к ним с помощью тех же
команд, что использовались при их создании, только с флагом -q, при этом запрашивать надо
значение флага -value, содержащего числовое значение.

Совет. Добавьте самостоятельно поле для задания спепени кривой.

Посмотрим, как можно также обновлять свойства элементов в окне. Я напомню, что скрипты
подобного типа довольно активно поедают память, особенно если у вас задана бесконечная
очередь Undo. Чтобы контролировать расход памяти, добавим еще одно числовое поле, которое
будет содержать количество свободной памяти и будет обновляться после каждого построения
кривой. Команда, с помощью которой можно узнать у MAYA, сколько, по ее мнению, еще есть
свободной памяти, называется memory.
Добавим также кнопку, которая будет очищать очередь Undo, это банальная задача, надо
только не забыть увеличить количество столбцов до трех в gridLayout.
Дополнительно добавим в окно галку, которая будет включать обновление экрана во время
построения кривой. Галка добавляется командой checkBox, однако лучше использовать команду
checkBoxGrp, так как она располагает метку слева от галки и лучше вписывается в дизайн нашего
окна. Кроме того, она позволяет создавать до четырех галок одновременно, поэтому для задания
значения галки (то есть для включения/выключения) надо использовать флаг -valuel, а не -value.
В цикле для построения кривой должна быть проверка типа:

if('checkBoxGrp -q -valuel REFR'==1) {refresh; }


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

global proc updateMemoryField()


{
float $memArray[] = 'memory -freeMemory';
textFieldGrp -e -text ($memArray[0]+" MB") FREEMEM;
}
//
global proc curveBuilderProc()
{
int $NumPoints=500;
float $Amp=3.0, $Freq=2.0, $Density=10.0, $xSpeed=5.0;
$NumPoints = 'intSliderGrp -q -value NUMP";
$Amp = 'floatSliderGrp -q -valueAMP';
$Freq = floatSliderGrp -q -value FREQ';
$Density = floatSliderGrp -q -value DENS';
$xSpeed = 'floatSliderGrp -q -value XSPEED';
if(objExists("myCurve")==1) { delete "myCurve"; }
int $i;
for($i=0; $i<$NumPoints; $i=$i+1)
{
float $t=$i/$Density;
float $x=$t/$xSpeed;
float $y=$Amp * sin($t*$Freq);
float $z=$Amp * cos($t*$Freq);
if($i==0) { curve -p ($x) ($y) ($z) -n "myCurve";}
else { curve -p ($x) ($y) ($z) -a "myCurve"; }
i f f checkBoxGrp -q -valuel REFR'==1) { refresh; }
}
updateMemoryField;
}

938 Книга Сергея Цыпцына


//
global proc curveBuilder()
[
string $win_name = "CURVE_BUILDER";
i f f window -ex $win_name '==1) { deleteUI $win_name; }
window -t "Curve Builder" $win_name;
columnLayout;
intSliderGrp -I "Num Points" -field 1 -value 500 -min 4 -max 5000 NUMP;
floatSliderGrp -I "Amplitude" -field 1 -value 3.0 -min 0 -max 10 AMP;
floatSliderGrp -I "Frequency" -field 1 -value 2.0 -min 0 -max 10 FREQ;
floatSliderGrp -I "Density" -field 1 -value 10.0 -min 0.01 -max 100 DENS;
floatSliderGrp -I "X Speed" -field 1 -value 5.0 -min 0.01 -max 50 XSPEED;
checkBoxGrp -I "Refresh Screen" -valuel 0 REFR;
textFieldGrp -I "Free memory" -text ("XXX MB") -editable 0 FREEMEM;
updateMemoryField;
separator -style "none" -h 15;
gridLayout -numberOfColumns 3 -ccllWidthHeight 128 32;
button -I "Build Curve" -w 124 -c "curveBuilderProc";
button -I "Flush Undo" -w 124 -c "flushUndo; updateMemoryField;";
button -I "Close" -w 124 -c ("deleteUI "+$win_name);
showWindow $win_name;
}
curveBuilder; // вызов процедуры

Так как внезапно обнаружилось, что команда memory возвращает массив чисел, то
пришлось создать маленькую процедуру updateMemoryField, которая берет первый элемент этого
массива и обновляет текстовое поле, содержащее количество свободной памяти. Эту процедуру
удобно вызывать сразу после построения кривой, а также после нажатия кнопки Flush Undo.

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

Дальнейшие улучшения построителя кривых ограничиваются только вашей свободной


памятью и маниакальной тягой к совершенству. Дам несколько поводов для размышлений и
дополнений.

Созданная кривая имеет третью степень по умолчанию, так как флаг d был опущен при
добавлении первой точки к кривой.

Можно посчитать время выполнения скрипта, воспользовавшись командой-секундомером


timerX. Выполнение ее без флагов в начале скрипта, запускает секундомер и возвращает текущее
время float $st='timerX";, а выражение timerX -st $st~; может возвратить в конце скрипта время,
прошедшее со времени запуска секундомера.

Наиболее красивым решением будет возможность вводить формулы в текстовые поля


и строить произвольную по ним. Для этого понадобится команда eval, позволяющая исполнить
любую строку, содержащующая в переменной как MEL-команду.
MEL, или MAYA Embedded Language 939
Взрослые мальчики, конечно, заметят, что цикл неоптимизирован: например, проверки
в цикле не являются примером для подражания. Однако в данном случае производительность
скрипта - не основная его ценность. Если вы все же озабочены оптимизацией, не добавляйте точки
к кривой в цикле, а накапливайте в строке длинную команду типа curve -p ... -р ..., чтобы после
выхода из цикла выполнить эту строку как MEL-команду с помощью команды eval.

Еще более взрослые мальчики обнаружат, что у сплайновых кривых есть удивительный
атрибут .nurbsCurve, содержащий полное описание самой кривой в виде набора данных (см.
документацию к команде setAttr). В атрибут можно «запихать» все описание кривой одной
командой setAttr, и тем самым мгновенно построить (или перестроить) кривую целиком.

Работа с меню. Минимизация всех открытых окон


Мой опыт общения с начинающими MEL-маньяками показывает, что все они прежде всего
озадачены тем, как добавить свои пункты меню в основное меню MAYA или как переименовать уже
имеющиеся майские меню. Что ж, придется отдать дань /или: воздать должное/ тяге к хакерству
и самоутверждению.

Поставим простую задачу: в майском меню Window последние пункты отвечают за работу с
открытыми окнами, но среди них нет команды, позволяющей быстро минимизировать все открытые
окна. А такая потребность возникает довольно часто. Напишем сначала такую процедуру, а потом
добавим ее в основное меню MAYA.

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

Точно так же, как для получения списка объектов в сцене существует команда Is, так и
для работы со списками существующих окон, меню и других элементов интерфейса есть команда
IsUI.
Ее надо использовать с одним из необходимых флагов. Например, для получения созданных
в MAYA окон нужно выполнить:

IsUI -wnd;
// Result: AEWindow CURVE_BUILDER CommandWindow MayaWindow //
Дальше можно пустить в ход уже отлаженную выше технологию для работы со списком
объектов в цикле. Необходимо перебрать список и минимизировать все окна, кроме основного
окна MAYA. Минимизировать любое окно можно, просто установив его «минимизированность» в
единицу, то есть изменив значение флага -iconify (такой флаг есть у команды window).

Например, чтобы минимизировать саму MAYA, можно выполнить:

window -e -iconify 1 MayaWindow;

Как вы уже догадались, MayaWindow - это имя главного окна MAYA.


Итак, читаем список открытых окон, перебираем его в цикле и минимизируем все, кроме
главного:

string $it;
string $windows[] = 'IsUI -windows';
for ($it in $windows)
{
if ($it != "MayaWindow")
{
window -e -iconify 1 $it;

940 Книга Сергея Цыпцына


}

Откройте побольше окон и выполните эти содержательные строки - все окна слетятся в
нижнюю часть экрана.

Примечание. Любители компактных записей, знающие, что фигурные скобки можно


не писать, если блок состоит из одной команды, могут усушить код доследующих
строк:

string $it;
for ($it in 'IsUI -wnd') if ($it != "MayaWindow") window -e -i 1 $it;

Для того, чтобы ловко вызывать написанные строки, оформим их в виде процедуры minAll-
Win и сохраним в файле minAllWin.mel на диске в пользовательской папке scripts, где этот файл
будет виден для MAYA как скрипт.

global proc minAllWin()


{
string $it;
string $windows[] = 'IsUI -windows";
for ($it in $windows)
{
if ($it != "MayaWindow")
{
window -e -iconify 1 $it;
}
}
}

Теперь можно минимизировать все окна простой командой minAllWin. На мои предложения
повесить эту команду на горячую клавишу или на кнопку на полке, настоящие MEL-маньяки с
негодованием возопят: «Хотим добавить команду в основное майское меню Window!». Что ж,
желание маньяка - закон...

Сначала читаем список всех существующих меню в MAYA:

IsUI -menus;
// Result: AEdeformersSubMenu AEdynamicsSubMenu AEhelpMenu AEkinematicsSubMenu AElightSub-
Menu AEshadingSubMenu

timeSliderTangentsltem unassignASItem unassignHDItem //

Удобнее, кстати, сделать это «в столбик», с помощью команды print, печатающей массив
строк, возвращаемый командой IsUI

print ('IsUI -menus');

Почитав полученный список, можно найти в нем строки начинающиеся на слово main. Это
и есть названия всех меню из главного окна MAYA. Нас интересует меню с названием mainWindow-
Menu.

Если мы знаем название меню, то добавить к нему дополнительный пункт можно командой
menultem, в которой надо указать, к какому меню мы собираемся добавить новый пункт.

Выполните в Script Editor команду

menultem -I "Minimize All Windows" -c "minAllWin" -p mainWindowMenu MINALLWIN;

Для меню, точно так же, как и для кнопки, с помощью флагов -I и -с указываются текстовое

MEL, или MAYA Embedded Language 941


название и вызываемая команда.

А вот флаг -р (-parent) используется, чтобы определить, к какому существующему меню


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

deleteUI MINALLWIN;

начисто удалит авторский пункт меню и вернет меню Window прежний вид.
Даже если вы еще не объявили процедуру minAllWin, новый пункт меню все равно
добавится, только будет выдавать сообщение об ошибке при попытке его выполнить.

Если вы хотите добавить совершенно новое меню в окно MAYA, следует использовать
команду menu, а в качестве родителя (флаг -parent) указать главное окно MAYA. Например:

menu -I "Maya ver. 20.5 Menu" -p MayaWindow M20;


menultem -I "Make Nice";
menultem -I "Make Cool";
menultem -I "Make All I Need";
menultem -I "Quit" -c "quit -f";

Заметьте, что в командах menultem, следующих непосредственно за командой menu,


указывать «родителя» через флаг р необязательно. Новые пункты меню будут добавляться к
последнему меню, созданному командой menu.

Для взрослых. Для команд работы с меню есть вариант команды setParent, позволяющий
указать, к какому меню мы собираеся последовательно добавлять новые пункты командами menu-
Item. Для этого достаточно выполнить

942 Книга Сергея Цыпцына


setParent -m MenuName;

Совет. Давайте своим меню осмысленные имена. Это позволит вам удалить их
позже - или отредактировать.

В заключение могу добавить, что если вы хотите добавлять меню в свои окна, при создании
окна следует включить флаг -menubar, выключенный по умолчанию. Например:

window -menubar 1 -t "Drop windows controls" DROPWINO;


menu-I "File...";
menultem -I "New";

На этом я бы хотел закончить рассказ об использовании элементов интерфейса. Все


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

Как заставить MAYA выполнять команды при загрузке


Умиротворенные умы, добавившие свои пункты меню в различные места MAYA, некоторое
время пребывают в полном блаженстве. Свои меню работают, окна минимизируются, MAYA сверкает
новизной. Однако выйдя из MAYA и вернувшись обратно, разработчики интерфейсов будущего
обнаружат, что все добавленные в предыдущем сеансе MAYA пункты меню бесследно исчезли!
Вопрос, очевидно, состоит в том, как заставить MAYA выполнять нужные команды каждый раз при
открытии MAYA?

Для этого используется файл со специальным именем userSetup.mel. Если он существует


в вашей папке scripts, MAYA будет выполнять все содержащиеся в нем команды.

Создайте такой файл, введите в него строку:

menultem -I "Minimize All Windows" -с "minAllWin" -p mainWindowMenu MINALLWIN;

Сохраните файл в вашей папке scripts, чтобы он был виден для MAYA.
Перегрузите MAYA.

Новое меню теперь будет появляться автоматически.

Совет. Иногда возникает ситуация, когда у пользователя существуют два файла


userSetup.mel. Один в папке maya\scripts, а другой в папке с номером версии (типа
maya\6.5\schpts). Старайтесь избегать такой ситуации, так как предсказать
поведение MAYA при загрузке вам будет довольно сложно. Используйте только
один файл userSetup.mel.

Внимание. В старых версиях MAYA в документации встречается ошибка,


описывающая, что вместо userSetup.mel надо использовать файл userStar-
tup.mel. Будьте внимательны: эту же ошибку можно обнаружить на древних
ресурсах по MAYA в интернете.

Важно знать о том, что все команды из файла userSetup.mel выполняются до открытия
новой сцены. Если вы написали в этом файле строки, создающие новые объекты или меняющие
значения атрибутов существующих объектов (например, стандартных камер), они не будут иметь
никакого эффекта, так как MAYA создаст новую сцену после выполнения команд из файла user­
Setup.mel.

Если вы хотите, чтобы в вашей новой сцене всегда создавался новый объект(ы) (например,
камера bottom) вы должны добавить нужные команды в файл initAfter.mel, который можно

MEL, или MAYA Embedded Language 943


разыскать в «родных» скриптах MAYA в папке startup. Как и в случае с другими стандартными
скриптами, поведение которых вы хотите модифицировать, лучше скопировать этот файл в свою
директорию scripts и добавить нужные строки в конец скопированного файла. Модификации
родных скриптов MAYA посвящен следующий раздел.

Немного о хакерстве, или моя MAYA


Рано или поздно вы, наконец, поймете, что внешний вид MAYA целиком в ваших руках, так
как папка с многочисленными скриптами, используемыми самой MAYA для своих нужд, совершенно
открыта и лежит, как правило, по адресу X:\Program Files\Alias\MayaN.N\scripts.
Некоторые из вас найдут весьма поучительным чтение этой папки перед сном или в
моменты душевного подъема. Там содержится масса примеров для подражания и образцы того,
как сами разработчики MAYA используют MEL в своих высоких и низких целях.

Более того, некоторые безнравственные умы наверняка решат что-нибудь подправить


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

Совет. Если вы решили подправить что-нибудь в родных майских скриптах,


не сохраняйте изменения в оригинальных файлах. Вместо этого скопируйте
оригинальный скрипт в вашу папку scripts и сохраняйте изменения там. Так как
MAYA в поисках неизвестной команды сначала просматривает пользовательские
папки scripts, то в первую очередь она найдет вашу версию скрипта в ваше папке.
Это крайне удобно еще и потому, что если вы что-то испортили или сделали
ошибку приводящую к некорректной работе, то MAYA может просто перестать
запускаться. Простое переименование файла в вашей папке scripts восстанавливает
работу MAYA no умолчанию.

Приведу пример для начинающих хакеров, как «подправлять» интерфейс MAYA безопасными
методами, а заодно, как искать нужные для редактирования файлы.

Если вы нажимаете над объектом на экране правую кнопку мыши, появляется контекстное
меню, которое вы, предположим, хотите дополнить. Иногда удобно бывает спрятать или удалить
объект, не выбирая его (например, вы уже выбрали нужные вершины и хотите спрятать мешающий
объект, чтобы продолжить выбор вершин). Добавим в это меню пару пунктов. Как добраться до
этого меню? В каком родном майском файле оно описано.

Берем название какого-нибудь пункта из контекстного меню, например, «Untemplate» (не


надо брать расхожее «Select»), и делаем в операционной системе поиск MEL-файлов, содержащих
это название в папке, где лежат майские скрипты.

Получив список файлов, методом пристального взгляда или методом перебора определяем,
что нам нужен файл dagMenuProc.mel.

После этого немедленно копируем его в свою пользовательскую папку scripts.


Открываем его и ищем строку «Select», причем ищем вместе с кавычками, ведь при
описании пунктов меню обычно используется команда типа menultem -I ". . .".
Действительно, в файле находится строка:

menultem -I "Select" -с ("select -r " + Sobject);

Добавляем прямо вслед за ней еще две строки:

menultem -I "Select" -с ("select -r " + Sobject);


menultem -I "Delete" -с ("delete " + $object);
menultem -I "Hide" -c ("hide " + $object);

944 Книга Сергея Цыпцына


Чтобы исправленный скрипт заработал, можно перегрузить MAYA, а можно, не выходя из
MAYA, выполнить в меню Script Editor пункт File=>5ource Script и указать в качестве обновляемого
только что отредактированный и сохраненный файл в пользовательской папке scripts.
После этого, нажав правую кнопку мыши над любым объектом, вы увидите два
дополнительных пункта меню, которые работают вне зависимости от того, выбран объект под
курсором мыши или нет.

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

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

При выходе из блока или процедуры, значения переменных, объявленных в этой


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

global proc fun1()


{
global int $GlobalValue;
int $a;

}
// —
global proc fun2()
{
global int $GlobalValue;
int $b;

MEL, или MAYA Embedded Language 945


Как нетрудно догадаться, MAYA сама хранит массу информации в глобальных переменных.
Получить их список можно командой env (а лучше print 'env').

Создание интерфейса с помощью веб-браузера.


Радикально альтернативный подход
Начиная с шестой версии в MAYA появился встроенный веб-браузер. Внешне это выглядит
довольно банально в любой панели можно теперь открыть окошко браузера с помощью меню
Panels=>Panel=>Web Browser.

Конечно, удобно открывать справочники и учебники прямо в панели MAYA, однако наличие
браузера имеет еще много дополнительных и не сразу очевидных преимуществ.

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


Во-вторых, в коде этой страницы вы можете использовать при определении ссылок вместо
протокола http: новый протокол mel:. При этом вместо перехода по этой ссылке, будет происходить
выполнение MEL-команды, указанной в определении ссылки. Например:

<а href="mel://nurbsCube/">Create default cube</a>

В-третьих, с помощью команды webBrowser вы можете открыть мини-браузер в отдельном

946 Книга Сергея Цыпцына


окне и загрузить туда свою страницу:

window;
columnLayout;
webBrowser -width 800 -height 600
-url "file:///C:/Program Files/Alias/Maya6.5/bin/res/intro/intro.html";
showWindow;

На своей странице вы можете вместо кнопок, выполняющих команды, использовать ссылки


с протоколом mel: , содержащие эти команды. Если вам знакомы средства быстрой разработки
веб-страниц, то задача создания собственных интерфейсов, сводится просто к веб-дизайну.

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

В-пятых, Macromedia Flash легко прикручивается к майскому браузеру (надо лишь при
установке указать, вместо дефолтной, папку типа
C:\Program Files\Alias\MayaN.N\bin\plugins
в которой содержится информация о встроенном браузере). После этого вы можете использовать
все возможности Flash для создания интерфейсов.

Дальнейшее развитие этой темы выходит за рамки книги, однако пользователи,


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

Все, что вы хотели узнать про MEL


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

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

Во-первых, переменные для хранения промежуточных данных.

Во-вторых, условные переходы типа if() {} else{}, для сравнения данных и выполнения
наборов команд при выполнении определенных условий.

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

В-четвертых, процедуры, позволяющие объявить целый набор команд в виде одной MEL-
команды.

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

Некоторые практические советы


Для тех, кто уже начал осваиваться в MEL и даже получать удовольствие от этого, приведу
некоторое количество полезных советов.

1. Используйте MEL Studio Pro. Пожалейте свои глаза и нервы.

MEL, или MAYA Embedded Language 947


2. Не жалейте времени на комментарии. Особенно в начале файла. Вам самим, а также
другим читателям и писателям будет легче разобраться в том, что делает ваш загадочный
скрипт.
3. Если вы используете циклы, перед запуском скрипта сохраните где-нибудь его текст.
Никакой защиты от бесконечного выполнения циклов не предусмотрено. Поэтому если условие
выхода из цикла по каким-то причинам не будет достигнуто, MAYA просто «уйдет в кому», из
которой вам ее не удастся вернуть.

4. Для хоть какой-то защиты от бесконечных циклов есть несколько вариантов. Первый
- официальный: использовать команду progressBar с флагом -islnterruptable для работы с main
progress bar (см. описание команды progressBar). Второй - неофициальный: нужно скачать
плагин keylnterrupt с сайта www.highend3d.com и использовать в цикле функцию опроса нажатых
клавищ.

5. Если вы собираетесь запустить приложение с помощью команды system, но хотите,


чтобы MAYA не зависала, ожидая окончания работы этого приложения, используйте команду start
для операционной системы Windows. Например: system( "start notepad" ); Альтернативный способ,
не зависящий от операционной системы, состоит в использовании команды exec.

6. Если вы пишете скрипт, производящий манипуляции над объектами, старайтесь работать


с выделенными объектами. Помните про шаблон

string $list[] = 'ls -sl';


string $item;
for($item in $list)
{
....

7. Если вы обращаетесь к конкретному объекту по имени, проверяйте наличие этого


объекта в сцене. Если этого объекта не существует, ваш скрипт даст ошибку.

if(objExists("myCurve")) { . . . }

8. Если вы открываете новое окно, проверьте, не открыто ли оно уже. И в случае его
существования, удалите его, чтобы всегда создавать только одну копию окна. Для этого не
забывайте давать окнам имена.

i f ( ' window -ex DROP_WINDOW) { deleteUI DROP_WINDOW; }


window -t "drop attributes" DROP_WINDOW;

9. Если элементов интерфейса немного, то можно придумать им свои имена, задаваемые


командой создания этих элементов. Однако взрослые мальчики стараются использовать имена
для элементов интерфейса, которые им назначает MAYA (если при создании не указывать явное
имя).

string $but = 'button -I "Format All Disks" -c "confirmDialog"';

10. Мировые координаты компонент (например, вершин) можно узнать с помощью команд
pointPosition или xf orm. Последняя команда - исключительна полезна для работы с трансформациями
и пивотами.

11. Команда eval (или evalEcho) позволяет выполнить любую переменную, содержащую
строку, как MEL-команду. Ее удобно использовать при построении кривых или поверхностей,
накапливая длинную строку в цикле, а потом выполняя ее одним махом, как команду.

12. Вот несколько полезных команд, наличие которых не так очевидно и отыскать
которые методом тыка не всегда возможно:

948 Книга Сергея Цыпцына


• tokenize - позволяет разделить строку на части, используя любой символ, как разделитель
внутри строки (например, косая черта, как разделитель между папками в полном имени файла);
• catch и catchQuiet - позволяют продолжить выполнение скрипта, даже если произошла
ошибка;
• refresh - обновляет экран;
• scriptJob - задает команду или процедуру, выполняющуюся при определенном событии
или условии;
• image - вставляет картинку в окно, как элемент интерфейса;
• connectControl - присоединяет элемент интерфейса к заданному атрибуту (используется,
например, для присоединения «галки» checkBox к логическим атрибутам типа visibility);

• about - сообщает массу интересной информации;


• colorAtPoint - возвращает цвет (или альфу) текстуры в точке, заданной своими UV-
координатами;

• scmh - секретная команда, позволяющая имитировать щелкание мышью в определенном


месте. С ее помощью, можно, к примеру, строить кривые, проходящие через заданные Edit
Points.

13. Последний совет специально для исследователей MEL. Как можно чаще используйте
команду whatls. Если она вдруг выдаст странный ответ типа Run Time Command:

whatls RenderlntoNewWindow;
// Result: Run Time Command //

не унывайте. Дайте еще одну команду:

runTimeCommand -q -с RenderlntoNewWindow;
// Result: renderlntoNewWindow render //
whatls renderlntoNewWindow;
// Result: Mel procedure found in: C:/Program Files/Atias/Maya9.5/scripts/others/renderWindowPan-
el.mel //

14. P.S. He забывайте, что MAYA различает маленькие и большие буквы.

История. Я опять не хочу в Париж


Цепь событий, приведших меня во французскую столицу, началась примерно за полгода до
того, как я забрался на Эйфелеву башню.

После защиты диссертации я тихо и мирно занимался научной деятельностью в Московском


университете. Честно говоря, это было наиболее интересное и увлекательное время в моей
жизни - с точки зрения профессиональной деятельности. Хаотическая динамика и прикладная
аэромеханика захватили меня полностью. Более азартного и творческого занятия мне с тех пор не
удалось найти. Как бы ни были увлекательны компьютерные технологии, по сравнению с научной
деятельностью, они похожи на игрушки для системы MS-DOS. He сочтите за снобизм, это сугубо
мое личное мнение, просто наиболее полно мне удалось реализовать свои творческие амбиции
именно в науке. По рисованию в школе я имел стабильное три, а отсутствие способности чисто
спеть любую мелодию лишило меня возможности стать звездой самодеятельности.

Но начало девяностых годов складывалось не лучшим образом, и когда выживать на


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

MEL, или MAYA Embedded Language 949


компании Steepler. Крупнейшая в России компания продавала не только компьютеры, но и
программное обеспечение, которое, по законам бизнеса, полагалось технически поддерживать.
В конце разговора Руст назвал сумму зарплаты, в двадцать пять раз превышавшую мой тогдашний
доход. Вы когда-нибудь получали такие предложения? Тем не менее, ни один мускул (и даже
голос) не дрогнул на моем лице, и я непринужденно сказал, что подумаю и перезвоню, после чего
положил трубку, внезапно похолодевшими руками.

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


с точки зрения отечественной науки, и я, как и следовало ожидать, не устоял. Позвонив еще
раз, и уточнив количество нулей перед запятой (а то мне начало казаться, что я ослышался при
первом разговоре), я, как будто бы нехотя, согласился, хотя сам не мог поверить в реальность
происходящего.

Работа оказалась довольно интресной и, самое главное, веселой. Я попал в отдел по


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

Были, правда, в моей работе и некоторые нюансы. Сначала я оказывал техническую


поддержку пользователям, купившим у нашей компании продукты Microsoft, затем мы стали
продавать еще Symantec, Borland и Corel. Компания постоянно расширяла бизнес и подписывала
новые дистрибуторские соглашения, и в списке продуктов, обеспеченных технической поддержкой,
появлялись Adobe, Aldus, Lotus... (Помните такой продукт - Lotus 1-2-3? А я очень хорошо
помню...) Хорошо хоть сетевой отдел прикрывал поддержку по Novcll NetWare, однако мне срочно
приходилось осваивать еще десятки программ от более мелких (и не очень) производителей:
Delrina, Watcom, WordPerfect... Курсы по IBM OS/2, сменялись обучением Lotus Notes, при этом в
перерывах я осваивал систему at-команд для модемов ZyXEL и писал бухгалтерию на MS Access.
Конечно, расширенное сознание и тренированная университетом память позволяли перемалывать
мегабайты информации и повышать эрудицию до чудовищных высот, однако всему есть предел. Этот
предел наступил, когда было подписано соглашение с компанией Oracle о продаже ее «тяжелых»
продуктов. Я сказал «хватит», и под угрозой схождения с ума, ограничил список производителей,
продукты которых я был готов поддерживать. Компания вошла в положение и в целях сохранения
моего психического здоровья даже решила морально поддержать меня.

Поддержка заключалась в следующем: блиставшая тогда на рынке программных продуктов


фирма Borland (интересно, кто-нибудь помнит ее программы под названием Paradox или Quattro
Pro?) устраивала для своих крупных дистрибуторов технический семинар, и не где-нибудь, а в
Париже. Как технический специалист, я был откомандирован на этот семинар с целью повышения
и без того зашкаливающей эрудиции и поднятия боевого духа. В то время слово «Париж»
являлось для меня неким символом, если не сказать фетишем, олицетворяющим квинтессенцию
«заграницы».

За день до отлета, поздним вечером, я, как обычно, сидел за двумя своими компьютерами
и неистово нажимал кнопки, рисуя в уме нечеловеческие красоты французской столицы. И тут в
комнату зашел мой начальник, однокурсник Гриша, и, увидев меня за компьютерами, удивленно
спросил: «Ты ведь завтра летишь в Париж?». Я довольно кивнул. Следующий вопрос был уже
менее понятен: «Ты что, так полетишь в Париж?». Глядя на мои вопросительно ползущие брови,
Гриша уточнил: «Ты что, полетишь в Париж в таком виде?». Надо сказать, что вид у меня был
вполне технический: любимая футболка-долгожитель, довольно целые джинсы и очень длинные
волосы. Гриша, человек хорошего вкуса и легкого пижонства, тоже, очевидно, мысленно наделял
Париж какими-то сверхестественными романтическими свойствами и ему, Грише, казалось
кощунственным лететь туда, не одевшись соответственно и не приведя себя в соответствие с
иллюзорными представлениями.

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


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

950 Книга Сергея Цыпцына


моим внешним преображением и готов подстричься со мной за компанию (хотя с его прической
можно было ехать не только на семинар в Париж, но на прием к английской королеве). Дальше
было хуже (или - лучше). Аки агнец на заклание, я был подстрижен, снова погружен в машину,
отвезен на Новый Арбат в дебри магазинов, где был одет в белоснежную рубашку, модный костюм,
тесные туфли и умопомрачительный галстук, как сейчас помню, от Юдашкина (галстук храню до
сих пор - сувенир!).

Когда мы вернулись назад, наш завскладом (мой очередной однокурсник Джон) взглянув
на меня, появившегося в проеме двери офиса, вежливо спросил: «Вы из какой компании? Получать
или заказывать?». Потом он долго корил меня за то, что я не хожу в таком виде на работу каждый
день. По его мнению, все девушки прилегающих к офису районов были бы счастливы и невменяемы
при одном только моем появлении. (Джон, кстати, сам ходил на работу в галстуке.)

Честно сказать, я сам себя плохо узнавал в новом обличье. Чувство какой-то незащищенности
усугублялось короткой прической, а при попытке сесть на рабочее место галстук от Юдашкина
агрессивно бросался на клавиатуру.

Однако на следующий день, я, напялив на себя для пущей важности модный белый
плащ, вылетел рейсом Москва-Париж. Прибыл я на место довольно поздно и, добравшись до
шедеврально-урбанистического района Ля Дефанс, разместился в Новотеле и уснул, как убитый,
переполненный впечатлениями и ожиданиями.

Каково же было мое удивление, разочарование, смущение, ярость и досада, когда утром,
облачившись в свои романтические доспехи, я спустился в холл и попал с общество остальных
специалистов, приехавших на семинар. Стоит ли упоминать, что все они были одеты в любимые
футболки и архетипичные джинсы. Я клял Гришу, Джона и себя за лубочный образ мысли,
мчась по коридору и срывая с себя чужеродные покровы. Хорошо хоть нормальная одежда была
благоразумно захвачена с собой, и скоро я уже чувствовал себя в своей тарелке, поскрипывая
старыми коссовками. Волосы, правда, пришлось отращивать целый год.

Да, кстати, о Париже.


В Париже мне более всего запомнилась компания Borland: умопомрачительные рестораны,
прогулки по Сене на корабле с логотипом компании, фантастическое шоу в варьете «Парадиз
/1атин», где на головы посетителям из-под купола планировал целый космический корабль с
надписью Borland, из которого выскакивали изумительные девушки, олицетворяющие, очевидно,
высокое качество программных продуктов компании.

Сам же Париж произвел на меня впечатление тягостное, если не сказать отвратительное.


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

С тех пор меня совершенно не тянет в Париж. А также в парикмахерскую. Ну, и на Новый Арбат...
Paint Effects
Рисовальные эффекты
Именно так зачастую переводят название модуля Paint Effects.

Сразу уточню - это не программа трехмерного рисования на поверхности объектов, и


использовать Paint Effects в этом качестве, вообще говоря, неудобно. Это отдельный, довольно
нетрадиционный, инструмент с изящной парадигмой.

В основе Paint Effects лежит понятие штриха (Stroke), который можно нарисовать на любой
поверхности, на обычной двумерной плоскости или просто в произвольной области трехмерного
пространства. В первом и последнем случаях это кривая на поверхности или в ЗD-пространстве,
обладающая набором свойств, определяющих, как этот штрих будет выглядеть и как будет вести
себя в сцене. Если это штрих, из которого должны расти деревья или волосы, то при любом
положении камеры это будут настоящие деревья или волосы, которые еще и развеваются на ветру и
имеют набор динамических характеристик, таких, как упругость или плотность. Трюк заключается
в том, что трехмерные поверхности в данном случае не используются, а в каждый момент времени
с чудовищной скоростью генерируется плоское изображение процедурного трехмерного объекта,
каким он должен быть в этом месте - с учетом положения камеры, источников света, анимации,
динамики и пр. Если сделать облет такого объекта, скажем дерева, то получится совершенно
корректная картина, с трехмерным объектом в центре.

В понятие "кисть" (brush) в данном случае входит набор свойств, которыми обладают
оставляемые ею штрихи. Кроме упомянутых деревьев и волос, рисовать можно огнем, молниями,
различными растениями, жирными трехмерными мазками масляных красок, макаронами (да-да!),
водой, снегом и много еще чем. Это лишь часть кистей, уже имеющихся в Paint Effects, но ведь
кисти можно модифицировать, делать новые, можно смешивать их между собой и, естественно,
сохранять, создавая свои библиотеки. Рисовать можно и текстурами, которые накладываются
вдоль штриха различными способами. Коль скоро вид штриха определяется набором его
атрибутов, то различные кисти - это просто MEL-скрипты, заполняющие атрибуты определенными
значениями. Для удобства атрибуты разбиты на функциональные группы, отвечающие за размер
кисти, цвет и текстурирование, тени, иллюминацию, свечение, топологию создания и анимацию
роста при рисовании, поведение и силы взаимодействия, скручивание, жесткость и множество
других параметров. Естественно, что для штрихов определяется чувствительность к нажатию - в
случае использования пера. Созданные таким образом объекты могут отбрасывать тени на себя
и окружающие поверхности, могут деформироваться при помощи обычных сплайновых кривых,
способны конвертироваться в полигоны и обладают массой удивительных свойств.

После такого бурного, но довольного абстрактного вступления нетерпеливые умы уже


вероятно закипают от любопытства и раздраженного желания узнать, как же на самом деле
устроены эти всемогущие Paint Effects. He тут то было.

Рекомендации по освоению Paint Effects


Для начала я советую как следует «наиграться» с Paint Effects. Для этого следует всего
лишь выполнить Paint Effects=>Get Brush..., затем в окне Visor выбрать любую кисть и неистовыми

Анимация 955
движениями мыши или пера измазать всю перспективную камеру, время от времени меняя кисти.
Можно также изредка нажимать кнопку Render и исторгать восхищенные возгласы или крики
отвращения.

Не забывайте, что во время рисования у вас в руках инструмент Paint Effects Tool, и чтобы
избавиться от него, достаточно выбрать Select Tool или нажать ' q ' .

Имейте в виду, что можно рисовать не только «по земле», но по любой поверхности. Для
этого достаточно предварительно выбрать ее и сделать «рисуемой»: Paint Effects=>Make Paintable,
а затем продолжить эксперименты, уже проводя штрихи на ней.

Поглядывайте в Outliner и Attribute Editor во время безумных экспериментов с рисованием.


Это подготовит вас к дальнейшему чтению книги (если у вас, конечно, после этого будут силы
читать).

Если у вас неплохо развито абстрактное мышление, попробуйте представлять себе


штрихи Paint Effects, как затекстурированные кривые. Затекстурированные хитрым образом - с
использованием множества параметров и сложных процедурных трехмерных текстур.

Если вы нажмете клавишу '8', то попадете в панель Paint Effects. Конечно, очень здорово
наблюдать штрихи Paint Effects прямо во время рисования такими же, какими они выглядят
при рендеринге. Однако будьте готовы к странным перерисовкам экрана, подвисаниям MAYA и
прочим мелким неприятностям, особенно если у вас не самая свежая видеокарта. Я использую
этот режим, только для обычного плоского рисования (Paint=>Paint Canvas). В других случаях, я
стараюсь не нажимать '8' и не использовать Panels=>Panel=>Paint Effects. Кстати, чтобы вернуться
в нормальный режим, надо просто снова нажать '8'.

Классовая принадлежность Paint Effects


Если попробовать отнести Paint Effects к какой-нибудь привычной категории объектов,
получится довольно противоречивая картина.

С одной стороны Paint Effects - это средство создания трехмерных объектов. Благодаря
возможности конвертации любого штриха в полигональную поверхность, можно с уверенностью
отнести Paint Effects к средствам моделирования.

С другой стороны, методы визуализации в виде полупрозрачных спрайтов и способы


анимации сильно напоминают систему частиц.

Наличие упругости в виде процедурных пружин также усиливает сходство с динамикой.


Однако отсутствие реальной геометрии и полностью процедурное описание делают Paint Effects
похожими на огромную трехмерную процедурную текстуру, внешний вид которой настраивается
только с помощью всевозможных параметров.

Для особо эстетствующих умов я бы мог назвать Paint Effects L-системой с человеческим лицом.
Судя по тому, что сами разработчики запихали меню Paint Effects в режим Rendering, для них этот
модуль ближе всего к визуализации.

Впрочем, как бы мы ни назвали модуль Paint Effects, это никак не повлияет на его возможные
применения.

Применения Paint Effects


Тут конечно хочется написать: «С помощью Paint Effects можно делать всё!», или лучше
«Paint Effects предназначены для делания всего!». Если пренебречь вопросами качества, в общем
так оно и есть. Когда-то, знакомясь с Paint Effects, я с удивлением обнаружил, что с помощью

956 Книга Сергея Цыпцына


трехсот шестидесяти семи атрибутов можно описать объект практически любой формы. Было
странное ощущение, что разработчики обнаружили универсальную формулу описания мира и
внедрили ее в MAYA 2.5...

Дело в том, что невозможно назвать, для чего конкретно лучше всего использовать Paint
Effects, так же, как нельзя сказать, что лошади в MAYA получаются отлично, а вот чайники - так
себе. Вы должны сами определить границы использования Paint Effects, экспериментируя с их
многочисленными атрибутами.

Чтобы не попасть под огонь критики, я просто приблизительно переведу список категорий
кистей, доступных в стандартной поставке. Итак с помощью Paint Effects можно распылять краски,
красить шкуры животных, делать постройки, облака, электрические эффекты, перья, волокно,
огонь, плоть и кровь, цветы, продукты питания, разные глупости, галактики, стекло, свечения,
травку, волосы, несъедобные жидкости, штрихи фломастеров, металл, чайники, масляные краски,
бумагу, пастельные и карандашные рисунки, мелкотравчатые растения, деревья, подводный мир,
акварели, воду, природные явления.

Одно я могу сказать точно: Paint Effects не предназначены для суперфотореалистичного


моделирования антропоморфных персонажей. А также для их гиперреалистичной анимации.
Часто в отдельное применение Paint Effects выделяют создание всяческой растительности, типа
цветов, деревьев и прочей «ботаники». Это обусловлено тем, что часть атрибутов имеют типично
ботанические названия, например: листья, цветы и ягоды. Впрочем, эти же атрибуты используются
и для менее органических объектов.

Применение Paint Effects в качестве системы обычного двухмерного рисования довольно


эффективно. Богатый набор кистей делает возможным быстрое создание бесшовных текстур.
Пользователи, знакомые с пакетом Microsoft Expressions, найдут много знакомых возможностей и
идей.

Примечание. Купив Expressions, Microsoft довольно долго мариновала его в вяло-


развивающемся состоянии (это, впрочем, привычныая картина - вспомните
судьбу Softimage в лапах Microsoft). Некоторое время назад появилась очередная
реинкарнация Expressions в виде пакета Acrylic - изрядно растолстевшая, но не
сильно продвинувшаяся вперед программа.

Моделирование всяческой процедурной геометрии возможно не только благодаря наличию


сотен атрибутов, но и вследствие того, что кисти поддерживают использование MEL-скриптов в
процессе построения штрихов Paint Effects.

Так как любую кривую можно превратить в штрих Paint Effects, то задача рендеринга кривых
(wireframe rendering) решается в MAYA просто и быстро, причем внешний вид кривых определяется
параметрами кистей, включая текстуры и тени на кривых.

Paint Effects также часто применяются для создания нефотореалистичных эффектов (NPR).
Один из примеров - Tomcat Cartoon Shader (http://www.toonshade.com/), исключительно удачный
плагин к MAYA, позволяющий рендерить объекты в мультипликационном стиле.

В седьмой версии MAYA появился новый модуль MAYA Toon, для создания контуров и заливок,
основанный на технологии Paint Effects.

Штрихи Paint Effects, просчитанные отдельным слоем (и, возможно, с анимацией), могут
быть эффективно использованы на этапе композитинга. Например, растущие орнаменты могут
быть превращены с помощью нужных фильтров в морозные узоры, постепенно заполняющие весь
экран.

Если я добавлю, что штрихи Paint Effects можно подставлять в частицы и устраивать, к
примеру, взрыв на макаронной фабрике или салют из веток молодого дуба, то некоторые из еще
неокрепших майских пользователей испытают некоторую растерянность.

Paint Effects 957


Поэтому перечислять дальнейшие прямые и косвенные применения Paint Effects нет
смысла. Лучше перейдем к их природе.

Природа Paint Effects. Штрихи


Итак, в основе архитектуры Paint Effects лежат два базовых понятия: штрих (stroke) и
кисть (brush).

Штрих - это линия, которую пользователь рисует на экране мышью или пером.
Соответственно, штрих имеет набор атрибутов (как и любой объект в MAYA), определяющий его
свойства.
Надо понимать, что в основе штриха, даже можно сказать «под штрихом», всегда
лежит реальная сплайновая кривая. Она, как правило, спрятана (hidden), поэтому на экране не
отображается. Далее я буду употреблять термин «нижележащая кривая» (Stroke Path Curve),
напоминающий о том, что штрих это всегда пара, состоящая из кривой и ноды типа stroke.

Такая кривая всегда создается в момент рисования штриха. По умолчанию она имеет
вторую степень, однако вы можете проделать с ней любые безнравственные действия с помощью
операций редактирования сплайновых кривых (меню Edit Curves).

По аналогии с Сreate=>Pencil Curve Tool, во время рисования кривая, лежащая в основе


штриха, сэмплируется, то есть разбивается на контрольные точки с заданной частотой. Если вы
рисуете быстро - точек на кривой меньше, если ведете перо медленно - кривая более «густая».
Именно форма этой кривой определяет форму штриха.

Примечание. Помните, что всегда можно изменить количество точек на кривой


«под штрихом» - либо операцией Paint Effects=>Curve Utilities=>Simplify Stroke Path
Curves (она уменьшает количество точек в четыре раза и, кстати, задает третью
степень кривой), либо обычной операцией Rebuild Curves, либо MEL-командой sim-
plifyStrok.es. Никто также не запрещает вам таскать кривую за контрольные
точки.

Сам по себе штрих - это не кривая, а нода типа stroke со своими атрибутами, которая
«лежит» на кривой, и определяет свойства самого штриха. Ее атрибуты появляются, как правило,
во второй закладке в Attribute Editor, в то время как в третьей закладке находятся атрибуты
кисти.

958 Книга Сергея Цыпцына


Атрибут Sample Density задает плотность штриха по отношению к нижележащей кривой.
Это довольно важный атрибут, определяющий «насыщенность» штриха, то есть частоту, с которой
из штриха что-то растет.

Начало и конец штриха на кривой определяют атрибуты Min Clip и Max Clip. Штрих может
начинаться в середине нижележащей кривой. Эти атрибуты очень удобно использовать для
анимации «ползущих» или «растущих» штрихов.

Нижележащая кривая всегда имеет нормаль, поэтому при выключенном атрибуте Use Nor­
mal, штрих будет использовать именно нормаль с кривой, а при включенном фиксированное
направление нормали, заданное в поле Normal. Нормаль нужна в тех случаях, когда из штриха
что-то растет, чтобы определить направление «произрастания».

Если штрих нарисован на поверхности (или на плоскости сетки), то атрибут Surface Offset
позволяет «утопить» весь штрих или же приподнять его над этой поверхностью.

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

Для этого достаточно выбрать кривую и выполнить Paint Effects=>Curve Utilities=>Attach


Brushes to Curves. Последняя использованная кисть будет назначена на штрих, созданный из
кривой.

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

Для взрослых. Если вы используете перо, то при рисовании в атрибутах штриха, сохраняется
не только количество (плотность) точек, но и сила нажатия (pressure) на перо во время рисования.
Это распределение силы нажатия можно затем использовать для управления любым атрибутом
кисти в разделе Pressure Mapping.

Paint Effects 959


Если общая форма штриха определяется его атрибутами и формой нижележащей кривой,
то его внешний вид полностью задается кистью, которая, скажем так, наложена или назначена
(как текстура) на этот штрих. Поговорим далее о кистях.

Природа Paint Effects. Кисти


Как я уже упоминал, проще всего представлять штрихи Paint Effects как текстурированные
кривые. Роль текстур в данном случае выполняют кисти (brushes), целиком определяющие внешний
вид штриха. Штрихи и кисти - объекты независимые. Десять штрихов могут иметь одинаковую
кисть, однако каждый штрих может иметь только одну кисть, определяющую его вид. Если удалить
кисть, присвоенную штриху, штрих не будет визуализироваться вообще.

Если вы уже поэкспериментировали с кистями, кое-кто из вас мог заметить, что все кисти,
даже радикально отличающиеся друг от друга - это все один и тот же объект, точнее нода типа
brush. Таким образом, все кисти отличаются друг от друга только значениям атрибутов для одной
и той же ноды. Если проводить навязчивую аналогию с текстурами, то все штрихи радикально
разного внешнего вида, от макарон до цветов - это все однотипные кривые, затекстурированные
одной и той же текстурой с различными значениями цвета, прозрачности, размера, ширины, шума
и массы других параметров.

Из этого следует несколько выводов.

Во-первых, кисти, которые вы выбираете в окне Visor - это банальные MEL-скрипты, просто
задающие нужные значения соответствующим атрибутам кисти, используемой для рисования.

Во-вторых, кисть можно «скопировать» с выбранного штриха (Paint Effects=>Get Settings


from Selected Stroke), а затем назначить скопированные значения для атрибутов на другой штрих
(или даже на несколько штрихов) (Paint Effects=>Apply Settings to Selected Stokes)

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

960 Книга Сергея Цыпцына


атрибутов которой представляют собой попросту усредненные значения между «макаронными» и
«цветочными» атрибутами.

Для того, чтобы смешать кисти, достаточно выбрать в окне Visor, к примеру, макароны, а
затем, даже ничего не рисуя, нажать правую кнопку мыши над любой другой кистью, например,
над цветами, а затем выбрать Blend Brush 50%.

После этого у вас в руках окажется кисть, состоящая из цвето-макарон. Смешивать также
можно только значения атрибутов, определяющих форму (Blend Shape) или только цвет (Blend
Shading).

Смешивание кистей
Откройте новую сцену.

Создайте окружность: Create=>NURBS Primitive=>Circle.


Переверните ее: rotateX=180.
Сдублируйте ее два раза и приподнимите копии по вертикали (translateY=1; translateY=2).
Создайте источник света: Create=>Lights=>Point Light.
Поднимите его: translateY=10.
Выберите верхнюю окружность.
Затем возьмите в руки кисть: Paint Effects=>Get Brush.
Выберите в разделе flowers кисть dahriaRed.mel.

Рисовать ничего не надо.

Назначьте данную кисть на выбранную окружность: Paint Effects=>Curve Utilities=>Attach


Brush to Curves. Из окружности вырастут цветы.

Сейчас у вас в руках инструмент Paint EffectsTool.

Чтобы не переключаться в Select Tool, но быстро выбрать среднюю окружность, щелкните


правой кнопкой мыши прямо над ней и выберите Select (можно также просто выбрать вторую
окружность в Outliner).

В окне Visor, в разделе food выберите кисть nooddles.mel, а затем снова назначьте эту
кисть на выбранную окружность: Paint Effects=>Curve Utilities=>Attach Brush to Curves.
Из окружности полезут макароны.

Выберите нижнюю окружность.

Paint Effects 961


Перейдите в окне Visor в раздел flowers и нажмите правую кнопку мыши над кистью dahl-
iaRed.mel.

В выпавшем меню выберите Blend Brush 50%.


Теперь у вас в руках цвето-макаронная кисть. К сожалению, это никак не отражается нигде.
Назначьте эту кисть на выбранную нижнюю окружность: Paint Effects=>Curve Utilities=>Attach Brush
to Curves.

На окружности появятся цвето-макароны.

Нажмите '8', если хотите рассмотреть их получше.

Или отрендерите изображение.

Цвето-макаронная кисть имеет значения атрибутов, равные усредненным значениям


атрибутов для цветов и для макарон.

Последняя кисть. Template Brush


Экспериментируя с кистями некоторые изворотливые умы наверняка начали догадываться
о существовании последней использованной кисти. Так же, как MAYA запоминает последний
использованный инструмент (Tool), она сохраняет информацию и о том, какая кисть использовалась
последний раз в текущей сессии MAYA. Существует некий буфер, который называется Template
Brush, куда автоматически копируются значения всех атрибутов последней использовавшейся
кисти. Если MAYA только что запущена и никаких кистей еще не использовалось, в этом буфере
находится кисть по умолчанию - простая черная линия без всяких выкрутасов и отростков.

Все операции, копирующие параметры кисти с выбранного штриха (Get Settings from Se­
lected Stroke) или на выбранный штрих (Apply Settings to ...), используют Template Brush как буфер
для хранения параметров кисти. В этом смысле Template Brush сильно напоминает обычный буфер
обмена, куда можно скопировать выделенный текст, а затем вставить его в нужное место. Следует
постоянно помнить, что в этом буфере всегда находятся параметры какой-нибудь кисти, либо
выбранной вручную, либо скопированной с выбранного штриха при помощи операции Get Settings
from Selected Stroke.

Операция Paint Effects=>Curve Utilities=>Attach Brush to Curves, превращающая обычную


кривую в штрих, также берет атрибуты кисти для штриха из буфера Template Brush.
Соответственно, сбросить все параметры в значения по умолчанию в буфере Template Brush можно
операцией Paint Effects=>Reset Template Brush. Это может понадобиться, если вы конструируете
кисть с нуля.

Атрибуты кисти
Бесстрашные умы, ведомые майским принципом - изучать новый объект, исследуя
назначение его атрибутов, наверняка были несколько обескуражены количеством атрибутов
для ноды типа brush. Чтобы еще больше устрашить отважных исследователей, могу предложить
выбрать саму кисть как объект (например, нажав кнопку Select в Attribute Editor, в третьей закладке
для атрибутов кисти), а затем открыть Channel Box и почитать на досуге списочек атрибутов,
разворачивающийся до пола.

Естественно, чтобы описать все на свете, требуется некоторое количество атрибутов.


Любопытные умы даже могут определить это количество, дав в Script Editor команду:

size(' listAttr brush 1');


// Result: 376 //

962 Книга Сергея Цыпцына


Триста семьдесят шесть - это и есть количество атрибутов ноды типа brush. Конечно, не
все они используются для описания формы и цвета кисти, но, тем не менее, количество слегка
подавляет. (Количество атрибутов возрастает от версии к версии).

Боюсь, что у меня нет никакого хитрого совета для того, чтобы побыстрее разобраться с
устройством кистей, кроме банальной рекомендации прочитать раздел документации «Paint Ef­
fects Brush Settings» (проще найти его через поиск, чем вручную), последовательно описывающий
назначение всех атрибутов кисти. Сам я когда-то распечатал эти сто страниц и неторопливо их
прочел. Я также далек от мысли переводить этот раздел на русский язык, некоторые авторы уже
пытались это делать. Приведу лишь описания ключевых для понимания атрибутов, а также тех из
них, чье использование довольно неочевидно.

Для удобства работы с такой прорвой атрибутов удобнее всего использовать Attribute Edi­
tor, где они (атрибуты) разнесены по разделам. В дальнейшем я постараюсь указывать название
раздела при ссылке на тот или иной атрибут.

Два ключевых типа кистей. Tubes


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

Атрибут Tubes (раздел Tubes) определяет, будут ли произрастать и ветвиться из штриха


дополнительные кривые или штрих будет визуализироваться сам по себе.

Терминологический комментарий. Я долго находился в некотором затруднении, не зная,


как адекватно перевести слово Tubes. Всякие «стволы», «побеги», «стебли», «аппендиксы»,
«выросты» не подходили. Я решил, что иногда, как это не банально, буду говорить просто «трубки»,
а в случае биологической направленности буду употреблять «отростки». Таким образом, если
включить атрибут Tubes=On, из штриха во все стороны полезут разные трубки кривые, которые
могут иерархически ветвиться, напоминая, в первую очередь, деревья и кустарники.

Если Tubes=Off, все атрибуты из раздела Tubes становятся недоступны и никак не влияют
на внешний вид штриха.

Ниже я опишу два примера для работы с простыми и «ветвистыми» кистями, а сейчас
опишу еще немного ключевых атрибутов кистей.

Paint Effects 963


Размер кисти
Общий размер кисти определяется атрибутом Global Scale. В случае обычных (не
ветвистых) кистей это просто ширина штриха, однако в случае растительности на штрихе этот
атрибут пропорционально изменяет как ширину штриха, так и длину и ширину произрастающих
ответвлений.

Атрибут Brush Width (раздел Brush Profile) изменяет только ширину штриха, что в случае
ветвистых кистей определяет окрестность вокруг штриха, из которой растут трубки.

Природа кистей. Спрайты. Визуализация штрихов.


В чем же секрет чудовищной скорости визуализации штрихов Paint Effects? Целые участки
леса могут быть посчитаны в течение минуты. Дело в том, что при рендеринге не создается и не
просчитывается никаких реальных поверхностей. Никаких полигональных сеток или сплайновых
поверхностей.

Отображение штрихов происходит с помощью большого количества полупрозрачных дисков


(stamps). Такие микродиски имеют только радиус, цвет и прозрачность, поэтому изображение
составляется из них очень быстро. Радиус дисков соответствует ширине штриха (или трубки) на
данном участке, цвет и прозрачность вычисляются на основе значений атрибутов из разделов
Shading и Texturing.

Единственный произвольный параметр - это количество дисков, используемое для


визуализации штриха с данной кистью. Такая насыщенность дисками задается для кисти в разделе
Brush Profile с помощью атрибута Stamp Density.

Примечание. Аналогичный принцип используется в Renderman при рендеринге частиц -


правда, там на частицы можно накладывать материалы.

Если задать значение Stamp Density слишком маленьким, например, равным единице, то
диски сразу станут видны.

Соответственно, чем больше Stamp Density, тем более плотным будет изображение, но
время рендеринга также будет возрастать из-за увеличивающегося количества дисков. По-другому
можно сказать, что Stamp Density определяет степень перекрытия дисков между собой.

В случае Stamp Density=2, диски перекрываются между собой наполовину.

964 Книга Сергея Цыпцына


Это ключевой атрибут, непосредственно влияющий на время рендеринга, поэтому
старайтесь задавать его минимально возможным с точки зрения качества изображения.
Кроме удивительной скорости рендеринга, следует отметить еще и более чем скромные
требования к оперативной памяти при просчете штрихов Paint Effects. В силу того, что raytrac-
ing не используется, нет необходимости держать в памяти весь массив штрихов и их сегментов.
Рендереру достаточно загружать в память данные всего об одном сегменте штриха, отрисовывать
его и переходить к следующему сегменту (реально в память загружаются и отрисовываются
одновременно двадцать сегментов - для распараллеливания и ускорения). Соответственно, расход
памяти при таком подходе является мизерным.

Природа кистей. Рендеринг. Композитинг. Постэффекты


Коль скоро «дисковый» способ рендеринга довольно радикально отличается от
традиционных технологий визуализации, то наряду с чудовищной скоростью, он имеет некоторое
количество недостатков.

Для просчета штрихов Paint Effects используется отдельный рендерер. Сцена, содержащая
Paint Effects, просчитывается в два прохода, отдельно для штрихов и для «нормальных» объектов.
После чего изображения штрихов и остальных объектов складываются методами композитинга с
использованием информации о глубине (Z-channel). MAYA сама занимается таким композитингом,
но если вам сильно хочется или крайне необходимо сделать это вручную, такая возможность
есть.

Достаточно в Render Globals открыть раздел Paint Effects Rendering Options и расставить
там нужным образом галки Enable Stroke Rendering и Only Render Strokes.

Однако помните, что при складывании слоев МАУА использует дополнительную инсайдерскую
информацию, полученную при рендеринге и многослойные каналы глубины (Z-depth). Поэтому,
как правило, результат композитинга слоев, сделанный MAYA, будет лучше попыток «склеить»
изображения самостоятельно в программе типа Shake или After Effects.

Таким образом, штрихи Paint Effects принадлежат к классу «продвинутых» постэффектов,


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

К основным ограничениям Paint Effects относится прежде всего невозможность просчета


отражений и преломлений в других поверхностях, то есть использования raytraycing.

Тени от штрихов могут быть просчитаны методом Depth Map. Поддерживается как
отбрасывание теней на другие «реальные» поверхности, так и самозатенение. Также есть
возможность генерации быстрых «фальшивых» теней. Все атрибуты, относящиеся к теням,
находятся в разделе Shadow Effects. Естественно, что raytracing-тени не поддерживаются.

Работа с обычными штрихами. Рендеринг кривых


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

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

В качестве задачи выберем wireframe-визуализацию полигонального объекта. Объект,


естественно, будет поражать своей новизной.

Paint Effects 965


Создайте полигональную сферу по умолчанию.
Задайте Radius=3.
Приподнимите ее: translateY=3.
Хорошей привычка при работе с Paint Effects (и не только с Paint Effects) - в самом начале создать
источник света:
Create=>Lights=>Directional Light.
Разверните его: rotateX=-45.
Прибавьте мощности: lntensity=3.
Выберите все полигональные ребра на сфере.

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

Превратите выбранные ребра в обычные кривые: Edit Curves=>Duplicate Surface Curves.


Сгруппируйте полученные кривые в группу Ctrl-g, для удобства выбора и перемещения.
Выберите сферу и спрячьте ее: Ctrl-h.

Примечание. Если вы хотите выбрать и скопировать только видимые ребра,


тогда предварительно необходимо включить Backface Culling=full в атрибутах
полигональной сферы (закладка Shape, раздел Mesh Component Display).

Откройте Visor и выберите кисть: раздел pens, кисть ballpointRed.mel.


Важно помнить, что при выборе кисти она попадает в буфер Template Brush.
После этого можно выбрать Select Tool, чтобы ничего случайно не нарисовать.

Убедитесь в том, что группа groupl, состоящая из кривых, выбрана, и выполните операцию
Paint Effects=>Curve Utilities=>Attach Brush to Curves.

Все выбранные кривые будут превращены в штрихи, на которых назначены кисти, имеющие
точно такие же значения атрибутов, как и последняя использованная кисть, то есть кисть ballpoin­
tRed.mel из буфера Template Brush.

Одна незадача. Как следует из Attribute Editor, для каждого штриха создалась своя
собственная кисть и если мы хотим редактировать внешний вид каркасной сферы, скажем так, из
одного места, то неплохо было бы «синхронизировать» все кисти, а еще проще говоря, назначить
одну кисть на все штрихи. На данный момент все штрихи имеют разные кисти, хотя и с идентичными
значениями атрибутов.

Выберите все штрихи (например, так: Edit=>Select All by Type=>Strokes), а затем выполните
операцию Paint Effects=>Share One Brush, которая возьмет кисть с последнего выбранного штриха

966 Книга Сергея Цыпцына


и назначит ее на все остальные штрихи.

Теперь если выбрать любой штрих, то для него в Attribute Editor появляются атрибуты
одной и той же кисти, типа ballPointRed780.

Просчитайте изображение.

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

Кисть, которую мы выбрали, по умолчанию не реагирует на освещение. Исправим это.


Выберите любой штрих в Outliner, для него в третьей закладке в Attribute Editor будут
отображаться в атрибуты общей для всех штрихов кисти.

Откройте раздел Illumination и включите галку Illuminated.

Изменим также цвет на более яркий.


Откройте раздел Shading и задайте Color1 ярко-красным, а также полностью уберите
прозрачность.

Примечание. Атрибуты с индексом 2 из раздела Tube Shading (Color2, Incandes­


cence!, Transparency?) используются только тогда, когда включены «ветвистые»
штрихи (Tubes=On), для того, чтобы окрашивать основания и концы трубок в
разные цвета.

Просчитайте изображение.

Теперь «проволочная сфера выглядит нормально освещенной.


Увеличьте ширину штрихов.
В разделе Brush Profile задайте brush Width=0.02.

Если вы хотите придать «проволоке» более металлический вид, задайте параметры блика
в разделе Illumination: 5pecular=0.4, Specular Power=60, Specular Соlоr=бледно-красный.

Paint Effects 967


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

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

Внимание! Для текстурирования цвета и прозрачности используется одна и та же текстура.


Невозможно использовать разные текстуры для этих параметров, можно лишь независимо менять
«степень влияния» текстуры на прозрачность или цвет с помощью атрибутов Тех Color/Opacity
Scale.
Включив Map Color, задайте Texture Type=Fractal.
Коль скоро мы хотим задать плоский «рисованный» вид, установите Map Method=Tube 2D
(Tube 3D задает нормальный трехмерный цилиндрический маппинг вокруг штриха).

Примечание. Опция Map Displacement действует только в том случае, если тип
кисти установлен как Brush Type=Mesh. В этом случае штрих рендерится не в виде
микродисков, а как цилиндрическая полигональная трубка.

Задайте ниже атрибуты фрактала: Fractal Amplitude=5, Fractal Ratio=1, Fractal Thresholds,
так, чтобы придать цвету довольно грубый и жесткий вид.

Для усиления грубости уберите размывание текстуры: Blur Mult=0, Smear=0.

Немного растянем фрактал по вертикали, чтобы добавить шума поперек штрихов.


Для этого установите RepeatV=0.05, RepeatU=0.01, чтобы определить продольные «засечки»
на штрихах.

968 Книга Сергея Цыпцына


Теперь изображение стало совсем грубым.

Коль скоро мы теперь стремимся к нефотореалистичному, «бумажному» виду, зададим


белый цвет фона.

Для этого выберите камеру persp в Outliner и откройте для нее в Attribute Editor раздел
Environment. Там задайте Background Color абсолютно белым.

Снова вернитесь к атрибутам кисти. Наиболее пытливые умы разглядели в разделе Textur­
ing два атрибута для текстур, Тех Color 1 и Тех Color2, вроде как определяющих цвет текстуры, в
нашем случае фрактала. Однако несмотря на то, что эти цвета черно-белые, сфера имеет явно
выраженную красную окраску.

Дело в том, что цвета текстуры Тех Color1 и Тех Color2 умножаются на основной цвет
штриха, заданный в разделе Shading с помощью атрибута Color1. Кроме того, они дополнительно
умножаются на значение атрибута Тех Color Scale.

Поэтому если вы хотите (а вы наверняка хотите), чтобы цвет штриха целиком определялся
цветами текстуры Тех Color1 и Тех Color2, просто сделайте атрибут Color1 в разделе Shading
абсолютно белым.

Теперь можно задавать любые значения для Тех Color 1 и Тех Color2.
Нас может еще смущать, что при таком рисованном стиле штрихи выглядят слишком
«круглыми» или «трехмерными». Очевидно, что реальное освещение, заданное нами в начале,
теперь как бы мешает.

Откройте раздел Illumination и выключите галку Illuminated.

Качество рендеринга штрихов задается в Render Globals. Установки для параметра Quality,
в отличие от нормальных поверхностей, не влияют на уровень антиалиасинга штрихов.
Для того, чтобы улучшить качество рендеринга штрихов, надо в Render Globals открыть
раздел Paint Effects Rendering Options и включить галки Oversample и Oversample Post Filter.

Сохраните сцену (wireSphere.ma)

Для полноты картины отбросим тени от сферы.

Создайте полигональную плоскость: Create Polygon Primitive=>Plane.


Растяните ее: scale=40.
Вернитесь к атрибутам кисти.
Откройте раздел Shadow Effects и включите галку Cast Shadows. Теперь надо включить отбрасывание
теней в атрибутах источника света.
Выберите directionalLightl и в Attribute Editor в разделе Shadows включите галку Use Depth Map
Shadows.
Поставьте довольно высокое разрешение карты для тени Dmap Resolution=4096.
Чтобы размыть тень как следует, задайте Dmap Filter Size=12.

Просчитайте картинку.

В данном случае, нас не интересуют тени от штрихов на самих штрихах, поэтому можно
не выключать опцию Use Mid Dist Dmap. В противном случае пришлось бы выключить ее и задать
значение Dmap Bias=0.2, чтобы убрать тень от плоскости на самой плоскости.
Можно задать для плоскости белый цвет, однако более красивым решением будет использование
материала Use Background.

Выберите плоскость, нажмите над ней правую кнопку мыши и выберите в меню:
Materials=>Assign New Material=> Use Background.
В атрибутах этого материала задайте Shadow Mask=0.5, чтобы сделать тень более серой.

Paint Effects 969


Картинка готова для дальнейшего использования. Пытливые умы могут также заглянуть в
ее альфа-канал.

Сохранение собственных кистей


Сохраним кисть для потомков - было бы жалко упустить такой случай войти в историю.
Выберите любой штрих и выполните операцию Paint Effects=>Get Settings from Select­
ed Stroke. После этого все настройки нашей гениальной кисти попадут в буфер Template Brush.
Осталось сохранить их в виде новой кисти.
Выполните Paint Effects=>Save Brush Preset...
Откроется окно Save Brush Preset.
Класть на полку (То Shelf) такую шикарную кисть было бы непростительно, поэтому выберите
опцию То Visor, а в поле Visor Directory укажите имя существующей категории кистей, например,
pens. (В этом случае, вы должны иметь права на запись в соответствующую папку на диске. Если
таких прав нет, то впишите имя новой категории типа MySuperBrushes и создайте такую папку
вручную, в нужном месте.)
Не забудьте дать кисти какое-нибудь название в поле Label, например, oldPen.

Нажмите кнопку Save Brush Preset.


Откройте Visor: Paint Effects=>Get Brush.
Перейдите в категорию pens (или другую, созданную вами заново) и разыщите там новую кисть.

970 Книга Сергея Цыпцына


Один небольшой недочет: мы забыли сделать иконку, хотя такая возможность была - с
помощью кнопки Grab Icon.

Чтобы не переделывать заново, создадим совсем хорошую иконку прямо сейчас.


Отрендерите картинку, не закрывая окна Visor.

Теперь в окне Render View выберите в меню View=>Grab Swatch to Hypershade/Visor.


Затем выберите на картинке любой, желательно квадратный, регион и перетащите его
средней кнопкой мыши на черную иконку новой кисти в Visor.

Иконка должна принять вид выбранного региона. Теперь вы в любой момент можете
выбирать новую гениальную кисть и использовать ее в своей работе.

Работа с кистями растительного и животного происхождения


Теперь разберем пример работы с «ветвистыми» кистями. Напомню, что когда значение
атрибута Tubes=On, сами штрихи не визуализируются, а вместо этого из них в разные стороны
растут трубки-стволы, которые могут и дальше ветвиться в виде сучьев (Branches), веток (Twigs),
листочков (Leaves), цветочков (Flowers) и ягодок, то есть бутонов (Buds). Конечно, ботанически
ориентированные названия используются здесь весьма условно, так как с помощью таких
иерархических отростков можно смоделировать все, что угодно. Все вышеперечисленные
участки штрихов могут быть независимо затекстурированы, что придает системе дополнительную
гибкость.

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

Итак, мы собираемся сделать с помощью Paint Effects каких-нибудь джульбарсов, например,


косяк жуков или стадо муравьев.

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


Создайте сплайновую плоскость (Create=>NURBS Primitive=>Plane; PatchesU/V=3) или
загрузите свою любимую ландшафтную модель.

Растяните ее: scale=25.


Можно немного помять ее с помощью Artisan или просто потаскать за вершины, чтобы
создать неровности ландшафта.

Рисование по поверхности
Сейчас мы нанесем на поверхность гениальный мазок. Этот штрих мы впоследствии
превратим в стаю муравьев, а потом даже заставим их бодро бегать. Как и в предыдущем
примере, я бы сам, пожалуй, нарисовал обычную кривую на поверхности и превратил ее в штрих
- но как же я тогда расскажу про операцию Make Paintable и про сглаживание штрихов? Поэтому в
образовательных целях начну с рассказа о том, как рисовать штрихи на поверхности,
Прежде всего «обнулите» кисть, находящуюся в буфере Template Brush. Ведь мы будем
создавать ее с нуля.
Выполните Paint Effects=>Reset Template Brush. Теперь для этой кисти заданы параметры
по умолчанию - унылый черный штрих.
Выберите поверхность и выполните Paint Effects=>Make Paintable.
Теперь все последующие штрихи будут ложиться на эту поверхность, а не на горизонтальную
плоскость XZ.
Возьмите в руки кисть: Paint Effects=>Paint Effects Tool.

Paint Effects 971


Нарисуйте на поверхности линию, предполагаемый путь для муравьев. Не делайте сильных
изгибов, муравьи этого не любят (их подташнивает).

Для пытливых умов замечу: чтобы увидеть сплайновую кривую, лежащую в основе штриха,
надо в Outliner показать Display=>Shapes и заглянуть в «шэйп» плоскости.
Если вновь проведенный штрих уже выбран, загляните в Attribute Editor. Так как руки у
вас наверняка дрожали от волнения (или по любой другой причине), штрих мог выйти не совсем
гладким.
Задайте в атрибутах штриха Smoothing=10, это сгладит форму штриха.

Редактирование атрибутов кисти


Перейдите в третью закладку, там находятся атрибуты кисти. Займемся вивисекцией.
Откройте раздел Tubes и включите галку Tubes.
Из штриха вырастут черно-белые отростки. Сначала удобнее работать с формой одного
отростка, а потом, добивших нужного вида, задавать необходимое количество и плотность для
штриха в целом.

Поэтому в разделе Tubes=>Creation задайте пока Tubes per Step=0, a Start Tube=1.
В начале штриха вырастет одинокий стартовый отросток.
Коль скоро все ваши муравьи примерно одного размера, задайте Length Min=0.7, Length
Мах=0.8. Когда муравьев будет много, их длина будет варьироваться в этом диапазоне.

Конвертация Paint Effects в полигоны


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

Примечание. В седьмой версии у штрихов появился новый атрибут Draw As Mesh и в


настройках Paint Effects Tool он включен по умолчанию. Если вы хотите следовать
картинкам, полученным для шестой версии MAYA, выключите этот атрибут в
Attribute Editor во второй закладке для штриха. Если оставить его включенным,
вам не придется принудительно конвертировать штрих в полигоны, как описано
в этой главе.

Предлагаю следующий выход. Коль скоро штрих пока довольно неплотный, имеет смысл

972 Книга Сергея Цыпцына


сконвертировать его в полигоны и контролировать форму на полигональной сетке. Дело в том, что
при конвертации штрихов Paint Effects в полигоны полностью (ну, почти полностью) сохраняется
Construction History, то есть последующее изменение атрибутов кисти будет изменять полученную
полигональную сетку. Проверим это.

Если штрих выбран, откройте Option Box операции Modify=>Convert=>Paint Effects to Poly­
gons. Задайте Vertex Color Mode=Color; Quad Output=On; Hide Strokes=Off; Poly Limit=0.
Последний параметр снимает ограничение на максимальный размер полученной при
конвертации полигональной сетки. Мы также не хотим прятать исходные штрихи.

Нажмите кнопку Convert.


Полученную полигональную трубку просто сдвиньте в сторону.

Настройка ширины
Снова выберите штрих, и в атрибутах кисти в разделе Creation задайте Tube Widthl =0.2,
Tube Width2=0.2.

Это немедленно отразится на поверхности.

Перейдите в ниже в раздел Width Scale и, напрягая память, вспомните, как, по-вашему,
выглядит муравей в профиль. Постарайтесь, в соответствии с этими воспоминаниями, задать
график для атрибута Width Scale.

Совет. Перед редактированием профиля выберите единственный маркер в


разделе Width Scale и задайте для него lnterpolation=Spline. Тогда все последующие
добавленные маркеры (простым щелчком в поле графика) будут иметь один и
тот же тип интерполяции, что сделает редактирование более простым.

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

Задайте чуть большее значение Segments=24.

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

Paint Effects 973


Напомню: сейчас мы редактируем профиль ствола (Branch), если выражаться в ботанических
терминах, хотя используем его (ствол) для создания основного тела бедного животного. Далее в
своих безнравственных целях мы попробуем для моделирования лап использовать сучья (Twigs)
или листья (Leaves). Да не смутит вас эта, явно растительная терминология.

Выращивание конечностей. Работа с атрибутами кисти


Откройте ниже раздел Growth и попробуйте включить опцию Branches (разветвления
или сучья). Так как муравьи-мутанты с двумя головами нас пока не интересуют - выключите ее
скорее.

Включение опции Twigs (ветки) дает неплохой начальный результат для изготовления
конечностей.

Однако их (веток) свойство повторять форму основного ствола - делает их малопригодными


для изготовления конечностей. Кроме того, для веток невозможно задать независимое количество
сегментов.

Поэтому выключите опцию Twigs.


Будем делать конечности с помощью листьев. Да, именно листьев.
Включите опцию Leaves.
Однако условные слабо-зеленые листья появляются только на самом штрихе, а вот
полигональное туловище никак не реагирует на их появление.

974 Книга Сергея Цыпцына


Примечание. Это относится к шестой версии. В седьмой и выше при использовании
атрибута Draw As Mesh штрих отображается на экране абсолютно корректно.
Поэтому, если у вас MAYA выше седьмой версии, можете пропустить
переконвертацию в полигоны.

К сожалению, Construction History не распространяется так далеко. Перестроим заново


полигональное туловище.

Выберите в Outliner группу brushNMeshGroup и удалите ее.

Затем снова выберите штрих и выполните операцию Modify=>Convert=>Paint Effects to


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

Напомню, что полигональную модель мы используем в качестве интерактивного наглядного


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

Выберите штрих и в атрибутах кисти доберитесь до раздела Tubes=>Growths=>Leaves.


Задайте количество листьев в пучке равным двум: Leaves In Cluster=2.
А среднее количество пучков задайте больше трех: Num Leaf Clusters=3.5.
Ширину листьев на концах и основаниях определите как: Leaf Base Width=0.05; Leaf Tip
Width=0.005.

Начало появления листьев на стволе Leaf Start задайте равным 0.2.


Углы наклона относительно ствола определите как: Leaf Angle1=90; Leaf Angle2=80.
Коль скоро конечности у муравья будут довольно «голенастыми» и не слишком гибкими,
сделайте количество сегментов минимальным: Leaf 5egments=2.
И свернем, наконец, листья в трубочки: Leaf Flatness=0.

Paint Effects 975


Теперь согнем листья, то есть ноги: Leaf Bend=-120.
Такое большое значение используется из-за того, что ноги имеют всего два сустава, в
противном случае придется сильно помучиться с изгибом.

Сейчас муравей, в общем, почти готов, но, правда, смотрит он куда-то вдаль. Вернем его
на путь истинный то есть поставим вдоль пути-штриха.

Направление роста и ориентация по пути


Направление роста ствола-туловища относительно штриха определяется в разделе
Tubes=>Creation с помощью атрибутов Elevation (вертикальный наклон) и Azimuth (азимут,
горизонтальный поворот).

Установите все эти четыре атрибута (Elevation Min/Max, Azimuth Min/Max) в ноль.
Муравей, конечно, повалится на землю и даже развернется по касательной к штриху в
точке, где он произрастает. Однако на земле он будет валяться кое-как, на боку, и все усилия,
направленные на то, чтобы привести его в чувство, с помощью атрибутов из разделов Creation и
Grow, ни к чему не приведут.

Оказывается, в атрибутах кисти по умолчанию затесался один ненулевой атрибут, который


подкручивает туловище-ствол вокруг продольной оси.

Называется этот атрибут Twist Rand и искать его надо в разделе Tubes=>Behaviour=>Twist.

Примечание. В седьмой версии этот атрибут переехал в Attribute Editor «наверх»

97Ъ Книга Сергея Цыпцына


- в отдельный раздел Twist.

С неподдельным возмущением установите Twist Rand=0, и после этого муравей нормально


ляжет на брюхо.

А то, что он провалился в землю не страшно.

Достаточно перейти в закладку с атрибутами штриха (strokeShapeBrush) и задать там


значение Surface Offset=0.6.

Это приподнимет весь штрих над поверхностью, однако имейте в виду, что муравей пока
просто громадный, и после того, как мы его радикально уменьшим (Global Scale) и размножим,
значение Surface Offset надо будет уменьшить.

Примечание. В разделе Tubes=>Behaviour=>Forces есть два атрибута, позволяющих


прижать растительность к пути, то есть к линии штриха. Первый называется
Path Follow и определяет, как растущие из штриха сегменты повторяют форму
линии штриха в целом. Второй атрибут, Path Attract, задает, насколько верхушки
сегментов притягиваются к пути штриха (или отталкиваются от него). Можете
немного поэкспериментировать с ними, однако лучше вернуться к ним после
постановки движения муравьев вдоль пути, иначе муравьи могут начать ползти,
странно изгибаясь.

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


сцену (antBody.ma)

Некоторые дотошные умы захотят еще и сделать небольшую условную анимацию


конечностей, чтобы муравьи во время своего массового перемещения еще и шевелили лапами.

Paint Effects 977


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

Анимация листьев-конечностей
Чтобы подергать муравья за лапы, откройте раздел Leaves в атрибутах кисти и пошевелите
вручную за атрибуты Leaf Start, Leaf Anglel/2 и Leaf Twirl. Понятно, что ставить ключи на движение
лап - это безумие, поэтому нам на помощь придет процедурная анимация, то есть expressions.
Чтобы «дергать» за лапы постоянно во время анимации и при этом не держаться за мышь,
введите в поле Leaf Anglel следующее выражение, начинающееся со знака «равно»:
=90+ noise(time*15)*50;

Не забудьте нажать Enter, чтобы создать expression.


Если вы ввели все правильно, муравей начнет неистово сучить лапами.

Примечание. Конечно, эти движения синхронны для всех лап, но мы ведь на данный
момент лишь создаем видимость шевеления конечностями, и этого вполне
достаточно. Кроме того, задать формулу для индивидуальной анимации каждой
лапы довольно сложно (хотя и можно), а займет это некоторый объём книги в
виде безумного количества кода на MEL. Для фанатов программирования дам совет
обратить внимание на атрибут Runtime Script в разделе User Mel Scripts.

Для анимации остальных атрибутов нажмите правую кнопку мыши над сиреневым полем
Leaf Anglel и выберите Edit Expression.

В появившемся окне Expression Editor введите следующий текст:

brush2.leaf Angle1=90 + noise(time*15)*50;


brush2.leafAngle2=80 + noise(time*15+5)*50;
brush2.leafTwirl=noise(time*10)*0.2;
brush2.leafStart=0.28 + noise(time*7)*0.05;

Имейте в виду, что "brush2" это имя кисти, которую мы редактируем. Если у вас оно
другое, используйте в Expression Editor точное имя вашей кисти.

Примечание. Те, кому по жизни не нравится функция noise, могут исправить


ее на функцию sin, чтобы дергание конечностей было более периодическим и
регулярным.
brush2.leafAngle1=90 + sin(time*15)*50;
brush2.leafAngle2=80 + sin (time*15+5)*50;
brush2.leafTwirl= sin(time*10)*0.2;
brush2.leafStart=0.28 + sin (time*7)*0.05;

Все эти безумные формулы задают колебания около значений, определенных нами ранее.
Те же, кого пугает одно лишь упоминание об expression, могут попытаться воспользоваться
разделом Tubes=>Behavior=>Turbulence, однако создаваемая таким образом анимация действует
на все сегменты, а не только на листья-лапы, и поэтому больше подходит для раскачивания всего
туловища-ствола целиком.

Сохраните файл (antBodyAnim.ma).

978 Книга Сергея Цыпцына


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

Полигональная поверхность нам больше не нужна.


Выберите в Outliner группу BrushNMeshGroup и удалите ее. Наиболее осторожные могут ее
просто спрятать.

Создайте источник света: Create=>Lights=>Point Light.


Приподнимите его повыше: translateY=10.
Просчитайте картинку.

Полученный муравей уже вполне заслуживает включения в галерею современного


минималистического искусства, однако займемся его прозаической покраской.

Откройте атрибуты кисти и перейдите в раздел Shading. Коль скоро мы собираемся


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

Установите в разделе Shading цвет Color1 в белый, и убедитесь, что в подразделе Tube
Shading цвет Color2 также белый.

Перейдите в раздел Texturing и включите галку Map Color. После этого нужно определить
тип текстуры, накладываемой на штрих.

Задайте Texture Type=File, a Map Method=Tube3D, коль скоро мы собираемся положить


текстуру на муравья как на обычный трехмерный цилиндрический объект.

Ниже, в поле Image Name, введите имя текстуры - например, выберите из стандартного
набора текстур для кистей Paint Effects карту для кожи змеи:

X:\Program Files\Alias\MayaX.X\brushlmages\snakeskin2.iff

Параметры повторения тектуры (Repeat U/V) и размывания ее (Blur Mult) можете подобрать
по своему усмотрению.

Paint Effects 979


К сожалению, шкура муравья отсутствует в стандартном наборе.
Посчитайте изображение.

Муравей несколько плоский. Это всё из-за того, что по умолчанию кисть не освещается
источниками света и поэтому не имеет трёхмерного объема.

Откройте раздел Illumination и включите галку Illuminated.

А заодно, чтобы муравей был более «блестящим», установите атрибуты блика: 5pecular=1,
Specular Power=80.

Цвет блика можете сделайте желтым.

Атрибут Translucence определяет светопроницаемость материала. Так как брюхо у муравья


бывает полупрозрачным, можно увеличить это значение: Translucence=0.4.

Просчитайте картинку и убедитесь в том, что муравей стал более объемным.

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


вполне достаточно. Можно сохранить сцену как заготовку для просчета общих планов со
средним качеством. Однако любители гипотетических крупных планов наверняка начнут пугать
окружающих недостаточным качеством картинки. Что ж, опять пойдем у них на поводу. Продолжим
патологическое улучшение качества.

Методы рендеринга Paint Effects


Напомню: по умолчанию штрихи рендерятся с помощью большого количества микродисков
(stamps). Однако возникают ситуации, когда данная технология уже не обеспечивает нужного
качества и «объемности» картинки. В этом случае имеется возможность изменить тип кисти, то
есть задать другой метод визуализации штрихов.

Самый первый атрибут в Attribute Editor определяет технологический метод просчета для
кисти. Установите Brush Type=Mesh.

Штрихи с кистью такого типа уже не будут визуализироваться как набор дисков, а в
процессе рендеринга будут просчитываться как настоящие полигональные трубки.
Замечу, однако, что процесс превращения штрихов в полигоны происходит в этом случае
«на лету» и только в процессе рендеринга. Никакой новой геометрии в сцене не появляется, и,
следовательно, память на нее не расходуется.

Итак, установив Brush Type=Mesh, просчитайте изображение.

Муравью явно не хватает полигонов для объема. Не обязательно увеличивать количество


реальных сегментов (Segments) для всей кисти (тем более, что это может сильно повлиять на общую
форму штриха): достаточно увеличить количество подразбиений только для визуализации.
Откройте раздел Mesh, который стал доступным после изменения типа кисти Brush Type на Mesh.
Увеличьте в нем количество долей-сегментов вокруг оси штриха: Tube Sections=12.

980 Книга Сергея Цыпцына


Задайте также дополнительное подразбиение вдоль оси штриха: Sub Segments=2.
Включите также галку End Caps, чтобы закрыть дырки на краях цилиндров.
Включение опции Per Pixel Lighting сделает блики на поверхности просто изумительными,
на радость любителям крупных планов, однако немного замедлит просчет.

Отрендерите картинку.

Внешний вид муравья, конечно, сильно улучшился, однако странные артефакты


поразили его тело. Это связано с тем, что по умолчанию в атрибутах кисти задано небольшое
сглаживание краев штрихов при рендеринге. Это хорошо смотрится в случае Brush Type=Paint,
то есть при использовании «дискового» метода. Однако при использовании полигонов могут
возникать вывернутые нормали и разные отверстия, особенно в местах соединения или на краях
сегментов.

В разделе Brush Profile задайте Softness=0, отменив тем самым сглаживание краев.

Примечание. После того, как мы задали новый тип рендеринга, можно


поэкспериментировать с опцией Map Displacement в разделе Texturing. Степень
деформации поверхности регулируется, очевидно, значением атрибута Displace­
ment Scale.

С туловищем муравья теперь полный порядок. Покрасим лапы с помощью текстуры. До сих
пор они имели такой же узор, как и туловище, однако окрашивались в зеленоватый оттенок.

Тектстурирование листьев-конечностей
Откройте раздел Tubes=>Growth=>Leaves и сразу измените цвета Leaf Color1 и Leaf Color2
на чисто белый, чтобы при умножении на текстуру, они не вызывали изменения цвета.
Снимите галку Leaf Use Branch Тех, которая по умолчанию задает использование для
листьев текстуры основного ствола.

В поле Image Name задайте путь к независимой текстуре для листьев-конечностей.


Это может, например, быть еще одна карта для кожи змеи из стандартного набора текстур
для Paint Effects:

X:\Program Files\Alias\MayaX.X\brushlmages\snake1.jpg

Paint Effects 981


Просчитайте изображение.

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


планов и прочей макросъемки наверняка вновь возмутятся тем, что на лапах отсутствуют ворсинки.
И хотя мохнатые лапы бывают обычно только у пауков, оставим такое невежество на совести
фанатов макрообъектива и примемся за размохначивание лап.

Шипы и мохнатые лапы


В Attribute Editor наверху, в разделе Mesh, есть подраздел Thorns on Mesh (шипы на
поверхности).

Откройте его и включите галку Thorns on Leaves.


Задайте атрибуты шипов: Thorn Density=20; Thorn Length=0.1; Thorn Base Width=0.01; Thorn
Tip Width=0.003.

Сделайте цвет шипов светло-коричневым.

Посчитайте пауковидного муравья.

Усы, цветы и прочие отростки


«А усы-то, усы!», - воскликнут маньяки крупных планов. Под таким беспардонным
давлением мы вынуждены изготовить усы - с помощью цветков (flowers), растущих на концах
основного ствола.

Откройте раздел Tubes=>Growth и включите галку Flowers.


Затем перейдите ниже в подраздел Flowers и задайте следующие значения.
Сделайте две тычинки в цветке: Petal in Flower=2, количество цветков установите в
единицу: Num Flowers=1.

Направьте усы-цветы вперед: Flower Angle1 =30.


Разведите концы немного в стороны: Petal Bend=1.
И вверх: Petal Twirl=-0.5.

Сделайте усы не плоскими, а цилиндрическими: Flatness=0.


Задайте оба цвета Petal Color слегка серыми.

Мы не будем назначать на усы отдельную текстуру и снимать галку Flower Use Branch Тех,
поэтому они будут иметь тот же узор, что туловище, но более темного оттенка.

982 Книга Сергея Цыпцына


Чтобы улучшить общее качество картинки, как обычно, откройте Render Globals и в разделе
Paint Effects Rendering Options включите опции Oversample и Oversample Post Filter.
Отрендерите тараканистого муравья. Любители крупных планов будут счастливы в своём
перфекционизме.

Самое время сохранить сцену (antBodyTextured.ma).

Размножение муравьев
Теперь займемся разведение муравьев в больших количествах. Прежде всего уменьшим
нашего монстра.

Задайте в атрибутах кисти Global Scale=0.6.

Затем перейдите в раздел Tubes=>Creations и установите Tubes Per 5tep=2; Start Tubes=0.
Возникнет узкая дорожка из муравьев.

Чтобы ее расширить, откройте раздел Brush Profile и увеличьте ширину штриха: Brush
Width=4. Дорожка превратится в шоссе из муравьев.

Коль скоро мы уменьшили размер громадных муравьев, необходимо перейти в атрибуты


самого штриха и уменьшить значение отступа от поверхности Surface Offset, так чтобы муравьи не
сильно летали в воздухе.

Paint Effects 983


Примечание. Если поверхность довольно изогнутая, а ширина штриха достаточно
большая, вы можете заметить, что на краях штриха некоторые муравьи либо
проваливаются под землю, либо наоборот парят в воздухе. Это связано с тем,
что кривизна штриха задается только вдоль линии самого штриха. Расширение
(то есть увеличение Brush Width) задает просто плоскую ленту, повторяющую
изгибы поверхности вдоль, но не поперек линии штриха (поперек линии штриха
полоса абсолютно плоская). В тех случаях, когда надо обеспечить более плотное
прилегание к поверхности достаточно широкой полосы штрихов, необходимо
провести несколько параллельных линий меньшей ширины и плотности.

Анимация вдоль пути

Теперь займемся анимацией по пути. Чтобы создать движение вдоль пути надо анимировать
длину и расположение самого штриха.

Выберите в Attribute Editor вторую закладку с атрибутами самого штриха.


Откройте раздел End Bounds и задайте значение Мах Clip=0.5.
Это укоротит штрих наполовину, так как этот атрибут определяет конец штриха относительно
нижележащей кривой.
Поставьте ключ на этот атрибут в первом кадре.
Затем перейдите в сто пятидесятый кадр, задайте Мах Clip=1 и снова поставьте ключ на
этот атрибут.
Штрих начнет просто удлиняться со временем.
Чтобы заставить муравьев ползти, надо также проанимировать начало штриха, чтобы оно
двигалось синхронно с концом штриха.
Перейдите в первый кадр и поставьте ключ на Min Clip=0.
Перейдите в кадр 150, задайте Min Clip=0.5 и поставьте ключ.
Теперь длина штриха сохраняется постоянной, так как начало и конец анимированы синхронно.
Если вы хотите, чтобы муравьи уползли в какую-нибудь дыру, то есть неожиданно скрылись
из вида, перейдите в кадр 300, задайте Min Clip=1 и поставьте ключ на этот атрибут.
Длина штриха станет нулевой, так как начало и конец совпадают (Min Clip=Мах Clip=1) и все муравьи
теперь пропадут.

984 Книга Сергея Цыпцына


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

Такое случается, когда штрих имеет недостаточную внутреннюю плотность (разрешение)


и изменение атрибута Min Clip на 0.003 не вызывает сдвига начала штриха. Иначе говоря, штрих
недостаточно просэмплирован. Это происходит на этапе рисования, если линия рисуется слишком
быстро и штрих получается «прореженный». Напомню, что во время рисования вдоль штриха
сохраняется информация о форме, силе нажатия и скорости ведения пера или мыши.
Чтобы увеличить внутреннюю плотность штриха, достаточно изменить для него атрибут
Sample Density.

Задайте Sample Density=2.

Кроме увеличения подробности штриха это, естественно, удвоит количество муравьев.


Если на ваш вкус их стало что-то слишком много, вы всегда можете изменить атрибут Tubes per
Step для кисти, чтобы добиться нужного количества.

Теперь муравьи продвигаются вперед в каждом кадре и к трехсотому кадру полностью


уползают «под землю».

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

Для начала не забудьте в атрибутах штриха задать корректное значение Surface Offset,
чтобы муравьи не парили над поверхностью, а ползали по ней.

Можно слегка проанимировать ширину штриха Brush Profile - для получения эффекта
расползания.

Чтобы сделать опережающее-отстающие движения внутри потока, проанимируйте немного


атрибут Tube Rand около значения 0.7.

В разделе Tubes=>Behavior=>Forces есть два атрибута, задающих притяжение муравьев к пути.


Атрибут Path Follow и определяет, как растущие из штриха сегменты повторяют форму линии
штриха в целом.

Второй атрибут, Path Attract, задает, насколько верхушки сегментов притягиваются к


пути штриха (или отталкиваются от него). Анимируя их, можно задавать хаотическое рыскание из
стороны в сторону.

В этом же разделе есть атрибут Rand, позволяющий случайно деформировать муравьев.


Легкая анимация этого атрибута около нуля даст неплохой результат.

Примечание. «Легкая анимация около нуля» означает создание выражения типа


brush2. random = 0 + noise(time*5)*0.1
или же пробивание множества ключей на всем диапазоне анимации.

В разделе Tubes=>Behavior=>Turbulence можно задать, чтобы муравьи изгибались целиком,


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

Примечание. «Травянистый ветер» (Grass Wind) отличается от «древесного» (Tree

PaintEffecis 985
Wind) тем, что первый нагибает стволы целиком, а второй больше действует на
концы-верхушки.

Изменение индивидуальных атрибутов вдоль пути


И в заключение разговора об анимации приведу одну довольно изощренную технику,
позволяющую изменять различные параметры кисти вдоль штриха. Например, в нашем случае
хотелось бы, чтобы ширина штриха была различной на разных участках. Одна ширина задается
одним атрибутом кисти Brush Width и остается постоянной для всего штриха.

Для таких целей используются кривые, сохраняющие силу нажатия на перо при рисовании
штрихов. «А если нет пера, и есть только одинокая мышь?» - спросят неимущие умы. В этом случае
такие кривые можно создать и отредактировать в любой момент времени.

Выберите штрих с муравьями и выполните операцию Paint Effects=>Curve Utilities=>Create


Pressure Curve. (Имейте в виду, что через Option Box можно задать количество контрольных вершин
на этой кривой.)

Рядом со штрихом возникнет кривая первой степени.

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

Выберите созданную кривую и, схватив ее на любую контрольную вершину, оттащите эту


точку в сторону.

Затем выберите штрих, и в его атрибутах откройте раздел Pressure Mapping.


Задайте Pressure Map1=Width; Pressure Map2=Off.
Теперь на том участке, где отредактированная кривая сильно отличается от первоначальной
формы, ширина штриха существенно больше.

986 Книга Сергея Цыпцына


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

Таким образом, можно задать связь между формой кривой (точнее, ее разницей с
оригинальной формой) и любым атрибутом кисти, лежащей на штрихе. Поэкспериментируйте с
огромным выпадающим списком Pressure Map1.

К сожалению, данная техника плохо работает с анимацией MinClip/MaxClip, так как в этом
случае длина штриха и его положение в пространстве становятся непостоянными. Соответственно,
в каждом кадре будет изменяться расстояние между штрихом и созданной кривой, что приводит к
«расползанию» штриха. В принципе можно согласовать анимацию длины штриха и формы кривой
Pressure Curve, но это потребует некоторых усилий и работы с Hypergraph.
Заметьте также, что при создании Pressure Curve в сцене появится новый expression,
собирающий данные о расстоянии между штрихом и кривой, и передающий эти данные как силу
нажатия (Pressure) в атрибуты штриха.

Тени
Осталось положить любимую текстуру на «землю» и включить тени у источника света.
Напомню, что Paint Effects использует только тени типа Depth Map.
Выберите источник света pointLightl и включите в Attribute Editor, в разделе Shadows,
галку Use Depth Map Shadow.
Поставьте разрешение карты теней побольше (Dmap Resolution=2048) и «размойте» тени
(Dmap Filter Size=4).

Этого достаточно, чтобы муравьи отбрасывали тень на поверхность. Но если вы хотите,


чтобы они отбрасывали тени друг на друга или чтобы тени от других объектов появлялись на
муравьях, тогда необходимо предпринять следующие действия.

Выключите галку Use Mid Dist Dmap и после этого, если необходимо, немного увеличьте
Bias (0.005), чтобы вручную задать отступ тени от «земли», которая сама на себя отбрасывает тень
в случае Use Mid Dist Dmap=Off.

Если тень не находится на месте или пропадает в определенных областях, можно


попробовать снять галку Use Auto Focus и задать вручную значение Focus Width.

Paint Effects 987


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

Теперь можете отсчитать анимацию целиком. Можете устраивать облеты камерой вокруг
массового переселения муравьев и смело влетать в толпу переселенцев, не пугаясь крупных
планов. (Кстати, в атрибутах штриха по умолчанию включена галочка Motion Blurred.)

Сохраните сцену (antBodyFinal.ma). Мирмекологи бьются в экстазе.

Природа кистей. Тени


Кроме того, что реальные тени от штрихов и на штрихах могут быть просчитаны только
методом Depth Map, существует еще ряд ограничений при работе с картами теней.

Во-первых, для корректного вычисления Dmap-теней необходимо выключить опцию Use


Mid Dist Dmap в атрибутах источника света в разделе Shadows. Дело в том, что штрихи Paint Ef­
fects не являются поверхностями, и метод вычисления тени от серединного сечения поверхности
будет давать некорректные результаты при вычислении теней на самих штрихах - как от других
штрихов, так и от других поверхностей.

Во-вторых, после выключения опции Use Mid Dist Dmap, как правило, необходимо настроить
атрибут Dmap Bias, чтобы вручную задать отступ тени от объекта, который ее отбрасывает. Обычно
нужно немного увеличить значение этого атрибута.

В-третьих, существует жесткое ограничение для вычисления теней: в области генерации


теней должна быть хоть одна небольшая поверхность, отбрасывающая тени, иначе тени от
штрихов не будут вычисляться. Область генерации теней для разных типов источников света могут
различаться. Если для Spot Light это конус, то для point Light - это шесть пирамид направленных по
осям локальной системы координат, в каждой из которых должна присутствовать часть реальной
поверхности, отбрасывающей тени.

В-четвертых, так как штрихи - довольно тонкие объекты, лучше размывать тень от них.
Атрибут Filter Size должен быть установлен по крайней мере в двойку.

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

Анимация кистей и штрихов


Поговорим теперь о дополнительных возможностях анимации штрихов Paint Effects.
Прежде всего, совершенно очевидно, что все атрибуты кистей и штрихов можно анимировать.
Причем можно ставить ключи или писать небольшие expression для циклических и хаотических
движений, использовать Set Driven Key и другие стандартные средства анимации.

В разделе Tubes=>Behavior=>Turbulence находятся уже готовые к употреблению expressions,


позволяющие как следует гнуть и трясти штрихи без расстановки ключей.

Различные виды процедурных деформаций штрихов доступны в разделе Tubes=>Behavior=


displacement, Bend, Spiral и Twist.

Напрямую «уцепиться» контрольные вершины сегментов, из которых состоят штрихи,


нельзя (например, погнуть листья руками или подвесить яблоко на дерево). Однако две хорошо
задокументированные процедуры на языке MEL могут быть написаны и указаны в полях Creation

988 Книга Сергея Цыпцына


Script и Runtime Script. С их помощью можно контролировать и редактировать любой сегмент
штриха. Обсуждение этих процедур выходит за рамки книги, поэтому скажу лишь, что в каталоге
scripts/paintEffects есть примеры их использования.

С помощью атрибутов из раздела Gaps можно «выкусить» целые участки штриха и сделать
анимацию прерывистых линий, типа дождевых струй или всяческих штрихпунктиров.
В принципе, наряду с процедурными деформациями есть возможность гнуть штрихи Paint Effects
вручную. Для этого используются специальные кривые, о которых мы сейчас и поговорим.

Ручная деформация штрихов Paint Effects


Напрямую схватиться на участок штриха, например, за ветку, нельзя, однако возможно
создать обычные кривые, которые будут выступать в роли деформеров для сегментов штрихов,
наподобие Wire Deformer.

Попробуем погнуть вручную некоторые стандартные кисти.


Создайте в новой сцене окружность: Create=>NURBS Primitives=>Circle.
Затем возьмите кисть: Paint Effects=>Get Brush...
В разделе flowerMesh выберите кисть roseRed.mel.
Рисовать ничего не надо, переключитесь в Select Tool и выберите окружность.
Выполните операцию Paint Effects=>Curve Utilities=>Attach Brush to Curves.
Возникнут три одинокие розы, висящие вниз головой
В атрибутах штриха установите Sample Density=2, чтобы роз было побольше и откройте раздел
Normal Direction.

Если вы хотите, чтобы розы не использовали нормаль, вычисленную на основе формы


кривой, задайте вручную направление нормали, вдоль которого розы будут направлены.
Включите галку Use Normal и заметьте, что поле Normal определяет вектор (0,1,0), торчащий
вертикально вверх. Розы вытянутся вверх.

Установите в атрибутах кисти, в разделе Brush Profile, ширину штриха Brush Width=0.1,
чтобы розы росли поближе к кривой.
Перейдите в камеру front и нарисуйте две вертикальные кривые по краям окружности,
растущие из «земли».

Paint Effects 989


Вернитесь в перспективу.

Выберите обе нарисованные кривые, а затем штрих из роз.


Выполните операцию Paint Effects=>Curve Utilities=>Set Stroke Control Curves.

Розы слегка выпрямятся, повторяя форму кривых.


Выберите контрольные вершины одной из кривых и изогните конец кривой.
Некоторые розы немного качнут головами - вслед за изогнутой кривой.

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

990 книга Сергея Цыпцына


Искать эти атрибуты будем в атрибутах кисти в разделе Tubes=>Behavior=>Forces.
Первый атрибут, Curve Follow, определяет, как сегменты (в данном случае, розы) повторяют
форму кривой целиком. Иными словами, насколько розы стремятся принять форму контрольной
кривой (или кривых). Штрихи при этом не притягиваются к кривым, а стремятся расти, параллельно
повторяя путь кривой.

Второй атрибут, Curve Attract, определяет, насколько сегменты притягиваются к


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

Примечание. Оба этих атрибута могут принимать отрицательные значения и


задавать степень отталкивания. Кроме того, они могут иметь значения больше
единицы, задавая при этом интересные эффекты типа собирания сегментов в
гармошку при больших значениях Curve Follow.

Задайте сначала Curve Follow=0, а потом большое значение притяжения: Curve Attract=5,
чтобы убедиться, что розы действительно притягиваются к кривым.

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

Задайте Curve Follow=0.9, чтобы «выпрямить» розы, то есть заставить из расти вдоль
контрольных кривых.

Третий атрибут, Curve Max Dist, определяет максимальный радиус действия контрольной
кривой. Если его значение равно нулю, то ограничения на радиус действия нет, и штрихи всегда
находятся под усредненным влиянием всех контрольных кривых, независимо от расстояния до
них.
Задайте Curve Max Dist=.5. Тогда розы, растущие из правой полуокружности будут
притягиваться к одной кривой, а из левой - к другой. Иными словами, деформация одной из
кривых никак не скажется на удаленных от нее розах.

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

Совет. Если задать отрицательное значение атрибута Curve Attract и небольшое


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

Проанимируем контрольные кривые с помощью, например, динамики волос и посмотрим,


как это повлияет на движение роз.

Выберите обе контрольные кривые и превратите их в динамические кривые: Hair=>Make


Selected Curves Dynamic.

В Outliner появится новая нода hairSystem1, отвечающая за свойства системы волос (или
динамических кривых).

Выберите ее и выполните операцию: Hair=>Convert Selection=>to Follicles, чтобы выбрать


сами динамические кривые, входящие в систему, и добраться до их индивидуальных свойств.
Откройте Channel Box и установите Point Lock=Base, чтобы закрепить только основание
выбранных динамических кривых.

Подробнее о работе с системой волос можно прочитать в соответствующей главе.

Paint Effects 991


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

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

Выберите обе динамические кривые на экране, затем выберите штрих и снова выполните
операцию Paint Effects=>Curve Utilities=>Set Stroke Control Curves. Это заменит предыдущие
контрольные кривые на новые.

Все значения атрибутов Curve Follow, Curve Attract, Curve Max Dist останутся прежними,
поэтому нет нужды их настраивать заново.

Примечание. Количество контрольных кривых и, соответственно, их наличие


всегда можно проверить в атрибутах штриха (не кисти) в разделе Input
Curves=>Control Curve.

Запустите анимацию. Теперь розами управляют динамические кривые.


Выберите объект hairSystem1 и в Attribute Editor в разделе Dynamics задайте Stiffness=0.06,
чтобы уменьшить упругость динамических кривых.

Розы станут клониться к земле сильнее.

Про остальные особенности динамики волос можете почитать в нужной главе, а сейчас
для системы волос hairSystem1 просто включите небольшую турбулентность (lntensity=0.2) в
разделе Turbulence, чтобы создать иллюзию ветра, покачивающего розы (точнее, покачивающего
контрольные динамические кривые).

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

Сохраните сцену (contolCurves.ma).

Однако в тех случаях, когда вы просто хотите придать штрихам упругости, не прибегая
к помощи динамики и контрольных кривых, можно воспользоваться возможностью создания
встроенных пружин.

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

«Процедурные пружины» - означает, что никакая динамика не используется для вычисления


движения, а все траектории вычисляются по формулам, иначе говоря, с помощью expressions.
Тех, кто занервничал при слове expressions, поспешу успокоить: программировать ничего не надо,
все формулы создаются автоматически.

В предыдущей сцене выберите объект hairSystem1 и выполните операцию Hair=>Delete


Entire Hair System, для того чтобы удалить систему волос и все, связанные с ней кривые. Розы

992 Книга Сергея Цыпцына


распрямятся, так как все контрольные кривые для них были удалены. (Если у вас возникли
проблемы на этом этапе, просто удалите вручную все объекты кроме nurbsCirclel и stroke"!.)
Теперь выберите штрих и выполните операцию Paint Effects=>Brush Animation=>Make Brush
Springs.

Запустите анимацию. Ничего не происходит, только в Attribute Editor появилась закладка


для какого-то expressionl. Для того, чтобы увидеть пружины в действии, надо как следует потрясти
кривую или поверхность, из которой растут штрихи.

Запустите интерактивную анимацию: Solvers=>Interactive Playback. (Я думаю, вы давно


выложили этот пункт меню на полку, чтобы всегда иметь его под рукой).
Во время анимации выберите окружность и Move Tool и хорошенько потрясите ее вдоль оси
X. Розы ответят возмущенным раскачиванием.

Совет. Можно обойтись и без интерактивной анимации. Достаточно


предварительно выбрать окружность, выделить на манипуляторе Move Tool ось
X, а затем запустить обычную анимацию и трясти окружность средней кнопкой
мыши.

Чтобы изменить упругость или жесткость пружин, достаточно выбрать штрих и в атрибутах
кисти открыть последний раздел Extra Attributes. Там находятся добавленные в ходе операции
Make Brush Spring динамические атрибуты, которые можно редактировать.

Чувствительность к тряске определяется атрибутом Spring Travel. Затухание остаточного


движения - значением Spring Damp. Нулевое значение Spring Stiffness задает бесконечную
жесткость, то есть выключает эффект пружин.

Paint'Effecis 993
Для взрослых. Вы всегда можете разыскать и модифицировать автоматически
созданный expression в окне Expression Editor. Его незамысловатый код
свидетельствует о том, что на основе координат кривой, из которой растут
штрихи, в текущем и предыдущем кадрах вычисляется вектор силы, направленный
в сторону, противоположную движению. Этот вектор присваивается атрибуту
кисти Uniform Force, определяющему произвольную деформацию, действующую на
штрих.

float $px = pointOnCurvelnfo1.positionX;


float $py = pointOnCurvelnfo1.positionY;
float $pz = pointOnCurvelnfo1.positionZ;
float $wx - nurbsCircle1.lastWX;
float $wy = nurbsCircle1.lastWY;
float $wz = nurbsCircle1.lastWZ;
float $vx = nurbsCircle1.lastVX;
float $vy = nurbsCircle1.lastVY;
float $vz = nurbsCircle1 .lastVZ;
float $stiff = roseRed1.springStiffness;
float $istiff = 1-$stiff;
float $damp =1 - roseRed1.springDamp;
float $travet = roseRed1.springTravel;
float $fx - 0; float $fy = 0; float $fz = 0;
if( frame > 2 ){
$fx = roseRed1.uniformForceX * $istiff + $stiff * ($wx - $px) * $travel + $vx;
$fy = roseRed1.uniformForceY * $istiff + $stiff * ($wy - $py) * $travel + $vy;
$fz = roseRed1.uniformForceZ * $istiff + $stiff * ($wz - $pz) * $travel + $vz;
nurbsCircle1.lastVX = $vx * $damp -$fx * $stiff;
nurbsCircle1.lastVY = $vy * $damp -$fy * $stiff;
nurbsCircle1.lastVZ = $vz * Sdamp -$fz * $stiff;
}else{
nurbsCircle1.lastVX = 0;
nurbsCircle1.lastVY = 0;
nurbsCircle1.lastVZ = 0;
}
roseRed .uniformForceX = $fx;
roseRed1.uniformForceY = $fy;
roseRed1.uniformForceZ = $fz;
nurbsCircle1.lastWX = $px;
nurbsCircle1 .lastWY = $py;
nurbsCircle1. lastWZ = $pz;

Поэкспериментируйте с различными значениями для атрибутов пружин. Может поставить


анимацию на перемещение окружности и убедиться, что пружины будут корректно отрабатывать
остаточные движения.

Для того, чтобы избавиться от пружин, достаточно в атрибутах кисти открыть раздел
Tubes=>Behavior=>Forces и нажать правую кнопку мыши над полем Uniform Force, а затем выбрать
в выпавшем меню Delete Expression.

994 Книга Сергея Цыпцына


Ручная анимация. Модификаторы
В седьмой версии появилась возможность создавать универсальные модификаторы для
штрихов. Идея очень проста. Достаточно выбрать штрих и выполнить операцию Paint Effects=>Create
Modifier.

После этого возникнет объект в виде сферы (или куба), влияющий на штрих выбранным
вами образом.

Если открыть для модификатора Attribute Editor, то можно задать, каким образом он будет
модифицировать атрибуты штриха и кисти.

Например, все штрихи, попадающие внутрь модификатора, могут менять свой цвет
(анимация температуры).

Либо модификатор может гнуть близлежащие штрихи

Paint Effects 995


Можно также устраивать деформацию с помощью формы модификатора.

Настройка влияния производится, очевидно, заданием соответствующих атрибутов


модификатора и, возможно, их анимации.

Анимация роста и старения


Как анимировать движение или выращивание Paint Effects вдоль линии штриха мы уже
рассмотрели на примере с переселением муравьев.

Однако иногда встает задача анимации роста, то есть удлинения всех сегментов поперек
линии штриха.

Конечно, первое, что приходит в голову в этом случае это анимация атрибутов Length Min
и Length Max. Однако это повлияет лишь на основной ствол штриха. Листья, цветочки и прочие
детали придется также удлинять вручную.
Анимация атрибута Global Scale принесет весьма посредственный результат: общее укрупнение и
расширение размеров всего штриха.
Дляанимации плавноговыращивания всяческой растительности (и нетолько растительности)
в атрибутах кисти существует специальный раздел Flow Animation.
Для практического примера используйте предыдущую сцену или создайте простой штрих,
из которого растут цветы в достаточном количестве.
Для того, чтобы работать с анимацией роста, есть несколько простых правил.

Во-первых, выберите штрих, и в разделе Flow Animation для атрибутов кисти включите
галку Time Clip.

Во-вторых, задайте скорость анимации роста. Например, Flow Speed=1. Скорость анимации
измеряется в циклах в секунду, так что не задавайте слишком больших значений.

В-третьих, задайте начальное время, с которого начнется анимация роста. Это время
задается в секундах, так что если вы зададите Start Time=2, то штрихи начнут расти с пятидесятого
кадра (при условии, что глобальная скорость анимации установлена в 25 fps).

В-четвертых, если вы делаете анимацию выращивания чего-нибудь, выключите галку Tex­


ture Flow, так как вы наверняка не хотите, чтобы текстура плыла по объекту одновременно с его
ростом.

996 Книга Сергея Цыпцына


Таким образом, если вы задали Time Clip=On, Flow Speed=1, Start Time=0, Texture Flow=Off
для роз из предыдущей сцены, то вы должны наблюдать, как они вырастают, начиная с первого
кадра, и полностью распускаются к сотому кадру.

Задайте Flow Speed=0.5, чтобы замедлить рост.


После этого установите End Time=8, то есть примерно двести кадров.
Запустите анимацию и посмотрите, как розы начинают исчезать после двухсотого кадра.

Если задать End Time=4, розы начнут исчезать, еще не появившись полностью после сотого
кадра.

Таким образом, можно анимировать не только рост, но и исчезновение штрихов. Помните,


что моменты начала роста и исчезновения задаются в секундах.

Примечание. Когда скорость анимации роста Flow Speed установлена в единицу,


розы вырастают полностью примерно за девяносто кадров, то есть за 3-4
секунды. Причем наряду с анимацией роста происходит распускание листьев,
цветов и прочие вторичные движения. Для единичной скорости среднее время
вырастания штриха составляет 1-2 секунды, распрямление ствола - 0-5 секунд,
разворачивание листьев - 2-3 секунды, распускание цветов - 3-3,5 секунды. Если
вы хотите предсказать примерное время (в кадрах) полного вырастания штриха,
поделите эти цифры на значение Flow Speed, а затем умножьте на скорость
анимации в кадрах (25 fps).

Paint Effects 997


В случаях, когда растительность представляет из себя какую-нибудь ползучую лиану или
веселый клубок змей, бывает полезно включить опцию Stroke Time, чтобы задать дополнительный
рост вдоль линии штриха. При включении Stroke Time раньше будут появляться и расти сегменты,
располагающиеся в начале линии штриха, а сегменты, растущие в конце линии штриха, будут
появляться в последнюю очередь.

Установите Stroke Time=On.


Чтобы лучше увидеть эффект роста вдоль пути, задайте в разделе Tubes=>Creation значение
Tubes per Step=1, для увеличения количества роз.

Таким образом, вы можете выращивать штрихи Paint Effects в нужном месте с необходимой
скоростью. Не забывайте устанавливать время исчезновения (End Time) достаточно большим,
чтобы не допустить внезапного пропадания штрихов с экрана.
Для взрослых. Атрибут Time по умолчанию связан с глобальным системным временем.
Однако, как и в случаях с частицами или другими объектами, имеющими связь со временем, вы
можете искажать течение времени, ускорять и замедлять его, разворачивать его вспять, просто
разорвав стандартную связь и устанавливая ключи на атрибут Time.

Искусственное размножение
Если вы делаете с помощью Paint Effects «густые» процедурные объекты типа волос
или травы, не требующие листьев или цветочков с ягодками, существует способ радикального
увеличения плотности или густоты создаваемой растительности за счет применения технологии
Multi Streaks. Ее принцип основан полностью на трюке, который используется при размножении
частиц типа Multi Points или Multi Streaks.

Чтобы дополнительно размножить имеющиеся штрихи, достаточно задать в атрибутах кисти


Brush Type=Thin Line, а в разделе Thin Line Multi Streaks определить количество дополнительных
линий (Multi Streaks), растущих рядом с основным «стволом».

998 Книга Сергея Цыпцына


Там же можно задать радиусы окрестности, в которой появляются эти дополнительные
линии (Multi Streak Spread), а также их отличие по цвету от основных линий.

Увеличение количества визуализируемых штрихов в разы приводит, однако, к весьма


незначительному увеличению времени рендеринга, процентов на 5-10.

Авторисование
Часто возникает задача равномерного покрытия поверхности штрихами. В отличие от
меха или волос, штрихи Paint Effects не растут прямо из поверхности, а используют кривые как
свою основу. Поэтому задача сводится к рисованию множества кривых-штрихов, равномерно
располагающихся на поверхности. В принципе вы можете написать такой скрипт самостоятельно,
но для не совсем взрослых мальчиков такой скрипт уже написан и располагается в меню Paint Ef­
fects в виде операции Auto Paint.

Перед применением этой операции, очевидно, необходимо выбрать поверхность, а


рисование будет происходить последней использованной кистью {Template Brush).

Настройки и параметры случайного и равномерного авторисования достаточно интуитивно


понятны, чтобы опустить их подробное описание. Помните только о том, что чем более хорошие
UV-координаты на поверхности (в случае полигонов), тем лучше она будет покрыта штрихами.

Некоторые замечания по поводу рендеринга


Как я уже упоминал, штрихи Paint Effects просчитываются с помощью специального
рендерера и затем «складываются» с основным изображением сцены с применением методов
композитинга. Совершенно очевидно, что в такой ситуации получить отражения и преломления
«честным» способом невозможно.

Однако существует масса способов получить отражения и преломления, не прибегая к


использованию raytracing-методов. Отражения на объекте можно получить, просчитав штрихи
Paint Effects из камеры, расположенной внутри объекта, и наложив полученное изображение как
карту отражений (Reflection Map).

Для получения преломлений (например, в бутылке) необходимо сначала просчитать только


штрихи Paint Effects (а все остальные объекты спрятать), затем создать «заднюю плоскость» lm-

Paint Effects 999


age Plane и назначить на нее полученное изображение (Fit to Resolution Gate). Далее, включить
для этой плоскости опциию Visible in Refraction и, самое главное, с помощью атрибута Depth
задать для нее расстояние от камеры, примерно равное или чуть большее расстояния до бутылки.
Затем нужно спрятать все штрихи, показать бутылку и прочитать сцену. Изображение штрихов
преломится в бутылке.

Если же вам все-таки необходим честный raytracing-просчет, например, в mental ray,


вы всегда можете сконвертировать штрихи Paint Effects в полигональную сетку и просчитать ее
вашим любимым рендерером с применением всех модных технологий. Операция конвертации
(Modify=>Convert=>Paint Effects to Polygon), наследует не только анимацию и Construction History,
но и цвет, и освещение штрихов. Правда, размер сцены и количество свободной памяти в случае,
например, пары густых опушек леса остается на вашей совести.

Есть еще один способ просчитывать Paint Effects как полноправного участника сцены, а
не как пост-процесс. Это использование Renderman for Maya. Рейтрейсинг, тени Deep Shadow, все
новомодные «фишки» рендеринга - к вашим услугам при просчете штрихов Paint Effects.

Туман, глубина и прозрачные объекты


Следует постоянно помнить, что Paint Effects просчитывается отдельным проходом и
складывается затем с изображением сцены методами композитинга с учетом информации из
канала глубины (Z-depth).

По умолчанию в атрибутах камеры, в разделе Output Settings, установлена опция Depth


Type=Furthest Visible Depth. Это означает, что за максимальную глубину в каждом пикселе
принимается граница наиболее удаленного от камеры объекта. В этом случае, даже если вы
поместите штрихи Paint Effects за прозрачным объектом, они все равно будут появляться перед
ним.

Если вы хотите, чтобы штрихи «прятались» за объектом, установите Depth Type=Closest Vis­
ible Depth. Если вы используете с сцене также туман (fog), то вы должны использовать включить
галку Transparency Based Depth для достижения необходимого эффекта.

1000 Книга Сергея Цыпцына


Оптимизация просчета и интерактивной работы
Как обычно, в заключение приведу несколько практических советов по работе с Paint Ef­
fects, касающихся ускорения как интерактивной работы, так и времени рендеринга штрихов.
Для начала подумайте, не стоит ли вам поменять видеокарту (про апгрейд процессора говорить
банально - это слишком универсальный совет). Старые видеокарты могут сильно тормозить при
отображении Paint Effects на экране.

Если вы планируете работать с Paint Effects действительно много, подумайте также о


покупке планшета. Это расширит ваши возможности, особенно на стадии рисования.

Если создаваемые вами кисти довольно густые и тяжелые и, как следствие, еле ворочаются
на экране, задавайте для таких штрихов низкое качество отображения. Для этого установите
значение атрибута Display Quality для штриха равным 50, 25 или 10 процентам. «Круглое» значение
поможет мысленно оценить реальную густоту при рендеринге по сравнению с экранной картинкой.
Если, например, Display Quality=25, плотность штрихов на экране будет в четыре раза меньше,
чем при рендеринге. Помните также, что в атрибутах самой кисти есть параметр Simplify Meth­
od, определяющий, как понижать качество отображения на экране: либо сокращая количество
сегментов в линиях (segments), либо сокращая число самих линий (tubes per step).

Помните о том, что чем больше основные стволы будут ветвиться (раздваиваться), тем
больше будет веток, и как следствие, листьев, и прочих деталей. Причем рост количества деталей
будет весьма стремительным. За ветвление отвечает атрибут Split Max Depth в разделе Branches,
так что увеличивайте его с осторожностью.

Интуитивно понятно, что надо стараться задавать минимально допустимые значения


«количественных» атрибутов, определяющих количество деталей (Twigs/Leaves in Cluster, Num
Twigs/Leaves in Cluster).

Количество линий (tubes) и их сегментов задается атрибутами Tubes per Step и Segments. Их
увеличение замедляет рендеринг и отображение прямо пропорционально. Кроме того, изменение
количества сегментов радикально изменяет форму штриха, поэтому старайтесь задать число
сегментов в самом начале редактирования кисти.

На время рендеринга оказывает непосредственное влияние значение Stamp Density,


определяющее количество микродисков, используемых для отображения одного сегмента. Для
некоторых кистей он по умолчанию установлен в четыре и более, хотя может быть уменьшен до
двух-трех без потери качества. Это зависит от близости камеры к штриху и от размеров самого
штриха.

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

Если штрихов много и все они были созданы вручную, то интерактивное отображение
на экране можно ускорить, «упростив» кривые, лежащие в основе штрихов. Для этого можно
воспользоваться операцией Paint Effects=>Curve Utilities=>Simplify Stroke Path Curves. Как правило,
нарисованные штрихи порождают кривые, содержащие сотни контрольных вершин. Сократив их
количество, можно существенно оптимизировать сцену.

Еще один способ оптимизировать работу со штрихами состоит в следующем: надо зайти на
сайте www.highend3d.com и в разделе Maya=>Tutorials найти и прочитать развернутые комментарии
на все случаи жизни (Paint Effects FAQ) от разработчика модуля Paint Effects Данкана Бринсмита.

Paint Effects 1001


История
Если вы часто летаете самолетами и у вас нет абонемента в бизнес-класс, существуют
способы существенно улучшить свои жилищно-сидячие условия на борту воздушного судна.
Необходимо лишь войти в роль представителя какой-нибудь любимой в народе профессии.
Например, артиста или депутата. Однако на артиста (а точнее, на известного артиста) надо быть
сильно похожим, прикинуться депутатом иногда не позволяет возраст, и тогда проще всего войти
в роль спортсмена. Их, спортсменов, любят не меньше, чем артистов, однако в лицо знают далеко
не всех.

Однажды я летел в Египет, причем сильно опаздывал. Опоздание на регистрацию чартерного


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

Со мной летел известный авантюрист-серфер Сергей «Кальмар» Лазуткин, и мы на ходу


разработали план захвата самолета, а точнее первого ряда в первом салоне. Примчавшись на
стойку подходящей к концу регистрации, мы бодро спросили девушку, глядевшую в наши билеты:
«А остались ли хорошие места для сборной России по виндсерфингу?». Девушка, на нашей счастье,
попалась эрудированная, и слово «виндсерфинг» вызвало у нее только положительные эмоции.
К тому же за неделю до этого мы вернулись из того же Египта и были буквально прокопчены на
майском африканском солнце. Тот факт, что катались мы тогда на кривых ногах-руках и с трудом
поворачивали на сильном ветру, ничуть нам не помешал представиться членами сборной России:
ведь мы знали основы терминологии, могли делать умный вид на суше, а чемпионов в этом виде
спорта мало кто в народе знал в лицо.

В ответ на нашу загорелую просьбу и демонстрацию длинных ног, не влезающих ни в


один проход между креслами, девушка совершенно растаяла и выдала нам места в первый ряд,
обычно оставляемые для родителей с детьми. Более того, закрыв неожиданно стойку регистрации,
она взяла нас за руку (или за руки) и провела без очереди через огромную толпу на паспортном
контроле со словами: «пропустите сборную России, у них самолет вылетает срочно». Получив
такую поддержку и фору во времени, мы, воодушевленные успехом, заскочили в бар, чтобы перед
отлетом пропустить, по традиции, чашку чего-нибудь с лимоном.

К сожалению, девушка в баре оказалась не такой интеллектуалкой как предыдущая, и


поэтому привычную уже просьбу: «А не найдется ли для сборной России по виндсерфингу...» она
прервала простодушным вопросом: «А што это такое, виндсерфинг?». И тут, совершенно случайно, я
раскрыл один из мужских журналов, валявшихся на стойке бара и служивших элементом интерьера
заведения. На открытой наугад странице я обнаружил статью про виндсерферов с отличными
фотографиями и немедленно воскликнул: «Как вы не знаете, что это такое? Так вот посмотрите
скорее, кто мы такие!». Фотографии волн, парусов и мускулистых парней были действительно
профессиональными, и девушка, потеряв дар речи, готова была отдать нам все имущество
бара, включая себя, чем чуть не воспользовался Кальмар, пригласив ее осмотреть служебное
помещение. Однако времени было, увы, в обрез, и мы помчались на посадку, прихватив в качестве
трофея все журналы со стойки бара. Ворвавшись в салон и заняв вдвоем весь первый ряд, я было
сделал попытку прорваться в бизнес-класс, однако был остановлен командиром корабля в связи
с отсутствием соответствующего билета. Ну и бог с ними, с командирами - зато стюардессы всего
мира, как мы теперь знаем, относятся к серферам с восхищением и нежностью. Прежде чем уснуть,
с наслаждением вытянув ноги, я успел услышать, как Кальмар задал очередной вопрос: «А есть ли
на борту усиленное питание для сборной России по виндсерфингу?». Проснувшись, я обнаружил,
что перед ним стоит целая стопка аэрофлотовских обедов и он с достойным для сборной России
аппетитом их методично уничтожает. Оказав помощь товарищу по сборной в этом нелегком деле,
я подумал что, жизнь спортсмена имеет массу преимуществ, особенно когда рядом нет тренера.
Стоит ли упоминать, что к выходу из самолета нас пригласили первыми...

1002 Книга Сергея Цыпцына


Динамическая симуляция
Это мой самый любимый раздел MAYA. Можно сказать, что это ее игровой движок. Эта
часть программы позволяет бесконечно играть с MAYA и самому быть изобретателем правил игры.
Я намеренно оставил слово «симуляция» для перевода термина «simulation», который означает
«моделирование». Только это не геометрическое моделирование поверхностей и кривых, а
физическое моделирование движения динамических систем. Моделирование движения объекта
или системы (по-английски обозначаемого как «simulation»), с моей точки зрения, действительно
лучше называть симуляцией, так как в рамках MAYA этот процесс предназначен не только для
физически правдоподобного воспроизведения траектории объектов, но и для создания новых
типов движения, не столько научно-корректных, сколько эффектных и выразительных. Конечно,
основная отправная точка при построении динамической системы - «похожесть» на реальные
явления, видимые вокруг, однако финальный критерий - не полное совпадение с физикой
окружающего мира, а впечатление, производимое на зрителя, или довольное лицо режиссера.

Динамика в MAYA является еще одним способом создания анимации. Однако анимация в
этом случае не определяется как набор ключевых кадров или формул, задающих, где и в какое
время объекту необходимо точно быть. Вместо этого, задается только начальное состояние
объекта (или системы объектов), а затем формулируется свод законов, определяющих правила
воздействия окружающего мира на объект. Такие, например, как сила ветра, притяжение земли,
бардак в роте, сопротивление воздуха и проч. Дальнейшее движение объекта MAYA рассчитывает
сама, на основе этих законов и начальных условий.

В принципе, можно представлять себе динамическую симуляцию движения как один


огромный expression, в котором прописаны формулы, в соответствии с которыми будет двигаться
объект при воспроизведении анимации. У вас нет возможности редактировать саму логику или
формулы этого expression, однако вы можете свободно изменять многочисленные параметры,
«торчащие наружу», такие как сила воздействия полей, трение, рассеяние энергии и другие.
Глотнувшие MAYA пользователи тут же сообразят, что эти параметры, естественно, хранятся в
атрибутах соответствующих объектов, и сами эти атрибуты можно анимировать традиционными
«ручными» способами, изменяя силу или даже законы воздействия окружающей среды на систему
объектов. Это и создает ощущение игры и вседозволенности. Ибо типичный процесс работы с
динамикой заключается в изменении условий и параметров и очередного запуска анимации на
воспроизведение плюс ожидания с замирающим сердцем: «А что получится на этот раз?», или
«Какого буйвола, все опять разваливается, все не так, как надо!?». Идет постоянная игра.

Какие же объекты или системы анимируются с помощью таких «игровых» методов?

Самое очевидное применение физической симуляции - динамика твердых тел, когда


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

Другое применение связано с необходимостью время от времени пускать пыль в глаза.


Это системы частиц. Майская динамика частиц являет собой очень удачное сочетание гибкости,
мощности и в тоже время простоты управления. Есть альтернативные программы для работы с
частицами, позволяющие разрабатывать более «тяжелые» или «физически корректные» эффекты,
однако майская система частиц отличается тем, что позволяет действительно быстро настроить
логику движения частиц, и сделать это довольно простыми методами, добиваясь результата за
минимальное время.

Динамика движения волос обычно выделяется в отдельный класс симуляции реалистических


движений. Дабы сразу развеять иллюзии, сразу скажу, что модуль MAYA Fur не обладал и не
обладает никакими средствами физического моделирования движения меха. Вся анимация
меховой «шкуры» производится за счет деформации нижележащей поверхности или вручную, с
помощью посредников-аттракторов. Реальная динамика волос появилась в MAYA только с шестой
версии на основе модуля MAYA Hair. Альтернативой ему является плагин Shave and Haircut for MAYA
от Джо Альтера (www.joealter.com).

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

Динамическая симуляция 1005


значительных вычислительных мощностей, поэтому интерактивная работа с анимацией в этом
случае редко представляется возможной. Этот вид динамики реализован в MAYA на основе модуля
MAYA Fluids.
Движение тканей также представляет собой типичную задачу динамики. В силу
необходимости рассчитывать огромное количество траекторий для точек, контролирующих
поверхность, эта задача также требует значительной мощности процессора и для интерактивного
воспроизведения нуждается, как правило, в предварительном просчете. Модуль MAYA Cloth решает
это задачу в максимально «текстильных» терминах, оперируя такими понятиями как «швы»,
«вытачки», «пуговицы» и др. Есть также альтернативная система для работы с тканями в MAYA.
Это плагин Syflex - коммерчески оформленная технология анимации тканей, использовавшаяся,
например, при производстве фильма Final Fantasy (www.syflex.biz).

А как же динамика мягких тел (soft body dynamics), о которой все столько слышали? Это
всего лишь часть динамики систем частиц. Остроумная и эффективная идея заключается в том,
что частицы могут полностью контролировать движение контрольных вершин поверхности или
кривой. Иначе говоря, точки контрольные точки поверхности намертво «прилипают» к частицам
и двигаются вместе с ними по законам динамики, при этом деформируя поверхность. Главный
плюс динамики мягких тел (хотя удачнее было бы называть ее динамикой деформируемых тел)
- ее интерактивность. Благодаря этому эта технология часто служит эффективной альтернативой
системам анимации тканей.
Динамика твердых тел
Начнем со слепого примера. То есть сделаем некоторую последовательность действий
без комментариев, вслепую, а затем поговорим о принципах динамики твердых тел, на примере
только что произведенных, лихорадочных действий.

Колбасинг
Создайте NURBS-сферу.
Размножьте ее. Зайдите в Option Box для Edit=>Duplicate и установите TranslateZ=3; Number
of Copies=4.

Нажмите Duplicate.

Это создаст пять сфер, распределенных вдоль оси Z.

Выберите все сферы.

Нажмите F4. Выполните Fields=>Gravity. Нажмите Play.


Все сферы стремительно падают вниз. Попробуем прибить первую к земле гвоздем. (Не
забывайте нажимать Stop перед любыми очередными действиями.)

Выберите первую сферу.


Откройте Option Box для Soft/Rigid Bodies=>Create Nail Constraint.

Установите Constraint Type=Nail.


Нажмите Apply и не закрывайте Constrain Option Box.

Динамическая симуляция 1007


Нажмите Play.

Первая сфера осталась "прибита" гвоздем и никуда не падает.


Теперь свяжем первую и вторую сферы.
Выберите первую и вторую сферы (только их, не зацепив созданное поле гравитации или
гвоздь (их проще выбирать их в Outliner).
Установите в Option Box новый тип «закрепления»: Constraint Type=Pin.
Нажмите Apply.
Нажмите Play.
Повторите это для остальных пар сфер (2 и 3, 3 и 4, 4 и 5).
Закройте окно Constrain Option Box.
Нажмите Play.
То, что происходит на экране, лучше всего характеризуется многофункциональным словом
«колбасинг». Заметьте, что мы не поставили ни единого ключа и не написали ни одного expression
для создания такой замысловатой анимации.

Встаньте в первый кадр.


Создайте окружность Create=>NURBS Primitives=>Circle.
Разверните ее (rotateX=90) и растяните слегка по X.
Нажмите Ctrl+d (Duplicate). Получится пять окружностей.
В Outliner перетащите и бросьте средней кнопкой мыши nurbsCircle1 на nurbSphere1, nurb-
sCircle2 на nurbSphere2 и т.д., «припарентив» таким образом все окружности к соответствующим
сферам.

1008 Книга Сергея Цыпцына


Выберите на экране все кривые по порядку, от первой до пятой, и выполните
Surfaces=>Loft.
Нажмите Play.
Теперь это уже суперреалистичный колбасинг.
Сохраните файл (kolbasing.ma).

Теперь немного комментариев.


Никакого отношения к динамике мягких тел происходящее на экране не имеет. Этот
результат есть сочетание Construction History, иерархии и динамики твердых тел. Начнем с конца,
то есть с поверхности, которая в каждом кадре помнит о том, что она проходит через окружности.
Окружности, в свою очередь, ничего не знают про динамику, они просто следуют за своими par­
ent-объектами. А вот сферы, превращенные неуловимым образом в твердые тела, двигаются по
законам динамики. Вот про законы мы сейчас и поговорим.

Но сначала история из «майского» фольклора. Мой хороший знакомый, Леша Мельников,


как-то рассказал мне вот такую историю коммерческого применения MAYA в повседневной жизни.
В 1998 году Леше довелось работать в компании, которая совершенно официально и одной
из первых в России получила настоящую MAYA 1.O. Работала хорошо MAYA только на рабочих
станциях 02 от компании Silicon Graphics, но довольно весело крутила динамику твердых тел.
Быстро разобравшись с законами динамики, Леша с друзьями изготовил ультрафотореалистичную
рулетку и такой же шарик, превращенный в твердое тело. Все дальнейшие вечера и ночи были
предопределены. Каждый мог сделать ставку, а MAYA-крупье задавала случайную начальную
скорость и направление движения шарика. Ночи напролет крутилась рулетка, и для кого-то MAYA
иногда обеспечивала приятную прибавку к зарплате. Однако пикантная деталь этой истории в том,
что качество отображения текстур на объектах в то время было отвратительным, а параметр tex­
ture resolution в принципе отсутствовал в Attribute Editor. Поэтому, чтобы определить выигравший
номер, приходилось каждый раз рендерить текущий кадр!..

Законы динамики
Для адекватной работы с динамикой необходимо иметь представление о том, как все-
таки вычисляются траектории объектов на основе заданных параметров и какие правила надо
соблюдать, чтобы динамика работала корректно и предсказуемо.
Для расчета движения тех или иных объектов всегда используется некий Решатель (Solv­
er), то есть тот, кто решает, как будут двигаться объекты, которыми он управляет. Для твердых
тел это Rigid Body Solver, для одежды cpSolver, для волос - hairSystem. Атрибуты таких решателей,
как правило, доступны через Attribute Editor и определяют то, как точно или как быстро будет
производится расчет движения и какие факторы будут при этом учитываться. Не обязательно
вникать в суть алгоритмов, используемых в этих решателях, важно усвоить один общий принцип
работы всех этих «больших expressions».

Динамическая симуляция 1009


Прежде всего, всегда заданы начальные условия. Их можно задать вручную, просто
расположив объекты в первом кадре надлежащим образом, либо сохранив состояние объектов в
любом другом кадре как начальное.

А дальше МАУА рассчитывает траекторию объектов в каждом кадре на основании информации


о положении объектов в предыдущем кадре.

Примечание. Я говорю «положение» объектов, имея в виду, конечно, позиции и


скорости объектов. Корректнее говорить о «состоянии» объектов, пусть это и
будет слишком психоаналитически.

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

Отсюда следует набор несложных законов.

Закон динамики 1.
Скорость воспроизведения анимации должна быть всегда равна Play Every Frame.

Действительно, если MAYA в режиме воспроизведения real-time начнет «ронять» кадры,


расчет траекторий в пропущенных кадрах производиться не будет, и последующие за ними
кадры будут вычисляться с ошибкой. При пропуске большого количества кадров это приводит к
совершенно неадекватным результатам. Этот закон нарушается чаще всего, и первое, что надо
проверить, когда появляются «глюки» при работе с динамикой - это скорость воспроизведения
анимации. Коварство заключается еще и в том, что если скорости перемещения небольшие, а сцена
не сильно тяжелая, пропуск кадров при проигрывании анимации вызывает лишь незначительное
отклонение траектории от аналогичной, но просчитанной в каждом кадре. Но при рендеринге
(где траектория просчитывается в каждом кадре) позиции объектов будут слегка отличаться от
наблюдаемых в окне камеры. Иногда этим можно пренебречь, иногда - нет.
Поэкспериментируйте.

1010 Книга Сергея Цыпцына


Искусственно утяжелите сцену с цепочкой шаров.
Например, установите для loft атрибут sectionSpans равным 200.
Проиграйте сцену в режиме realtime, остановитесь в районе пятисотого кадра, запомните
его номер, верните sectionSpans в единицу, сдублируйте поверхность.
Теперь снова проиграйте анимацию сначала, но в режиме Play every frame. Остановитесь
в том же кадре и сравните результат.

Закон динамики 2.
Анимация должна воспроизводиться всегда только вперед.
Попытки проиграть анимацию назад ни к чему не приводят. MAYA запоминает несколько
предыдущих кадров, но сделать расчет движения назад уже выше ее возможностей. Дело в том,
что численные методы, лежащие в основе расчета траекторий и используемые Rigid Body Solv­
er, не работают «вспять». Еще раз: положение объекта в текущем кадре вычисляется на основе
информации о предыдущем кадре.

Примечание. Некоторым пытливым умам, читающим эту книгу, наверное,


посчастливилось закончить школу и даже поступить в технический институт.
Те из них, кто доучился курса до третьего, могут смутно помнить названия
«численные методы», «метод Эйлера», «метод Рунге-Кутты» и совсем жуткие
«методы Адамса». Да, это все из той же оперы. В Attribute Editor для Rigid
Body Solver вы даже можете выбрать, какой метод использовать при расчетах
и увеличивать точность за счет измельчения шага по времени для борьбы с
большими скоростями.

Закон динамики 3.
Первый кадр анимации всегда должен быть «первым» с точки зрения динамики.
Иначе говоря, номер стартового кадра для воспроизведения анимации должен совпадать с
атрибутом startTime для Rigid Body Solver. Дело в том, что когда вы создаете первое твердое тело
(а точнее когда появляется новый Rigid Body Solver), MAYA запоминает номер начального кадра
анимации и делает его первым кадром для начала расчета динамики.

Если после этого вы сдвинете начальный кадр на TimeLine, при воспроизведении MAYA
перестанет попадать в первый кадр динамики и возвращать объекты в стартовые позиции. У вас
просто все «залипнет».

Динамическая симуляция 1011


Важно понимать, что для динамики всегда определено понятие первого (а лучше сказать
- «начального», или «стартового») кадра, в котором все объекты возвращаются в свои начальные
позиции и получают начальные скорости. Номер этого кадра хранится в атрибуте startTime ноды
rigidSolver, отвечающей за все численные расчеты. Его можно менять, например, в тех случаях,
когда вы хотите, чтобы динамика начинала работать только с какого-то конкретного кадра. Так
что третий закон динамики можно скорректировать так: начальный кадр анимации должен быть
меньше начального кадра динамики.

Недоразумения часто возникают, когда для стартового кадра анимации на TimeLine


установлено «кривое» значение типа 1.04, а начальный кадр динамики равен строго единице.
Если объекты не возвращаются обратно, проверяйте эти значения.

Закон динамики 4.
Нельзя безответственно щелкать мышью в TimeLine и там же, абы как,
перетаскивать мышью текущее время.
Когда вы щелкаете мышью на временной линейке, пытаясь сразу встать, к примеру, в
пятьсот пятый кадр, MAYA пытается посчитать позиции объектов в этом кадре и ищет информацию
об их положении в предыдущем, пятьсот четвертом кадре, однако вы же не были ни в пятьсот
четвертом, ни в пятьсот третьем кадрах, поэтому MAYA робко ставит объекты в положение «от
балды». Это в последние годы характер MAYA сильно улучшился, а раньше она просто зависала от
такой бесцеремонности, пытаясь одним махом просчитать все пятьсот недостающих кадров.

Поэкспериментируйте.

Щелкните мышью в любой кадр «подальше» от начала, напомните положение объектов, а


затем «честно» проиграйте анимацию до этого кадра.

Сравните результат.

Совет. Если вам нужно «ненадолго заскочить» в любой кадр без проигрывания
анимации (и, как следствие, без перепросчета динамики или обновления Construc­
tion History), используйте на таймлайне среднюю кнопку мыши.

Закон динамики 5.
Твердые тела не должны пересекаться в начальном кадре.
Во всех кадрах, кроме начального, MAYA отслеживает столкновения между объектами и не
дает им проникать друг в друга. Единственный кадр, в котором их можно перемещать вручную,
это начальный кадр динамики. В нем MAYA никак не может вам помешать расположить объекты
так, чтобы они пересеклись, и злорадно нажать кнопку Play. Но ничего хорошего не выйдет. MAYA
разразится в Script Editor сообщениями о взаимопересечении твердых тел и впадет в легкий
ступор.

// Warning: Rigid Body interpenetration occurred between 'rigidBody2' and 'rigidBody1'. //

Если в ваши планы не входит доводить MAYA до истерики, избегайте проникновения твердых
тел друг в друга в первом кадре.

Поэкспериментируйте с цепочкой шаров. В начальном кадре выберите последний шар (loft


можно спрятать) и «вдвиньте» его в предпоследний.

1012 Книга Сергея Цыпцына


Проиграйте анимацию, наблюдая, как MAYA истошно ругается в Script Editor, а в конце
концов агонизирует.

Концепция твердости тел


В предыдущем примере мы делали все «вслепую», поэтому и твердые тела появились
у нас в сцене неуловимым образом. Причем никакого уточнения, активные они или пассивные,
мы не делали. Все получилось само собой. Давайте сделаем упражнение, ошеломляющее свое
новизной - прыгающий по плоскости шарик. И посмотрим, как же на самом деле устроены твердые
тела, в какой момент они возникают в сцене и насколько они твердые.

Если вам лень изготавливать NURBS-сферу и полигональную плоскость, откройте файл


ballStart.ma.

Будем действовать последовательно. Сначала превратим шар в твердое тело.


Выберите сферу.
Выполните Soft/Rigid Bodies=>Create Active Rigid Body.
Если проиграть анимацию, ничего не происходит. Очевидно, не хватает силы тяжести.
Ничего не выбирайте, снимите выделение со сферы.
Создайте силу тяжести. Выполните Fields=>Gravity.
Шар стоит на месте, как влитой. Гравитация появилась и в Outliner и на экране в
виде маленькой иконки. В отличие от реального мира, в MAYA созданные силы или поля могут
присутствовать в сцене, но не действовать на выбранные объекты. Для того, чтобы объекты начали
«чувствовать» динамические поля, их надо присоединить к этим полям.
Такое присоединение осуществляется через редактор динамических отношений:

Динамическая симуляция 1013


Windows=>Relationship Editors=>Dynamic Relationships.
Откройте его.
Слева находится аналог панели Outliner, и если выбрать в нем объект (в нашем случае,
шар), то справа появится список присутствующих в сцене полей, к которым можно присоединить
объект, то есть заставить эти поля влиять на объект.
Выберите слева наш шар, а справа выберите gravityField1 (он станет бледно-желтым,
причем повторный выбор поля отсоединит его от объекта).

Теперь шар стремительно падает вниз.


А сейчас просто создайте еще одну сферу и, пока она выбрана, сразу выполните
Fields=>Gravity. Новое тело сразу начинает падать. Из этого следует вывод о неуловимых для
человеческого глаза действиях, происходящих при создании полей.
На самом деле, когда создается новое поле, MAYA производит три неявные операции.

Первое. Создается новое поле и проверяется, не выбраны ли какие-нибудь геометрические


объекты. (Легальные геометрические объекты, в данном случае - это сплайновые и полигональные
поверхности, об остальных чуть позже).

Второе. Если поверхности выбраны, они автоматически превращаются в активные твердые


тела (правильнее говорить: для них создаются активные твердые тела).

Третье. Вновь созданные активные твердые тела автоматически присоединяются к


созданному полю.

Об этом необходимо помнить каждый раз при создании нового поля. Зачастую пользователи,
привыкшие к автоматическому созданию твердых тел и назначению полей, забывают выбрать
поверхность , а потом сильно удивляются, почему это созданные поля не влияют на объекты и
пытаются наплодить еще пару-тройку более «надежных» полей.

Совет. Посмотреть, какие поля влияют на выбранный объект, можно в окне Dy­
namic Relationships, однако еще проще это сделать прямо в окне камеры в режиме
wireframe. Розовым окрашиваются иконки полей, влияющих на выбранный объект,
и наоборот, если выбрать в Outliner любое поле, то розовыми становятся все
объекты, на которые это поле действует.

Давайте «отвердим» плоскость и разберемся в активности и пассивности твердых тел.

Выберите плоскость и выполните Soft/Rigid Bodies=>Create Passive Rigid Body.


Шар перестанет пронзать плоскость, и, безвольно подпрыгнув, свалится на бок.

Концепция твердости. Когда мы превращаем поверхность (сплайновую или


полигональную) в твердое тело (rigid body), безразлично пассивное или активное,
она приобретает свойство сталкиваться и взаимодействовать с другими
твердыми телами. Тут можно привести довольно дурацкую, но по сути верную
аналогию с рекламой зубной пасты «Колгейт»: если при создании твердого тела
выбранную поверхность помазать «Колгейтом», это придаст ей твердость и
защиту от проникновения внутрь. А если говорить «по-майски», на поверхности

1014 Книга Сергея Цыпцына


создается новая нода (hsidBody), содержащая набор атрибутов, определяющих
физические свойства твердого тела. Этот слой зубной пасты или новую ноду (кому
как нравится) можно разглядеть в Channel Box или в Attribute Editor под названием
rigidBodyff. Атрибуты твердого тела определяют его свойства, касающиеся
динамического взаимодействия с полями и другими телами.

Активные твердые тела могут двигаться только под действием сил и


столкновений с другими твердыми телами (как пассивными, так и активными).
Они игнорируют поставленные на них ключи, expressions, констрейны и прочие
методы обычной анимации. Их движение обусловлено только динамикой.

Пассивные твердые тела служат лишь для того, чтобы служить препятствием на
пути активных твердых тех. Это просто поверхности, намазанные «Колгейтом»,
от которых могут отскакивать активные тела. На них не действуют поля, они
не сотрясаются от ударов. Зато их можно анимировать всеми традиционными
способами, задавая их движение «вручную».

При постановке ключей на твердые тела возникает некоторое количество «непоняток».


Обозначу некоторые из них.

Если ставить ключи на имеющееся пассивное твердое тело, оно действительно начинает
двигаться по ключам с одной маленькой «засадой»: ключей не видно на TimeLine! Более того,
попытка удалить ключи через Channel Box ни к чему не приводит. Ключи у пассивного твердого
тела можно удалить только в Graph Editor! Поэтому я бы посоветовал перед анимацией любого
пассивного твердого тела группировать его с самим собой, а ключи ставить на получившуюся
группу (если вы не собираетесь анимировать пассивность/активность - но об этом см. ниже).
Если же ставить ключи на имеющееся активное твердое тело, то ключи-то будут поставлены, однако,
вместо того чтобы их игнорировать, как положено активному твердому телу, произойдет смешивание
двух анимаций: от динамики и от ключей. Причем по умолчанию приоритет анимационной кривой
равен единице, а вес динамики равен нулю. При этом активное твердое тело начинает вести себя
непредсказуемо и к нему добавляется атрибут типа blendRigidBody#, отвечающий за смешивание
двух типов анимаций. Чтобы как-то исправить положение надо установить его в единицу, чтобы
тело управлялось только динамикой. Пытливые умы спросят, а зачем ставить ключи на активное
тело? Ответ будет дан ниже, при обсуждении анимации активности твердых тел.

Свойства твердых тел


Этот раздел можно было бы начать и сразу же закончить одним предложением: чтобы
разобраться со свойствами твердых тел, надо просто изучить, за что отвечают атрибуты ноды rig-
idBody для любого твердого тела. (Не забывайте: взрослые мальчики работают с документацией.)
Однако некоторые комментарии не помешают.

Часть атрибутов отвечает за «твердую» часть, независимую от пассивно-активного статуса.


Установите для обеих поверхностей атрибут bounciness в единицу, чтобы задать абсолютно упругий
отскок и задайте себе вопрос, а почему круглый шар норовит постепенно ускакать куда-то вбок?
Или он не круглый?

При создании твердых тел MAYA предлагает ненавязчивый сервис: для симметричных
сплайновых поверхностей центр масс твердого тела слегка смещается от центра (это связано
с разбиением сплайновых поверхностей на полигоны для динамики). Если для шара обнулить
атрибут centerOfMass, то он будет уныло скакать в центре плоскости.

Атрибуты типа centerOfMass (центр масс), impulse (грубо говоря, ускорение), spinlmpulse
(вращательное ускорение), mass (масса) оказывают влияние только на активные твердые тела, в
то время как bounciness (упругость) или friction (трение) изменяют характер взаимодействия для
обоих типов твердых тел.

Динамическая симуляция 1015


Совет. Атрибут damping является исключительно полезным, если надо немного
«притормозить» разогнавшееся активное твердое тело или создать иллюзию
наличия сопротивления окружающей среды. Этот атрибут отвечает за
принудительную потерю скорости в каждом кадре, независимо от действия любых
полей.

Важно понимать, что NURBS-поверхности при превращении в твердые тела разбиваются


на невидимые полигоны, предназначенные только для расчета столкновений. Количество этих
полигонов, то есть степень разбиения, можно уменьшать или увеличивать, изменяя атрибут Tes-
selation Factor, доступный для редактирования только через Attribute Editor в разделе Performance
Attributes. Там же можно обнаружить атрибут standln, позволяющий задать более простую форму
тела для расчета столкновений, чтобы при отслеживании соприкосновений использовалась не
реальная геометрия, а подходящих размеров сфера или куб.

Совет. Не используйте сложные модели в качестве твердых тел. Вместо них


используйте модели попроще, а «хорошие» поверхности просто прикрепляйте к
твердым телами, например, с помощью операции parent. К примеру, если вы при
помощи динамики роняете на землю или, пардон, на чью-нибудь одинокую голову
(детализированную притом), совершенно необязательно превращать ее в твердое
тело, а проще сделать полигональную грубую болванку и уронить на землю ее,
тогда как голову просто припарентить к этой (предусмотрительно спрятанной)
болванке.

Анимация активности твердых тел


Но самое удивительное заключается в том, что пассивность или активность - тоже свойства
твердого тела, задаваемы атрибутом active. При этом его, очевидно, можно даже анимировать.
Попробуйте включить этот атрибут (то есть задать active=on) для твердого тела на плоскости и
посмотрите, как она стала реагировать на удары. На нее не действует сила тяжести, поэтому она
не падает вместе с шаром, хотя теперь она стала полноценным твердым телом.

Пытливейшие умы немедленно воскликнут: «Так ведь можно организовать, таким образом,
чемпионат по бросанию твердых тел!». Сначала пассивное твердое тело анимируется обычным
способом, например, следуя с помощью констрейна за размахивающейся рукой персонажа, а
затем, в момент броска, анимируется изменение атрибута active с off на on. И твердое тело должно
взлететь в воздух, наплевав на любые констрейны, так как оно становится в этот момент активным
твердым телом. Сейчас мы проверим эту гипотезу и заодно сделаем упражнение, иллюстрирующее
уже перечисленные законы динамики.

А напоследок сформулируем еще один закон.

Закон динамики 6.
Твердые тела должны сталкиваться внешними сторонами. Иначе говоря, нормали у
сталкивающихся поверхностей должны торчать наружу, а точнее в сторону столкновения. У любой
поверхности есть две стороны, и твердые тела должны сталкиваться теми сторонами, из которых

1016 Книга Сергея Цыпцына


торчат нормали. Если нормали направлены не в ту сторону, их можно развернуть с помощью
соответствующих инструментов моделирования (Edit NURBS=>Reverse Surface Direction или Edit
Polygons=>Normals=>Reverse).
Проведите эксперимент, переверните плоскость вверх ногами, а заодно покажите на ней
нормали. При проигрывании анимации шар пронзает плоскость, a MAYA уже знакомо ругается в
Script Editor.

Этот закон связан с тем, что при столкновении объектов MAYA должна определять, в какую
сторону отталкивать поверхности друг от друга после столкновения. За направление отталкивания
берется нормаль к поверхности, поэтому в последнем случае шар «проваливается» в плоскость и
«выталкивается» вниз, по нормали к плоскости.

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


поверхностей: это может привести к «залипанию» или «скрещиванию»
поверхностей. Если хотите, чтобы поверхность «работала» с обеих сторон,
дублируйте ее (или делайте Offset), выворачивайте нормали, загибайте края.

Катание шаров
Создайте новую сцену.
Перейдите в камеру front. С помощью CV Curve Tool постройте профиль кегли.
Используйте привязку к сетке и располагайте первые две-три точки на горизонтальной
оси, давая вертикальную "устойчивость" профилю.
Последние две точки также расположите на одной горизонтальной прямой, чтобы сделать
гладкую вершину. Ведите кривую по часовой стрелке.

Динамическая симуляция 1017


Выберите кривую.
Выполните Surfaces=>Revolve.
Удалите историю.
Удалите кривую.
Перейдите в перспективу и уменьшите кеглю до адекватных размеров (scale=0.1).
Выполните Display=>NURBS Components=>Normals (Shaded Mode) и убедитесь в том, что
нормали на поверхности торчат наружу. Это должно стать привычкой. Постоянно помните про
шестой закон динамики.

Если по какой-то причине нормали направлены внутрь объекта, выполните Edit


Surfaces=>Reverse Surface Direction.

Отключите нормали и продолжайте.

Копируя полученную поверхность, расположите шесть объектов в виде пирамиды.


(Ненасытные умы могут составить пирамиду из десяти объектов.)

Не сдвигайте кегли по вертикали! Это нарушит пятый закон динамики, по которому


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

Выберите все кегли и, на всякий случай, установите в Channel Box для них translateY=0.
Создайте плоскость любого типа.

1018 Книга Сергея Цыпцына


Растяните ее в виде "дорожки".

Выберите все кегли.


Выполните Fields=>Gravity.
Это создаст поле силы тяжести, превратит все кегли в активные твердые тела и присоединит
эти тела к созданному полю.
Нажмите Play.
Кегли табором уходят в землю.
Превратите в дорожку в пассивное твердое тело.
Для этого выберите ее и выполните Soft/Rigid Bodies=>Create Passive Rigid Body.
Нажмите Play.
Кегли теперь должны стоять, как вкопанные.
Осталось их чем-нибудь сбить.
Создайте NURBS-сферу. Передвиньте ее в начало дорожки и превратите в активное твердое
тело: Soft/ Rigid Bodies=>Create Active Rigid Body.

И не надо создавать еще одну гравитацию!

Совет. Все построения всегда проводите в первом кадре! Это позволит избежать
неожиданностей при проигрывании анимации.

Теперь надо дать шару начальную скорость, и для этого не надо воздействовать на него

Динамическая симуляция 1019


полем или ударять другим шаром. В атрибутах твердого тела имеются нужные величины.
В Channel Box, в атрибутах твердого тела, для сферы задайте начальную скорость по
соответствующей оси (initialVelocityX=-10).

Нажмите Play.
Шар, не торопясь и не вращаясь, плывет над дорожкой с заданной скоростью и вяло
врезается в пирамиду. Очевидно, на него не действует сила тяжести. Коль скоро поле гравитации
уже есть, осталось только присоединить шар к нему.

Откройте Window=>Relationship Editors=>Dynamic Relationships.


Слева выберите сферу, а справа укажите на gravityFieldl.
Пожелтевшее название gravityFieldl указывает на присоединение поля гравитации к
выбранному объекту.

Альтернативный способ присоединить объект к полу, не открывая никаких окон, состоит в


выборе объекта и поля и выполнении пункта меню Fields=>Affect Selected Objects.

Теперь шар также неторопливо катится и упирается в пирамиду из кеглей, но не в силах


сбить хотя бы одну.

Увеличьте начальную скорость (initialVelocityX=-30).

Очевидно, что шару не хватает массивности, ведь сейчас массы кеглей и шара одинаковы
и равны единице.

Установите атрибут mass для шара равным десяти.

Теперь шар разбивает пирамиду как положено.

А дальше эксперименты с анимацией ограничены только вашими фантазиями и опытом


игры в боулинг. Если вы сильно искушены в этом деле, можете сместить шар правее от центра

1020 Книга Сергея Цыпцына


дорожки и подкрутить его, задав initialSpinX=180. Почему так много? Потому, что угловая скорость
задается в градусах-в-секунду, и 180 соответствует пол-оборота в секунду. Можете сделать дорожку
длиннее, поиграть с трением (friction) дорожки и шара. Изменить упругость отскока (bounciness)
и т.д.

Когда вы сделаете, наконец, копию боулинг-центра из «Большого Лебовского», настанет


время задать самому себе несколько вопросов.

Вопрос первый. Если анимация вас устраивает, может быть, имеет смысл избавиться от
динамики и «запечь» движения всех объектов в ключи, то есть в анимационные кривые? Уход
от динамики имеет смысл по многим причинам. Например, вы вдруг захотите передать сцену с
анимацией пользователям другой 3D-программы или в отдельную систему рендеринга, которая
ничего не знает про майскую динамику. Или у вас возникнут сомнения, что рендеринг корректно
подхватит динамику при просчете с пятисотого кадра. И, наконец, вам захочется ожесточенно
повозить мышкой по таймлайну, проигрывая анимацию вперед-назад.

Вопрос второй. Кто-то выше упоминал про бросание твердых тел. А тут идеальный случай,
чтобы вложить шар в конечность персонажа и бросить его, анимируя эту конечность.

Эти вопросы мы сейчас разберем, но сначала сформулируем еще один дополнительный


закон динамики и обрисуем методы борьбы с его нарушениями.

Дополнительный закон динамики: Большая скорость - главный враг динамики.


Если вы зададите скорость «выстрела» шара около ста (initialVelocityX=-100), то MAYA
еще справится с такой «стрельбой». Однако если установить initialVelocityX=-1000, шар пробьет
пирамиду насквозь и умчится вдаль. MAYA просто «не успеет» обсчитать такие быстрые перемещения.
Посудите сами: в первом кадре шар находится над дорожкой, а во втором должен быть уже в районе
горизонта. При этом MAYA, конечно, делает дополнительные отсчеты-проверки между соседними
кадрами для определения столкновений, но частоты (или густоты) таких промежуточных отсчетов
просто не хватает, и на больших скоростях шар просто успевает задевать пирамиду в соседних
отсчетах.

Чтобы увеличить частоту проверок между кадрами, надо уменьшить значение атрибута
Step Size для ноды rigidSolver, которая отвечает за просчет динамики. Закладку этой ноды всегда
можно отыскать в Attribute Editor для любого твердого тела или можно напрямую найти ее в меню
Solvers=>Rigid Body Solver.

Динамическая симуляция 1021


Уменьшите Step Size до 0.002.
Тогда сверхзвуковой шар будет задевать пирамиду даже на килоскоростях. Очевидно, что
уменьшение шага численного метода ведет к увеличению времени просчета динамики, однако за
большие скорости приходится платить высокой точностью и увеличенным временем расчета.

Старайтесь избегать появления в сцене высоких скоростей. Они могут возникать не


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

Анимация активности, или ручное бросание твердых тел


А теперь попробуем скрестить динамику и обычную анимацию, имитируя бросок шара
рукой. Если вы меняли Step Size в ноде rigidSolver верните его в 0.03. А начальное значение
скорости шара сейчас не имеет особого значения: ведь мы надеемся унаследовать скорость шара
от бросающей руки в момент отпускания.

Установите InitialVelocityX в ноль.

Для начала надо перейти в камеру front и сделать простую руку, делающую бросок в
течение сорока кадров. Одного IK Handle вполне хватит для постановки анимации.
Готовый файл с такой рукой называется bowlingHandStart.ma.

Возмущенный комментарий. Если сейчас, исходя из определений активных и пассивных


твердых тел, превратить шар в пассивное твердое тело (установив его атрибут active=off) и
«вложить» его в руку, создав Point Constrain к, например, IK Handle, то шар беспрекословно
приконстрейниться к руке и будет весело раскачиваться над дорожкой... Однако при попытке
отцепить его от руки, превратив его в активное твердое тело в каком-нибудь кадре и проанимировав
изменение атрибута active с off на on, шар просто начинает подозрительно крутиться в руке.

1022 Книга Сергея Цыпцына


Виной тому смешивание анимации, возникающее при создании констрейна для уже
имеющегося твердого тела. Даже для пассивного твердого тела создается атрибут blendPoint и
нода blendPair, позволяющие смешивать анимацию констрейна и динамику.

Хотя казалось бы, какое движение может быть у пассивного твердого тела от динамики?
Тем не менее, даже анимация атрибута blendPoint не может помочь: шар просто отваливается и
замирает в неопределенной позиции.

Чтобы сделать все «по-старому» (так, как в ранних версиях MAYA), то есть отцепить вовремя
шар от руки, проанимировав атрибут active, надо сначала приконстрейнить объект к руке, потом
сделать из него пассивное твердое тело и только потом поставить ключи на атрибут active.
Выберите шар и удалите с него твердое тело: Edit=>Delete by Type=>Rigid Bodies.
Теперь выберите IK Handle, затем шар и «прибейте» шар к руке: Constrain=>Point.
Выберите шар и создайте пассивное твердое тело: Soft/Rigid Bodies=>Create Passive Rigid Body.
Никаких дополнительных атрибутов и смешивания анимации не возникло. Меня это слегка
удивляет.
Теперь мы имеем пассивное твердое тело, зажатое в руке, и надеемся бросить его,
поставив два ключа в соседних кадрах.
Поставьте ключ на атрибут active=off, например, в тридцать пятом кадре, затем перейдите
в тридцать шестой кадр, установите active=on и поставьте еще один ключ.
При проигрывании анимации шар в тридцать шестом кадре превращается в активное
твердое тело, отцепляется от руки, наследует начальную скорость с анимационной кривой и
плавно плывет по воздуху.
Присоедините его к гравитации.
А скорость бросания можно теперь регулировать, изменяя анимацию руки. Шар будет
наследовать скорость и направление полета в момент отпускания. Не забывайте только, что
момент отпускания определяется по положению двух соседних active-ключей у твердого тела.
Сохраните файл (bowlingHandFinal.ma).

Вывод следующий: чтобы бросить объект как твердое тело, надо сначала приконстрейнить
его к другому движущемуся объекту, а затем превратить его в пассивное твердое тело. В момент
броска следует анимировать в двух соседних кадрах изменение атрибута active с off на on.
Пытливые умы могут аналогичным образом также «поймать» объект, просто подведя руку
в нужное положение рядом с объектом и анимировав атрибут active обратно, с on на off. Результат
«ловли» можно посмотреть в файле bowlingHandCatch.ma.

Избавление от динамики. Выпекание ключей


Вне зависимости от того, бросаете ли вы шар рукой или просто «стреляете» начальной
скоростью, вернемся к задаче избавления от динамики и перевода всей анимации в ключи.
Дело в том, что процесс превращения траекторий объектов в анимацию по ключам относится не
только к динамике, а к любой неключевой анимации вообще. Этот процесс называется «запеканием»
(baking) в ключи. Иногда также говорят «испечь анимацию».

Объект может быть анимирован «неявным» образом, то есть может не зависеть от своей
анимационной кривой, а зависеть от анимации другого объекта либо через Set Driven Key, либо
через IK Solver, констрейн или expression. Самый популярный пример - это скелет, анимированный
с помощью IK Handles. Сами кости не содержат ключей, однако часто бывает необходимо перевести
движения IK Handles в анимацию самого скелета (то есть костей), например, при экспорте в игровой
движок.

Во всех таких случаях можно превратить движение объекта в анимацию по ключам. В нашем
случае кегли и шар движутся по законам динамики, поэтому построим для них анимационные
кривые и заодно посмотрим, как «вычищать» динамику из сцены.
Выберите все кегли и шар.
Откройте Option Box операции Edit=>Keys=>Bake Simulation.
Установите Time Range=Start/End и задайте временной диапазон, на котором следует

Динамическая симуляция 1023


превратить динамические траектории в анимацию по ключам.
В нашем случае просто надо определить, какого количества кадров хватит для этого
конкретного эпизода.
Оставьте Hierarchy=Selected, так как мы не имеем дела со скелетонами.
Опция Channels определяет, на какие каналы, то есть атрибуты, проставлять ключи. В
нашем случае, мы знаем, что изменяются только атрибуты translate и rotate у выбранных объектов,
поэтому в Channel Box надо выбрать эти шесть атрибутов и установить опцию Channels=From Chan­
nel Box. В противном случае, вы можете установить эту опцию в Аll, а потом выполнить операцию
удаления во всей сцене «статических ключей» (Edit=>Delete All by Type=>5tatic Channels), чтобы
избавиться от горизонтальных анимационных кривых (точнее, прямых), определяющих статическую
анимацию.

Параметр Sample by определяет, как часто будут «пробиваться» ключи для выбранных
атрибутов, единица же означает, что ключи будут ставиться в каждом кадре. В случае
множественных столкновений лучше оставить этот параметр равным единице.
Нажмите Bake.
MAYA проиграет один раз анимацию на указанном отрезке времени и сконвертирует
траектории в анимационные кривые.
Возможно, что ключи не будут видны на выбранных объектах, так как они до сих пор
являются твердыми телами, которые следует немедленно удалить.
Выберите кегли и шар (если они еще не выбраны) и выполните Edit=>Delete All by Type=>Rigid
Bodies.
Чтобы окончательно «зачистить» динамику, удалите поле гравитации. (Дотошные умы
могут также удалить Rigid Body Solver.)
Теперь можно неистово проигрывать анимацию в любом направлении и с любой
скоростью.
Если зайти в Graph Editor, можно убедиться, что новоиспеченные анимационные кривые
выглядят слегка угрожающе и редактированию, вообще говоря, не подлежат.

1024 Книга Сергея Цыпцына


Вы можете попытаться выполнить в Graph Editor операции Simplify Curve или Resam-
ple Curve, чтобы сократить количество ключей на кривых, однако в нашем случае это занятие
практически безнадежное и, самое главное, совершенно бесполезное, так анимация полностью
готова и в редактировании не нуждается.
Если надо переделать или как-то поправить анимацию, достаточно открыть предварительно
сохраненную сцену с динамикой, произвести корректировки там и испечь анимацию заново.
Сохраните сцену (bowlingFinalBaked.ma).

Свойства полей
До сих пор мы использовали только одно поле гравитации и в основном работали со
свойствами твердых тел. При изучении свойств полей, естественно, проще всего применить
метод тыка, создавая новые поля, присоединяя их к объектам и исследуя результат воздействия.
Кроме того, вооружившись главным принципом изучения MAYA, нужно просто посмотреть на
атрибуты создаваемых полей и усвоить, за какие свойства полей эти атрибуты отвечают. Было
бы нерационально (да и неинтересно) перечислять здесь список всех имеющихся полей, нудно
описывая их свойства. Давайте сделаем небольшой пример, иллюстрирующий работу с полями и
обобщающий характерные свойства всех полей вообще.

Примечание. По поводу полей чаще всего задаются такие вопросы. Первый из них
- что такое поле Newton и чем оно отличается от гравитации или от поля Ra­
dial? Ответ: Ньютоновское поле похоже на точечную гравитацию, то есть тела
ускоряются не вдоль некоторого общего направления, а притягиваются к точке
- центру поля. Сила притяжения зависит от массы тел и от расстояния до центра
поля (хотя атрибут useMaxDistance no умолчанию выключен), а наличие атрибута
minDistance позволяет выключить поле с некоторой окрестности от его центра.

Второй вопрос - что такое поле Volume Axis? Ответ: Это некоторое обобщение всех возможных
полей, позволяющее задать объем, внутри (или снаружи) которого действует поле. Можно задавать
характер движения вокруг или вдоль оси, проходящей через этот объем, и некоторые другие
свойства. С помощью этого поля удобно, например, наполнять частицами некоторые области
пространства или делать «объемные» эффекты (типа атомного взрыва). Кстати, ограничивать
объемом действие поля можно для всех имеющихся полей с помощью атрибута volumeShape.

Игра «Место под солнцем»


Создайте три примитива.
Пусть это будут полигональные поверхности: сфера, цилиндр и тор.
Задайте для них небольшое количество subdivisions в Channel Box (например, восемь),
чтобы динамика считалась без рывков.
Растащите их в разные стороны от центра, выберите их и присоедините к ним радиальное поле:
Fields=>Radial.

Динамическая симуляция 1025


Объекты испуганно убегают от центра.
Как следует из вида иконки для поля Radial, на объекты воздействует центральное поле
сил, центр которого определяется translate-атрибутами объекта radialFieldl. Поглядим на атрибуты
поля в Channel Box.

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

Сила воздействия поля на объекты определяется атрибутом magnitude, но трюк состоит в


том, что, как правило, величина этого атрибута отрицательная. При этом направление действия
поля «выворачивается».

Установите magnitude для radialFieldl равным 5. И вы получите первый уровень игры


«место под солнцем».

Выберите все твердые тела и увеличьте bounciness до 0.9, чтобы игра стала более
веселой.
На выбранные тела навалите поле Vortex (вихрь), чтобы начать закручивать их вокруг
вертикальной оси (направление оси, очевидно, также задается атрибутами этого конкретного
поля).
Объекты постепенно раскручиваются и, под воздействием центробежной силы,
преодолевают притяжение к центру, определяемое радиальным полем. Попробуем ограничить
радиус действия поля vortexFieldl, так чтобы, выйдя за него, объекты попадали в объятия radial­
Fieldl и снова стремились к центру.

Выберите vortexFieldl и установите maxDistance=5. При этом надо проверить, включен ли


атрибут useMaxDistance. Поле типа Vortex как раз является одним из полей, у которых этот атрибут
выключен по умолчанию.

Включите его, то есть установите в on.

Теперь объекты будут раскручиваться только в окрестности начала координат, а на


«окраинах» на них будет действовать только притягивающее радиальное поле. С течением
времени, однако, объекты все равно накапливают энергию и вырываются даже за пределы его
зоны влияния. Посмотрим на зону влияния radialFieldl.

Выберите его и обратите внимание на параметр attenuation, который определяет характер


затухания силы воздействия поля по мере удаления от центра поля. Лучше всего визуально
представлять и редактировать радиус действия (maxDistance) и затухание (attenuation) при помощи
манипулятора, который можно включить, либо выбрав в Toolbox инструмент Show Manipulator Tool,
либо с помощью горячей клавиши «t».

На экране появляются голубые точки-слайдеры, позволяющие интерактивно изменять


значения обозначенных атрибутов (даже во время проигрывания анимации).

1026 Книга Сергея Цыпцына


Кривая, на которой визуально находится слайдер, для attenuation отображает график
затухания силы в зависимости от расстояния. Если attenuation=0, то сила поля не затухает и
одинакова во всей зоне влияния поля, определяемой атрибутом maxDistance. Если значение atten­
uation равно единице, то сила поля затухает линейно, а если больше единицы, то экспоненциально
и очень быстро.

Задайте attenuation=0 для radialField1, a rnaxDistance=100, чтобы объекты притягивались к


центру одинаково внутри сферы с радиусом 100.

А для vortexField1 задайте maxDistance=10.

Теперь траектории объектов напоминают движения планет (напомню, что radialField1.


magnitude=-5, a vortexField1.magnitude=5).

Разогнав «планеты» по кругу, вы можете выключить «раскрутку», установив vortexField1.


magnitude=0. (Например, поставив два ключа на magnitude).

С отличие от реальных планет, наши объекты будут постепенно ускоряться, пока не улетят в
открытый космос. Можно немного притормозить движение, добавив, например, силу сопротивления
среды (или, как говорят физики, «стабилизировать систему, добавив диссипации»).

Выберите все объекты и создайте поле сопротивления среды: Field=>Drag.


Его сила по умолчанию весьма невелика.
Увеличьте magnitude до 0.9.
Теперь объекты немного тормозятся и раскручиваются не так быстро.
Поиграйте с большими значениями magnitude (3-5), посмотрите как объекты чувствуют
себя помещенными в воду или другую вязкую жидкость.
Сохраните файл (gameLife.ma).

Дальнейшую игру можно продолжать бесконечно. Можно комбинировать поля в любом


количестве, независимо устанавливая для каждого из них силу и зону влияния, можно анимировать
их атрибуты, временно выключая (magnitude=0) и включая действие полей, можно перемещать
сами поля в пространстве, припарентивать их к объектам - в общем анимировать их как любые
другие объекты в MAYA.

На этом этапе можно сделать следующий вывод, обобщающий принципы работы с


динамикой твердых тел.

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

Динамическая симуляция 1027


другими объектами с помощью констрейнов или Set Driven Key.

Теперь необходимо рассмотреть дополнительные возможности управления движением


активных твердых тел.

Конструктивные констрейны для твердых тел


Как мы уже обсудили выше, активные твердые тела могут двигаться под влиянием
полей и соударений о другие тела. Однако неплохо бы уметь ставить и более интеллектуальные
ограничения на движение активных тел для конструирования целых динамических механизмов.
Такие ограничения традиционно называются констрейнами, и для твердых тел существует целый
набор таких механических элементов. (Не путайте их с анимационными констрейнами из меню
Constrain, предназначенными для связывания движений объектов, не относящихся к динамике!)
Например, чтобы сделать простейший маятник, достаточно создать для активного твердого тела
в поле гравитации констрейн типа Nail и переместить его в первом кадре в нужную точку подвеса
маятника.

Работа с констрейнами была уже немного проиллюстрирована в разделе «Колбасинг» в


начале этой главы. Констрейны, как правило, связывают между собой движение двух объектов
однако при создании констрейна для одного твердого тела второй конец констрейна остается
свободным и может быть проанимирован вручную произвольным образом. Это относится к пружинам
(Spring Constraint) и вращению вокруг оси (Hinge Constarint). Прибивание к точке (Nail Constraint)
требует выбора только одного объекта, а связывание «скобой» (Pin Constraint) создается только
для двух твердых тел.

Создание констрейнов - процесс интуитивно понятный, традиционно требующий


предварительного выбора объектов. Атрибуты констрейнов также немногочисленны и прозрачны
для понимания. Я приведу небольшой пример конструирования устройства, требующего
комбинирования констрейнов для достижения нужных механических свойств. Не забывайте что
позиция любого констрейна может быть проанимирована любыми доступными в MAYA способами.

Подвесной таран
Сконструируем таран, представляющий собой бревно, подвешенное на двух цепях.
Лучшее бревно - это полигональный цилиндр, лежащий на боку (rotateX=90, scaleY = 5)
Сделайте его, выберите и создайте поле гравитации: Field=>Gravity.
Нажмите Play.
Цилиндр норовит выпасть снизу из монитора.
Попытки создать два Nail Constraint для одного цилиндра приводят к неутешительному
выводу о том, что констрейн всегда крепится к твердому телу строго в центре масс. Редактируя
положение атрибутов centerOfMass, можно смещать точку крепления, однако иметь два центра
масс невозможно по определению, и поэтому подвесить цилиндр за две точки так просто не
получится.

1 028 Книга Сергея Цыпцына


Идея состоит в том, чтобы создать две точки крепления в виде небольших твердых тел,
которые можно прикрепить к бревну, например, при помощи Pin Constraint. А эти тела-крепления
можно потом подвесить в пространстве обычным Nail Constraint.
Создайте два полигональных кубика и расположите их ближе к краям цилиндра в местах
подвеса.

Превратите их в активные твердые тела: Soft/Rigid Bodies=>Create Active Rigid Body.


Пытливые умы тут же возопят: «А как же пятый закон динамики о непересечении твердых
тел!!». И будут правы. Но мы и не собираемся использовать эти кубики для столкновений с другими
телами и хотим сохранить их расположение относительно бревна.
Поэтому установите для них в Channel Box атрибут твердого тела collisions=off.
Это исключит два этих тела из расчета столкновений и отменит их способность сталкиваться
с другими телами.

Теперь прикрепим каждый кубик к цилиндру.

Выберите сначала первый кубик, затем цилиндр и выполните Soft/Rigid Bodies=>Create Pin
Constraint. Передвиньте центр созданного констрейна внутрь кубика.

Динамическая симуляция 1029


Проиграйте анимацию, посмотрите, как движутся объекты.
Теперь выберите кубик и «прибейте» его к «воздуху» с помощью Soft/Rigid Bodies=>Create
Nail Constraint.
Переместите центр нового констрейна вверх по вертикали.

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


должно неподвижно повиснуть на двух креплениях.
Осталось толкнуть его вдоль оси.
Задайте initialVelocityZ=5 для твердого тела на цилиндре. Таран готов.

Если хотите внезапно оборвать один из констрейнов, просто проанимируйте для него
изменение атрибута constrain с on на off в любом кадре.

1030 Книга Сергея Цыпцына


Твердые сабдивы
При попытке создать твердое тело из subdivision surfaces вы получите от ехидное замечание
и сообщение об ошибке.

// Warning: Skipping subdivSphere1Shape: Can't make a subdivision surface a rigid body. //


// Error: A NURBS or polygonal surface must be selected to create a rigid body. //

Последнее заявление означает, что только полигональные и NURBS-поверхности


заслуживают права называться твердыми телами.

Однако, пользуясь родственными связями между полигонами и сабдивами, попробуем


что-нибудь придумать.

Создайте полигональную плоскость, наклоните ее и превратите в пассивное твердое


тело, а затем создайте и приподнимите сабдив-сферу (Create=>Subdiv Primitives=>5phere). После
неудачных попыток превратить ее в активное твердое тело нажмите над ней правую кнопку мыши
и выберите в меню режим Polygon.

Вокруг сферы появился прокси-куб, а если включить в Outliner отображение shape-нод, то


можно увидеть, что под одной transform-нодой subdivSphere1 находятся две ноды, отвечающие за
полигональную и сабдив-поверхности. Теперь можно смело превращать объект в твердое тело.

Динамическая симуляция 1031


Если сфера выбрана, просто выполните Fields=>Gravity.
Это автоматически создаст твердое тело (из полигональной поверхности) и присоединит
к нему поле. Несмотря на замечания в Script Editor, MAYA создала активное твердое тело. Но! При
создании тела ведь использовалась полигональная форма, то есть куб. И поэтому сфера весело
скачет внутри твердого кубика, который и сталкивается с плоскостью.

Дальше будет несложно сделать так, чтобы полигональная прокси-сетка была «поближе»
к самой сабдив-поверхности. Для этого служит операция Subdiv Surfaces=>Collapse Hierarchy.
Выполните ее для выбранной сферы.

Возникнет копия сабдив-поверхности, у которой однако, нулевой уровень вершин


расположен там, где раньше был первый уровень. Поэтому при переходе в режим Polygon прокси-
сетка уже не просто куб, а сглаженный куб.

Если вас не устраивает эта сетка в качестве объекта, аппроксимирующего поверхность


твердого тела, вы можете сделать Collapse Hierarchy еще раз, и так до тех пор, пока не будете
полностью удовлетворены формой сетки.

Именно эту сетку в дальнейшем следует использовать для расчета столкновений. Для
наглядности можно в Outliner даже удалить сабдив-shape у новой поверхности, а оставшуюся
полигональную сетку превратить в твердое тело. После чего взять первоначальную сферу, удалить
с нее твердое тело и припарентить ее к новой сетке.

Итак, чтобы можно было «бросать» и «стукать» твердые тела, полученные из сабдивов,
надо сделать несколько действий.

1032 Книга Сергея Цыпцына


1. Выбрать сабдив и выполнить Subdiv Surfaces=>Collapse Hierarchy нужное количество раз
(без фанатизма), чтобы прокси-сетка нового объекта в режиме Polygon примерно повторяла форму
сабдив-поверхности.
2. Превратить новую поверхность в твердое тело, сделав это в режиме Polygon. После
этого можно даже удалить у него сабдив-shape.
3. Оригинальную поверхность нужно припарентить к твердому телу, чтобы она двигалась
вместе с ним.

Просчет ненужных столкновений


Львиная доля времени во время просчета динамики тратится на просчет столкновений
между телами. В тех случаях, когда характерно только столкновение множества небольших
объектов с крупной преградой, а взаимодействиями между самими объектами можно пренебречь,
можно драматически ускорить просчет и увеличить в разы количество обсчитываемых объектов,
отменив необходимость учитывать взаимные столкновения твердых тел друг с другом. Как раз на
эту тему будет следующий пример.

Искусство бить посуду


Посмотрим теперь, как «расколотить» твердое тело на некоторое количество осколков.
Если вас искушает операция Effects=>Shatter, можете самостоятельно поиграть с ней, чтобы
убедиться, что предсказуемого эффекта от нее трудно добиться. А задав число осколков больше
сорока, вы наверняка отправите MAYA в отпуск за свой счет. Лучший способ распилить объект на
куски - это сделать осколки руками. Сколько надо и там, где надо. Неоценимую помощь здесь
окажут инструмент Paint Selection Tool и операция Edit Polygons=>Extract (не забудьте только
включить Polygon=>Tool Options=>Keep Faces Together).

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

Посмотрим, как ее можно решить на практике. Если вам лень делать посуду и уж тем
более пилить ее на куски, откройте файл teapotCracked.ma и убедитесь, что в нем находятся
несколько полигональных осколков, чайника плотно прилегающих друг к другу.

Выберите плоскость и превратите ее в пассивное твердое тело.


Затем выберите все осколки и превратите их в активные твердые тела.
Только не нажимайте кнопку Play, иначе MAYA уйдет в кому: ведь мы нарушили пятый закон
динамики о несоприкасаемости твердых тел в первом кадре. Но мы не хотим обтачивать осколки
и обеспечивать зазор между ними. Вместо этого разрешим им проникать друг в друга, а точнее,
отключим у них способность сталкиваться друг с другом.
Для этого у всех выбранных осколков в Channel Box установите для твердых тел атрибут
collisions в off, после чего эти тела перестанут реагировать на столкновения.

Динамическая симуляция 1033


Теперь для всех осколков можно также установить начальную скорость initialVelocityY=-
10, чтобы они бодро рухнули на плоскость.
Однако избавив осколки от необходимости сталкиваться друг с другом мы также запретили
им сталкиваться с любыми твердыми телами вообще! Чтобы исправить это недоразумение и
придать плоскости эксклюзивное право отбивать любые удары (даже от объектов с выключенным
атрибутом collisions) воспользуемся секретным атрибутом (а точнее, секретным значением) col-
lisionLayer. По умолчанию сталкиваются между собой только те твердые тела, у которых значение
атрибута collisionLayer совпадает. Тела, у которых он имеет разные значения, просто игнорируют
друг друга. Однако существует еще и секретнейшее значение этого атрибута, равное минус
единице, которое заставляет объект сталкиваться со всеми твердыми телами, вне зависимости от
значений их атрибутов collisions и collisionLayer.
Выберите плоскость, и для твердого тела установите collisionLayer=-1.
После этого осколки весело отскочат от плоскости и улетят за горизонт. Если выбрать их и
создать поле гравитации, это поможет уронить их на плоскость после раскалывания.

Если некоторые осколки проваливаются сквозь поверхность или застревают в ней, то


откройте Solvers=>Rigid Body Solver и установите Collision Tolerance = 0.002, чтобы уменьшить
допуск, внутри которого тела считаются столкнувшимися.
Сохраните файл (teapotCrackedDynamics.ma).
Усовершенствуем немного эту сцену. Пытливые умы наверняка захотят бросать на плоскость
не расколотый, а красивый и модный чайник, а в момент удара производить подмену.
Импортируйте в сцену небитый чайник из файла teapot.mа.
File=>lmport...
В первом кадре он должен располагаться в том же месте, что и осколки. Идея состоит в
том, чтобы сначала сделать осколки пассивными твердыми телами и припарентить их к целому
чайнику. Целый чайник можно швырнуть на плоскость как активное твердое тело, а в момент
удара (или чуть раньше) спрятать его и сделать осколки активными твердыми телами (поставив
ключи), надеясь на то, что они после этого заживут своей активной жизнью.
Выберите целый чайник (все дальнейшие операции выбора удобно делать в Outliner) и превратите
его в активное твердое тело.

Задайте ему небольшую начальную скорость initialVelocityY=-5 и убедитесь, что он падает


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

Не забывайте, что у всех осколков выключен атрибут collisions, поэтому никаких «залипаний»
между целым чайником и осколками не происходит.
Теперь аккуратно выберите все осколки и установите в Channel Box для твердых тел
атрибут active в off. Это сделает их пассивными твердыми телами. Обнулите у них начальную
скорость, чтобы они были совсем пассивными: initialVelocityY =0.
В Outliner или Hypergraph припарентите все осколки к целому чайнику (выделите,

1034 Книга Сергея Цыпцына


перетащите и бросьте их всех на объект teapot средней кнопкой мыши). После этого они должны
двигаться вместе с ним.

Осталось выбрать момент и включить атрибут active для осколков.


Выберите все осколки, проиграйте потихонечку до момента столкновения и поставьте на
атрибут active два ключа для всех (!) твердых тел/осколков: первый active=off за один кадр до
удара, а второй active=on в следующем кадре.

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

Динамическая симуляция 1035


Сохраните файл (teapotCrackedDynamicsSwitch.ma)

Секретные атрибуты и слежение за ударами


Предположим, что мы хотим, чтобы в момент удара чайника о плоскость у него вылетало
из носа возмущенное облако пара. «Ничего сложного! Эмиттер в нос и пару-тройку ключей
в момент удара на атрибут rate», - воскликнут недостаточно пытливые умы. Однако любители
почитать документацию могут предположить, что можно найти такой атрибут у твердого тела,
который отвечал бы за состояние «стукнутости» и позволял бы отслеживать момент удара. Имея
такую информацию, мы могли бы написать несложный expression, который бы «включал» источник
частиц в момент удара и выключал бы его потом.

Для начала сделаем источник пара.


Выполните Particles=>Create Emitter.
В Channel Box задайте для него следующие атрибуты:
emitterType=Directional;
directionX=0;
directionY=1;
spread=0.3;
speed=5.

Это создаст источник частиц, стреляющий вертикально вверх с небольшим углом


распыления. Переместите источник в нос чайника (в первом кадре!), перетащите и бросьте его на
чайник средней кнопкой в Outliner, припарентив его, таким образом, к чайнику.

Теперь из носа падающего чайника непрерывно идетусловный пар. Можно теперь установить
в ноль значение атрибута rate для эмиттера и попытаться включить его только в момент удара.
Пытливые умы уже, конечно, слазили в раздел документации, предназначенный для взрослых
мальчиков, то есть в описание ноды типа rigidBody, и нашли, что у нее есть атрибут contactCount,
отвечающий за количество столкновений в текущем кадре. Иначе говоря, у любого твердого тела
(пассивного и активного) есть атрибут, имеющий, как правило, нулевое значение, но как только
в некотором кадре тело соударяется с другим объектом, в этот атрибут записывается количество
соударений именно (и только) в этом кадре. Если десять чайников синхронно упадут на плоскость,
то для пассивного твердого тела на плоскости в момент удара в атрибут contactCount запишется
значение 10. В тех кадрах, где тело ни с кем не контактирует, атрибут снова принимает нулевое
значение.

Теперь надо выбрать чайник и посмотреть, как называется твердое тело для него (rigid-

1036 Книга Сергея Цыпцына


Body 17, в моем случае).

Откройте Windows=>Animation Editors=>Expression Editor (еще проще сделать это, выбрав


любой атрибут в Channel Box, и по правой кнопке мыши выбрать в меню Expressions...).
Создайте новый expression следующего содержания:

if(rigidBody17.contactCount>0) emitter1.rate=1000;
else emitter1.rate=0;

Дословно так переводится на человеческий язык: «Если в данном кадре количество


соударений больше нуля, то включить источник (emitter1 - это точное имя источника частиц) на
полную мощность, а в противном случае - выключить его.».

Однако если проиграть анимацию, ничего не происходит. Оказывается, надо включить


секретную галку, для того, чтобы MAYA начала отслеживать и накапливать информацию о
столкновениях. Эта галка располагается в атрибутах для Rigid Body Solver.
Откройте Solvers=>Rigid Body Solver и в разделе Rigid Solver States включите галку Contact Date.
После этого MAYA начнет собирать информацию о контактах твердых тел и обновлять у них
атрибуты contactCount. А чайник начнет выбрасывать возмущенные струйки пара в момент удара
о плоскость. Если чайник улетает в небо, присоедините его к гравитации и увеличьте упругость
отскока: bounciness=1).

С помощью атрибута contactCount и несложного expression можно производить в момент


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

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

Пытливые умы, однако, быстро сообразят, что вместо ключей, можно использовать
аналогичный expression для переключения статуса активности осколков точно в момент удара,
после чего чайник будет раскалываться на куски при столкновении с любым препятствием. Надо
только не забыть про то, что в первом кадре осколки обязаны быть пассивными.
Выберите в первом кадре все осколки и удалите для твердых тел в Channel Box ключи с атрибута
active.

Для наглядности создайте еще один expression следующего вида для любого осколка,
например, для rigidBody1:

if(frame==1) rigidBody1 .active=0;


if (rigidBody1 7.contactCount>0) rigidBody1.active=1;

Динамическая симуляция 1037


Или, в переводе с марсианского: «Если кадр первый, сделать осколок (rigid Body1) пассивным.
Если чайник (rigidBody17) ударился обо что-то, сделать осколок (rigidBody1) активным.».
Внимательно следите за именами твердых тел: я намеренно оставил имена по умолчанию,
так как при автоматическом создании твердых тел никто обычно не меняет имена нод типа rigid-
Body.
Теперь в момент удара один осколок отваливается от чайника, а остальные продолжают
следовать за ним. Если вас раздражает этот источник частиц, можете его удалить, он был создан
только в учебных целях.

Дальше все зависит от вашего темперамента. Если не лень, можете написать expression типа:

if(frame==1) {
rigidBody1.active=0; polySurface9,visibility=0;
rigidBody2.active=0; polySurface15.visibility=0;
rigidBody3.active=0; polySurface21.visibility=0;
// ....
teapot_Snape.visibility=1;
}

if (rigidBody1 7. contactCount>0) {
rigidBody1 .active=1; polySurface9.visibility=1;
rigidBody2.active=1; polySurfacel 5.visibUity=1;
rigidBody3.active=1; polySurface21.visibility=1;
// ...
teapot_Shape.visibility=0;
}

Такой expression будет переключать активность у всех осколков, а заодно показывать их на


экране только в момент удара, одновременно пряча чайник (файл teapotCrackedDynamicsSwitch-
Expression.ma).

Если же написание длинного expression вызывает у вас отвращение, можете просто открыть
Connection Editor и соединить атрибут active осколка, проанимированного с помощью expression, со
всеми атрибутами active остальных осколков. (Выбрать ноды rigidBody можно в Outliner, включив
Display=>5hapes.)

1038 Книга Сергея Цыпцына


А заодно можно соединить и атрибуты visibility у соответствующих объектов.

Такой файл сохранен как teapotCrackedDynamicsSwitchConnection.ma.

ДЛЯ взрослых. Взрослые мальчики, читающие документацию, конечно же обнаружили рядом


с атрибутом contactCount описание атрибута contactPosition, содержащего массив координат для
всех столкновений в текущем кадре. При попытке задействовать его в expression, однако, могут
возникнуть проблемы, так как необходимо учитывать, что это не просто три числа для координат
столкновения, а набор из нескольких трехмерных координат, поэтому необходимо указывать
индекс массива, то есть номер столкновения. Как правило, нас интересует первое столкновение
в кадре, то есть элемент массива с нулевым индексом.

Например, если вы хотите в предыдущем примере с непрочным чайником испустить


некоторое количество частиц в момент удара точно в месте соприкосновения чайника с плоскостью,
надо написать следующий expression:

Динамическая симуляция 1039


if(rigidBody17.contactCount) {
vector $col = <<rigidBody17.contactPosition[0].contactX,
rigidBody17.contactPosition[0].contactY,
rigidBody 17.contactPosition[0].contactZ >>;
int $i;
int $emitCount = 10;
string $objectName="partideObj";
string SemitCmd = "emit -o " + $objectName;
string $emitCmd1 = " -at velocity ";
for( $i = 0; $i < $emitCount; $i++ ) {
SemitCmd += " -pos " + $col;
vector $vel = sphrand(5);
SemitCmd 1 += " -w " + $vel;
} //endfor

eval( SemitCmd + SemitCmdl );

} //endif

Для испускания частиц я использовал функцию emit, которая позволяет создать некоторое
количество частиц без всяких источников. Не забудьте только предварительно создать пустой
объект из частиц particleObj, который будет содержать испускаемые частицы. Это можно сделать,
просто выполнив команду "particle -n particleObj".

Идея о том, чтобы в момент столкновения сдвигать источник точно в место столкновения
и включать его там, не является удачной. Попробуйте и убедитесь сами, почему. В этом случае
expression будет выглядеть следующим образом:

if(rigidBody17.contactCount) {
emitter2.tx = rigidBody17.contactPosition[0].contactX;
emitter2.tx = rigidBody17.contactPosition[0].contactY;
emitter2.tx = rigidBody17.contactPosition[0].contactZ;
emitter2.rate=1000;
}
else emitter2.rate=0;

Уловки и трюки при работе с динамикой


Далее я хочу сформулировать некоторое количество уловок, советов и комментариев
по поводу работы с динамикой твердых тел. В принципе сформулированных законов динамики
достаточно для эффективной работы. Главное: надо помнить, что взаимодействие конкретного
тела и поля устанавливается абсолютно независимо от других полей и тел и что поля могут быть
проанимированы точно так же, как и другие объекты в MAYA. Сначала некоторое количество общих
советов о том, как работать с твердыми телами.

Поведение, а не траектория
Когда вы пытаетесь заставить двигаться в нужном направлении систему твердых тел,
старайтесь думать о поведении системы, а не о конкретных траекториях. В отличие от ключевой
анимации, вы воздействуете на траекторию твердых тел при помощи посредников: полей, свойств,
ударов или констрейнов. Поэтому ваше управление движением носит характер инструкций типа
«лететь в нужном направлении» или «вести себя определенным образом». Если вы пытаетесь
обеспечить точное попадание в нужное место в определенный момент времени, значит вы выбрали
не тот инструмент (я имею в виду динамику). Например, если вы пытаетесь попасть с помощью
динамики мячом в баскетбольное кольцо, вас ждет длительная возня с начальной скоростью и

1040 Книга Сергея Цыпцына


направлением броска (если вы, конечно, не прочитали предварительно учебник по баллистике).
Проще либо бросить мяч назад из кольца, либо нарисовать вручную его траекторию и попасть в
кольцо с первого раза, анимируя мяч по пути.

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

Твердые тела всегда остаются твердыми


Если вы сделаете анимацию формы активного твердого тела прямо во время движения
(например, с помощью blendshape, lattice или просто анимируя вершины), вы увидите, что тело
«фиксирует» свою форму в первом кадре и для расчета столкновения использует именно эту
форму, а не полученную в результате анимации. Поэтому не получится «честно» деформировать
твердое тело в момент удара. Применяйте в таких случаях уже приведенный выше совет: пусть за
столкновение отвечает невидимое твердое тело, а за деформацию - привязанная к нему обычная
проанимированная поверхность. Конечно, можно пытаться колдовать с назначением нового
начального положения при каждом ударе с помощью expression, однако руками все получится
гораздо выразительнее. Кроме того, помните о том, что тела, сильно деформирующиеся при
ударе, как правило, не сильно отскакивают от препятствия.

Соблюдайте скоростной режим


Еще раз повторю уже обозначенный выше совет: контролируйте скорость. Наличие высоких
скоростей делает динамическую систему «жесткой» и трудной для численного интегрирования.
Если объекты начинают пролетать сквозь друг друга, уменьшите атрибут Step Size для Rigid Body
Solver. (Предварительно, конечно, проверив, что скорость воспроизведения анимации установлена
в Play every frame).

Используйте альтернативную динамику


Если в процессе анимации, например, цепи с помощью твердых тел количество констрейнов
перевалило за десять, и MAYA все больше «уходит в себя» во время обсчета столкновений, то
расширьте сознание и посмотрите, какие альтернативные методы можно использовать в том или
ином случае.

Для анимации цепей и других «висячих» механизмов хорошо подходит динамика волос
или одежды, которая выдаст необходимое движение, а части механизма нужно будет должным
образом закрепить на деформирующейся кривой или поверхности.

Россыпи твердых тел с количеством более ста быстро доведут MAYA до истерики, так что в
этом случае используйте динамику частиц и технологию инстансирования (подстановки) объектов
в частицы.

Почаще испекайтесь
Если вас полностью устроил результат динамической симуляции, переведите ее в
ключи, удалите все тела, сохраните сцену и забудьте про настройки динамики. Это позволит
вам сосредоточиться на последующих задачах без необходимости прилежно выполнять законы
динамики. Можно также использовать кэширование с помощью операций Solvers=>Memory
Caching=>Enable/Disable/Delete.

Если вдруг после операции Bake обнаружились проблемы - например, объекты движутся
совсем не так, как во время обычного воспроизведения, вылечить это поможет включение

Динамическая симуляция 1041


кэширования движения выбранных твердых жестких тел с помощью операции Solvers=>Memory
Caching=>Enable. После одноразовой симуляции (проиграйте один раз сцену), можно начинать
делать Bake. Также кэширование можно включать/выключать с помощью атрибута Cache Data для
ноды Ridid Body Solver в Attribute Editor.

Кстати, для того чтобы после операции Bake снова сделать твердые тела динамическими,
а не анимированными по ключам, нужно удалить для них все анимационные кривые и выполнить
операцию Soft/Rigid Bodies=>Break Rigid Body Connections.

Небольшая история из жизни активных твердых тел. В далеком, историческом уже 1985
году мы с моим другом Парфентием поехали на прогулку в музей-усадьбу Архангельское. Поехали,
естественно, не одни. (Да и разве можно представить себе двух разгильдяев с третьего курса
университета, добровольно отправляющихся в музей-усадьбу?). Дело в том, что «на картошке»
(для недряхлых читателей: это - культовый феномен той поры, а не название дискотеки) мой
друг Парфентий познакомился с белокурой девушкой, и ему надо было срочно произвести на
нее впечатление. Дабы не бросать друга на произвол романтических отношений, я призвал на
помощь свою хорошую знакомую, и мы отправились производить убийственное впечатление
на ничего не подозревавшую блондинку. По такому случаю, мой друг Парфентий надел свой
умопомрачительный коричневый плащ и сделал очень приветливое лицо. Была поздняя осень
и будний день. Мы все четверо долго тряслись в полупустом рейсовом автобусе, и, наконец,
почти достигли цели. Цель была близка, но не давалась в руки, а точнее, в ноги. Огромные
ворота, предваряющие вход с усадьбу, оказались наглухо закрыты, и никаких признаков жизни
в зоне видимости не наблюдалось. За решетками забора призывно и романтично потряхивали
остатками листвы многовековые деревья, также жаждущие произвести впечатление на белокурую
бестию, но мы, к сожалению, находились по другую сторону жизни, где веселые проезжающие
камазики приветливо пшикали в нас выхлопными газами и норовили прижать поближе к забору.
Было принято решение действовать по правилу правой руки, то есть идти вправо вдоль забора,
ожидая либо открытой калитки, либо дырки в заборе, либо милостей судьбы. Музей-усадьба,
однако, оказался чудовищно велик, практически необъятен. И, что самое печальное, обнесен
бесконечным трехметровым забором из металлических прутьев с острыми концами. Когда мы
практически потеряли надежду, а блондинка заметно занервничала, мы заметили участок забора,
украшенный неопределенного вида ромбовидными металлическими украшениями. Они позволяли
практически без труда влезть на забор и также с него спуститься. Романтические кущи с той
стороны продолжали нас манить, и мы весело и по очереди преодолели преграду. Последним же
преодолевал ее мой друг Парфентий. Забравшись наверх, он не захотел бездарно и невыразительно
слезать вниз, а помня о целевом назначении поездки, легко и непринужденно прыгнул с высоты
трех метров. Однако шикарный коричневый плащ, не пожелав быть элементом спортивной формы,
коварно зацепился за острые концы прутьев забора. Мой друг рухнул вниз, как твердое тело, у
которого неожиданно включили все констрейны. Плащ оказался на удивление прочен, и мой друг
повис на заборе, запутавшийся в одежде и распятый в собственных рукавах. Там он жалобно и
возмущенно бился, пока мы, превозмогая приступы хохота и сострадая ближнему, не подползли к
нему, то и дело сгибаясь пополам от смеха, и не освободили его из объятий собственного плаща.
Последний был разорван ровно на две половины, а приветливое лицо Парфентия утратило отчего-
то свою непроницательность. Далее, нам все-таки удалось прогуляться по музею-усадьбе, и хотя
позднеосенняя температура задевала за ноль, мой друг, непринужденно перекинув половинки
плаща через руку, проявлял чудеса морозоустойчивости. Центральная же фигура всей этой
истории, ничего не подозревающая блондинка, была так поражена всем произошедшим, что
через некоторое время вышла замуж за моего друга Парфентия, и до сих пор находится под
впечатлением динамики твердых тел все эти годы.

1042 Книга Сергея Цыпцына


Динамика частиц
Системы частиц используются с компьютерной графике с тех самых незапамятных времен,
когда трудолюбивые аниматоры, прокладывавшие траектории для пятисот тысяч капель воды в
очередном спецэффекте, не взбунтовались и не подняли восстание. Они захватили нескольких
программистов, которые, под угрозой дисквалификации и перевода в заливщики, придумали,
наконец, и написали первую программу для анимации систем частиц. С тех пор работа с системами
частиц в любых 3D-пакетах имеет примерно общую идеологию, основанную на массовом поведении
объектов и законах управления системой в целом, без рассмотрения индивидуальных движений
каждого участника системы. При работе с частицами основное внимание уделяется тому, как
система себя ведет целиком и какое впечатление (или какой эффект) это поведение производит.

Применения систем частиц


Частицы используются для производства самых разных спецэффектов. Прежде всего,
это всяческая пиротехника: фейерверки, дымы, взрывы и прочие разрушительные действия.
Отдельно стоит задача изготовления огня различного вида. Природные явления - например,
дождь, снег, всяческие бураны, метели и другие осадки - также делаются с привлечением
частиц. Сюда же относятся атмосферные явления, такие как смерчи, молнии, облака. Далее
можно упомянуть пыль и различные сыпучие субстанции. Особняком стоит симуляция движения
жидкостей: это достаточно сложная задача, которая распадается на несколько различных типов
анимации. Например, брызги, движение водной поверхности, вытекание жидкости из сосуда и
другие. Некоторые из этих подзадач удобно решать с помощью динамики частиц, для других типов
движения жидкости удобно использовать модуль Fluid Effects или специализированные пакеты
типа RealFlow (смотрите на www.nextlimit.com).

Более причудливые применения частиц встречаются в виде концепции мягких тел (Soft
Body), когда при помощи частиц производится деформация поверхностей. Анимация остаточных
движений также может быть смоделирована с помощью системы частиц и мягких тел.

Отдельный вид использования частиц - это подстановка вместо них геометрических объектов
и симуляция культурно-массовых мероприятий. Такая подстановка, называемая инстансированием,
может быть использована для анимации косяков рыб, стай птиц, роя пчел или первомайской
демонстрации, когда объекты, имеющие собственную независимую анимацию, следуют вдоль
траекторий, определяемых движением частиц. Вопрос взаимодействия или столкновения объектов
в этом случае остается открытым и отдается на откуп более специализированным системам
анимации массовых беспорядков типа Massive.

Частицы такжеиспользуются вразличныхсистемах визуализации: для нефотореалистического


рендеринга (например, для имитация живописи), для рендеринга объемов (в частности,
медицинская тематика или научная визуализация: погода, столкновение галактик и проч.).

Особенности работы с частицами


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

Знание, мягко говоря, основ многослойного композитинга также абсолютно необходимо,


так как практически все спецэффекты «доводятся» в 2D, а иногда и полностью производятся там
же. Плотность и объем частиц часто увеличиваются за счет складывания нескольких слоев с
разумным количеством частиц, вместо рендеринга одного прохода с безумным числом частиц.

Знание физики, а точнее теоретической механики и векторной алгебры, совершенно


необходимо для непринужденного написания эффективных expressions, управляющих скоростью

Анимация 1045
и ускорением частиц. Кроме того, желательно иметь пытливый ум, склонный к экспериментам
и всяческим издевательствам над окружающей природой. С помощью динамики частиц можно
направить такие склонности в созидательное русло.

При создании разного рода эффектов приходится постоянно балансировать между двумя
полюсами. С одной стороны, реалистичность движения и соответствие физическим законам,
с другой - производимое впечатление и соответствие художественному замыслу. Приоритет,
естественно, имеет последний, поэтому, увлекшись игрой с полями и программированием
реальных взаимодействий, не старайтесь сделать все «по-честному», как в учебнике физики.
Легкое преувеличение физических законов, как правило, идет на пользу любому эффекту.

Природа частиц
Кстати, в соответствии с принципами корпускулярно-волнового дуализма, всё вокруг нас
суть частицы, да и сами мы из них состоим.

Поскольку вы уже знакомы с динамикой твердых тел, можно сказать, что частицы это
крошечные твердые тела, настолько мелкие, что у них отсутствует поверхность. Иначе говоря,
это бесконечно малые, но тяжелые точки. Из отсутствия поверхности следует их неспособность
сталкиваться друг с другом, то есть частицы по умолчанию «не чувствуют» друг друга, даже
находясь в одной точке пространства - они «проникают», или «пролетают», друг сквозь друга.
Именно отсутствие взаимных столкновений и, как следствие, необходимости эти столкновения
просчитывать делает возможным интерактивную анимацию тысяч частиц. Для эксперимента
можете создать сотню активных твердотельных шариков в виде горизонтальной сетки 10x10 и
напустить на них поле Radial с отрицательным значением magnitude. В момент столкновения
всех шаров MAYA попросится в небольшой отпуск, и дальнейшую анимацию нельзя будет назвать
интерактивной.

Однако, если у всех шаров выключить способность к столкновениям (атрибут collisions=off),


анимация будет проигрываться весьма бодро.

1046 Книга Сергея Цыпцына


Аналогично твердым телам, частицы подчиняются первым четырем законам динамики,
сформулированным выше. На них точно так же действуют поля, которые тоже присоединяются к
частицам в Dynamic Relationships.

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


упругостью. При этом они могут умирать, раскалываться на куски (то есть, на самих себя) или
испускать новые частицы.

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

В отличие от твердых тел, частицы имеют не только начальную скорость, но и редактируемые


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

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

Они имеют собственное время жизни и ещё массу интересных свойств. Речь о них пойдет ниже.

Работу с частицами можно условно разбить на три этапа: создание системы частиц, анимация
и визуализация. (И никаких скелетонов!). Начнем с создания нужного количества частиц.

Создание системы частиц

Существует множество способов для создания частиц.

Прежде всего, их можно нарисовать вручную при помощи Particles=>Particle Tool. Это,
конечно, довольно экзотический метод, позволяющий вам по умолчанию просто создавать
частицы на экране, аналогично процессу рисования кривых, и завершать создание объекта из
частиц нажатием Enter. Объект типа particle состоит из компонент, являющихся индивидуальными
частицами, так же, как кривая или поверхность состоят из своих контрольных вершин. В Op­
tion Box для Particles=>Particle Tool есть настройки, позволяющие создавать сразу сетку или даже
куб из частиц, два раза щелкнув в окне, обозначая диагональ сетки, и нажав Enter. Это бывает
полезно, когда надо уложить частицы на плоскость ровным слоем.

Динамика частиц 1047


Однако чаще всего частицы не создаются вручную, а испускаются из какого-нибудь
источника. Источником может быть точка в пространстве, называемая на жаргоне эмиттером (emit­
ter). Источником частиц также могут быть точки кривой или поверхности, а точнее, компоненты
объекта. Поэтому сами частицы тоже могут быть источниками других частиц. Частицы можно
испускать прямо с поверхности или из кривой. Можно испускать их в момент столкновения частиц
с препятствиями. И, наконец, их можно создавать в expression или скриптах, пользуясь функцией
emit. Разберем концепцию испускания более подробно.

Совет. Если вы хотите создать сетку из частиц, точно повторяющую вершины


заданной поверхности, превратите поверхность в мягкое тело с опциями по
умолчанию (Soft/Rigid Body=>Create Soft Body). Затем, выбрав созданные частицы,
выполните операцию unparent, а на исходной поверхности удалите историю (или
удалите в Hypergraph нужную входящую связь для shape-ноды поверхности).

Источники частиц

Самый простой источник частиц - точечный эмиттер.

Создайте его, выполнив Particles=>Create Emitter.


Все параметры, задаваемые через Option Box, можно отредактировать после создания в
Channel Box или Attribute Editor.

Основными атрибутами, определяющими свойства источника, являются тип (emitterType),


напор (rate) и скорость испускания (speed).

Примечание. Иногда MAYA несколько «глючит» и вместо точечного источника


создает объемный в виде кубика. Это «лечится» открытием Option Box для
Particles=>Create Emitter и нажатием кнопки Create.

По умолчанию создается точечный источник, «стреляющий» во все стороны (тип Omni).


Тип источника задается атрибутом emitterType, и он может быть установлен в Directional, Omni
или Volume.

Тип Volume превращает точечный источник в объемный и позволяет с помощью атрибута


volumeShape задавать несколько примитивных форм, из объема которых будут испускаться
частицы. Атрибуты, следующие за volumeShape в Channel Box, позволяют задать дополнительные
параметры испускания частиц из объема.

1048 Книга Сергея Цыпцына


Задайте тип созданного источника как Directional, и направьте струю вверх, установив
атрибуты direction в (0, 1, 0).

Совет. Не обязательно устанавливать направление испускания с помощью


атрибутов direction. Можно оставить их значения по умолчанию, а реальное
направление испускания настраивать, просто вращая источник как обычный
объект.

Чтобы распылить струю, установите атрибут spread, отвечающий за угол распыления, в 0.3
(единица соответствует полному раскрытию, или 180 градусам).

Совет. Настраивать основные атрибуты источника удобно с помощью


манипулятора (Manipulator Tool), вызываемого нажатием клавиши t.

Примечание. Очень важно понимать, что при выполнении операции Create Emit­
ter, создаются два объекта: сам источник и частицы, вылетающие из него. Это
следует хотя бы из Script Editor, выдающего следующую информацию:
emitter -pos 0 0 0 -type omni -r 100 . . . ;
// Result: emitter1 //
particle;
// Result: particle1 particleShape1 //
connectDynamic -em emitterl particlel;

Дело в том, что частицы, испускаемые эмиттером, не принадлежат ему и не входят в


состав его компонент, а представляют собой полностью независимый объект. Однако после
создания источника и частиц, последние присоединяются к нему, точно так же, как твердые тела
присоединяются к полям. Вы можете проверить это в Dynamic Relationships, включая и выключая
это присоединение. Не забудьте только включить наверху опцию Emitters или Аll.

Динамика частиц 1049


Отсюда следует очень важный вывод, расширяющий сознание: один источник, может
испускать сразу несколько систем частиц, каждая из которых обладает разными свойствами и
может быть присоединена к своим полям. И наоборот: десять разных источников могут испускать
одинаковые частицы, принадлежащие одному объекту типа particle. Если ваше сознание
недостаточно расширено, чтобы осмыслить эти факты, мы вернемся к этому позже.

Выберите частицы и выполните Fields=>Gravity.

Это автоматически присоединит созданное поле к выбранным частицам. Чтобы струя все-
таки била вверх, надо увеличить скорость испускания частиц из источника (или уменьшить силу
гравитации).

Выберите эмиттер и задайте значение атрибута speed равным 10, а также уменьшите spread
до 0.1.
Задайте rate=240.
Атрибут rate определяет, сколько частиц вылетает из источника в течение одной секунды.
Поэтому, если в общих установках у вас стоит скорость анимации, равная 24 кадрам в секунду, то
при напоре 240 частиц в секунду в каждом кадре будет появляться 10 новых частиц.

1050 Книга Сергея Цыпцына


Столкновения с препятствиями
Быстро проверим взаимодействие частиц с полями и способность ударяться о
препятствия.

Создайте NURBS-конус.
Сделайте из него «тарелку» (scale = 5, 0.2, 5) и опустите его немного вниз (translateY=-1).
Частицы пролетают сквозь него без малейших сотрясений.

Внимание! Не надо делать из препятствия пассивное твердое тело, чтобы


частицы начали от него отскакивать. Активное тело тоже не надо делать.

Для частиц существует свой вид «зубной пасты», которой надо покрыть поверхность,
чтобы она затвердела и стала отталкивать частицы. Столкновения частиц с поверхностью не имеют
никакого отношения к динамике твердых тел, и расчет их производится совершенно независимо,
их собственным Решателем (Solver).

Выберите сначала частицы, затем конус и выполните Particles=>Make Collide.


На конусе появится дополнительная нода geoConnector, а частицы начнут отскакивать от
поверхности.
Чтобы уменьшить упругость отскока, установите для geoConnector атрибут resilience
равным 0.3 (аналог bounciness для твердых тел) и добавьте немного трения: friction=0.2.
Если нода geoConnector не появляется в Channel Box, например, после удаления истории,
её всегда можно разыскать в Attribute Editor для выбранной поверхности.

Теперь частицы стекают с поверхности. А нода geoConnector - своеобразный отвердитель


поверхности и позволяет частицам отскакивать от объекта.

Совет. Если установить атрибут resilience в отрицательное значение, это


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

Ещё одно отличие от твердых тел состоит в том, что частицам совершенно все равно, где
у поверхности нормаль. Они будут одинаково успешно отскакивать от обеих сторон поверхности.

Примечание. Глазастые умы, конечно, заметят (особенно на виде сверху), что


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

Динамика частиц 1051


Дело в том, что NURBS-поверхности (как и в случае твердых тел) для расчета столкновений
разбиваются на некоторое количество полигонов. Это количество регулируется атрибутом tessela-
tionFactor ноды geoConnector, по умолчанию он равен 200.

Установите tesselationFactor=700, чтобы снизить «полосатость».


Сохраните файл (fontain.ma). Он нам ещё пригодится.

Испускание частиц с поверхностей и кривых


Чтобы быстро создавать объемы частиц в нужном месте или «облеплять» объект частицами,
удобно испускать частицы с поверхностей или кривых (дальше будем для простоты говорить о
поверхностях). В этом случае источником частиц становится как бы сама поверхность. (Реально,
конечно, создается объект типа emitter, который просто имеет дополнительные соединения с
поверхностью, через которые он получает информацию о геометрической форме объекта и
испускает частицы точно с поверхности. Исследовать эти соединения вы можете в Hypergraph.)
Удобно исследовать поверхностное испускание на примере плоскости. Если у вас отвращение
к плоским объектам, возьмите любую модель (в случае сабдивов, можно применять трюки,
описанные для динамики твердых тел).

Создайте любую плоскость.


Выберите ее, растяните немного и выполните Particles=>Emit from Object.
Частицы начинают испускаться, но не с поверхности, а из точек-компонент поверхности!
Это происходит от того, что по умолчанию тип источника установлен в Omni. Таким образом,
если для поверхностного эмиттера выбран тип Omni или Directional, источниками становятся
компоненты поверхности.

1052 Книга Сергея Цыпцына


Установите emitterType=Surface для созданного источника (он, кстати, прячется в Outliner
«внутри» поверхности).
Теперь частицы испускаются равномерно со всей плоскости. Для поверхностных источников
существует несколько специфических атрибутов, определяющих направление и плотность
испускания по отношению к самой поверхности.
По умолчанию количество частиц, вылетающих в единицу времени (то есть в секунду)
и определяемой атрибутом rate, не зависит от площади поверхности. Однако если включить
атрибут scaleRateByObjectSize, то значение rate будет определять количество частиц вылетающих
с единицы площади. А со всей поверхности будет испускаться число частиц равное произведению
rate на площадь поверхности.
Включите scaleRateByObjectSize=on для источника. Плотность частиц увеличилась в
соответствии с размерами плоскости.

По умолчанию частицы летят по нормали к поверхности. Если вы хотите развернуть


направление на противоположное, установите атрибут normalSpeed в минус единицу. Атрибут tan-
gentSpeed определяет, насколько частицы будут отклоняться вдоль поверхности. Если установить
tangentSpeed=1, a normalSpeed=0, испускание будет производиться целиком вдоль поверхности.
Эти атрибуты служат коэффициентами, на которые умножается скорость, определяемая атрибутом
speed.

Пытливые умы, наверное, уже в нетерпении елозят мышкой. Ведь если плотность
испускания может зависеть от площади поверхности, то, может быть, она может меняться и вдоль
самой поверхности?! Например, в зависимости от цвета поверхности, а точнее, в зависимости от
некоторой текстуры, определяющей области испускания с разной плотностью.
Выберите источник, откройте Attribute Editor и в разделе Texture Emission Attributes
найдите атрибут Texture Rate, позволяющий изменять плотность испускания в зависимости от
цвета текстуры (от яркости, если быть точным).

Нажмите на шашки справа от Texture Rate, чтобы назначить текстуру на этот атрибут.
Выберите в появившемся окне, например, Checker или File с вашей любимой картинкой.
Осталось включить самую главную галку Enable Texture Rate (находящуюся сразу под атрибутом

Динамика частиц 1053


Texture Rate) и вот частицы теперь вылетают из светлых областей, определяемых текстурой.

Совет. Откройте Attribute Editor для текстуры Checker1 и в разделе Effects


установите атрибут Filter в ноль. Это уберет размытие текстуры и некоторую
«грязь» при испускании частиц с краев плоскости.

Примечание. Как нетрудно заметить, текстура, управляющая испусканием, не


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

Пытливые умы, конечно, увидели, что над атрибутом Texture Rate есть аналогичная
конструкция для управления цветом частиц. И хотя про визуализацию частиц мы ещё не говорили,
проделаем похожие действия для того, чтобы частицы при испускании наследовали с текстуры
свой цвет.

Выключите галку Enable Texture Rate, чтобы было удобнее наблюдать эффект наследования
цвета по всей поверхности.

Включите галку Inherit Color (наследовать цвет) и нажмите на шашки справа от атрибута
Particle Color, чтобы назначить текстуру на этот атрибут.

Выберите в появившемся окне текстуру типа File и для нее загрузите в поле Image Name
любое растровое изображение (например, hotelFacade.jpg) из папки brushlmages, входящей в
состав MAYA.

Однако даже если вы не забудете включить отображение текстур на экране (6), цвет частиц
остается серым. Включение/выключение галки Inherit Color тоже не помогает, однако зоркие и
пытливые умы заметят в Script Editor возмущенные возгласы MAYA:

Warning: particleShapel does not have the following attribute: rgbPP. Please add this attribute in order
for inheritance to work.

Отсюда следует, что частицы не имеют атрибута, отвечающего за цвет (да-да, по умолчанию
частицы - бесцветно-серые) и что такой атрибут им надо добавить.
Чтобы сделать это, надо выбрать сами частицы, открыть Attribute Editor и в разделе Add

1054 Книга Сергея Цыпцына


Dynamic Attributes (добавление динамических атрибутов) нажать кнопку Color.
В появившемся диалоге следует выбрать вторую галку, так как мы хотим добавить каждой
частице свой цвет, а не всем - один и тот же, общий.
Дальше надо нажать кнопку Add Atribute, и у частиц появится атрибут rgbPP, позволяющим
всем частицам иметь собственные цвета.

Про статические, динамические и per-particle1 атрибуты мы поговорим позже, а сейчас вы


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

Установите для источника rate=500, чтобы получить более «плотную» картинку.


Откройте Windows=>Rendering Editors=>Hypershade, разыщите в закладке Textures текстуру
f i l e l , перетащите её средней кнопкой мыши из Hypershade в Attribute Editor и бросьте её прямо на
атрибут Texture Rate.
Включите галку Enable Texture Rate.
После этого одна текстура будет управлять одновременно и цветом и плотностью испускания.
Можете поменять изображение для текстуры f i l e l , выбрав, например, bubble.iff из той же папки.

1 Индивидуальные, по каждой отдельной частице. - Примеч. автора.

Динамика частиц 1055


Сохраните файл (emitFromSurface.ma).

Свойства и атрибуты частиц


Непросвещенные умы, наверное раздраженно ищут способ увеличить визуальный размер
частиц. Манипулятор Scale, однако, помогает в этом очень плохо. Очевидно, размер надо искать в
свойствах самих частиц.
С созданием и испусканием частиц мы немного разобрались, но прежде чем начать
их неистово анимировать, надо изучить некоторые их собственные свойства. Эти свойства,
определяемые, естественно, атрибутами, влияют не только на внешний вид, но и на характер
движения, поэтому их необходимо учитывать и использовать при анимации.
Но сначала разберемся с размером и внешним видом частиц, чтобы наблюдать происходящее
на экране в разных вариантах.
С точки зрения внешнего вида существует несколько разных типов частиц. Каждый тип
предназначен для определенного вида спецэффектов и может быть выбран в Attribute Editor, в
разделе Rendering Attributes.

1056 Книга Сергея Цыпцына


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

Sprites - мини-плоскости, всегда ориентированные в сторону камеры, на них можно


накладывать текстуры с изображением и прозрачностью. Это - рабочие лошадки с мире частиц.

Streak - летающие точки с «хвостами», причем длина хвоста пропорциональна скорости


частиц. Соответственно, у неподвижных частиц «хвост» уменьшается до нуля, и частица становится
невидимой.

Динамика частиц 1057


Multipoint/Multistreak - создают вокруг каждой точки дополнительное облако из частиц.
Размер окрестности и количество дополнительных частиц можно задавать в атрибутах, и это
позволяет визуально увеличивать плотность и объем частиц, не просчитывая дополнительные
траектории.

Blobby Surface - «склеивающиеся поверхности», сферы, которые могут «слипаться»,


образуя однородную массу.

1058 Книга Сергея Цыпцына


Clouds - объемные газообразные частицы, имитирующие облака, дым или пар.

У каждого типа частиц есть свои атрибуты, отвечающие за специфические свойства того
или иного типа: например, у Spheres за размер отвечает радиус, а у Point - атрибут point size.
Поэтому после каждого изменения типа частиц необходимо нажать кнопку Current Render Type,
чтобы в Attribute Editor появились атрибуты (и слайдеры к ним) для этого, конкретного типа
частиц.

Совет. Очень удобно использовать тип Streaks для визуального контроля как
направления, так и величины скорости движения частиц. Размер и длину «хвоста»
у этик «стриков» можно выбрать в Attribute Editor и использовать их до тех пор,
пока не придет время визуализировать частицы нужным образом.

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

Продолжительность жизни и курение сигарет


Так как частицы могут возникать не в первом кадре, у них есть определенно задаваемое
время рождения. Следовательно, у каждой частицы свой возраст (age), определяемый, как время,
прошедшее с момента рождения до текущего кадра. По умолчанию все частицы бессмертны, то есть
живут вечно, однако для них все же определен атрибут lifespan, который позволяет пользователю
задать время их жизни. Этот атрибут можно редактировать и анимировать, симулируя эффект
«умирания» или исчезновения частиц.

Откройте новую сцену и создайте источник частиц с параметрами по умолчанию


(Particle=>Create Emitter, emitterType=Omni).

После такой гигантской работы необходимо передохнуть. Если вы курите, то - перекурить.


Поглядите на кончик своей сигареты. Почему дым идет вверх? Очевидно, потому что он теплый.
Однако у наших частиц нет атрибута «температура», поэтому нам придется симулировать поднятие
дыма подручными полями.

Выберите частицы и создайте поле гравитации (Fields=>Gravity).


Атрибут magnitude установите в -3, это заставит гравитацию приподнимать частицы вместо

Динамика частиц 1059


того, чтобы ронять их.

Продолжая глядеть то на экран, то на сигарету, вы, по-видимому, вскоре подумаете о том,


что дым будет исходить из её кончика с такой скоростью, только если в нее сильно дуть.

Поэтому выберите источник и уменьшите скорость испускания: speed=0.02. Заодно,


сделайте дым поплотнее, установив rate=300. (Размер точек-частиц можете задать в Attribute
Editor, каким угодно - это несущественно и никак не влияет на динамику, массу и движение
частиц.)

Дым, однако, имеет свойство исчезать, растворяясь в воздухе...


Выберите частицы и откройте Attribute Editor.
В разделе Lifespan Attributes параметр Lifespan Mode установлен в Life Forever, то есть
сулит частицам вечную жизнь.

Установите его в Constant.


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

Это напоминает ровный огонек с одним небольшим недостатком - все частицы умирают
синхронно и резко. Пожалуй, стоит добавить «долгожителей», то есть сделать так, чтобы одни
частицы жили дольше, а другие умирали раньше остальных.

1060 Книга Сергея Цыпцына


Чтобы ввести разброс по времени жизни, задайте Lifespan Mode = Random Range. Еще
установите отклонение от основного возраста Lifespan Random=0.5. Теперь частицы исчезают не
так резко.

Реально время жизни для частиц сейчас располагается в диапазоне [0.75; 1.25], так как
формула для вычисления возраста в случае Range range выглядит следующим образом:
Lifespan ± Lifespan Random/2.

Атрибут Random Range определяет, таким образом, диапазон разброса времени жизни, а
не величину отклонения.

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


Задайте для частиц Lifespan=5, a Lifespan Random=3.
Для источника установите скорость испускания speed =0.02.
Условный дымок поднимается вертикально, причем уносится вверх с постоянным
ускорением. Так, наверное, вел бы себя дым в плотно закупоренном пространстве, где нет ни
сквозняков, ни самого сопротивления воздуха. Сквозняки мы сможем организовать с помощью
поля турбулентности, а вот сопротивление среды проще всего имитировать уменьшением атрибута
conserve для самих частиц. Этот атрибут настолько важен и полезен, что заслуживает небольшого
отступления.

Conserve как тормозящая сила любого прогресса.

По умолчанию частицы не обладают никаким сопротивлением движению. Если они


получают начальную скорость при испускании, то, в силу отсутствия полей и препятствий, будут
продолжать равномерное прямолинейное движение. Часто это делает их слишком «подвижными»,
а общее движение слишком резким. Кроме того, бессознательно глаз наблюдающего за потоком
частиц чувствует «нефизическое» отсутствие силы сопротивления среды. Для придания частицам
«вязкости» или легкого сопротивления движению используется атрибут conserve, который
имитирует трение о невидимую среду.

Чисто математически, conserve - это коэффициент, на который умножается скорость


частиц в каждом кадре. А так как величина силы трения обычно пропорциональна скорости, то
conserve можно рассматривать как характеристику трения. Будьте осторожны: если с первом кадре
скорость свободно движущейся частицы равна, к примеру 10, то при conserve=0.9 в следующем
кадре она будет равна 9, в третьем кадре 8.1, в четвертом - 0.729, . . . в двадцать пятом - 0.78! То
есть за одну секунду скорость упадет более чем в десять раз. Поэтому в основном, используются
значения conserve близкие к единице.

Поля, действующие на частицы, склонны разгонять частицы до больших скоростей, а мы


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

Динамика частиц 1061


воспрепятствовать нарастанию скоростей и резкой смене движений - это использовать атрибут
conserve.

Вернемся к дыму.

Выберите частицы и в Attribute Editor в разделе General Control Attributes установите


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

Выберите частицы.
Создайте поле турбулентности: Fields=>Turbulence.
Так как сквозняки должны возмущать воздух во всем пространстве, не затухая по мере
удаления от центра поля, сразу установите атрибут attenuation в ноль.

Сквозняк появился, только какой-то «статичный». Поле турбулентности влияет на ускорения


частиц, но совершенно одинаково для всего пространства.
Увеличьте частоту турбулентности, установив атрибут frequence=2.
Это ненадолго возмутит систему, но при проигрывании сначала все опять «устаканится»,
хотя и с большим «изгибом» струи дыма.

1062 Книга Сергея Цыпцына


Очевидно, что необходимо как-то шевелить поле турбулентности, то есть нужно
проанимировать какой-нибудь ее атрибут, отвечающий за форму «хаоса». В нашем случае удобно
использовать атрибуты Phase, задающие сдвиг фазы при вычислении турбулентности. Если
пошевелить, например, атрибут phaseX в Attribute Editor прямо во время проигрывания, можно
увидеть, что частицы весьма чувствительно откликаются на такое шевеление. Вы можете просто
поставить ключи на этот атрибут, добиваясь того, что он будет меняться «туда-сюда». Однако мы
поступим как взрослые пиротехники.

В Attribute Editor для поля турбулентности введите в ячейку атрибута phaseX следующее
выражение:
=noise(time)
и нажмите Enter.

Обратите внимание как ловко расширилась ячейка для ввода формулы при вводе знака
'='. Таким образом был быстро создан простой expression, изменяющий атрибут phaseX от -1 до
1. Функция noise это «помятый синус», его график представляет собой гладкую кривую, которая
«псевдопериодически» меняет свое значение в диапазоне от -1 до 1.

Теперь дымок бодро извивается на сквозняке в соответствии с изменениями формы поля


турбулентности.

Если частота изменения формы поля кажется вам слишком высокой, нажмите правую
кнопку над атрибутом phaseX прямо в Attribute Editor и выберите Edit Expression.
В появившемся Expression Editor отредактируйте формулу следующим образом:

turbulenceField1. phaseX=noise(time / 3 )*0.8

Не забудьте нажать кнопки Edit и Close.


Это уменьшит резкость в движении дымка.

Динамика частиц 1063


Чтобы сделать его ещё более плавным, добавьте вязкости: выберите частицы и уменьшите
атрибут conserve до 0.8.

Совет. Иногда при испускании частиц они вылетают «пачками», и в потоке


частиц появляются длинные «просветы». Это связано с тем, что когда точечный
источник в каждом кадре испускает много частиц с приличной скоростью, за время
одного кадра они успевают улететь довольно далеко от следующей за ним порции
частиц. Чтобы уменьшить влияние этого эффекта, можно заставить источник
испускать частицы не из точки, а из некоторой окрестности, определяемой
атрибутами maxDistance и minDistance.

Установите для источника атрибут maxDistance=0.02, чтобы частицы испускались не из


точки, а из небольшого сферического объема.

Дальнейшие улучшения движения зависят от вашей тяги к совершенству и медитации на


сигаретный дым. Не бойтесь экспериментировать и играть с атрибутами частиц и полей.
Только сохраните предварительно файл (smoke. ma).
Последнее, что, наверное, смущает медитирующие умы, что на экране дым не растворяется
в воздухе, как в жизни, а просто внезапно исчезает. Действительно, с понятием «прозрачность»
мы ещё не оперировали, занимаясь только анимацией.

Немного забегая вперед, добавим дыму прозрачности (а точнее непрозрачности, ибо в


динамике используется слово opacity, противоположное официальному термину transparency).

Примечание. Чехарда с opacity и transparency сложилась исторически. Дело в том,


что пакет Dynamation, являющийся прародителем майской динамики, был написан
задолго до того, как первая версия MAYA увидела свет. А чтобы не портить жизнь
уже имеющимся пользователям и поклонникам этого уникального пакета, было
решено оставить его основные понятия без изменений.

Выберите частицы, откройте Attribute Editor и в разделе Add Dynamic Attributes нажмите
кнопку Opacity.

Из двух вариантов выберите второй (Add Per Particle Attribute), чтобы добавить
индивидуальной прозрачности для каждой частицы.

Чуть выше, в разделе Per Particle (Array) Attributes, появится атрибут opacityPP, с которым,
очевидно надо что-то сделать.

Нажмите правую кнопку мыши на сером поле справа от имени атрибута, и в появившемся
меню выберите Create Ramp.

1064 Книга Сергея Цыпцына


Не забудьте выключить режим wireframe, и вы увидите, что частицы, перед тем как
исчезнуть, начинают растворяться в пространстве.

Чтобы отредактировать степень прозрачности частиц, снова нажмите правую кнопку мыши
на поле OpacityPP.

На этот раз там появится самое длинное меню в мире, прорвавшись сквозь которое
выберите Edit Ramp.

Вам потребуется некоторое время для того, что бы осознать, как текстура влияет на
прозрачность (точнее, как она «лежит» на частицах, ведь у них нет ни поверхности, ни UV-
координат), однако пытливые умы, используя метод пристального взгляда, быстро догадаются, что

Динамика частиц 1065


текстура типа Ramp «лежит» на времени жизни частиц. Более «молодые» частицы берут значение
прозрачности с нижней части текстуры, а более «старые» с верхней части.

Отредактируйте текстуру так, чтобы частицы с самого начала имели некоторую прозрачность
(серый цвет внизу), а начинали исчезать после половины прожитого времени жизни.

Для взрослых. В данном случае возраст частиц неявным образом передается на V-


координату текстуры Ramp. Можно использовать и любой другой атрибут частиц
(для того, чтобы вычислять «забираемый» с текстуры цвет). Для этого при
создании текстуры Ramp достаточно выбрать Option Box и там указать, какой
атрибут будет управлять V-координатой. Там же можно задать и атрибут для
U-координаты, а тип текстуры указать как UV-ramp.

Это, в общем-то, экзотика, и для таких случаев лучше пользоваться expression, но иногда
удобно использовать позиции частиц как UV-координаты для текстуры, определяющей некоторые
свойства частиц - например, массу.

Сохраните файл (smoke.mа).

1066 Книга Сергея Цыпцына


Отложим визуализацию никотиновых испарений до соответствующего раздела о
хардверном рендеринге. А сейчас подведём некоторые итоги, основываясь на опыте от сделанного
упражнения.

Время жизни и возраст частиц


Время жизни - ключевой атрибут и свойство частиц. Он позволяет задать динамику изменения
свойств частиц индивидуально для каждой частицы. В отличие от общего системного времени,
время жизни и возраст частицы (хранящийся в атрибуте age) определены для каждой частицы
индивидуально и позволяют задать динамику изменения свойств каждой частицы независимо
от других. Время жизни позволяет работать с постоянно «обновляющимися» потоками частиц и
является совершенно незаменимым свойством при производстве различных «пиротехнических»
эффектов.

Следует различать время жизни (lifespan) и возраст частиц (age). Время жизни - это
атрибут, который можно редактировать и анимировать, влияя на продолжительность жизни частиц
на экране. Возраст - это не редактируемый (read-only) атрибут, который содержит информацию
о том, сколько времени прошло с момента рождения частицы. Как только значение атрибута age
становится больше значения, определяемого lifespan, частица исчезает.

Массивные атрибуты (Per Particle Array Attributes)


При анимации прозрачности дыма или испускании наследующих цвет частиц, я уже
упоминал о том, для частиц существуют индивидуальные атрибуты. Разберемся с этой концепцией
поподробнее.
Если открыть Attribute Editor для частиц, то, как и для любого объекта в MAYA, он содержит
атрибуты, определяющие свойства объекта целиком, ничего не говоря про свойства компонентов
объекта. Однако совершенно очевидно, что для частиц должны задаваться характеристики,
определяющие не только общие для всех частиц свойства (типа conserve), но параметры,
уникальные для каждой частицы. Интуитивно понятно, что у каждой частицы есть своя позиция и
скорость («И даже ускорение!», воскликнут особо пытливые умы, умудрившиеся закончить среднюю
школу). Понятно и то, что эти характеристики частиц надо хранить в некоторых атрибутах, чтобы
иметь возможность их контролировать. Также хорошо бы всегда иметь под рукой цвет, массу
или прозрачность каждой частицы, чтобы работать с ними на индивидуальной основе. Ясно, что
все эти свойства должны храниться в атрибутах, вопрос лишь в том, как устроены эти атрибуты.
Можно предположить, что если объект типа particle содержит, например, десять тысяч частиц,
то где-то должны находиться десять тысяч атрибутов, определяющих позиции, ещё десять тысяч,
определяющих скорости, массу, цвет и т.д. Однако вместо того, чтобы плодить десятки тысяч
атрибутов, для каждого индивидуального свойства частиц существует один (но очень большой)
массивный атрибут, содержащий в себе все позиции или все скорости частиц в данном объекте.
Говоря формально, для частиц определены атрибуты типа массив (array), содержащие наборы
данных определенного типа. Например, атрибут mass представляет собой набор чисел типа float,
характеризующий массы всех частиц. А атрибут velocity содержит набор векторов (то есть троек
чисел), описывающих скорости всех частиц в данном объекте типа particle.
В Attribute Editor для частиц есть раздел Per Particle (Array) Attributes, содержащий такие
массивные атрибуты.

Динамика частиц 1067


В дальнейшем я буду называть их индивидуальными (per particle) атрибутами. Можно
представлять их себе таким образом, что у каждой частицы есть свой микронабор атрибутов (posi­
tion, velocity, acceleration, mass ...), определяющих только ее свойства.
Нетерпеливые умы, спросят, а как редактировать такие атрибуты, ведь поля для них в At­
tribute Editor недоступны для ввода, а те, кто собирался ввести туда десять тысяч скоростей через
точку с запятой, уже разочарованно вздохнут. Пока ответ будет краток: нажмите правую кнопку
мыши над одним из этих полей и увидите возможные способы работы с такими атрибутами. Об
этих способах мы поговорим буквально через пару абзацев, а сейчас разберемся с динамическими
атрибутами для частиц.

Индивидуальные динамические атрибуты


Как уже упоминалось выше, по умолчанию частицы не имеют цвета. То есть они видны,
как серые, но никаких атрибутов, характеризующих цвет у них по умолчанию нет. Так же, как нет
атрибутов, характеризующих прозрачность или размер. Все эти атрибуты добавляются к частицам
по мере надобности, то есть являются динамическими. Этому можно даже придумать объяснение.
Например, заговорить про оптимизацию ресурсов.
Во-первых, если добавить к частицам индивидуальную прозрачность (opacityPP), то для
объекта в десять тысяч частиц это ведет к появлению атрибута длиной в десять тысяч чисел
(а для цвета в тридцать тысяч чисел). Но не факт, что в каждом случае прозрачность будет
использоваться, поэтому добавлять ее, как и цвет, по умолчанию ко всем частицам было бы
несколько расточительно.

Во-вторых, для разных типов частиц необходимы разные атрибуты для редактирования
внешнего вида частиц. Для сфер, например, нужен радиус, а для спрайтов размер по X и Y.
Поэтому вешать на частицы атрибуты на все случаи жизни (а точнее, для всех типов частиц) было
бы опять же неэкономно.

Некоторая часть атрибутов присуща частицам изначально. Позиция (position), скорость


(velocity), ускорение (acceleration) и масса (mass) участвуют в расчетах траекторий частиц и
существуют у любых вновь созданных частиц. Индивидуальное время жизни (lifespanPP) также
присутствует всегда, хотя используется лишь в зависимости от значения Lifespan Mode.

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


огромного количества полезных атрибутов в описании ноды типа particle.

Остальные атрибуты добавляются к частицам по мере необходимости. Такое добавление


происходит либо автоматически (например, когда вы выбираете новый тип частиц в разделе
Render Attributes и нажимаете кнопку Current Render Type), либо вручную, когда вы сознательно
добавляете, например, цвет ко всем частицам.
Самые бдительные умы, однако могут заметить, что при добавлении цвета или прозрачности,
всегда есть две возможности: добавить один цвет ко всем частицам (per object attribute) или
добавить свой цвет к каждой частице (per particle attribute).

Понятно, что в первом случае добавляется один обычный числовой атрибут, который можно
разыскать и отредактировать в Attribute Editor в разделе Render Attributes. Во втором случае в
списке индивидуальных атрибутов в разделе Per Particle (Array) Attributes появляются атрибуты
rgbPP и opacityPP, соответственно. Резонно было бы задать вопрос: а можно ли задавать не только
индивидуальную прозрачность или цвет, но еще и радиус сферы или размер спрайта для каждой
частицы?

Конечно можно. Если для добавления цвета и прозрачности есть специальные кнопки,

1068 Книга Сергея Цыпцына


то для всех остальных дополнительных атрибутов существует кнопка General, которая просто
открывает окно для добавления атрибутов (доступное также через основное меню Modify=>Add At­
tribute). Если для обычных объектов мы обычно просто добавляем динамический атрибут с новым
именем и собираемся использовать его по своему усмотрению, то для объектов типа particle уже
существует набор готовых атрибутов, каждый из которых предназначен для управления вполне
определенными свойствами.

Эти атрибуты перечислены в закладке Particle окна Add Attribute.

Причем в этом списке находятся имена всех возможных атрибутов для добавления к
частицам. В том числе уже добавленные или существующие на выбранном объекте. При попытке
добавить такой, уже существующий атрибут будет просто выдаваться сообщение об ошибке.
Кроме того, в списке перечислены все атрибуты для всех типов частиц. И в принципе
можно добавить индивидуальный размер спрайтов к частицам типа сфер MAYA не будет вас ругать
и ошибки это не вызовет, так что руководствуйтесь здравым смыслом.
К тому же в этом списке в общую кучу свалены и per object атрибуты (то есть общие для
всех частиц) и per particle, или индивидуальные атрибуты. Причем отсутствие букв РР (Per Par­
ticle) не означает, что атрибут имеет тип per object. Напротив, большинство атрибутов являются
индивидуальными, то есть добавляются к отдельным частицам.
К сожалению, эти атрибуты не перечислены в описании ноды particle, поэтому пытливые
умы, бескомпромиссно желающие ознакомится с их типом и предназначением, должны найти
в документации раздел List of particle attributes и прочитать необходимые комментарии (таких
разделов, с одинаковым именем, кстати, два - в разделе Dynamics и MEL and Expressions,
соответственно, причем первый из них более подробный). Ниже я расскажу о некоторых из них,
но, безусловно, не обо всех.
Наличие такого списка, естественно, не исключает того, что мы можем добавить к частицам
свой атрибут с произвольным именем и использовать его в своих целях, например, для Particle
Instancer, как будет рассказано ниже.

Динамика частиц 1069


Вопрос приоритетов
Некоторые въедливые умы, глядя на рядом стоящие в списке атрибуты с одинаковым
именем, но разным предназначением, например radius и radiusPP, или incandescence и incandes-
сепсеРР, ехидно спросят: «А что же будет, если добавить к частицам оба атрибута с одинаковым
именем, один для всего объекта, а другой для каждой частицы?»
К примеру, добавляя цвет к частицам, можно добавить цвет для всех частиц целиком, а
после этого можно добавить цвет для каждой частицы отдельно. Что же будет в этом случае?
Обычно это вопрос приоритетов. Как правило, индивидуальные атрибуты имеют приоритет над
обычными, то есть при окрашивании частица будет использовать свой индивидуальный цвет (rg-
ЬРР), а не цвет для всего объекта целиком. То же самое относится к прозрачности, радиусу,
размеру спрайтов и некоторым другим атрибутам. Однако для времени жизни использование
атрибута lifespan или lifespanPP определяется значением параметра Lifespan Mode. А в случае
использования механизма goal (о котором ниже), общий goal и индивидуальный goalPP вообще
перемножаются. Как видите, никакого алгоритма для запоминания обнаружить не удается,
поэтому придется перечитывать этот абзац каждый раз, когда вы начнете добавлять атрибуты к
частицам.

Работа с индивидуальными атрибутами


Теперь, как и было обещано выше, самое время разобраться, как же все-таки редактировать
и анимировать индивидуальные (per particle) атрибуты. Очевидно, что должны быть какие-то
методы «массового» редактирования таких атрибутов.

Основных возможностей три: использование Component Editor, применение текстуры типа


ramp и работа с expressions. Рассмотрим их подробнее.

Component Editor
Для тех, кто любит вбивать цифры в клеточки, в MAYA встроена особая реинкарнация Mi­
crosoft Excel, позволяющая быстро вбить значения десяти тысяч скоростей для каждой частицы
или отредактировать цвет каждой пятой из них. Эта реинкарнация расположена по адресу
Windows=>General Editors=>Component Editor. Чтобы увидеть в нем значения индивидуальных
атрибутов, следует выбрать некоторое количество частиц как компоненты, то есть по правой
кнопке мыши, а затем уже разыскать в Component Editor закладку Particles.

1070 Книга Сергея Цыпцына


Значения всех атрибутов можно просто менять от руки, а номера частиц указаны в крайнем
левом столбце. Таким образом, можно даже вручную передвигать конкретные частицы, задавая
значения атрибута position. Хотя это весьма экзотический случай. Разберем небольшой пример
неудачного использования Component Editor. Пример адекватного применения можно найти ниже,
в разделе про мягкие тела.

Как обсыпать объект частицами?


Возьмите любую свою модель или создайте примитивный тор. Задача состоит в том, чтобы
облепить модель частицами, которые можно было бы впоследствии сдуть или разогнать ветром.
Выберите модель, создайте поверхностный источник частиц: Particles=>Emit from Object.
Задайте для источника emitterType=Surface.
Установите значение rate достаточно большим, чтобы частицы испускались довольно
плотным потоком (например, rate=10000). А затем просто установите значение скорости испускания
в ноль: speed=0.

Объект начнет покрываться неподвижными частицами. Чтобы слой частиц был не


таким плоским и немного более «мохнатым», увеличьте совсем чуть-чуть скорость испускания:
speed=0.01, проиграйте анимацию примерно до трехсотого кадра и остановитесь.

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

Динамика частиц 1071


Обнуление скоростей. Начальное состояние
Такое запоминание текущего состояния динамики и сохранение его в качестве начального
кадра производится операцией Solvers=>Initial State=>Set for All Dynamic.
Выполните эту операцию в текущем кадре и проиграйте анимацию сначала. Вы увидите,
что частицы теперь уже существуют в первом кадре.

Теперь просто удалите источник и снова проиграйте анимацию. Одна маленькая незадача
- частицы немного двигаются.

Примечание. При сохранении начального состояния частиц запоминаются не


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

Нужно просто притормозить частицы, чтобы в первом кадре было просто неподвижное
облако. Самый простой способ состоит в том, чтобы вбить частицам нулевые скорости от руки.
Сделать это надо в первом кадре.
Нажмите правую кнопку мыши над частицами и выберите Particles.
Затем выберите все частицы прямо на экране и откройте Component Editor.
Разыщите в нем закладку Particles и обнулите значения всех атрибутов velocity для всех частиц.
Это просто сделать, выделив три заголовка столбцов Velocity и сразу напечатав ноль в появившуюся
ячейку. (Другой способ ввода значений в диапазон ячеек: выделить первую ячейку, а затем
- последнюю и нажать клавишу Shift.) Так как частиц довольно много, возможно придется
подождать.

Примечание. В Component Editor пo умолчанию включен режим Hide Zero Columns,


который прячет столбцы, у которых все ячейки содержать ноль. Имеет смысл
выключать этот режим, чтобы не искать потерянные столбцы. Это можно
сделать через меню Options.

1072 Книга Сергея Цыпцына


Однако при дальнейшем проигрывании анимации частицы все равно двигаются. Не помогает
даже повторное сохранение начального состояния. Секрет заключается в том, что Component Edi­
tor не в состоянии отобразить атрибуты для сотни тысяч частиц, которые выбраны на экране. Это
следует хотя бы из сообщения в Script Editor:

select -rparticle1.pt[0:133331] ;
// Warning: Displaying the first 1024 rows from a total of 133334. //

Действительно трудно представить адекватную работу с таким количеством частиц через


ввод числовых значений. Поэтому в Component Editor отображаются данные только для первой
тысячи частиц.

Примечание. Надо сказать, что в версии MAYA 6.5 производительность Component


Editor была радикально улучшена и ограничение на тысячу частиц было снято.
Тем не менее, если загрузить в Component Editor сотню тысяч частиц, придется
изрядно подождать обновления результатов редактирования.

Как же все-таки выйти из положения и затормозить частицы?

Бесполезный Component Editor можете закрыть (а можете и не закрывать для контроля


значений скоростей отдельных частиц).

Воспользуемся универсальным тормозом в виде атрибута conserve для частиц. Как вы


помните, это имитация силы трения или умножитель для скорости частиц.
Вернитесь в первый кадр.
Выберите частицы и установите в Channel Box для них conserve=0.
Теперь достаточно перейти во второй кадр: в этот момент скорость частиц умножится на
ноль, а ввиду отсутствия полей, никакого ускорения также не возникнет.
В принципе вы можете проиграть анимацию и дальше, чтобы убедиться, что частицы
полностью неподвижны. Помня, что состояние частиц описывается не только позициями, но
значением скоростей, надо срочно запомнить такое состояние с неподвижными частицами в
качестве начального.

Выполните Solvers=>Initial State=>Set for All Dynamic.


И после этого не забудьте вернуть conserve в прежнее значение, ведь в дальнейшем
частицы не должны так сильно тормозиться.
Теперь в первом кадре имеется неподвижное облако частиц, повторяющее форму объекта,
на которое можно дунуть любым полем, что вы можете сделать в свободное от чтения книги время
(particleTorus.ma).

Динамика частиц 1073


Использование текстуры Ramp для управления частицами
Рассмотрим теперь, как можно редактировать индивидуальные атрибуты более
интеллектуальным способом, нежели прямое вбивание значений в ячейки. Очевидно, должны
существовать способы задавать распределение значений индивидуальных атрибутов в зависимости
от времени или от других параметров. Чтобы сразу не бросаться в программирование формул
с помощью expression, рассмотрим сначала менее жесткий и довольно остроумный способ
редактирования и анимации индивидуальных атрибутов - с помощью текстуры ramp.
Идея состоит в том, что текстура ramp по умолчанию представляет собой просто градиент,
то есть плавный переход от одного цвета к другому. Если эти цвета поставить в соответствие
значениям атрибутов частиц, а сам переход привязать к времени жизни, мы можем формулировать
законы плавного изменения атрибутов частиц в зависимости от их возраста.

Примечание. В общем-то, не обязательно привязывать переход на текстуре только


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

Сделаем небольшой пример на использование текстуры для управления размером частиц,


ибо управление цветом выглядит совсем банально.
Поместим некоторое количество пузырей в цилиндрический объем.
Для этого создайте источник частиц: Particle=>Create Emitter.
Установите emitterType=Volume, rate=10 и volumeShape=Cylinder.
Чтобы частицы летели вертикально вдоль оси, задайте следующие значения: awayFrom-
Center=0, awayFromAxis=0, alongAxis=0.5.

1074 Книга Сергея Цыпцына


Теперь займемся частицами.
Выберите их и в Attribute Editor задайте Particle Render Type=Spheres.
Испугайтесь, нажмите кнопку Current Render Type и задайте radius=0.1.

Теперь все частицы имеют одинаковый радиус и улетают в бесконечность. Мы хотим


сделать так, чтобы пузыри постепенно надувались и в конце концов лопались, то есть исчезали.
Можно, конечно проанимировать общий атрибут radius, но тогда все пузыри будут надуваться
синхронно, а мы хотим, чтобы радиус каждого пузыря менялся независимо от других и зависел
только от возраста пузыря. Очевидно, надо добавить каждой частице индивидуальный радиус.
В Attribute Editor нажмите кнопку General в разделе Add Dynamic Attributes.
В закладке Particles выберите radiusPP и нажмите ОК.
Атрибут radiusPP тут же появится в разделе Per Particle (Array) Attributes.

Пока ничего не произошло, так как никаких значений для radiusPP не задано.
Нажмите правую кнопку мыши справа от имени атрибута и в появившемся меню выберите
Create Ramp.
Снова испугайтесь и запустите анимацию.
Возьмите себя в руки и методом пристального взгляда установите, что частицы стали
исчезать примерно через двадцать пять кадров после рождения, то есть за время жизни они

Динамика частиц 1075


стремительно сдуваются от единичного радиуса до нулевого.

Так и есть. После создания текстуры ramp MAYA автоматически переключила параметр
Lifespan Mode в Constant, и время жизни частиц стало равным одной секунде.
Задайте Lifespan=4.
Радиус теперь, очевидно, изменяется в зависимости от градиента, задаваемого текстурой.
Доберемся до нее.
Нажмите правую кнопку справа от radiusPP (там теперь появилась ссылка на загадочный
arrayMapper), в выпавшем меню доберитесь до Edit Ramp.
Глядя на черно белый градиент, можно понять, что единичный радиус соответствует
белому цвету в нижней части текстуры, которая отвечает за начало времени жизни. Верхняя часть
текстуры соответствует концу времени жизни и черный цвет соответствует исчезающе-малому
радиусу.

Примечание. В случае скалярных (представленных одним числом) атрибутов


автоматически создается черно-белый ramp и в качестве значений для атрибутов
берется яркость, а не цвет. Кроме того, по умолчанию создается V-Ramp, поэтому
для визуального представления следует смотреть на левый край прямоугольника,
представляющего ramp в Attribute Editor.

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

1076 Книга Сергея Цыпцына


В разделе Color Balance установите значение атрибута Color Gain примерно в 0.1.
Это и будет множитель для радиуса получаемого с текстуры. (Можете установить его точно
в 0.1, вызвав Color Chooser и задав V=0.1).
А сам ramp можно теперь «перевернуть», чтобы белый цвет был сверху и пузыри надувались
по мере всплытия.

Очевидно, что выбирая разные типы типы интерполяции для ramp и редактируя цвета и
их расположение на текстуре можно добиваться довольно забавных эффектов. Но все они будут
иметь одно ограничение: частицы должны иметь время жизни. Ведь если установить Lifespan
Mode = Live Forever, то радиус частиц перестанет меняться, так как частицы останутся «вечно
молодыми». Поэтому применение текстуры ramp, для анимации индивидуальных атрибутов, как
правило, ограничено плавным изменением значений в зависимости от возраста частиц.

Для взрослых. Изучив в Hypergraph связи между paticleShape и arrayMapper несложно


установить зависимость атрибутов не только от времени жизни, но и от любого
другого атрибута частиц.

Если же мы захотим назначить всем частицам разный радиус уже при рождении и в
дальнейшем менять его по произвольным законам (например схлопывать частицу при достижении
определенной частоты), нам не обойтись без написания expression.
Сохраните сцену (bubbles.mа). Рассмотрим принципы написания expression для частиц на
примере этих же пузырей.

Динамика частиц 1077


Particle Expressions - от порядка к хаосу и обратно
Откройте сцену bubbles.mа.
В Attribute Editor нажмите правую кнопку напротив атрибута radiusPP и выберите в меню
Delete Array Mapper, чтобы удалить зависимость радиуса частиц от времени жизни.
Сейчас мы хотим задать всем частицам разный радиус прямо при рождении.
Снова нажмите правую кнопку напротив атрибута radiusPP и выберите Creation Expres­
sion. Появится Expression Editor, в котором следует ввести формулу для радиуса нарождающихся
частиц.
Введите формулу:

radiusPP=rand(0.01, 0.1);

и нажмите кнопку Create.


Теперь все частицы рождаются с разным радиусом. А созданный expression выполняется
для каждой частицы один раз во время её испускания. Введенная формула гласит: «присвоить
атрибуту radiusPP случайное число в диапазоне от 0.01 до 0.1».

Теперь надо что-то сделать с радиусом частиц.


Если снова нажать правую кнопку напротив radiusPP и выбрать Runtime Before Dynam­
ics Expression, снова появится Expression Editor с приглашением ввести формулу которая будет
выполняться не только при рождении частицы, а в каждом кадре, пока частица жива. Об этом
говорит включенная опция Runtime before Dynamics.
Снова введите формулу:

radiusPP=rand(0.01, 0.1);

Нажмите Create и почувствуйте разницу между Creation и Runtime Expressions. Теперь


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

1078 книга Сергея Цыпцына


Исправьте скорее последнюю формулу на следующую:

radiusPP=radiusPP*1.01;

и не забывайте нажимать каждый раз Edit после исправления.


Не закрывайте пока Expression Editor.

Частицы начнут благостно надуваться, так как их радиус, в соответствии с формулой,


немного увеличивается в каждом кадре. Причем теперь это надувание не зависит от того, имеют
ли частицы конечное время жизни или живут вечно. Увеличьте время жизни до шести секунд:
lifespan=6.

Запретим чрезмерное раздувание. Ограничим максимальный радиус частиц.


Исправьте последнюю формулу:

if(radiusPP<0.15) radiusPP=radiusPP*1.01;

Динамика частиц 1079


Попробуем проанализировать высоту поднятия пузырей и остановить их на каком-нибудь
уровне. Дополните последнюю формулу в Expression Editor следующим образом:

if(radiusPP<0.15) radiusPP=radiusPP*1.01;
vector $pos = position;
vector $vel = velocity;
if (Spos.y > 2) {
velocity = << $vel.x, 0, $vel.z >>;
}

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

Правда у нас частицы летят строго вертикально, поэтому никакого горизонтального


движения после остановки не наблюдается. Добавим его.

Измените последнюю строчку, добавив к горизонтальным составляющим скорости


небольшие возмущения:

if(radiusPP<0.15) radiusPP=radiusPP*1.01;
vector $pos = position;
vector $vel = velocity;
if (Spos.y > 2) {
velocity = « $vel.x+rand(-0.01,0.01), 0, $vel.z+rand(-0.01,0.01) »;
}

Теперь частицы начнут слегка «плавать» по поверхности. Дальнейшие эксперименты


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

После таких оптимистических заявлений, надо поговорить о том, чем отличаются expres­
sions для частиц (Particle Expressions) от обычных expressions, как и когда они выполняются и какие
основные трюки используются при анимации частиц с помощью expressions.

1080 Книга Сергея Цыпцына


Создание, выполнение и виды Particle Expressions
В отличие от обычных объектов частицы имеют свойство неожиданно рождаться. Либо
при испускании, либо при столкновении, либо после выполнения функции emit. Для таких частиц
определен момент создания (creation time). Поэтому в общем случае для частиц существует два
вида expressions: Creation expression и Runtime expression.

Runtime Expression для частиц похож на обычный expression для объектов - он выполняется
в каждом кадре при проигрывании анимации. Его основное отличие состоит в том, что он
выполняется в каждом кадре для каждой частицы. То есть если в кадре существует десять тысяч
частиц, то формула radiusPP=radiusPP*1.01 будет выполнена десять тысяч раз в каждом кадре! Об
этом следует помнить при написании особо изощренных expressions.

Creation Expression выполняется в каждом кадре, но только для тех частиц, которые в этом
кадре родились. В следующем кадре для них уже будет выполняться Runtime Expression.

Runtime Expression не выполняется в момент создания частицы, то есть Creation и Runtime


Expression не могут одновременно выполниться в одном кадре.

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

Примечание. Для частиц, не испущенных из источника, а созданных с помощью Par­


ticle Tool, Creation Expression выполняется при возвращении в первый кадр.

Runtime Expression, если говорить формально, выполняется для каждой частицы, чей
возраст (то есть атрибут age) больше нуля, каждый раз, когда MAYA вычисляет динамику. Если
параметр Oversampling (отвечающий за точность обсчета частиц и устанавливаемый в Solvers=>Edit
Oversampling or Cache Settings) равен единице, выполнение происходит в каждом кадре. Если, к
примеру, он равен четырем, то вычисление динамики и, как следствие, выполнение Runtime Ex­
pression происходит в четыре раза чаще (грубо говоря, четыре раза между соседними кадрами).
Ещё одно отличие от обычных expressions и объектов заключается в том, что для одного
объекта типа particle, а точнее, для ноды particleShape, всегда создается один Expression,
называемый как правило particleShapeX, в котором «зашиты» и Creation и Runtime Expressions. В
нем происходит вся работа с индивидуальными атрибутами частиц. Не надо создавать несколько
expressions для частиц! В Expression Editor такой expression всегда фигурирует под одним именем
и автоматически появляется, если выбрать shape объекта с частицами (то есть выбрать частицы и
нажать стрелку вниз).
Обычно Creation и Runtime Expressions редактируют и создают, попадая в Expression Editor
из Attribute Editor для частиц, нажав правую кнопку в поле индивидуальных атрибутов.

Это самый «легальный» способ открыть нужный expression, поэтому старайтесь использовать его.

Динамика частиц 1081


Примечание. Если в Expression Editor выбрать Select Filter=>By Expression Name,
а затем, указав на expression для частиц, закрыть его, то он «запомнит» свой
последний режим работы с частицами. Если после этого выбрать любой объект,
например, кривую, и открыть Expression Editor, он будет открываться в режиме
создания expressions для частиц, и попытка написать формулу для перемещения
кривой будет выдавать загадочные сообщения. Поможет только переключение
Select Filter=>By Object Name. Или же открытие Expression Editor пo правой кнопке
мыши из Attribute Editor или Channel Box. Это - «глюк».

Будьте также внимательны, устанавливая диапазон анимации. У частиц, по аналогии


с твердыми телами, есть атрибут Start Frame, определяющий, с какого кадра начнется расчет
динамики для выбранных частиц. По умолчанию, он равен единице, то есть динамика начинает
выполняться с первого кадра. Если диапазон анимации будет начинаться не с первого кадра, а
позже, проигрывание и возвращение анимации в начало (уже не в первый кадр) могут давать
непредсказуемые результаты. Следите за тем, чтобы значение атрибута Start Frame было не
меньше начального кадра диапазона анимации.

Теперь посмотрим, какие трюки можно использовать при работе с Particle Expressions.
Как убить конкретную частицу?

Конечно, любители вбивать цифры в клетки предложат выделить часть частиц, затем
открыть Component Editor и вбить ноль в столбец lifespanPP, не забыв при этом переключить
параметр Lifespan Mode в LifespanPP Only и сохранить начальное положение. А если надо убить
каждую пятую частицу, или, начиная с третьей сотни, каждую восьмую, или не убить, а заморозить
на месте? Взрослые мальчики, естественно, напишут expression, который и проделает всю грязную
работу.

Создайте обычный источник частиц, задайте ему emitterType=Directional, a rate=5.


Частицы, для наглядности, сделайте сферами.

Создайте Creation Expression для частиц.


Ещё раз повторю: совершенно все равно, на каком индивидуальном атрибуте щелкать
правой кнопкой мыши в Attribute Editor. Creation Expression создается один-единственный для
всех атрибутов и всех частиц.

1082 Книга Сергея Цыпцына


Введите формулу в Creation Expression:

if(particleld>10) lifespanPP=0;

и не забудьте нажать кнопку Create.


Формула гласит, что все частиц, номер которых больше 10, должны немедленно умереть,
так как их время жизни равно нулю. Все это происходит в том кадре, где частицы рождаются,
поэтому они даже не успевают появиться на свет.
Как справедливо замечают пытливые умы, Lifespan Mode должен быть обязательно
установлен в LifespanPP Only.

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

if(particleld%5==0)lifespanPP=0;

Это читается так: если остаток от деления нацело равен нулю, то - умереть. Это остаток от
деления номера частицы на пять. Остатки от деления проходят классе в четвертом, поэтому если
вы закончили только начальную школу, поверьте на слово.
Кстати, убивать частицу совсем не обязательно: можно просто обнулить её радиус или
переместить в другое место.

Динамика частиц 1083


Естественно, что выборочно редактировать атрибуты частиц с конкретными номерами
можно не только в Creation Expression, но и в Runtime Expression, изменяя свойства конкретных
частиц.

Как сделать часто или редко?

Иногда надо сделать так, чтобы изредка происходило некоторое событие, и степень
«редкости» хотелось бы регулировать.

Перепишите предыдущий expression следующим образом:

if(rand(1 )>0.9) velocity=-velocity;

Эта конструкция означает, что если очередное случайное число от нуля до единицы
оказалось больше, чем 0.9, то скорость частицы (ведь дело происходит при ее создании) меняется
на противоположную. Иначе можно сказать, что с вероятностью 10 процентов каждая следующая
частица полетит в другую сторону.

Формула if(rand(1 )>X) является универсальным способом организации вероятных событий.


Чем ближе X к единице, тем реже будет происходить событие.

В случае if(rand(1)>0.5) событие будет происходить с вероятностью пятьдесят процентов.

1084 Книга Сергея Цыпцына


Ода функции rand
Как заметили пытливые умы, редкий expression обходится без применения функции rand.
Действительно, эта простая функция, возвращающая одно число в заданном диапазоне, позволяет
организовать не только «массовые беспорядки», но и равномерное распределение некоторых
свойств среди достаточного большого количества частиц.

Главное достоинство этой функции - ее свойство возвращать новое случайное число при
каждом её вызове. То есть если в Runtime Expression для объекта из пяти тысяч частиц встречается
выражение типа

radiusPP=radiusPP+rand(-0.01, 0.01);

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

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

Примечание. Вызов rand(1) эквивалентен вызову/ rand(0,1). Соответственно,


rand(12.5) соответствует rand(0, 12.5).

Специально для трехмерных атрибутов типа скорости или позиции, существует объемная
реинкарнация этой функции под название sphrand(L), возвращающая случайный вектор заданной
длины. Компоненты этого вектора могут быть отрицательными. А для цвета можно воспользоваться
вызовом rand(<<x, у, z >>), возвращающим вектор (три числа), компоненты которого лежат в
диапазоне, от нуля до х, у, z, соответственно.

Измените expression из предыдушего примера следующим образом:

if(rand(1 )>0.5) velocity=sphrand(0.5);

Половина частиц полетит в случайном направлении, а половина продолжит прямолинейное


движение.

Динамика частиц 1085


До и после динамики
Обладатели «послепятых» версий MAYA, наверное, уже сгорают от желания узнать, когда
нужно выполнять Particle Expression - до или после динамики. До шестой версии MAYA в Attribute
Editor просто была неприметная, выключенная по умолчанию галочка Expression After Dynamics,
позволявшая выполнять имеющийся единственный Runtime Expression после динамики. Начиная с
шестой версии, для одних и тех же частиц можно создавать два разных Runtime Expression, один
из которых будет выполняться до вычисления динамики, а второй после. Я напомню, что все это
будет происходить в каждом кадре (точнее, в каждом oversampling-отсчете). Вся предыдущая
литература, учебники, упражнения и даже родная документация MAYA ссылается на Runtime Expres­
sion, предполагая, что он один, и не указывая, когда он выполняется: до или после динамики.

Внимание!! Если вы встречаете примеры на создание Runtime Expression или сами начинаете
экспериментировать, создавайте Runtime BEFORE Dynamic, выполняющийся до динамики. Оставьте
создание Runtime after Dynamic до тех времен, когда вы точно будете знать, что хотите проделать
над частицами некоторые действия после вычисления динамики.

Вычисление динамики означает складывание всех сил, производимых полями и расчет


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

Чтобы почувствовать разницу между before Dynamics и after Dynamics, откройте файл
smoke.ma.
Для того, чтобы сделать дымок не таким тонким и слегка его надуть изнутри, выберите
частицы и создайте для них следующий Runtime before Dynamic Expression:

acceleration = sphrand(1);

Это придаст каждой частице небольшое ускорение в случайном направлении. А затем


динамика добавит силу турбулентности и гравитации. Дымок станет более объемным, а
приведенный expression является универсальным трюком для «раздувания» частиц.

1086 Книга Сергея Цыпцына


Однако, если вы удалите этот expression и создадите Runtime after Dynamic Expression с
такой же формулой, частицы просто не отреагируют на ваши суетливые действия с ускорением и
будут двигаться, как раньше. Это связано с тем, что динамика сбрасывает ускорения частиц в ноль
перед каждым новым кадром и для расчета новых ускорений берет силы полей и то состояние, что
было перед ними (так положено по физике и математике).

Это ещё раз должно убедить вас использовать по умолчанию Runtime before Dynamic Expression.

Работа со скоростью и ускорением


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

Сделаем небольшой пример.


Создайте обычный источник частиц, задайте ему emitterType=Directional, rate=24, speed=5.
Если ваша машина просит апгрейда, задайте время жизни частиц равным десяти: lifespan=10.
Создайте локатор: Create=>Locator.
Назовите его lос, чтобы сэкономить время при написании expression и поощрить свою лень.
Сдвиньте его немного вверх.
Для частиц создайте такой Runtime Expression (здесь и далее, я буду подразумевать Runtime be­
fore Dynamic Expression):

vector $vloc = <<loc.tx,loc.ty,loc.tz>>;


vector $vpos = position;
vector $vres = $vloc - $vpos;
acceleration = $vres+sphrand(1);

Первая строка определяет вектор, торчащий из начала координат, в точку, где находится
локатор. Этот вектор одинаков для всех частиц, так как от них не зависит.

Динамика частиц 1087


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

Примечание. Три числа, определяющий вектор, задают направление и длину


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

Третья строка вычитает второй вектор из первого. Те кто успешно закончил начальную
школу помнят, что результатом будет вектор, направленный из конца второго ($vloc) на конец
первого ($vloc). To есть результирующий вектор направлен от частицы к локатору.

В четвертой строке ускорение направляется по результирующему вектору. Не забывайте,


что частицы имеют начальную скорость, полученную при испускании. При добавлении ускорения,
направленного на локатор, частицы пытаются «повернуть» в сторону локатора. Ускорение частиц
можно рассматривать как силу, «разворачивающую» конец вектора скорости (или «тянущую» за
конец вектора скорости). Чтобы немного притормозить частицы, задайте им conserve=0.999. Тогда
скорость начнет потихоньку падать, а сила поля, задаваемого ускорением, останется прежней.

1088 Книга Сергея Цыпцына


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

Почуствуйте разницу между скоростью и ускорением. Замените в последней, четвертой


строке acceleration на velocity, чтобы направлять частицы прямо на локатор.

vector $vloc = «loc.tx,loc.ty,loc.tz»;


vector $vpos = position;
vector $vres = $vloc - $vpos;
velocity = $vres;

Обратите внимание, что результирующий вектор определяет не только направление, но и


длину скорости, то есть её значение, влияющее на скорость полета частиц. Можете проанимировать
перемещения локатора, чтобы убедиться, что частицы продолжают стремиться к нему в любом
кадре.

Вернитесь к варианту с ускорением и немного надуйте поток частиц, добавив случайности


к вектору ускорения. Четвертая строка изменится следующим образом:

vector $vloc = <<loc.tx,loc.ty,loc.tz>>;


vector $vpos = position;
vector $vres = $vloc - $vpos;
acceleration = $vres+sphrand(1);

Динамика частиц 1089


Мы только что запрограммировали некоторое поле, которое притягивает частицы к
заданному объекту. Эта необходимость встречается в MAYA настолько часто, что в MAYA для нее
существует специальная операция, позволяющая обойтись без программирования и обладающая
массой дополнительных возможностей. Эта операция называется goal и позволяет направить
частицы не только к точке в пространстве, но и на поверхность объекта.

Goal, или воля к победе


Создайте простой источник частиц и какую-нибудь поверхность, например, сплайновый
конус (sections=20, spans=20).
Отодвиньте поверхность от источника.
Можете загрузить вместо конуса вашу любимую фотореалистичную голову.
Проиграйте анимацию немного.
Выберите частицы, а затем выберите поверхность.
Выполните операцию Particles=>Goal, попутно заметив, что в её Option Box был всего один
числовой параметр Goal Weight, равный 0.5.

Теперь уже существующие частицы, как безумные, бросаются на поверхность, а вылетающие


из источника стремятся к поверхности с некоторой закономерностью.

1090 Книга Сергея Цыпцына


После выполненной операции поверхностьстала «целью» для частиц (goal) и закономерность,
по которой они покрывают поверхность, заключается в следующем:

во-первых, частицы летят не на саму поверхность, а на её вершины,


во-вторых, первая частица стремится с первой вершине, вторая - ко второй, четырехсотая
(20x20) - к последней, четыреста первая частица - опять к первой и так далее, по кругу.

Примечание. На самом деле контрольных вершин у такого конуса - 460. Но об этом


знают только моделеры.

Первое, что хочется подрегулировать это степень стремления, тот самый goal weight,
промелькнувший при выполнении операции Goal. Его надо искать в атрибутах частиц: в Channel
Box он появляется как атрибут goalWeight[0], а в Attribute Editor в разделе Goal Weights and Ob­
ject под названием nurbsConeShape1. Это один и тот же атрибут, равный по умолчанию 0.5. Его
увеличение ведет у усилению притяжения частиц к поверхности, а установка в ноль заставляет
забыть о стремлении в поверхности вообще.

Динамика частиц 1091


Поставьте два ключа на этот атрибут: один в двухсотом кадре - для goalWeight=0 и один в
двести десятом для goalWeight=0.3.

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

Задайте conserve=0.95.
Теперь частицы «вспоминают» о своей цели только в сотом кадре и мягко стремятся к
своим вершинам.

Но не хватает хаоса, то есть все частицы стремятся к вершинам поверхности с одинаковой


силой. Можно, конечно, рявкнуть на них полем турбулентности или «надуть» их с помощью ex­
pression для ускорения. Но тем не менее вопрос об индивидуальной силе притяжения остается
открыт.

Пытливые умы, однако, уже заметили, что в Attribute Editor появился ещё один
дополнительный атрибут в разделе Per Particle (Array) Attributes.

Он называется goalPP и характеризует индивидуальной силу стремления к поверхности


для каждой частицы.

Дело в том, что индивидуальное ускорение частицы вычисляется умножением значения

1092 Книга Сергея Цыпцына


goalPP на общий для всех частиц goalWeight[0]. Это позволяет задать как общую меру притяжения,
так и индивидуальные множители для каждой частицы. По умолчанию goalPP равен единице,
поэтому все частицы имеют одинаковый вес.

Выберите частицы и создайте для них Creation Expression:

goalPP = rand(0.5, 1.5);

Таким образом, когда общая сила притяжения (goalWeigh[0]) станет равна 0.3, веса всех
частиц будут равномерно распределены в диапазоне от 0.15 до 4.5. Это заставит их стремиться к
поверхности с разной скоростью и добавит хаоса в их движение.

Кстати, в этом случае степень стремления задается для каждой частицы всего один раз -
при испускании, то есть в момент рождения. Чтобы сделать движение ещё менее упорядоченным,
скопируйте формулу для goalPP и создайте такой же Runtime Expression. Это заставит частицы
менять свою степень стремления к поверхности в каждом кадре.

Совет. Если вы хотите, чтобы источник испустил количество частиц, точно


равное количеству вершин, посчитайте, сколько вершин имеет поверхность, а
затем введите это число как значение атрибута Max Count для частиц.

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


необходимо анимировать не только общую степень стремления goalWeight[0], но и задавать
соответствующие значения для индивидуального атрибута goalPP, автоматически появляющегося
после выполнения операции Particles=>Goal.

Интерактивное взаимодействие с динамикой:


Interactive Playback
В шестой версии МАYA появилась возможность интерактивно взаимодействовать с динамикой
прямо во время воспроизведения анимации. Для этого в меню Solvers появился пункт меню In­
teractive Playback, после выполнения которого начинается проигрывание анимации, однако все
манипуляторы и возможность выбора объектов на экране остаются доступны. Во время анимации
вы можете перемещать источники, поля, объекты для столкновения с частицами или goal-объекты
прямо на экране. Крайне удобно вынести этот пункт меню на полку или назначить на горячую
клавишу. Интерактивные эксперименты можно проводить с частицами, флюидами или динамикой
волос.

Динамика частиц 1093


Многоцелевые частицы
«А что это за ноль в названии атрибута goalWeight[0] для частиц в Channel Box?»,- спросят
суперпытливые умы. Может ли быть, у частиц несколько целей?

Создайте ещё одну поверхность (например, политор, полигональный тор) или скопируйте
существующую.

Снова выберите частицы, затем новую поверхность и выполните Particles=>Goal.

Теперь частицы бодро летят на другую поверхность и после сотого кадра робко пытаются
дернуться в сторону конуса.

Очевидно, что вес новой поверхности больше, чем жалкие 0.3, которые имеет конус после
сотого кадра. Так и есть: в Channel Box для частиц теперь есть два атрибута goalWeight[0] и goal-
Weight[1], отвечающие за степень притяжения к конусу и тору, соответственно.

Исправьте goalWeight[1] на 0.3, и частицы будут пытаться занять положение, среднее


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

1094 Книга Сергея Цыпцына


Дальше понятно, что, анимируя веса разных поверхностей, являющихся Goal для частиц,
можно устраивать различные эффекты - типа пересыпания пригоршни частиц из одного места в
другое или роя мух, кидающихся на фотореалистичные объекты. Когда в разделе про мягкие тела
вы узнаете, что через частицы может проходит поверхность, вы будете наверняка обрадованы
возможностью динамического морфинга из одной формы в другую.

Поверхностей притяжения для частиц может быть сколько угодно, однако важно понимать,
что если количество атрибутов goalWeight[N] равно числу этих поверхностей, то атрибут goalPP
всегда один, и равняется индивидуальным для каждой частицы.

Совет. В качестве goal-объекта для частиц может выступать не только


поверхность, но и кривая, и даже другие частицы. Последний вариант очень удобен,
когда вам нужно запомнить положение частиц (скопировать их как объект), а позже
к нему вернуться (сделать скопированные частицы GOAI'OM для оригинальных).
Или организовать слегка отстающую «погоню» одних частиц за другими.

goalU) и goalV, или как уложить частицы точно на поверхность


Некоторые дотошные умы наверняка не удовлетворены тем, что частицы летят на вершины,
а не на саму поверхность. Тем более, что в случае NURBS-поверхностей контрольные точки вообще
не лежат на поверхности, и частицы будут висеть «около» объекта.

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

Выделите частицы и в Attribute Editor, в разделе Add Dynamic Attributes, нажмите кнопку
General, чтобы добавить эти секретные атрибуты.

В закладке Particles выберите атрибуты goalU и goalV и нажмите ОК. Эти названия появятся
в списке per particle атрибутов, а частицы станут лететь в одну точку.

Пытливые умы, конечно догадались, что по умолчанию значение атрибутов goalU/goalV


равно нулю, поэтому с их появлением частицы начинают лететь в точку поверхности с UV-
координатами (0,0). Таким образом, добавление этих двух атрибутов позволяет указать «место на
поверхности», куда должна лететь каждая частица.

Примечание. Важно хорошо представлять себе, что «место на поверхности» может


определяться только с помощью двух UV-координат, тех самых, по которым, как
правило, накладываются текстуры. Если для NURBS-поверхностей эти координаты

Динамика частиц 1095


определены однозначно, если не сказать шикарно, то для полигонов их может не
быть вовсе. Поэтому прежде, чем просить частицы полететь в определенное
«место на поверхности», надо убедиться, что такое место существует. Другими
словами, поверхность должна иметь адекватные UV-координаты - только тогда
можно указать частицам «место приземления», находящееся в диапазоне этих UV-
координат.

Если в качестве goalU или goalV указаны координаты, которые не существуют на


поверхности (например, отрицательные значения), частица будет стремиться к ближайшей точке
на поверхности или к точке с UV-координатами (0,0).

Откройте Creation Expression для частиц и дополните его двумя строчками:

goalPP = rand(0.5, 1.5);


goalU = rand(0,1);
goalV = rand (0,1);

После этого частицы будут равномерно облеплять поверхность.


Чтобы лучше увидеть это, удалите одну из поверхностей, a goalWeight оставшейся увеличьте до
0.9.

В этой формуле предполагается, что UV-координаты поверхности располагаются в диапазоне


от нуля до единицы. В случае NURBS-поверхностей, этот диапазон является также диапазоном
изменения параметров U и V, и может быть легко идентифицирован в Attribute Editor как значения
атрибутов Min Max Range U/V:

Если изменить диапазон разброса для goalU или goalV, частицы будут покрывать только
часть поверхности.

1096 Книга Сергея Цыпцына


Ещё раз отмечу, что назначение «места приземления» происходит в Creation Expression
один раз для каждой частицы. Если бы аналогичная формула стояла в Runtime Expression, частицы
бы лихорадочно носились по поверхности, меняя цель движения в каждом кадре. Если вы хотите,
чтобы частицы дополнительно хаотично ползали по поверхности, в Runtime Expression надо
прибавлять небольшие случайные величины к уже имеющимся (то есть определенным в Creation
Expression) значениями goalU и goalV.

Например:

goalU += rand(-0.001, 0.001);


goalV += rand(-0.001, 0.001);

И в заключение приведу пример Creation Expression (он, кстати, может быть использован и
как Runtime Expression), который заставляет частицы покрывать поверхность не хаотично, а рядами,
в виде прямоугольной сетки заданной плотности (в предположении о том, что UV-координаты на
объекте также представляют собой прямоугольную область, как на всех NURBS-поверхностях):

goalU=(id/50.)%1;
goalV=int(id/50)/50.%1;

или в более общей форме:

float $uRange=1.;
float $vRange=1.;
float $uGrid=50.;
float $vGrid=50.;
goalU=(id/$uGrid)%$uRange;
goalV=int(id/$uGrid)/$vGrid%$vRange;

Динамика частиц 1097


Концепция мягких тел
Идея мягких тел шокирующе проста. Чтобы её понять, надо проделать всего три
содержательных действия.

Создайте NURBS-плоскость (scale=20, patchesll=patchesV=30).

Выберите плоскость и превратите её в мягкое тело, выполнив Soft/Rigid Bodies=>Create


Soft Body, с установками по умолчанию.
А затем создайте поле турбулентности (Fields=>Turbulence), которое автоматически
прицепится к поверхности, так как она была выбрана в момент создания поля.
Проиграйте анимацию.
Если то, что происходило с твердыми телами в предыдущей главе ещё можно было
назвать универсальным словом «колбасинг», то к происходящему на экране сейчас подходящих
литературных слов уже не подобрать .

Кропотливые умы наверняка заметят какие-то точки, летающие вокруг да около поверхности.
Точки при ближайшем выборе и рассмотрении оказываются частицами. А метод пристального
взгляда позволяет определить, что частицы движутся под действием поля турбулентности.
Осталось понять, откуда они взялись.

1098 Книга Сергея Цыпцына


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

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

Перейдем к следующему разделу, описывающему, как подставлять вместо частиц реальные


геометрические объекты. Такой процесс называется инстансированием (particle instancing) и
позволяет быстро размножать объекты в огромном количестве и управлять их движением при
помощи динамики частиц.

Шутка. Про Particle Instancer я расскажу чуть позже, а сейчас изложу некоторое количество
замечаний и рассуждений относительно мягких тел.

Термин «мягкие» (soft) не совсем удачен, так как вызывает ассоциации с тканями, для
анимации которых существуют совершенно обособленные решения типа MAYA Cloth или Syflex
(см. www.syflex.biz). Назвать их «динамически деформируемые» было бы более корректно, но
настолько тяжеловесно, что я останусь в традиционной терминологии, а в устной майской русской
лексике прижился термин «софтбоди».

Хотя я сформулировал концепцию превращения объекта в мягкое тело только для


поверхностей, однако она справедлива и для кривых, и даже для Lattice-деформеров. То есть
для всех объектов, имеющих компоненты (правда, кроме частиц, для которых вы можете просто
скопировать particle-объект и назначить его как goal к оригинальным частицам).

Сабдивы не позволяют превращать себя напрямую в мягкое тело, однако вы всегда можете
применить трюк, описанный выше для твердых тел: перейти в режим Polygon и превратить в
мягкое тело полигональную сетку, окружающую сабдив. Либо назначить на поверхность (этот
трюк справедлив не только для сабдивов, но и для сложных поверхностей других типов) Lattice-
деформер и превратить в мягкое тело его. Это создаст мягкие динамические деформации для
любой поверхности.

Частицы, образующие мягкое тело, можно испускать из источника частиц. Достаточно


присоединить их к источнику в Dynamic Relationship. Это позволяет делать довольно забавные
эффекты с «выдуванием» поверхности из источника.

Теперь вернемся к предыдущему примеру и проделаем мысленно (но можно и на практике)


следующий опыт: если для частиц мягкого тела, разлетающихся под действием турбулентности,
создать точную копию плоскости и назначить её в качестве Goal для частиц, они наверняка
перестанут улетать далеко от плоскости и будут стремиться обратно к своим контрольным точкам.
Точнее, к контрольным точкам goal-плоскости. Оказывается, такой принцип используется при
создании «продвинутых» мягких тел, а параметры создания задаются через Option Box операции
Create Soft Body.

Удалите в предыдущем примере частицы или откройте новый файл и создайте сплайновую
плоскость заново (scale=20, patchesU=patchesV=30).
Выберите плоскость и откройте Option Box для Soft/Rigid Bodies=>Create Soft Body.

Динамика частиц 1099


Выберите Creation Option = Duplicate, Make Copy Soft.
А также включите Hide Non-Soft Object и Make Non-Soft a Goal.
Нажмите Create, чтобы создать мягкое тело.
Выбранные параметры означают, что выбранная поверхность будет сдублирована. Потом
копия поверхности будет превращенная в мягкое тело с частицами, а оригинальная поверхность
(Non-Soft) будет назначена как Goal для частиц. При этом она будет спрятана, и на экране останется
только мягкое тело. Так как две поверхности будут идентичны, каждая частица будет стремиться
в место своего рождения, то есть в соответствующую точку на спрятанной поверхности.
Снова выберите поверхность на экране (или частицы в Outliner) и создайте поле
турбулентности.
Теперь, чтобы заставить частицы пошевелиться, надо задать довольно приличную силу
поля (magnitude=50) и даже уменьшить атрибут attenuation до нуля.

Постоянно помните о том, что существует невидимая поверхность и что частицы стремятся
к ней с заданным весом. Этот вес можно найти в Channel Box для частиц как значение атрибута
goalWeight[0].

Установите его в 0.3 и посмотрите, как ослабилось притяжение к поверхности. Затем


задайте goalWeight[0]=1 и убедитесь, что частицы прилипли намертво к невидимой поверхности и
игнорируют любые внешние воздействия.

Вспомним, что у каждой частицы может быть свой собственный вес (атрибут goalPP),
который умножается на общий goalWeight. С его помощью можно сделать некоторые участки
поверхности «мягче» или «жестче» остальных. Для частиц, образующих мягкие тела, имеется
возможность, вместо создания expressions для goalPP, просто раскрасить поверхность мягкого тела
в черно-белые оттенки, задавая, таким образом, распределение goalPP вдоль поверхности.
Выберите плоскость и возьмите в руки инструмент раскраски весов мягкого тела: Soft/
Rigid Bodies=>Paint Soft Body Weights Tool.
Поверхность сразу окрасится в белый цвет, так как goalPP для всех частиц равен единице
по умолчанию.

В окне Tool Settings задайте Value=0.2 и нарисуйте что-нибудь на поверхности, напишите


любое слово.

1100 Книга Сергея Цыпцына


Если проиграть анимацию, двигаться будут только те области поверхности, для которых
вес частиц меньше единицы, то есть темные участки.

Раскраску поверхности можно применять для анимации остаточных движений (как


альтернативу Jiggle Deformer). Если анимированныйобъект превратить в мягкое тело вышеуказанным
способом, то при goalWeight=1 оно будет точно следовать за невидимым оригиналом. Далее с
помощью Paint Soft Body Weights Tool можно раскрашивать в серые оттенки те участки поверхности,
которые должны «отставать» при движении.

Попробуем превратить имеющееся мягкое тело с подобие занавески.

Динамика частиц 1101


Фальшивый занавес
Удалите все поля турбулентности из сцены, выберите поверхность и создайте поле
гравитации: Fields=>Gravity.

Покрашенные части слегка «провиснут». Идея состоит в том, чтобы закрепить только один
крайний ряд частиц, а остальные «отвязать» от невидимой goal-плоскости, задав для них goal-
РР=0.

Выберите в Outliner частицы и нажмите F8, чтобы перейти в компонентный режим.


Перейдите в окно Тор и выберите все частицы, кроме крайнего левого ряда.

Откройте Window=>General Editors=>Component Editor и найдите закладку Particles и


столбец goalPP.
Нажмите левую кнопку мыши над первой клеткой и, не отпуская, протащите до последней,
выделив, таким образом, все клетки. Или щелкните по заголовку столбца.
Введите 0 и нажмите Enter, изменив персональный вес goalPP для каждой выбранной частицы.

1102 Книга Сергея Цыпцына


Закройте окно. Нажмите F8. Перейдите в перспективу и нажмите Play. Основная часть
плоскости улетает вниз, так как все частицы, кроме крайнего ряда, больше не стремятся к
невидимой поверхности.

Если некоторые частицы, кроме крайних, остались на месте, это значит, что в Component
Editor «влезло» только 1024 из всех выбранных частиц, а часть осталась неотредактированной.
Повторите редактирование goalPP для оставшихся частиц, аналогичным образом.

Осталось вставить пружины, чтобы удержать свободные частицы от падения на самое дно.
Так же, как и для твердых тел, между частицами можно вставлять пружины. При этом, если
выбрать конкретные частицы как компоненты (и даже точки поверхности вместе с ними), пружины
будут натянуты только между выбранными компонентами. Если же выбрать мягкое тело как объект,
пружины будут создаваться для всех частиц, составляющих мягкое тело. Естественно, что должна
быть возможность как-то определить общий закон распределения пружин для целого массива
частиц, не определяя индивидуальные связи для каждой пары частиц.

Встаньте в первый кадр.


Выберите плоскость и откройте Option Box для Soft/Rigid Bodies=>Create Springs.
Установите Creation Method=MinMax; Max Distance=4;
Нажмите Create.
Метод MinMax натягивает пружины между всеми частицами, находящимися друг от друга

Динамика частиц 1103


не далее, чем на Max Distance, и не ближе друг к другу, чем на Min Distance. Он обеспечивает
равномерное покрытие частиц пружинами ограниченной длины. Метод Аll натягивает пружины
между всеми без исключения частицами и дает, как правило, слишком густые сетки из пружин.

Для того, чтобы анимация крутилась быстрее, спрячьте только что созданные пружины
(Ctrl+h). Очевидно, что пружинам не хватает жесткости. Также очевидно, что жесткость
определяется через атрибут stiffness у вновь созданного объекта spring1, который можно выбрать
в Outliner.
Задайте stiffness=20.
Спрячьте частицы, для красоты, и уберите координатную сетку.
При проигрывании могут наблюдаться высокочастотные «биения».

Это происходит от того, что частицы совершенно не тормозятся и в системе возникают


высокие скорости, которые, как известно, главный враг динамики.
Притормозите частицы: выберите их и задайте conserve=0.999.

Однако после этого, несмотря на то, что общее движение поверхности стало более
спокойным и затухающим, биения не прекратились. Для того, чтобы совсем от них избавиться,
надо увеличить точность просчета динамики частиц.
Для этого откройте Solvers=>Edit Oversampling or Cache Settings и введите значения 2 для
параметра Over Samples. Это позволит вычислять траектории и определять скорости частиц в два
раза чаще и, как следствие, в два раза точнее.

1104 Книга Сергея Цыпцына


После этого биения исчезнут, и «занавеска» начнет раскачиваться, постепенно затухая.

Примечание. Высокие скорости в системе обычно возникают при наличии «жестких»


элементов или сильно упругих взаимодействий. Мягкое тело нельзя довести до
состояния «нерастягиваемости», агрессивно увеличивая жесткость пружин:
это приведет лишь к появлению очередных биений, разрывающих поверхность в
клочья. Поэтому старайтесь избегать высоких значений для атрибут stiffness,
так как это привносит в систему высокоскоростные перемещения.

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


проиграйте примерно 115 кадров и выполните 5olvers=>lnitial State=>Set for All Dynamic.
Теперь анимация будет начинаться с этого кадра.

Динамика частиц 1105


Поставим препятствие на пути поверхности и заставим частицы, составляющие мягкое
тело, столкнуться с этим препятствием.
Создайте NURBS-сферу и опустите её вниз (translateX=translatY=-13; scale=5).

В первом кадре поверхности не должны соприкасаться.


Выберите частицы, затем сферу и выполните Particles=>Make Collide.
В Channel Box установите для geoConnector: Friction=0.1; Resilence=0;
Частицы не должны отскакивать вообще и будут немного тормозиться при соприкосновении.

Сфера взаимодействует с занавеской, но "прорывается" сквозь нее.

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

1106 Книга Сергея Цыпцына


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

Сгруппируйте обе сферы для синхронного перемещения, если вы собираетесь анимировать


их движение.
Поэкпериментируйте с атрибутами friction и resilience для ноды geoConnector у невидимой
сцены.

Динамика частиц 1107


Сохраните сцену (softBody.ma).
Как видите, применение динамики мягких тел для анимации «типа тканей» весьма
своеобразно. Такой подход имеет свои плюсы и минусы. Основное преимущество это практически
интерактивная скорость просчета динамики и гибкие возможности анимации с помощью
известных полей, goal, expressions и пр. Основной недостаток проблематичное взаимодействие с
препятствиями и полное отсутствие контроля взаимопроникновения.
Чтобы у вас не возникло иллюзии, что мягкие тела применяются исключительно для
анимации «тряпок», приведу ставший уже каноническим пример «выдувания» поверхности из
источника частиц.

Как надуть модель?


Этот пример базируется на понимании того, что частицы, составляющие мягкое тело,
ничуть не лучше и не хуже обычных частиц. Следовательно, их можно испускать из источников и
редактировать им время жизни.

Загрузите свою любимую модель (или файл headStart.ma) или создайте NURBS-сферу с
достаточным количеством изопарм.

Затем создайте обычный источник частиц (Create=>Emitter).

Напомню, что при создании источника вместе с ним появляется объект типа particle, то
есть частицы, вылетающие из источника.

Эти частицы надо выбрать в Outliner (они наверняка называются particle - !), и безжалостно
удалить.

Теперь выберите поверхность и превратите её в мягкое тело (Soft/Rigid Bodies=>Create


Soft Body) с опциями Creation Option = Duplicate, Make Copy Soft; Hide Non-Soft Object=On; Make
Non-Soft a Goal=On; Weight=0.5.

1108 Книга Сергея Цыпцына


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

Это можно сделать в Dynamics Relationship, выбрав слева частицы, а справа источник (и не
забыв включить наверху опцию Emitters).

Совет. То же самое можно сделать быстрее: выбрав частицы, затем источник и


выполнив в основном меню Particles=>Use Selected Emitter.

После этого, правда, ничего не изменится: новые частицы не появляются, старые стоят
на месте. Откройте Attribute Editor и в разделе Soft Body Attributes выключите галку Enforce Count
from History, которая удерживает постоянным количество частиц, составляющих мягкое тело и не
дает ему увеличиваться или уменьшаться.

Динамика частиц 1109


Теперь частицы начнут вылетать из источника и лететь на свои места: первая на первую
вершину, вторая - на вторую, и так далее, по кругу. Напомню, что у частиц имеется спрятанная
Goal-поверхность, к которой они стремятся.

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

Встаньте в первый кадр.

Выберите частицы, в Attribute Editor задайте Lifespan Mode=Constant, Lifespan=0. Перейдите


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

Теперь сохраните это состояние как начальное для всей динамики: Solvers=>lnitial
State=>Set for All Dynamics.

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


Lifespans=100.
Теперь можете наблюдать процесс «выдувания».

Несколько замечаний по поводу таких «надувательств».


Поэкспериментируйте с goalWeight[0] для частиц: это изменит плавность появления
поверхности и её степень стремления к спрятанному оригиналу.
Порядок и направление появления поверхности определяется нумерацией вершин. Для
NURBS-поверхностей его можно менять с помощью операции Edit NURBS=>Reverse Surface Direc­
tion.

Оригинальная поверхность, которая превращалась в мягкое тело, может быть как угодно
анимированной появляющееся «полотно» будет повторять все деформации и перемещения
оригинала.

Для поверхностей с большим числом вершин, особенно для полигонов, где нумерация
вершин не так очевидна, как для сплайнов, проще иногда создать Lattice-решетку и превратить ее

1110 Книга Сергея Цыпцына


в мягкое тело, а затем «надуть». Да-да, именно ее: ведь у нее тоже есть компоненты, и решетка,
следовательно, тоже может быть мягким телом.

Частицы можно просто спрятать, однако, если вы хотите, чтобы источник «выплюнул» ровно
столько частиц, сколько составляют мягкое тело, посчитайте количество вершин у поверхности
(или решетки) и задайте это значение для атрибута maxCount у частиц в Attribute Editor. Это
позволит ограничить появление лишних частиц, а при маленьком времени жизни создать эффект
умирания и рождения поверхности заново.

В случае NURBS-поверхности можно подобрать значение rate для источника так, чтобы
в каждом кадре появлялось количество частиц, равное числу точек, образующих один ряд
контрольных вершин поверхности. Тогда «рождение» поверхности будет особенно «гладким».
Сохраните сцену (headSoftBody.ma).

В заключение отмечу, что динамика мягких тел применяется не только для деформации
непосредственно поверхностей, но и для создания динамической деформации кривых, которые
можно потом использовать, к примеру, как IK Spline Handle или Wrap Deformer.

Также мягкие тела можно применять для медитации. Если вам это интересно, выполните
следующие упражнение.

Медитация на мягких телах


Сохраните все сцены.
Отключите телефон.
Включите источник бесперебойного питания.
Закройте дверь.
Откройте новую сцену.
Создайте NURBS-плоскость.
Задайте scale=20.
А также patchesll=patchesV=30.
В атрибутах материала lambert1, по умолчанию назначенного на плоскость, повесьте на
канал Color текстуру Ramp и установите для нее Type=Circular Ramp.

Теперь выберите плоскость и превратите её в мягкое тело с установками по умолчанию


Soft/Rigid Bodies=>Create Soft BodyfMake Soft].

Пока плоскость выбрана, создайте радиальное поле Fields=>Radial Field.


Приподнимите его немного (translateY=1) и задайте magnitude=-5.
Все готово к медитации, осталось спрятать ненужные вещи и навести порядок вокруг.
Выберите и спрячьте частицы и поле (Ctrl-h).

Динамика частиц 1111


Уберите с экрана сетку (DispLay=>Grid).
Задайте диапазон анимации равным 10000 кадров.
Установите цвет экрана абсолютно черным (Windows=>Settings/Preferences=>Colors=>Gene
ral=>3D View.
Перейдите в камеру Тор.
Выполните Display=>UI Elements=>Hide Ul Elements.
Спрячьте все меню (Ctrl-m, Shift-m).

Выключите свет, займите удобную позу и нажмите Alt-v. Надеюсь, в этой жизни мы ещё
увидимся...

Инстансирование. Подстановка объектов в частицы


Визуализация частиц в виде реальной геометрии применяется очень часто. Это, во-первых,
позволяет анимировать тысячи объектов в терминах динамики частиц, то есть в «массовом
порядке», а во-вторых, делает задачу рендеринга предсказуемой и традиционной.
Реализация этой задачи в MAYA достаточно изящна, хотя и не очень проста для восприятия.
Суть концепции управления движением объектов при помощи частиц можно хорошо усвоить,
только уже имея представления различных свойствах и атрибутах частиц и обладая навыками
написания несложных Particle Expressions. Разберем эту концепцию на несложном примере.
Чтобы не путаться с тысячах объектов, откройте уже имеющийся файл smoke.mа или
создайте обычный источник частиц.

Уменьшите rate для источника до двух.

1112 Книга Сергея Цыпцына


В эти редкие частицы попробуем «засунуть» реальную геометрию. Если у вас есть
любимая модель рыбы, птицы, бабочки, самолета или паровоза, импортируйте её в сцену. Если
нет, изготовьте что-нибудь продолговатое или сделайте импорт файла instancerBody.ma в сцену с
дымком (File=>Import).

Импортный самолет всех времен и народов несколько велик для подстановки в частицы,
так что задайте для него scale=0.2.

Отодвиньте его в сторону, чтобы он не мешал обзору частиц.

Как обычно, можно действовать двумя методами: либо выполнить операцию подстановки
с параметрами по умолчанию, а потом поправить нужные атрибуты, либо зайти в Option Box и
настроить нужные параметры с самого начала.

Особенность операции подстановки заключается в том, что её действие будет разным, в

Динамика частиц 1113


случае, если выполнить пункт меню Particle=>lnstancer (Replacement), и в случае, если открыть
Option Box этой операции и нажать кнопку Create.

Как следует из Help Line, чтобы подставить объект в частицы, надо сначала выбрать сам
объект (или объекты), потом частицы, а затем выполнить операцию подстановки. Однако если вы
откроете Option Box, сами частицы (так как они были выбраны в соответствии с рекомендациями
Help Line) попадут в список объектов для подстановки в самих себя. Это, естественно, создаст
некоторые проблемы и непонимание со стороны окружающих.

Поэтому мы будем действовать первым путем и настраивать параметры подстановки после


выполнения операции с опциями по умолчанию.

Выберите объект, затем частицы и выполните Particle=>lnstancer (Replacement).

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

Наблюдения за всякими скоплениями живности позволяют определить неформальное


правило их движения - участники коллективных перемещений двигаются «носом по скорости».
Поэтому для нашего авиакосяка надо задать аналогичное условие движение.

Параметры, определяющие подстановку объектов, можно отредактировать через атрибуты


частиц, расположенные в Attribute Editor в разделе Instancer (Geometry Replacement).

1114 Книга Сергея Цыпцына


С первого раза вообще ничего не понятно: по крайней мере, я бился с логикой этого раздела
около суток, используя, правда, «метод тыка». Основная идея в том, что слева расположены
названия атрибутов и параметров подставляемых объектов, а справа - атрибуты частиц. Так как для
каждой новой частицы создается новая копия объекта, для нее определяется, как индивидуальные
атрибуты частицы влияют на некоторые атрибуты этой копии.

Строка Position=worldPosition означает, что позиция подставляемого объекта совпадает с


мировой позицией частицы, в которую этот объект подставляется. Это в общем-то, очевидно, и
предполагается по умолчанию. С остальными атрибутами объекта все не так очевидно. Например,
у каждой частицы нет индивидуального атрибута scale, поэтому для управления размером объекта,
подставляемого в очередную частицу, можно использовать любой другой индивидуальный атрибут
частицы. В нашем случае, для анимации размера самолетов можно использовать атрибут opacit­
yPP, который управляет прозрачностью и постепенно уменьшается для каждой частицы. Однако по
умолчанию названия opacityPP нет в списке атрибутов, выпадающем напротив Scale.

Это связано с тем, что opacityPP - одно число, a scale - сразу три значения.
Чтобы MAYA автоматически пересчитывала одно значение в три одинаковых атрибута,
включите галку Allow All Data Types и в списке Scale появятся все индивидуальные атрибуты
частицы, а не только состоящие из трех значений.

Динамика частиц 1115


Выберите opacityPP в качестве атрибута, управляющего размером (Scale) объекта, и вы
увидите, как самолеты благополучно уменьшаются, перед тем, как исчезнуть.

Однако это по-прежнему не решает проблему плоско-параллельного перемещения


самолетов. Очевидно, для них надо задать способ вращения, то есть определить, как будут
вычисляться атрибуты rotate для каждого объекта, в зависимости от атрибутов частицы.
Но проблема состоит в том, что у частиц нет поверхности и, следовательно, нет атрибута ro­
tate, который можно было бы использовать для поворота подставляемых объектов. Поэтому, в

1116 Книга Сергея Цыпцына


отличие от scale, используется не прямое копирование атрибутов частицы в атрибуты объекта,
а вычисление поворотов на основе правил, аналогичных случаю движения по пути. Поэтому для
задания вращений в Attribute Editor есть целый подраздел.
Установите Aim Direction=worldVelocity. Это будет равносильно указанию: «повернуться
так, чтобы смотреть носом вдоль направления скорости».

Самолеты резко встанут на крыло и начнут летать левым бортом вперед. Проблема
аналогична случаю движению вдоль пути. Мы не определили, где у самолетов «нос», и они летят,
поворачиваясь вперед своей локальной осью X.

К сожалению, чтобы переопределить «носовую» ось, как в случае с motionPath, придется


завести новый атрибут (типа aimPP) и написать крошечный, но expression (типа aimPP=<<0,0,1>> ),
чтобы потом задать этот атрибут на вход параметру AimAxis.

Мы, однако, поступим проще.

Выберите оригинальный самолет и поверните его вокруг оси Y, так чтобы его нос смотрел
вдоль мировой оси X (rotateY=90).

Теперь сделайте Modify=>Freeze Transformation, но только для атрибутов rotate.

Динамика частиц 1117


Это развернет локальные оси объекта вдоль мировых осей, и самолеты полетят носом
вперед.

Примечание. Если сделать Freeze Transformation для всех атрибутов, а не только


для rotate, это обнулит также атрибуты translate, и получится так, что стоящий
в стороне самолет в этом положении имеет свое «начальное положение». Поэтому
при подстановке такие объекты будут иметь сдвиг от центра частицы, равный
смещению от начала координат.

Примечание. Помните о том, что, как и при движении вдоль пути, важна не
только ориентация «носа» объекта, но и направление, куда смотрит «макушка».
По умолчанию «макушка» - это локальная ось Y oбъекma(AimUpAxis), а направление
«вверх» задается вариантом AimWorldUp и, по умолчанию, является направлением
вдоль мировой оси Y (0,1,0).

Для взрослых. Поворачивать объект можно не только вдоль направления какого-


нибудь вектора, но и задавая точку (то есть три числа), на которую должен

1118 Книга Сергея Цыпцына


смотреть подставляемый объект. Для этого в Rotation Options используется
вариант Aim Position, для которого надо указать атрибут частицы, содержащий
координаты этой точки. Если, к примеру, все самолеты должны смотреть на
локатор, к частицам надо добавить per-particle атрибут типа вектор (например,
targetPP)

и написать Runtime Expression:

targetPP=<<locator1 .tx,locator1 .ty,locator1.tz»;

Затем надо указать в Rotation Options для частиц AimPosition=targetPP.

Это заставит все объекты смотреть не вдоль вектора, а на точку в пространстве, занимаемую
локатором.

Динамика частиц 1119


А кто же главнее - AimPosition или AimDirection, если задать оба варианта? Важнее Aim-
Direction, так как он выше в списке. Над ним есть ещё вариант Rotation, позволяющий просто
копировать три числа в атрибуты rotate объекта из указанного per-particle атрибута (это может
быть полезно для задания случайных вращений).

Сохраните сцену (instancerFinal.ma).

Можете увеличить rate у источника частиц и провести над ними любые издевательства
- самолеты будут послушно следовать за частицами. Только помните о том, что при столкновениях
с поверхностями будут использоваться частицы, поэтому объекты будут «проваливаться» в
поверхность (если надо, скопируйте и сдвиньте поверхность для обмана честных граждан).
Самолеты также ничего не знают (и никогда не узнают) друг про друга, ведь они - только
визуализация частиц, которые также ничего не знают друг о друге.

Попробуйте анимировать исходный самолет. Например, попросите его помахать крыльями


с помощью BlendShape или Bend Deformer. Вы увидите, что вся анимация полностью наследуется
подставленными объектами.

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

Изготовьте такую эскадрилью прямо в предыдущем файле с дымком (instancerFinal.ma),


размножив одинокий самолет в нужном количестве.

Задача состоит в том, чтобы заставить самолеты эскадрильи вылетать из источника по


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

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

Ещё профессиональнее будет удалить все источники, кроме одного, а оставшиеся несколько
объектов типа particle присоединить к одному источнику, чтобы он испускал сразу несколько
видов частиц, подставленных разными объектами. (Надо только не забыть в этом случае у всех
частиц выставить разные значения в разделе Emission Random Stream Seeds, чтобы они вылетали
из одного источника по-разному.)

1120 Книга Сергея Цыпцына


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

Если у вас в сцене остался объект instancerl, отвечающий за предыдущую подстановку,


удалите его, это убьет все самолеты, летающие вместе с частицами.
Выберите все самолеты эскадрильи, а затем частицы. Выполните Particles=>lnstancer(Replacemen
t).

Однако взлетать начнет только первый самолет.

Откройте Attribute Editor для частиц и в разделе Instancer (Geometry Replacement)


установите AimDirection=worldVelocity, чтобы самолеты развернулись. Попутно отметьте, что
немного выше есть загадочный параметр Objectlndex, установленный в None.

Динамика частиц 1121


Этот параметр отвечает за номер самолета в списке объектов, подставленных в частицы.
Посмотреть этот список можно, выбрав в Outliner объект instanced и открыв Attribute Editor.

Номера (индексы) объектов в списке начинаются с нуля, именно поэтому, если


objectlndex=None, то при подстановке используется первый объект (с индексом ноль). Если для
частиц в параметрах подстановки указать objectlndex=particleld, первые несколько объектов
появятся по очереди, однако потом начнет вылетать только последний объект, так как номера
вылетающих частиц (particleld) становятся больше, чем последний индекс в списке.

1122 Книга Сергея Цыпцына


Очевидно, необходимо создать атрибут, задающий номер объекта в списке, который будет
подставлен в конкретную частицу. Такой атрибут должен быть per-particle, то есть индивидуальным
и содержать одно число - индекс.

В Attribute Editor для частиц нажмите кнопку General в разделе Add Dynamic Attributes.
В появившемся окне для добавления атрибутов выберите Data Type=Float и Attribute
Type=Per Particle(Array).

Назовите атрибут indexPP и добавьте его.

Теперь надо задать закон изменения атрибута indexPP в зависимости от номера вылетающей
частицы.
Для того, чтобы объекты подставлялись в частицы по очереди и по кругу, создайте Crea­
tion Expression:

indexPP=particleld%6;

Здесь число 6 - это количество подставляемых объектов. А формула читается так: индекс
равен остатку от деления номера частицы на шесть.
Если вы хотите, чтобы объекты вылетали не по очереди, а в случайном порядке, то Crea­
tion Expression может выглядеть так:

indexPP = rand(0, 6);

Самое главное не забыть указать Objectlndex=indexPP в параметрах подстановки.

Динамика частиц 1123


Оригинальные самолеты эскадрильи можно спрятать, это не окажет влияния на
подставляемые объекты. Сохраните файл (instancerFinalMulti.ma).

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


объектов. Размер, повороты, видимость, номер объекта в списке - все эти параметры можно
анимировать с помощью создания дополнительных атрибутов и написания соответствующих ex­
pressions к ним.

К сожалению, при подстановке анимированного объекта в частицы никак нельзя задать


индивидуальный сдвиг анимации по времени для каждой копии подставляемого объекта. То есть
при подстановке машущего крыльями самолета все вылетающие объекты будут махать крыльями
синхронно.

Примечание без комментариев. Если вы хотите, чтобы объекты появлялись по


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

После подстановки нескольких объектов в одну систему частиц выберите в Outliner объект
instancer и задайте для него Cycle=Sequental.

Затем выберите частицы и в Attribute Editor, в разделе Instancer (Geometry Replacement),


установите CycleStartObject=particleld и Age=particleld.

1124 Книга Сергея Цыпцына


Чтобы осознать смысл проделанного, надо все-таки прочесть немного документации и
немного подумать.

Сжатие и растяжение динамики


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

На помощь приходит понимание того, что вся динамика зависит от системного времени,
которое в свою очередь, является обычным майским объектом, соединенным с динамическими
объектами связью между атрибутами. Следовательно, если «перехватить» эту связь, а затем
время немного растянуть или сжать и подать обратно на вход к динамике, можно изменять общий
темп выполнения динамики в сцене. После таких туманных заявлений проделаем два небольших
примера на работу со временем.

Ускорение/торможение падения твердых тел


Первый пример из динамики твердых тел. Пример очень прост домино падает на
плоскость под действием силы тяжести (scaleBodyDynamicsStart.ma). Если вам лень открывать
сцену, сделайте подкупающую новизной прыгающую сферу по плоскости.

Домино бодро падает на плоскость, но предположим, что по условиям "технического


задания" вся сцена - от начала падения до полной остановки - должна занимать строго определенное
время, например, 100 кадров. (При производстве рекламных роликов или телевизионных заставок

Динамика частиц 1125


такое жесткое нормирование времени, отпущенного на спецэффект - весьма распространенное
явление.) Однако сцена падения получилась продолжительностью в 160 кадров. Как быть?

Попытка соответствующим образом настроить параметры динамической системы, такие


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

Можно преобразовать динамическую сцену в анимацию по ключевым кадрам (bake simula­


tion), и к полученным анимационным кривым движения кубика применить технологию искажения
времени, но и этот путь не лишен недостатков. Во-первых, мы лишаемся всех динамических законов,
и становится проблематичным внесение исправлений в сцену (как то, пожеланий режиссера, типа
"Вот бы кубик прыгал повыше и повеселее!"). Во-вторых, после "испекания" может потребоваться
дополнительная обработка полученных анимационных кривых, например, Эйлерова фильтрация
кривых вращения. Наконец, этот путь просто неэлегантен.

Гораздо более плодотворной представляется идея изменить внутреннее (локальное)


время самой динамической системы. В случае твердых тел это внутренне время следует искать
в атрибутах "решателя" (Rigid Body Solver) именно он отвечает за создание динамической
анимации.

Откройте Solvers=>Rigid Body Solver и обратите внимание на атрибут currentTime - это и


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

1126 Книга Сергея Цыпцына


Атрибут currentTime не свободен, то есть имеет связь с другим атрибутом ( о чем
свидетельствует желтый цвет поля атрибута). Но нас это не должно пугать. Воспользовавшись Ну-
pergraph мы легко можем определить, что интересующий нас аттрибут напрямую связан с time1.
outTime, то есть с глобальным временем системы.

Разорвите эту связь прямо в Attribute Editor (правая кнопка мыши - Break Connection), a
затем в поле аттрибута currentTime введите строку:

=(160.0/100.0)*time1. outTime;

Это создаст простой expression, пересчитывающий и ускоряющий локальное время


"решателя" в 160/100=1.6 раз.

Теперь вся сцена с кубиком длится ровно желаемые 100 кадров, причем мы полностью
сохранили контроль над всеми управляющими параметрами и при необходимости можем её легко
модифицировать.

Примечание. В данном случае анимация начиналась с нулевого кадра и в атрибутах


«решателя» значение Start Time также равно нулю. Это важно, так как в первом (а
не в нулевом кадре) атрибут currentTime примет значение 1.6. Если бы все действия
были проделаны с кадром номер 1 в качестве начального, то при возвращении в
этот начальный кадр динамическая система бы не возвращалась в свое начальное

Динамика частиц 1127


положение. Использование нулевого кадра в качестве начального для динамики и
анимации решает эту проблему.

Примечание. Подергивания объектов после падения можно «заморозить», просто


анимировав атрибут active, то есть превратив после некоторого кадра все кубики
в пассивные твердые тела.

Замораживание частиц - остановка динамического времени


Чтобы сделать эффект типа «как в матрице», когда все объекты застывают на местах, а
продолжает двигаться только камера, можно просто расставить необходимые ключи на объектах и
камере. Однако на движение частиц ключи поставить нельзя, поэтому опять придется поработать с
локальным временем частиц. Оно является их собственным атрибутом, поэтому у каждой системы
частиц может быть свой темп выполнения динамики.

Откройте файл fountain.mа и сделайте анимацию камеры с сотого по двухсотый кадр. Если
вам лень, откройте файл scaleParticleDynamicsStart.ma.

Задача состоит в том, чтобы частицы замирали в момент движения камеры и снова
начинали двигаться после двухсотого кадра. Идея анимировать conserve от нуля до единицы не
очень хороша, так как частицы просто безвольно упадут вниз после обнуления скорости. Будем
дейтвовать радикально - поставим ключи на собственное локальное время частиц (не путать с
временем жизни).
Выберите частицы, а в Attribute Editor разыщите атрибут currentTime.
Он имеет связь с глобальным временем timel.outTime, которую необходимо немедленно
разорвать (Break Connection).

После этого частицы перестанут испускаться вообще. Ещё бы их внутренние часы


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

1128 Книга Сергея Цыпцына


Встаньте в первый кадр, задайте currentTime=1 и поставьте ключ на этот атрибут. Перейдите
с сотый кадр и установите currentTime=100 и снова поставьте ключ.

Частицы начнут «жить» только на этом интервале времени.

Встаньте в двухсотый кадр и опять задайте currentTime=100 и не забудьте поставить ключ.


Теперь время частиц отстает от глобального времени на сто кадров.
Перейдите в пятисотый кадр и установите currentTime=400. Это почти все, что требовалось сделать.
Если частицы немного ускоряются или тормозятся после «разморозки», необходимо посмотреть
на вид анимационной кривой для частиц в Graph Editor и при необходимости исправить все ключи
в тип Linear.

Динамика частиц 1129


Однако остались ещё кое-какие тонкости: например, после двухсотого кадра некоторые
частицы резко отскакивают от поверхности и как-то резко вылетают из источника. Это наводит на
мысль, что локальное время есть не только у частиц, но и у остальных динамических объектов,
принимающих участие в расчете движения частиц (в отличие от твердых тел, где все заботы по
расчетам на себя берет один объект Rigid Body Solver).

Так и есть: исследования в Hypergraph обнаруживают наличие атрибута currentTime у


объекта emitter1 и ноды geoConnector1.

Теперь выберите частицы, откройте Hypergraph и выполните Graph=>lnput And Output Con­
nections.

Чтобы не повторять процедуру постановки ключей и сделать решение более универсальным,


нужно просто подсоединить уже созданную анимационную кривую к атрибуту currentTime у двух
вышеперечисленных объектов.

Нажмите shift, перетащите и бросьте в Hypergraph средней кнопкой мыши анимационную


кривую на geoConnector1. В появившемся Connection Editor присоедините атрибут output к атрибуту
currentTime.

1130 Книга Сергея Цыпцына


Проделайте то же самое с анимационной кривой и источником emitter1.

Теперь все динамические объекты имеют общее «примороженное» время, определяемое


анимационной кривой. Однако в некоторых ситуациях частицы продолжают резко отскакивать от
поверхности после разморозки. Если это так, проделайте еще одно шаманское действие. Оно
связано с тем, что мы разорвали связи динамических объектов с системным временем и подсунули
им вместо этого анимационную кривую, которая с временем явно не связана (об этом подробнее
в изнаночной главе). Чтобы починить «динамику», соединим анимационную кривую и системное
время.

Выберите в Outliner ноду t i m e l , включив там отображение всех объектов в сцены. Загрузите
time1 в левую часть Connection Editor, а в правую часть загрузите анимационную кривую particle-
Shape1_currentTime, которую можно выбрать в Hypergraph.

Присоедините timel.outTime к particleShape1_currentTime.input.

Динамика частиц 1131


После такой магии частицы должны вести себя как положено.
Взаимодействия между частицами
Как я уже упоминал выше, частицы - с точки зрения динамики и расчета их траекторий
являются бесконечно малыми точками и поэтому не могут сталкиваться друг с другом. По умолчанию
соседние частицы ничего друг про друга не знают и знать не хотят. Существует несколько способов,
однако, заставить частицы взаимодействовать друг с другом. Следует помнить при этом, что сама
дискретная модель, используемая в майской динамике частиц, не очень хорошо подходит для
точного описания движения жидкостей и других сплошных сред, требующих расчета не только
скоростей, но и плотностей, давления, перемешивания и т.д. Для таких расчетов больше подходит
модуль MAYA Fluids или более специализированные отдельные программы.

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

Первый способ организовать взаимодействие частиц состоит в том, чтобы зайти на сайт
www.highend3d.com и в разделе MAYA выкачать несколько плагинов, вычисляющих поле взаимного
влияния частиц друг на друга. Все они делают примерно одно и тоже, а различаются лишь
производительностью.

Второй способ не нуждается в дополнительных программах и основан на свойстве


майских объектов, имеющих компоненты, служить источником динамических полей. В том числе
источником поля могут быть сами частицы, причем это поле может на них же и влиять. Чтобы как-
то подтвердить такие смелые заявления, проделаем небольшой пример для изготовления капли
неопределенного рода жидкости, представляя её как набор молекул, взаимодействующих друг с
другом.

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

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

1132 Книга Сергея Цыпцына


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

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


поверхностного натяжения. Поэтому второй силой будет поле взаимного притяжения.

Кандидатом на роль обеих сил будет поле типа Radial, позволяющее как притягивать, так
и отталкивать объекты. Осталось только придумать, как его «засунуть» в сами частицы.

Создайте «кристаллическую решетку» из молекул жидкости.

Для этого откройте Option Box для Particles=>Particle Tool, включите галку Create Particle
Grid, затем выберите опцию With Text Fields и введите для Minimum и Maximun Corner значения
(-1,-1,-1) и (1,1,1), соответственно.

Щелкните один раз мышкой прямо в окне перспективы и нажмите Enter.


В начале координат возникнет кристально чистый кубик из молекул. Чтобы они лучше
смотрелись, сделайте их сферами с радиусом равным 0.1.

Сохраните файл (dropStart.ma).

Динамика частиц 1133


Организуем поле взаимного отталкивания.

Выберите частицы и создайте радиальное поле: Fields=>Radial.


Займемся его атрибутами. Коль скоро молекулы должны отталкивать друг друга только
при значительном сближении, это поле должно иметь маленький радиус действия и быстрое
затухание.
Поэтому установите для него maxDistance=2 и attenuation=4.
Также следует предположить, что поле должно быть довольно сильным, и в связи с этим
задайте magnitude=39 и переименуйте поле в pushField.
После этого решетку начнет раздувать изнутри.

Совершенно очевидно, что центр действия поля находится в начале координат и что ни
о каком взаимном отталкивании речь пока не идет. Теперь осталось сделать так, чтобы частицы
стали источником поля.

Выберите поле pushField, а затем частицы.

Выполните Fields=>Use Selected As Source of Field (то есть «Использовать выбранный объект
как источник поля»).

Правда, после этой операции мало что изменится: поле по-прежнему находится в центре
и оттуда, не торопясь, влияет на частицы. Дело в том, что по умолчанию поле просто вставляется
в геометрический центр выбранного объекта и наследует его перемещения, оставаясь при этом
одной точкой. Чтобы поле стало действовать из каждой компоненты объекта, являющегося его
источником, надо в атрибутах самого поля включить параметр applyPerVertex.

Выберите поле pushField и в Channel Box установите applyPerVertex=on.


Теперь бедную решетку разрывает в клочья за пять кадров, ведь поле действует из каждой
частицы.

1134 Книга Сергея Цыпцына


Примечание. Напомню, что поле одновременно действует «из частиц» и «на
частицы», хотя такая одновременность совершенно не обязательна в общем
случае. Частицы могут быть источником поля, действующего на другие частицы
и не влияющего на «свои». Таким частицами удобно «обстреливать» мягкие
тела или скопления других частиц, вызывая возмущения среды от пролетающих
источников поля.

Сформируем силу поверхностного натяжения, не дающую частицам разлетаться.


Выберите частицы и снова создайте радиальное поле: Fields=>Radial.
Так как молекулы должны удерживаться от разлетания в некотором объеме, это поле будет
иметь больший радиус действия, чем pushField, но более слабую силу, направленную внутрь, а не
наружу.

Поэтому установите для него maxDistance=5, attenuation=4.


Задайте magnitude= -6 и переименуйте поле в pullField.
Сразу включите для него applyPerVertex=on.

Сделайте частицы также источником и этого поля.


Выберите поле pullField, а затем частицы. Выполните Fields=>Use Selected As Source of Field.

Сохраните сцену и запустите анимацию.


Теперь все силы пришли в движение, и молекулы, отталкиваясь друг от друга, вылетают
из зоны действия pushField и попадают в объятия pullField, которое притягивает их друг к другу.
Напомню, что радиус действия измеряется теперь как расстояние вокруг каждой частицы.
Молекулы теперь из всех сил изображают броуновское движение. Если отрендерить их с
помощью streaks, можно увидеть их безумные траектории.

Динамика частиц 1135


Чтобы движение не было столь суетливым, а также для придания капле жидкости некоторой
вязкости, надо поработать с атрибутом conserve.

Выберите частицы и задайте для них conserve=0.9.

Это снизит общую скорость движения молекул (напомню, что скорость частицы умножается
на значение conserve в каждом кадре) .

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

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

1136 Книга Сергея Цыпцына


Однако к трехсотому кадру молекулы перемешиваются в хаотическом порядке, в лучших
традициях броуновского движения.

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

Сохранитеобязательносценустекущимизначениями(dropPreset.ma) и поэкспериментируйте
со значениями magnitude, attenuation и maxDistance у обоих полей. Отмечу, что идея симулировать
взаимодействия частиц несомненно удалась: система остается устойчива и при этом сохраняет
некоторый объем в пространстве.

Приведу примеры довольно интересных наборов значений, дающих весьма любопытные


распределения частиц в пространстве.

Например установите для pushField.attenuation=1, a pullField.attenuation=2. Это разведет


молекулы на островки.

Динамика частиц 11 37
Если теперь уменьшить силу притяжения (pushField.magnitude=22), то частицы образуют
кольца и дуги.

Если дальше продолжить тенденцию уменьшения силы притяжения (pushField.magni-


tude=16), но сделать её более «объемной» через уменьшение затухания (pushField.attenuation=0.5),
молекулы начнут делиться на группировки и периодически перебегать от одного скопления к
другому.

1138 Книга Сергея Цыпцына


Если ещё уменьшить притяжение (pushField.magnitude=7), то все молекулы разбредутся по
четырем углам.

Эту игру можно продолжать очень долго. Экспериментируя с magnitude, attenuation


и maxDistance можно получать удивительные комбинации и переходы. Не забывайте также
про conserve для частиц. Если во время такой игры вас начнут посещать мысли об устройстве
этого мира или о тщете всего сущего, не пугайтесь: это происходит почти с каждым. Только не
рекомендуется слишком долго смотреть на переходы и изменения состояний молекул, дабы не
впасть в измененное состояние сознания, в котором слово MAYA предстанет перед вами в своем
истинном санскритском значении.

Одно маленькое неудобство для экспериментаторов заключается в том, что разные


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

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


значений, вернитесь к сохраненному файлу (dropPreset.ma) или задайте следующие значения:
pushField.magnitude=39, pushField.attenuation=4, pushField.maxDistance=2, pullField.magnitude=-6,
pullField.attenuation=4, pullField.maxDistance=5.

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


кристаллической решетки круглую каплю и бросим её на какую-нибудь поверхность.
Проиграйте анимацию до пятисотого кадра и выполните Solvers=>Initial State=>Set for All
Dynamics.

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

Выберите частицы и создайте гравитацию: Fields=>Gravity.

Частицы начнут падать. Создайте полигональную плоскость, опустите и растяните ее,


наклоните под углом 45 градусов.

Выберите частицы, затем плоскость и выполните Particles=>Make Collide.

Чтобы капля не съезжала, как на санках, с плоскости, задайте для появившейся в Chan­
nel Box ноды geoConnectorl значения friction=1, это придаст трение или прилипание капли к
поверхности.

Задайте также resilience=0.1, это позволит избежать упругого отскакивания капли.

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

Экпериментируем дальше.
Создайте источник частиц: Particles=>Create Emitter.
Сразу же удалите в Outliner появившиеся вместе с ним частицы.
Затем выберите каплю, потом источник и выполните Particles=>L)se Selected Emitter.
Это присоединит молекулы к источнику, то есть из него начнут появляться частицы, для
которых уже созданы и настроены два поля, обеспечивающие взаимодействие.
Отодвиньте источник от капли и уменьшите наклон плоскости, например, до пяти градусов.
Чтобы из источника появилось столько же молекул, сколько составляет каплю, выберите
частицы и задайте значение атрибута maxCount=250 (так как в каплю входит 125 молекул).

Если частицы очень резко вылетают из источника (ведь они появляются практически в
одной точке и начинают жутко отталкиваться друг от друга), можно задать для источника значение
атрибута maxDistance=0.5, чтобы частицы испускались из него не в точке, а в некоторой окрестности
с радиусом 0.5.

Упавшие на плоскость капли начнут притягиваться друг к другу, поскольку это одна система
частиц - необходимо лишь, чтобы они находились не дальше друг от друга, чем значение maxDis-
tance для поля pullField. (Можете уменьшить силу гравитации, чтобы капли не сильно плющило.)

1140 Книга Сергея Цыпцына


Дальнейшие эксперименты ограничены только степенью расширенности вашего сознания
и склонностью к издевательствам над частицами.
Выберите в Attribute Editor для частиц Render Type=Blobby Surfaces и установите Radius=1, Thresh-
old=1.

Назначьте на частицы какой-нибудь блескучий материал (типа blinn) и отрендерите


изображение.

Сейчас самое время перейти к обсуждению методов визуализации частиц, так как вопрос
этот настолько назрел, что... В общем, потому что уже пора.

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

Динамика частиц 1141


Во-первых, частицы каждый раз летают немного по-разному: из-за того, что у источников
и других динамических объектов есть различные «рандомайзеры», которые заставляют их каждый
раз двигаться хоть и чуть-чуть, но по-разному. Но если вы вас устраивает определенное движение
частиц и вы хотите, чтобы они двигались каждый раз именно так, как они только что двигались,
имеет смысл их скэшировать, чтобы каждый раз не пересчитывать их движение заново. В
отличие от твёрдых тел, траектории частиц нельзя «перевести в ключи», поэтому использование
кэширования единственная альтернатива повторному обсчету.

Во-вторых, вряд ли у вас получится отрендерить частицы с первого раза наилучшим


образом. Поэтому проще делать очередные попытки визуализации с уже просчитанными заранее
частицами (если их поведение и их траектории вас полностью устраивают).

В третьих, по интуитивно понятным причинам motion blur не всегда будет корректно


работать с траекториями частиц, вычисляемыми прямо в процессе рендеринга. В общем случае,
динамика «не знает», что будет в следующем кадре, пока не доберется до него.

Чтобы создать кэш для выбранных частиц, в /??/ текущем диапазоне анимации достаточно
выполнить Solvers=>Create Particle Disk Cache. B Option Box этой операции можно указать имя для
кэша (точнее, имя папки, в которой он сохраняется внутри текущего проекта).

Работа с разными кэшами довольно хитро организована в меню Solvers=>Edit Oversampling


and Cache Settings. Там же можно включать и отключать использование кэширования.

1142 Книга Сергея Цыпцына


Визуализация частиц
Как некоторые из вас, наверное, слышали, а многие и видели (получив в Script Editor
сообщение «Warning: Hardware rendering selected for particleShapel. Skipped.»), частицы в MAYA
можно рендерить двумя способами: назовем их «софтверно» и «хардверно». Первый термин
предполагает визуализацию частиц обычным рендером (или с помощью mental ray), второй способ
нуждается в комментариях.

Соответственно, существует два основных класса частиц. Первый предназначен для


обычного, «софтверного» рендеринга и в него входят частицы, имеющие Render Type равный
Blobby Surfaces, Clouds или Tubes. А буквы s/w в названии типа, говорят об их принадлежности к
софтверному классу. Как уже упоминалось выше, Blobby Surfaces предназначены для визуализации
скопления частиц в виде обтягивающей их поверхности. Clouds позволяют рендерить частицы
с помощью объемных материалов (volume shading), а не в виде поверхностей. Tubes являются
аналогом типа streaks, для которого размер частиц зависит от их скорости.

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


визуализированы обычным рендером. Именно поэтому вы получаете вышеупомянутое сообщение
при попытке просчитать хардверные частицы, нажав кнопку Render.

Не сильно искушенные в прелестях MAYA умы естественно возмущенно возопят, причем


два раза. «Зачем такой гем... , э-э беспорядок?» и «А как же тогда рендерить все остальные типы
частиц?».

На первый вопрос я могу ответить примерно следующее. Для изготовления многих


спецэффектов (типа взрывов, клубов пыли или стены из песка) требуются не тысячи, а десятки и
сотни тысяч частиц. Если всю эту массу засунуть в обычный рендер, результата придется ждать
очень долго, а памяти докупать очень много. О возможности эффективного экспериментирования
с внешним видом также можно будет забыть. Поэтому для эффективного просчета сцен с сотнями
тысяч частиц требуются специальные технологии и методы рендеринга. Один из самых эффективных
методов находится прямо перед вами -MAYA вполне ловко умудряется прокручивать во окне
перспективы весьма значительные объемы частиц. Поэтому ответ на второй вопрос заключается в
следующем: остальные типы частиц надо рендерить прямо с экрана, то есть используя видеокарту.
Конечно, при этом теряется некоторое количество преимуществ, доступных любому софтверному
рендеру. Видеокарта ничего не знает про отражения и преломления; качественный антиалайзинг
или сглаживание границ тоже остается за бортом; motion blur под сильным вопросом; тени и
освещение частиц также требуют отдельного разговора. Но самое главное, что вы получаете от
«аппаратного» рендеринга - это чудовищную скорость, за которую ему можно простить отсутствие
массы полезных вещей. Отсутствующие качества симулируются при хардверном просчете
различными способами. В основном они опираются на многопроходный (multipass) рендеринг
одного и того же кадра.

Для сглаживания краев и жульнического антиалайзинга используется метод camera jitter


(«нетрезвый оператор»), когда в каждом кадре камера немного подрагивает и снимает изображение
несколько раз с разных точек. Эти изображения потом усредняются и складываются в один кадр,
что дает эффект размытия краев, известный как «дешевый антиалиазинг».

Типы multistreak и multipoint также позволяют объемно размыть изображение, визуализируя


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

Эффект motion blur симулируется усреднением изображений, снятых в нужном количестве


в соседние моменты времени.

Динамика частиц 1143


Тени типа depth map поддерживаются для некоторых типов частиц (points, multipoints,
spheres), начиная с MAYA 4.5.

Остальные эффекты, как правило, симулируют уже на стадии композитинга, складывая


слои и проводя цветокорректировку.

«А как же нормальная геометрия? Ее тоже считать аппаратно?» - спросят обескураженные


начинающие супервайзеры спецэффектов. Нет, её надо считать обычными методами и на этапе
композитинга совмещать с уже имеющимся изображением частиц. Для этого существует масса
хороших программ и специально обученных людей.

Кроме того, подавляющее большинство просчитанных частиц, как правило, требуют


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

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

Примечание. Renderman for Maya умеет считать «хардверные» частицы вместе с


остальной геометрией, не разделяя частицы на два класса.

Аппаратный дымок
Откройте файл smoke.та и убедитесь, что для источника частиц задан rate=300 и maxDis-
tance=0.02.

Чтобы дым был более прозрачный, нажмите в Attribute Editor для частиц правую кнопку
мыши в поле атрибута opacityPP и выберите Edit Ramp.

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

1144 Книга Сергея Цыпцына


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

Сначала пойдем первым путем.

Выберите для частиц Render Type= Multipoint и задайте Multi Count=30, Multi Radius=0.05,
Point Size=1.
Это создаст вокруг каждой реальной частицы ещё тридцать штук, которые будут
использованы только для визуализации и не будут обсчитываться динамикой.

Теперь пора переходить непосредственно к рендерингу.


Окно для аппаратного просчета частиц располагается по адресу Windows=>Rendering
Editors=>Hardware Render Buffer.

Проиграйте немного анимации. И нажмите на «хлопушку» в нижней части окна - Hardware


Render Buffer.

Динамика частиц 1145


В окне отобразится просто копия экрана на черном фоне. Это и есть аппаратный рендеринг.
Выглядит угрожающе. Посмотрим, как можно улучшить картинку.
Для того, чтобы настроить параметры рендеринга, выберите в окне меню Render=>Attributes...
В Attribute Editor появятся атрибуты ноды defaultHardwareRenderGlobals, отвечающей за
визуализацию в окне Hardware Render Buffer.
В первом разделе можно установить общие параметры рендеринга.
Задайте Filename=smoke, Extension=name.0001.ext, End Frame=200, Resolution=640x480, Alpha
Source=Hardware Alpha.

Примечание. Сейчас трудно найти видеокарту, которая не поддерживала бы


просчет аппаратной альфы. Если же ваша карта все-таки не обладает такой
возможностью (a MAYA сразу сообщит об этом в Script Editor), можете выбрать
источником для альфа-канала яркость (Luminance) частиц. Это, однако, не всегда
будет давать хороший результат. Ведь более темные (с точки зрения цвета)
частицы станут более прозрачными и, кроме того, потеряется информация о
суммарной прозрачности в конкретной точке изображения.

Нас, однако, интересуют в первую очередь параметры, улучшающие качество изображения.


В разделе Render Modes включите галку Geometry Mask, чтобы аппаратный рендерер не считал
любую геометрию на экране, но в альфа-канале оставлял черный цвет в местах присутствия
поверхностей - для удобства последующего композитинга.

Галка Line Smoothing делает из квадратных точек круглые и сглаживает края частиц типа
streaks. Поэтому включите её тоже.

Основные трюки и ухищрения сосредоточены в разделе Multi-Pass Render Option.

Совет. Если после просчета, изображение тут же пропадает из окна, снимите


выделение с частиц. Это должно помочь. А увидеть их атрибуты можно, не
выбирая их: достаточно выбрать в Attribute Editor меню Focus=>particleName.

Включите галку Multi Pass Rendering, и вы увидите, что при нажатии на «хлопушку» MAYA
рендерит текущий кадр трижды. Выберите RenderPasses=7, и количество проходов увеличится до
семи.

Зачем это нужно? Дело в том, что для частиц выбран тип Multi Point и при каждом
повторном рендеринге кадра, дополнительные частицы появляются вокруг основных по-разному.
Потом все семь проходов-изображений складываются и усредняются, что дает эффект размытия и

1146 Книга Сергея Цыпцына


наполнения струи дыма. Преимущество частиц с приставкой multi в том, что насыщенность и даже
прозрачность струи не надо регулировать, изменяя частоту испускания или редактируя текстуру
для прозрачности. Достаточно выбрать частицы и порулить атрибут Multi Count, мгновенно
увеличивающий общее количество частиц.

Чтобы дополнительно размыть как сам дымок, так и его края, надо «потрясти» камеру.
В разделе Multi-Pass Render Option включите галку Anti Alias Polygons (это и есть атрибут,
отвечающий за дрожание камеры).

Задайте величину «дрожания камеры» в поле Edge Smoothing=5, а чтобы увидеть как MAYA
«трясет» камеру, можно дополнительно включить/выключить в разделе Display Options галку
Grid.

Теперь в окне Hardware Render Buffer выполните просчет всей последовательности:


Render=>Render Sequence.

Важный совет. Когда идет просчет последовательности, изображение


«подхватывается» прямо с экрана, поэтому если в момент рендеринга вы
заслоните любым окном область экрана, где находится Hardware Render Buffer,
содержимое этого окна попадет в отрендеренное изображение. К счастью, курсор
мыши можно беспрепятственно проводить над областью просчета - он в финальную
картинку не попадет.

Просчитанные изображения падают в папку images текущего проекта, а по окончании


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

Сохраните сцену как smokeHW_thin.ma.

Аппаратный дымок нового типа


Теперь попробуем визуализировать более брутальный дым, соответственно, ещё более
варварскими методами.

Выберите частицы и задайте для них Point Size=25 (да-да, двадцать пять), Multi Radius=0.5,
a Multi Count=1.

«А зачем делать Multi Count равным единице?», возмутятся пытливые, но неокрепшие умы.
А затем, что при каждом проходе частицы будут появляться в разных местах одного кадра и при

Динамика частиц 1147


складывании дадут заполнение пространства.

В случае использовании таких точечных монстров можно уменьшить количество


испускаемых частиц.

Задайте для источника rate=40.


Проиграйте анимацию и откройте Hardware Render Buffer.

Теперь дым рендерится «крупными» мазками.


Откройте Render=>Attributes...
В разделе Multi-Pass Render Option увеличьте количество проходов до шестнадцати (Multi
Pass=16) и запустите рендер.

Если вы хотите также сглаживания «по времени», укажите в поле Motion Blur количество
кадров, за которое будет просчитываться вышеуказанное количество проходов (если Motion Blur=0,
то просчитывается только текущий кадр).

Сохраните сцену (smokeHW_fat.ma).


После таких трюков и ужимок с аппаратным рендером посмотрим теперь, как можно
просчитать эти же частицы обычным, «человеческим» рендером.

Софтверный дым
Выберите частицы и в Attribute Editor задайте им Render Type=Cloud. Если теперь нажать
обычную кнопку Render Current Frame, частицы предстанут в окне Render View как странный
голубой дымок.

Если их заново выбрать, в Attribute Editor появится закладка particleCloudl, отвечающая за


объемный (volume) материал, присвоенный частицам этого типа.

Примечание. Если материал не появился в Attribute Editor, присвойте его вручную,


например, через меню на правой кнопке мыши. И не забывайте о том, что частицы
типа Blobby Surfaces требуют присвоения обычного (surface) материала, а для
типа Cloud нужен объемный материал particleCloud. Причем на частицы типа Cloud
можно назначать сразу два материала: surface и volume, так как при увеличении
атрибута Surface Shading у самих частиц сквозь «дым» может просвечивать
поверхность.

1148 Книга Сергея Цыпцына


Выберите закладку particleCloudl и вместо голубого цвета назначьте на канал Color
трехмерную текстуру Cloud.

Теперь частицы станут нормального светло-серого цвета. А чтобы поднастроить плотность


и прозрачность струи дыма, надо вернуться к атрибутам particleCloud.

Примечание. Не путайте материал particleCloud и текстуру Cloud. Текстура


отвечает лишь за распределение цвета в объеме, а материал определяет все
параметры визуализации облака частиц: плотность, прозрачность, светимость
и другие.

Уменьшите значения атрибутов Density и Blob Map, чтобы уменьшить плотность дыма и
понизить общую прозрачность.

Динамика частиц 1149


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

Сохраните файл (smokeSW.ma) и поэкспериментируйте с различными атрибутами


материала particleCloud. Я намеренно оставляю в стороне описание всех этих многочисленных
атрибутов, ибо не существует специальных волшебных чисел, которые бы делали супер-дым или
мега-облака. Все зависит от массы внешних параметров: освещения, размера сцены, количества
частиц и пр. Замечу лишь, что с помощью атрибута Blob Map удобно корректировать уже заданную
через атрибут Transparency объемную прозрачность.

ParticleSamplerlnfo - переносчик информации


Пытливые умы наверняка вспомнят, что для дыма была создана текстура ramp, управляющая
атрибутом opacityPP и задающая увеличение прозрачности в зависимости от времени жизни
частиц. Однако эта информация никак не попадает в частицы типа Clouds, так как они используют
значения прозрачности, определяемые атрибутами материала particleCloud, который, в свою
очередь, никак от текстуры ramp не зависит. Попытка назначить эту текстуру на прозрачность,
то есть на канал Transparency, ничего не даст, так как она ляжет на частицы, грубо говоря, по
поверхности, а нам надо, чтобы она лежала по времени жизни (или вдоль времени жизни).
Чтобы передать информацию о цвете или прозрачности, задаваемую для атрибутов rgbPP или
opacityPP с помощью expressions, текстур ramp или других методов, надо воспользоваться
утилитой (нодой) particleSamplerlnfo. Она передает в обычный материал, назначаемый на частицы
«софтверного» типа, значения индивидуального цвета, прозрачности и других атрибутов для
каждой частицы.

Откройте атрибуты материала particleCloud1 и назначьте на канал Transparency утилиту


particleSamplerlnfo.

Она располагается в закладке Utilities в разделе Particle Utilities.

1150 Книга Сергея Цыпцына


После этого частицы унаследуют свою прозрачность с атрибута opacityPP и станут еле
видны, так как мы недавно отредактировали текстуру ramp, задав ей практически черный цвет во
всех точках.

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

Напомню, что при помощи текстуры вы задает распределение прозрачности по времени


жизни. Общую прозрачность можно дополнительно настраивать с помощью атрибута Blob Map для
материала partideCloud1.

В моем понимании утилита particleSamplerlnfo действует следующим образом. Когда


доходит дело до просчета очередного пикселя, рендер определяет, какие частицы принимают
участие в формировании цвета для него. Для каждой частицы запрашивается материал, который
ей присвоен (partideCloud1), вычисляющий цвет и прозрачность на основе своих атрибутов Color,
Transparency и других. Соответственно, когда для каждой частицы он вычисляет прозрачность,
он обращается к ноде particleSamplerlnfo, присоединенной к атрибуту Transparency. Эта нода для
каждой частицы бодро сообщает её прозрачность в соответствии со значением opacityPP.

Динамика частиц 1151


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

Железный рендер
Количество модулей рендеринга в MAYA слегка подавляет, причем очередная версия так и
норовит подбросить ещё пару-другую методов рендерить объекты определенного типа.

До сих пор я употреблял термины «аппаратный» или «хардварный» рендер имея в виду
исключительно методы просчета через Hardware Render Buffer. Вплоть до пятой версии MAYA это
не вызывало никакого разночтения, однако в настоящее время приходится уточнять, что имеется
в виду под словом «аппаратный рендер».

Дело в том, что за время, прошедшее с выхода первой версии MAYA, сменилось не
одно поколение видеоускорителей. Современные видеокарты научились делать аппаратный
антиалайзинг, фильтровать текстуры, отображать бамп, работать со светом, туманом и многими
другими удивительными вещами. Однако Hardware Render Buffer за все эти годы не претерпел
практически никаких изменений. Его функцией всегда было одно: считать частицы со страшной
скоростью, максимально примитивным способом. То есть никаких преимуществ, кроме растущей
частоты ядра видеокарты и количества бортовой памяти, Hardware Render Buffer не использовал,
не использует и использовать не собирается. В этом есть определенное преимущество, так как уже
наработанные методы визуализации частиц будут давать предсказуемые результаты и в будущих
версиях MAYA.

Однако, чтобы получить возможность рендерить изображения на «железе» и при этом


использовать все новые и модные «фишки» современных видеокарт, в пятой версии MAYA появился
Hardware Render. Его технологическое позиционирование немного размыто. Теоретически он
предназначен для «предварительного» рендеринга или для просчета изображений, не требующих
«высокого качества». Он позволяет рендерить геометрию с учетом освещения, поддерживает
бамп, карты отражений, туман и ещё много чего.

Однако для просчета частиц он пока не может соперничать по скорости с Hardware Render
Buffer, а его способ работы с MultiPoints и MultiStreaks не позволяет использовать его для просчета
уже готовых сцен. Поэтому я ограничусь лишь упоминанием о том, что для его эффективного
использования вы должны иметь приличную видеокарту (требования к ней есть в документации),
и предложу проэкспериментировать с ним самостоятельно, на примере уже созданных сцен.

1152 Книга Сергея Цыпцына


А при упоминании про аппаратный рендер я по-прежнему буду иметь в виду Hardware
Render Buffer.

Практические советы и ухищрения


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

Прежде всего, некоторые советы: что и чем делать


Если нужен четко-понятный объем с динамичным светом (след от ракеты ночью, ночные
и дневные клубящиеся дымы, кучевые облака, взрывы), применяется как правило, тип Clouds
с использованием raytracing-теней и включенной опцией Surface Shading Shadow в установках
материала particleCloud. Если в этом случае также необходим motion blur, иногда используется
тип Tubes, который позволяет добиться некоего его подобия.

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

Для галактик, пыли и дыма, требующих турбулентности внутренних процессов (как у


сигаретного дыма, дымка из дула после выстрела) используйте Multi Point.

Брызги, фейерверки, трассирующие пули у виска, кислотный дождь - Streaks и Multi


Streaks.

Капли пота на лице трехмерного изваяния любимого начальника, подтеки крови, парафин,
кляксы в дневнике, прочие густые жидкости - Blobby Surfaces.

Море зеленого горошка, парад планет, стая футбольных мячей - Spheres.

Любителям посчитать пиксели на экране, сложить/перемножить четырехзначные числа,


проложить путь от номера 1 до 9999 (в общем, искать иголки в сенохранилищах) - Numeric.

Работа со спрайтами
Рабочие лошадки среди хардверных частиц - спрайты и мультистрики. Основные приемы
работы со спрайтами заключаются в следующем.

Прежде всего надо определить, что за характер у дыма/пыли, которые надо сделать,
и, соответственно, выбрать размер спрайтов и текстуру для них. При потревоженых архаичных
пыльных взвесях, вялотекущих отравляющих газах, тлеющих останках стада мамонтов обычно
требуется большой размер спрайтов, не очень большое их количество, довольно мелкий
фрактальный рисунок в текстуре и медленное движение/вращение.
Для инверсионных следов самолетов, пыли из под колес вашего «Феррари», хвостов от
летящих к вам в офис ракет лучше всего подойдет большое количество небольших по размеру
спрайтов с несильно проработанной структурой. Тут важнее динамика, изменение прозрачности,
размера и т.д.

Спрайты лучше просчитывать с применением motion blur. Правда, для этого сразу купите
пару жестких дисков под кэш.

Динамика частиц 1153


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

Освещать спрайты довольно сложно, гораздо проще заложить необходимое освещение и


затенение в текстуры, накладываемые на спрайты.

Лучше знать expressions, чем не знать... Это, впрочем, справедливо не только для
спрайтов, но ручная доводка их движения до воспаленного режиссерского замысла без expres­
sions практически невозможна.

Текстуры для спрайтов необязательно готовить в «Фотошопе», для последовательностей


текстур отлично подходят пакеты для композитинга типа AfterEffects, DigitalFusion, Shake и
другие.

Кроме того, спрайты можно делать цветными! И не только подготавливая цветные текстуры.
Если у вас есть черно-белые спрайты, попробуйте добавить к частицам атрибут rgbPP.

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

Прежде всего, их - как и таблеток от жадности - должно быть побольше, побольше...


Галка Line Smoothing в атрибутах Hardware Render Buffer - основной способ сгладить этот
тип частиц.

В отличие от спрайтов, их можно весьма успешно освещать. По возможности с разных


сторон, чтобы создать эффект объема.

Вместо motion blur проще использовать больше проходов (Multi-Pass), размывающих


частицы по пространству.

Для придания дополнительного объема можно делать несколько слоев, используя в


качестве альфа-канала отдельно просчитанную последовательность этих же частиц с включенным
атрибутом Color Accum.

Для эффективного управления цветом мультистриков бывает полезно испускать их с


поверхности, наследуя цвет с тектуры. А изменение цвета задавать в expressions.

Особенности работы с motion blur


Для софтверных типов частиц (типа Blobby Surface и Clouds) motion blur просто не работает,
так как майская тесселяция поверхностей меняется в каждом кадре, а для объемных материалов
MAYA не может его посчитать, потому что один пиксель окрашивается сразу многими частицами из
облака. Для Blobby Surfaces можно делать параллельное инстансирование сфер в эти же частицы
и блюрить их геометрию. Для Clouds можно дополнительно использовать частицы Tubes. (Кстати,
mental ray умеет считать motion blur для этих типов частиц, но для его настройки придется
попотеть).

Motion blur для спрайтов, как правило, необходим, и для его адекватного использования
необходимо соблюдать два принципа:

• Не переборщить, чтобы предыдущая неделя работы текстуровщика спрайтов осталась замечена


и он не дал бы волю давно накопившимся суицидальным позывам.
• Не «недоборщить», чтобы просчет кэша на 10 гигабайт был виден и зрителю и начальству,

1154 Книга Сергея Цыпцына


купившему, по вашему требованию, новый дисковый массив.

Чтобы спрайты при пересечении с поверхностью, по которой они скользят, не давали


четкую, грубую границу, можно заставить их с помощью expression подскакивать на небольшую
высоту в каждом полукадре, a motion blur размажет эти смещения в виде сглаженного контура.

За составление списка практических советов я благодарю Алексея Гусева. Он и его команда


из компании "Алгус-Студио" определенно должны быть занесены в книгу рекордов Гиннеса за
гигантское количество спецэффектов, производимых вединицу времени минимальным количеством
человек. Его работы вы могли видеть, например, в сериалах «Спецназ-1» и «Спецназ-2», а также
первый и второй фильм «Спецназа по-русски». А еще - в фильме «Солнце» Александра Сокурова,
где именно частицами и, в частности, спрайтами была решена огромная часть визуального ряда в
сцене сна императора Хирохито...

Длинная история
Мое самое экстремальное путешествие (как ни странно, связанное с компьютерами)
было в 1996 году на Ближний и Средний Восток. Я тогда ещё занимался продажей компьютерной
техники, и мы активно искали новые рынки сбыта. В нашей стране становилось тесно, и мы решили
поехать, куда бы вы думали?... Правильно, в Ирак. Ходили слухи, что вот-вот снимут эмбарго,
установленное после войны в заливе, и возникла идея рвануть туда, чтобы подготовить почву для
будущего бизнеса, дабы сразу после снятия ограничений на торговлю въехать туда на белом коне
с принтером и монитором.

Рвануть, конечно, хотелось быстро и без проблем. Однако выяснилось, что самолеты туда
не летают, телефонной связи нет, а ближайший аэропорт находится в Иордании, в Аммане, его
столице, от которой до Багдада около тысячи километров. Притом по единственной дороге, через
пустыню, с непонятным названием. Так что быстро не получалось. Без проблем тоже. Несмотря
на благополучное получение виз, в последний момент отказался от поездки заранее найденный
и арендованный переводчик-проводник, уже не раз проделавший этот путь. Если бы я наперед
знал, как все будет происходить, или просто был бы постарше, я бы благоразумно отказался от
такого вояжа. Однако общая тяга к путешествиям и легкий, но устойчивый аромат адреналина,
исходивший от самой идеи, окончательно нарушили гормональный баланс, и через неделю мы
втроем сидели в полупустом самолете иорданских авиалиний, разучивая варианты вежливых
приветствий на арабском языке.

В Аммане мы без проблем остановились в необъятных размеров мультизвездочной


гостинице и даже довольно быстро нашли «челнока» - одного из арабских водителей, регулярно
мотающихся в Багдад, чтобы заспекулировать там иорданскую кока-колу и сникерсы, а обратно
привезти дешевейшие иракские фрукты. Нюанс, правда, был в том, что челнок абсолютно не
понимал ни одного английского слова и ездил на огромном красном джипе Ford времен освоения
Америки Колумбом.

Начиналось все неплохо, отъезд на восток был назначен на раннее утро, и мы, утомленные
перелетами, переездами и переговорами, вползли в ближайший ресторан из лабиринта
предприятий питания многократнозвездочного отеля. Ресторан оказался индийский, и первая же
закуска, отправленная в рот, вызвала у меня желание вызвать пожарных, поэтому я попытался
торопливо заесть её близлежащим хлебом. Однако при выпечке хлеба вместо муки, скорее всего,
использовали красный перец, и вот я уже был готов испепелить своим дыханием всех местных
поваров. Помогла обычная советская ириска (это, кстати, реальный способ пожаротужения), и
я хорошо усвоил первый урок: в чужой стране не надо тащить в рот незнакомую, пусть даже
желудкопомрачительно выглядящую еду.

В шесть утра мы погрузились с джип-долгожитель и двинулись в сторону границы.


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

Динамика частиц 1155


некачественной воде/еде по ту сторону границы, мы по дороге запаслись стратегическим запасом
воды и, наверное, кубометром лепешек, справедливо рассуждая, что все остальное пропадет
по теплым солнцем. Забегая вперед, скажу: опасения не подтвердились, а в реке Тигр водятся
отличные вкусные карпы.

Четыреста километров пролетели быстро, и вот мы уже подъехали к иорданской таможне.


Пограничник посмотрел на нас странным, каким-то сожалеющим взглядом и, открыв нам ворота
в нейтральную территорию, выпустил нас из Иордании. Спереди маячил высоченный забор из
колючей проволоки и не менее высокие, витые металлические врата, с непонятными надписями и
желтыми звездами.

Притихший водитель давил на газ потихоньку, пока мы не въехали на загадочную иракскую


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

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

Разгадка оказалась прозаична и проста. Измученные месячной зарплатой в один доллар,


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

Дальше, после ожесточенной и довольно агрессивной схватки-торговли с этими военными


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

И тут возникла самая экстремальная ситуация за всю поездку, хотя формально все
выглядело очень спокойно. Как выяснилось, попасть на территорию Ирака можно, если у тебя,
помимо визы, есть ещё приглашение или подтверждение от организации, имеющей дело с
иностранцами. Мы такого приглашения не имели, и тогда в качестве приглашающей стороны
стали бодро называть самое могущественное (после министерства обороны) министерство нефти,
в которое, собственно, и собирались попасть. Возник некий казус, для разрешения которого был
вызван весьма приветливый человек с дежурной улыбкой, прекрасно говоривший по-английски
(и, наверняка, по-русски, хотя и скрывавшай такую способность). Он отобрал наши паспорта и
проводил нас в зал для, типа, VIP персон, где четыре часа поил нас чаем, вел туманные разговоры
и периодически ненадолго отлучался. Он имел плохо скрываемые повадки человека, давно
работающего в органах, а мы имели шанс получить крупные неприятности, но все равно тупо и
безыскусно излагали свою легенду: о намерениях вести активные переговоры в министерстве
нефти. С одной стороны, он мог просто отправить нас обратно - по формальному признаку, ввиду
отсутствия необходимых бумаг. С другой стороны, имя могущественного бизнес-партнера и
обескураживающая уверенность трех наглых русских разгильдяев нагоняли на него сомнения.
Сильно помогло, конечно, и российское гражданство, ибо отношение к русским в Ираке тогда
было более чем дружественным, в чем нам пришлось ещё не раз убедиться, выслушивая слова
поддержки в нашу сторону и проклятия в адрес некоторых других стран.

Нам фантастически повезло, потому, что дело происходило в пятницу - а это официальный

1156 Книга Сергея Цыпцына


выходной во все арабском мире. Частые отлучки нашего нового иракского знакомого были связаны
с попытками дозвониться с министерство и узнать правду о трех сомнительных иностранных
личностях. На наше счастье, все работники свято соблюдали выходной и правду узнать не удалось
(боюсь представить, что могло произойти, если бы стало известно, что о нас никто ничего не
знает). Когда все туманные темы и восточное красноречие иссякло, специалист по иностранцам
принял коварное решение. Оно заключалось в том, что мы можем въехать в страну без бумаги
от министерства, но выехать обратно без нее мы не сможем никогда, то есть нам лучше даже
не появляться на границе без такой бумаги. Мы пошли ва-банк и взревели: «Заметано! Отдавай
паспорта!». И уже собрались прыгать в машину, как наш приветливый иракский друг спросил
нас с елейной улыбкой: «А что, разве вы не знаете правило, для всех иностранцев, въезжающих
в страну частным образом?». Нам опять стало не по себе, и не зря. Выяснилось, что все белые
иностранцы, а тем более такие молодые и наглые как мы, являются потенциальной угрозой
не только нравственным устоям общества, но также и физическим. Короче, мы должны были
немедленно сдать анализ крови на СПИД прямо на границе, а на мои робкие возражения, что
результат вообще-то не будет готов через пять минут, был получен не менее елейный ответ:
«Если результат будет положительный - вас быстро найдут». И обезвредят, неявно звучало в конце
ответа...

Делать было нечего, и, убедившись в одноразовости инструментов этой восточной пытки,


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

Вконец измотанные и неформально обескровленные, мы забились в машину и въехали,


наконец, на территорию Ирака. Впереди было ещё шестьсот километров и три дня приключений.
Надо сказать, что лучших дорог я не видел нигде в мире. Несмотря на остатки сгоревших грузовиков
на обочинах, дорога была абсолютно гладкой, неимоверно широкой и кристально прямой. К
сожалению, наш джип-долгожитель не мог делать больше ста десяти километров в час, но нам
уже было не до всего этого: как только начало смеркаться, мы заснули. Как оказалось, ближе
к Багдаду заснул и наш водитель, и только чудовищная ширина дороги, отсутствие встречного
движения и заметенные песком крайние полосы помогли нам сохранить общее здоровье:
проснувшись от длительного визга откуда-то из-под колес, я стал неистово трясти водителя,
заодно удерживая руль. Дальнейший путь мы проделали, брызгая на него запасенной водой и
подкармливая остатками сникерсов.

Прибыв в Багдад, мы поселились в гостинице для иностранцев, и я почувствовал: время


повернуло вспять и вывернулось наизнанку. То есть мы попали в мир конца семидесятых, и при этом
появились в нем с «другой» стороны. На тщательно охраняемой территории стоял полигональный
куб гостиницы, куда вход местным жителям был строжайше запрещен. В самом отеле тяжелая,
темно-коричневая, угловатая мебель обрамляла хорошо просматриваемые и прослушиваемые
коридоры, за каждым поворотом которых дежурил очередной, ненавязчиво наблюдательный
сантехник или электрик. В безлюдных номерах стояли археологически привлекательные приемники
Грюндиг и холодильники Зил-Москва. Мы ощущали себя империалистами в отеле «Националь» на
улице Горького с разгар застоя...

К счастью, благодаря предусмотрительно проработанным ещё в Москве контактам, нам


удалось попасть в вычислительный центр министерства нефти и даже прочитать там небольшой
цикл лекций о состоянии компьютерной индустрии на текущий момент. Скажу честно, я испытывал
странные чувства: передо мной сидели интеллигентные люди, получившие прекрасное образование
в России и Америке, они имели отличный опыт работы и светлые головы, но за пять лет до нашего
появления их отрезали от всего внешнего мира. Совсем. Ни связи, ни почты, ни литературы,
ни даже радио, чтобы получать хоть какую-то информацию. Последнее освоенное чудо техники
хранилось в отдельной комнате и до сих пор работало - это был персональный компьютер PC XT
8086. При этом вычислительный центр адекватно работал и выполнял необходимые расчеты на
машинах типа VAX. Эти люди внимали любой информации с таким вниманием и ненасытностью,
что трудно было остановиться на какой-то конкретной области компьютерной отрасли и хотелось
рассказать абсолютно все, что знаешь сам. Я часами говорил на усталом, путанном английском,
испытывая бесконечное сочувствие и желание хоть как-то помочь.

Багдад оказался фантастически красивым городом. И невероятно огромным. Прекрасные

Динамика частиц 1157


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

Вечерами мы бродили по торговым улицам и ловили на себе ошеломленные взгляды:


если мой университетский друг, татарин Руст, предусмотрительно отрастил себе черную бороду
и практически сливался с пейзажем, то мы с рыжим Саней Григорьевым, при росте под метр
девяносто выглядели, как инопланетяне. Военные патрули, увидев российские паспорта, светлели
лицом и разражались громкими возгласами и жестами, означавшими, очевидно, рассказ о дружбе
между одними народами и совсем наоборот - между другими. Поменяв на черном рынке триста
долларов, мы получили битком набитый рюкзак денег, так что вместо кошелька приходилось
использовать объемистую сумку от видеокамеры. Как оказалось, Ирак - государство светское,
совсем не радикальное, и на его улицах идет нормальная жизнь цивилизованной столицы. Нам
даже удалось купить прифанкованного арабского джаза местного разлива, который мы слушали
на пути обратно.

Возвращение назад было феерическим: мы везли с собой бумагу о взаимопонимании и


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

Дабы добить под завязку и без того переполненное впечатлениями сознание, мы на


следующий день совершили вылазку на Мертвое море. Опять повторилось ощущение нереальности
происходящего, когда плоская и сумрачная, дождливая пустыня вдруг начала расступаться, а
дорога стала идти все вниз да вниз. Откуда-то вышло солнце, и мы оказались между невысоких
гор, хотя ехали, непрерывно спускаясь из пустыни, куда-то в дымку. Мне явно приходили на ум
ассоциации с обручевской Плутонией, тем более что температура тут, внизу, только повышалась
и скоро достигла двадцати пяти градусов - против семи там, наверху. Иорданский мертвоморский
курорт (по крайней мере, тот, на который мы попали) представлял собой пару досок, ведущих
к воде, и ржавую трубу с вялотекущей пресной водой, символизировавшую душ. Это, впрочем,
не имело никакого значения: феноменальное море было реальным и доступным. Нет смысла
рассказывать про него хоть что-нибудь, это надо испытать самому. Оказалось: все написанное о
нем в многочисленных источниках - правда. Скажу лишь, что несмотря на разряд по плаванию,
мне так и не удалось нырнуть глубже метра - ноги болтались вертикально над водой как две
макаронины, а неистовые гребки руками безуспешно и ненадолго погружали корпус сантиметров
на двадцать вглубь. В перерывах между попытками нырнуть мы играли в преферанс в самой низкой
точке планеты, щурились на причудливо преломленное соленым небом солнце и предвкушали
возвращение в мартовскую Москву.

Сознание было действительно расширено впечатлениями до предела. Я уже давно


придерживаюсь мнения, что сознание определяет бытие, а не наоборот, как нас учили в школе или
где-то еще. Средне-восточное путешествие так сильно перетряхнуло ценности и привязанности,
что в моей жизни начали происходить неслучайные события. По возвращении на родину я сильно
повредил ногу, осваивая сноуборд и бугельный подъемник. Это вынудило меня неделю находиться
вообще без движения и обдумывать собственное бытие. Знакомые девушки приносили еду и
тихо исчезали, обескураженные моим выражением лица. После этого я уволился со всех работ и
посвятил полгода раздумьям и безделью. А после этого попал, наконец, в компьютерную графику.
Но это уже - отдельная история.

1158 Книга Сергея Цыпцына


MAYA Fluids
MAYA Fluids - это специальный модуль, предназначенный для быстрого и качественного апгрейда
вашего компьютера. Начав работать с ним, вы с гарантием поменяете процессор на более быстрый,
под натиском кэш-файлов ваше дисковое пространство мгновенно закончится, а оперативную
память постигнет та же участь, что и дисковую. В результате, всего через неделю после активного
применения MAYA Fluids, у вас уже будет полностью обновленная машина, а производство анимации,
расчет спецэффектов и рендеринг сцен ускорится в разы. И это, в общем, не шутка: если вы
собираетесь считать что-то серьезное с помощью это модуля, уже сегодня рекомендую запастись
хотя бы дополнительным жестким диском для хранения кэш-файлов.

Ниже, для обозначения всей технологии MAYA Fluids, я буду часто употреблять обычное
русское слово «флюиды». Будучи напечатанным вот так, родимой кириллицей, оно внесет некий
романтический оттенок в текст, довольно далекий от романтики: ведь в устной речи, в устойчивой
жаргонной традиции «майщиков», оно прижилось именно таким, без разъяснений. А ту жидкую
субстанцию, поведение которой моделируется с помощью флюидов, я буду называть «сплошной
средой» - чтобы подчеркнуть ее отличие от «несплошного» набора частиц.

Перед тем, как броситься с головой во море флюидов, я сильно рекомендую освоить
работу с частицами и основные принципы динамики, описанные с соответствующей главе.
Почему? По простой причине: многие свойства флюидов автоматически становятся понятны по
аналогии с частицами. Принципы вычисления динамики в каждом кадре и ограничения, с этим
связанные, для обеих технологий одинаковы. Методы кэширования также весьма схожи. Поэтому
для описания многих свойств я буду использовать аналогии с частицами или же наоборот - по мере
необходимости, акцентировать внимание на разнице в подходах.

Область применения MAYA Fluids


Эта технология впервые была анонсирована на выставке Siggraph 2001 в августе 2001 года,
в составе версии MAYA 4.5. Она была призвана заполнить нишу динамической симуляции, которую
не могла закрыть дискретная модель динамики частиц. Как я уже упоминал, майские частицы
не могут напрямую влиять друг на друга и не взаимодействуют между собой. Это накладывает
вполне понятные ограничения на область их применения. Методы и алгоритмы динамического
моделирования, использованные во флюидах, занимаются как раз расчетами внутренних
взаимодействий жидких и газообразных сред.

Варианты применения MAYA Fluids довольно разнообразны. Всевозможная пиротехника,


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

Облака, сделанные с помощью флюидов, особенно хороши. Сквозь них можно летать, в них
можно плавать, к ним можно приближаться на любое расстояние, их можно отражать, преломлять,
затенять и даже считать с помощью mental ray. При этом изготавливать их довольно несложно,
динамического просчета они, как правило, не требуют, рендерятся предсказуемо, поэтому даже
если бы, кроме облаков, флюиды ничего больше делать не умели, они бы уже имели право на
существование как отдельная элегантная технология.

Формально говоря, есть еще целый класс феноменов, симулируемый с помощью флюидов.
Это «водные эффекты» (watereffects). Хотя правильнее их называть «эффекты водной поверхности».
К ним относятся океан (ocean) и водоем (pond). Они позволяют создавать и анимировать морскую
поверхность в любую погоду, равно как или более скромные явления, происходящие на поверхности
небольшого пруда, бассейна или лужи на затопленном перекрестке.

Флюиды 1161
Типы флюидов
Хотя океаны (ocean) и водоемы (pond) находятся в меню Fluids, язык все же не поворачивается
называть их флюидами, так как они представляют собой довольно обособленную технологию,
слабо напоминающую динамику жидких и газообразных сред. То есть формально и исторически
их к флюидам относят, но никогда так не называют. Ocean и Pond - достаточно независимые
имена, чтобы употреблять их по назначению. Часто их объединяют и относят к классу water ef­
fects.

Океан (ocean) вообще не имеет отношения не только к контейнерам и солверам (Solv­


er), но и вообще к динамике. Это просто сложный материал с огромным количеством атрибутов,
анимируемых по времени, назначаемый, как правило, на сплайновую поверхность специальной
топологии.

Водоем (pond) представляет собой плоский двухмерный контейнер, который, однако,


вместо расчета внутренних взаимодействий среды использует специальную динамику сетки из
пружин (Spring Mesh Solver) для симуляции движения водной поверхности.

К водным процедурам и эффектам я еще вернусь, а сейчас речь пойдет о реальных


флюидах, которые имеются в виду, когда речь идет о MAYA Fluids.

«Настоящие» флюиды представляют собой контейнеры, в которых проистекает настоящая


жизнь всяческих жидких и газообразных субстанций. Их тоже можно разделить на два класса.
Динамические эффекты (или динамические сетки) используют математические алгоритмы
расчета динамики жидкостей и газов для создания натурального и правдоподобного движения и
взаимодействия сплошной среды. Такая динамика опирается на метод Навье-Стокса для решения
системуравненийвчастныхпроизводных,описывающихэтодвижениеи взаимодействие. Этот метод
исключительно прожорлив (с точки зрения вычислительных ресурсов) и требует значительного
времени для своих расчетов. Зато вы можете использовать весь спектр динамических эффектов:
создавать и назначать поля сил, взаимодействовать с геометрией и частицами, контролировать
перемешивание, вязкость и даже температуру среды.

Статические эффекты не используют динамику вообще. Вместо нее движение среды


задается анимацией параметров, определяющих ее внешний вид. На цвет, прозрачность и другие
свойства назначаются объемные процедурные текстуры, атрибуты которых неистово анимируются,
создавая различные эффекты и симулируя движение внутри контейнера. Именно так чаще всего
создают облака.

Пытливые умы, наверное, уже раздражены употреблением термина «контейнер» без


всяких объяснений на этот счет. Что ж, попробуем объясниться.

Контейнеры и внутреннее устройство флюидов


Вычислительная модель, используемая MAYA Fluids, принципиально отличается от динамики
частиц. Она основана на уравнениях в частных производных и вместо расчета траекторий подвижных
точек занимается вычислением различных характеристик и свойств в фиксированных точках
сплошной среды. Соответствующие значения таких характеристик, как плотность, температура,
скорость, определенные в узлах сетки, покрывающей необходимый объем, полностью задают
состояние среды и ее динамические свойства.

1162 Книга Сергея Цыпцына


Таким образом, главное и принципиальное отличие флюидов от частиц заключается в
том, что точки (или ячейки), определяющие состояние сплошной среды, никуда не движутся,
а неподвижно зафиксированы в пространстве. И в результате расчетов изменяются не их
координаты, а характеристики или значения, задающие свойства среды. Соответственно, в отличие
от частиц, результатами динамической симуляции будут не траектории частиц среды, а сеточные
наборы данных для значений свойств среды в фиксированных ячейках, которые необходимо
интерпретировать для визуализации - а проще говоря, как-то отображать на экране.

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

Флюиды 1163
Отсюда самое главное свойство флюидов - движение и взаимодействие среды всегда
рассчитывается и осуществляется внутри фиксированного объема. Его и называют контейнером.
Именно его разбивают на сетку из неподвижных точек-ячеек, в которых и производят вычисления
характеристик среды. За границами контейнера никакого движения и визуализации не происходит.
Внутри контейнера движения ячеек-точек также отсутствуют. Происходят только вычисления, и их
результат затем различными способами визуализируется.

Естественно, это накладывает ограничение на типы эффектов, производимые с помощью


флюидов. Для создания глобальных феноменов и были созданы water effects во главе с ocean. A
характерная черта флюидов их локальность.

Размер и разрешение контейнера


Чтобы создать контейнер, достаточно выполнить соответствующий пункт в меню Fluid Ef­
fects. Контейнер - просто параллелепипед, обозначающий область пространства, в которой будет
произведено моделирование поведения сплошной среды. Хотя контейнеры могут пересекаться в
пространстве, содержимое одного из них не будет оказывать никакого влияния на содержимое
другого.

Неподвижные точки пространственной сетки, заполняющей контейнер, называются


воксели (voxels). (По аналогии с пикселями, только это «объемные пиксели»: voxel = volume pix­
el.) Для каждого вокселя вычисляют и в нем хранят значения ключевых параметров, описывающих
сплошную среду: плотность, скорость, температура и, может быть, цвет.

Комментарий. Если вы уже вошли во вкус изучения MAYA и поняли основной принцип,
заключающийся в исследовании атрибутов нового объекта, вам будет гораздо
проще следить за моими рассуждениями, открыв Attribute Editor для любого
контейнера и последовательно исследуя все его разделы. На мой взгляд, описание
целого класса явлений с помощью всего одного базового объекта и набора его
атрибутов - это исключительно удачный и эффективный принцип, как с точки
зрения архитектуры программы, так и с позиции изучения и экспериментирования.
Очевидные или легко исследуемые «методом тыка» атрибуты вообще нет смысла
описывать, поэтому я остановлюсь на ключевых для понимания моментах.

Интуитивно понятно, что чем больше точек в контейнере (то есть чем больше его
пространственное разрешение), тем подробнее и точнее будет описываться поведение сплошной
среды. Однако время расчетов и рендеринга будет возрастать многократно (ибо количество точек
это приблизительно X*Y*Z).

1164 Книга Сергея Цыпцына


Следует также понимать, что размер контейнера и его разрешение совершенно независимы.
Так, если вы просто растянете контейнер при помощи манипулятора Scale, вы лишь измените
видимый размер ячеек.

Если изменять размер контейнера с помощью атрибутов Size, значение плотности и других
параметров в ячейках будет пропорционально изменяться. В этом состоит отличие от простого
растягивания. Вы также можете воспользоваться операцией Fluid Effects=>Extend Fluid.
Чтобы изменить пространственное разрешение контейнера, нужно использовать операцию
Fluid Effects=>Edit Fluid Resolution.

Примечание. Старайтесь задавать разрешение пропорциональным размеру


контейнера. Это немного снизит время рендеринга и сохранит качество
визуализации одинаковым по всем осям контейнера.
Совет. Как только вы создали контейнер, сохраните сцену! И не в целях сохранности
ваших уникальных экспериментов, а для корректной работы с начальными
состояниями (Initial States) и кэшированием.

Содержимое и начинка контейнера


Основным параметром, без которого нет смысла говорить от существовании среды в
объеме, является плотность (density). Она характеризует наличие и количество среды в той или
иной точке пространства. Все остальные характеристики имеют смысл только в точках с ненулевой
плотностью.

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

Ключевой момент для понимания здесь таков: если во всех точках задана одинаковая
плотность, никакого перемешивания, а следовательно, и движения среды не произойдет. Поэтому
ни к чему не приводят попытки начинающих пользователей: залить контейнер равномерной
плотностью, а потом запустить анимацию.

Флюиды 1165
Для создания совсем изысканных эффектов, учитывающих явления горения и
теплопереноса, в каждой точке рассчитываются параметры температуры (temperature) и запаса
горючести (fuel). Более нагретые участки стремятся подняться вверх и отображаются, как правило,
с увеличенной яркостью (incandescence), а горючесть в точке определяет (вместе с плотностью),
как долго еще будет идти реакция тепловыделения в этом месте. По умолчанию расчет этих
параметров выключен, то есть вычисление реакций горения не производится, так как они требуют
дополнительных и ощутимых вычислительных затрат.

Для адекватной визуализации флюидов необходим, естественно, цвет (color), который


также надо определять в каждой точке контейнера.

Типы контейнеров и распределение свойств внутри них


Прежде всего, контейнеры бывают объемные (3D) и плоские (2D). Плоский контейнер
отличается от объемного тем, что у него пространственная сетка из точек в одном из направлений
имеет всего один слой (формально говоря, разрешение по оси Z равно единице). Хотя
пространственная ширина этого слоя может быть какой угодно.

Для взрослых. На самом деле плоский и объемный контейнер - один и тот же


объект, у которого отличается только значение атрибута is2d.

Следующее разделение контейнеров еще на два класса опирается на характер анимации


ключевых параметров контейнера.

Если плотность или любой другой атрибут изменяются динамически, то есть с помощью
солвера (Solver), производящего расчет динамики в каждом кадре, то контейнер называется
динамическим - как и эффекты, производимые с его помощью.

1166 Книга Сергея Цыпцына


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

Два метода анимации флюидов, динамический и текстурный - это принципиально разные


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

В разделе Contents Method задается метод изменения и вычисления каждого из ключевых


параметров флюида. Если хоть один из них установлен в Dynamic Grid, контейнер считается
динамическим. По умолчанию плотность и скорость считаются динамически меняющимися
параметрами, температура не используется, а изменение цвета вычисляется на основе атрибутов
из раздела Shading.

Если метод определен как Static Grid, значения параметра в точках сетки не будут
изменяться по времени. Выбор варианта Gradient позволяет быстро залить весь контейнер
предустановленными значениями параметра, которые также не будут изменяться при анимации.
Примечание. Динамически может изменяться только один атрибут, в то время как остальные
изменения будут заданы вручную либо с помощью статичных сеток, или с помощью градиентов.
Так, например, задав плотность как динамическую сеткоу, можно заморозить или даже просто
нарисовать распределение скоростей в пространстве, определив, таким образом, статичное поле,
которое будет «гонять» плотность по контейнеру.

Заполнение контейнера
Создайте трехмерный контейнер: Fluid Effects=>Create 3D Container. По умолчанию любой
контейнер пуст.

Иными словами, во всех точках контейнера значение плотности (впрочем, не только


плотности, но и некоторых других параметров) равно нулю. Чтобы заполнить контейнер сплошной
средой, можно использовать несколько методов: напустить в него немного вещества с помощью
источника (fluid emitter), залить его градиентом, нарисовать содержимое с помощью Paint Fluid Tool,
добавить с помощью кривой или загрузить содержимое из сохраненного или предустановленного
начального состояния. Все эти методы находятся в меню Fluid Effects=>Add/Edit Content.

Флюиды 1167
Имейте в виду, что использование градиентной заливки автоматически превращает
метод заполнения сетки контейнера (Content Method) в Gradient, а рисование, напротив, может
производиться только по статической или динамической сетке. В этом смысле градиенты стоят
несколько особняком от других методов работы с содержимым контейнера.
Проще всего, конечно, воспользоваться уже кем-то заготовленным содержимым контейнера.
Если ваш трехмерный контейнер выбран, выполните Effects=>Add/Edit Content=>lnitial States.
В появившемся окне Visor выберите раздел Clouds and Fog=>3D, а затем перетащите и бросьте
иконку cloud3DApply.mel прямо на контейнер в окне камеры.
Это заполнит контейнер уже сохраненными данными.
Не забудьте переключиться в Shaded Mode, нажав 5.

1168 Книга Сергея Цыпцына


Начальное состояние
Важно понимать, что так же, как для частиц и твердых тел, для флюидов определено
понятие начального кадра и начального состояния. В любой момент состояние контейнера (то есть
значения плотности, скорости и других атрибутов) можно сохранить, как начальное. Более того,
с помощью операции Fluid Effects=>Save State As можно сохранить начальное состояние в виде
предустановленного набора значений, появляющегося в окне Visor.
Важно и то, что вместе со значениями сохраняется пространственное разрешение контейнера,
поэтому при загрузке начального состояния из сохраненного файла изменяется также и количество
ячеек контейнера.

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

Примеры для изучения


Создавая такую сложную технологию, разработчики инстинктивно понимали, что и простым
смертным и даже пытливым умам будет весьма непросто постичь особенности реализации метода
Навье-Стокса. Поэтому они снабдили поставку MAYA некоторым количеством показательных
примеров.

Для работы с ними достаточно открыть новую сцену, а затем выполнить Fluid Effects=>Get
Fluid Example. В появившемся окне Visor достаточно выбрать интересующим пример и втащить его
в окно камеры средней кнопкой мыши.

Дальнейшее изучение сводится к анализу значений атрибутов контейнера методом тыка и


визуального контроля анимации методом пристального взгляда. Однако мало кто догадывается,
что главный сюрприз и помощь скрываются в самом низу Attribute Editor, в разделе Notes. Именно
там разработчики оставили свои комментарии и некоторые объяснения особенностей работы с
выбранными примерами.

Флюиды 1169
Кроме того, на сайте компании Alias можно скачать дополнительные Fluids Web Packs,
комплекты готовых примеров для дальнейшего изучения.

Также дополнительным подспорьем в освоении флюидов может стать изучение пресетов


(presets), то есть сохраненных наборов атрибутов, определяющих все свойства контейнера.
Скопировать любой такой набор в атрибуты выбранного контейнера можно прямо в Attribute Editor
через кнопку Presets. Для них также есть комментарии в разделе Notes.

1170 Книга Сергея Цыпцына


Заполнение контейнера раскрашиванием
Создайте двухмерный контейнер: Fluid Effects=>Create 2D Container.
Он, очевидно, пуст.
Чтобы добавить в него плотности, воспользуйтесь Fluid Effects=>Add/Edit Content=>Paint
Fluid Tool.

По умолчанию, в настройках инструмента Paintable Attribute установлен в Density,


а значение Value равно единице, и это означает, что при окрашивании в ячейки
контейнера будет занесено значение плотности, равное единице. (Это, впрочем,
не совсем так, я ниже расскажу об общем атрибуте Density Scale, но для понимания
принципа заполнения контейнера примем такое, допустимое упрощение.)

Выбрав другой атрибут (например, Color), вы сможете покрасить имеющееся содержимое


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

Комментарий. По умолчанию, в точках сетки находится «темно-бурое» значение


цвета (0.4, 0.4, 0.3), выбранное из совершенно загадочных соображений. Вы всегда
можете изменить его, залив весь контейнер нужным цветом с помощью операции
Flood. Помните, что цвет отображается только в тех местах, где значение
плотности не равно нулю.

Флюиды 1171
Так как по умолчанию включена галка Auto Set Initial State, можно начинать проигрывать
и останавливать анимацию, не выходя из инструмента рисования. Однако если вы покрасите что-
нибудь не в первом кадре, это состояние будет немедленно сохранено как начальное.

Примечание. Нетерпеливые умы могут даже красить контейнер прямо во время


анимации. При этом, если галка Auto Set Initial State включена, в момент отпускания
кисти, после очередного безумного мазка, текущее состояние анимации будет
сохраняться как начальное. В противном случае все нарисованные штрихи пропадут
при перемотке к началу анимации.

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

Выберите в настройках инструмента Paintable Attribute=Density And Color.


Согласитесь на все, если MAYA вас о чем-нибудь спросит.
Затем откройте ниже раздел Attribute Maps=>lmport и нажмите кнопку Import.
Выберите ваше любимое изображение (желательно достаточно контрастное, а еще лучше - с
альфа-каналом) и загрузите его в качестве карты плотности и цвета.

Совет. Сделайте предварительно разрешение контейнера пропорциональным


разрешению изображения. Это ощутимо улучшит качество отображения.

Выйдите из инструмента рисования и проиграйте анимацию, динамика сплошной среды


вычисляет новые значения плотности, скорости и цвета в каждой точке в каждом кадре.
Изображение «плывет» вверх.

1172 Книга Сергея Цыпцына


Комментарий. При импортировании карты плотности MAYA ожидает изображения
с альфа-каналом, из которого будет взята плотность как скалярная величина. Если
альфа отсутствует, берется яркость картинки. Если картинка яркая и не сильно
контрастная, может так случиться, что плотность равномерно распределится
по контейнеру и никакой динамики не получится.

Проконтролировать распределение плоскости можно, установив Shaded Display=Density в


Attribute Editor в разделе Display.

Я намеренно оставляю за кадром способы рисования по трехмерному контейнеру, оставляя


их пытливым умам для самостоятелного изучения. Очевидно, что Paint Fluid Tool применим и
для пространственного случая. Причем рисовать по объему придется, очевидно, по слоям. То
есть по фиксированным плоским «срезам» контейнера. Манипуляторы такого пространственного
рисования интуитивно понятны: можно выбирать ширину слоя для рисования и его положение
в контейнере. Переключение между горизонтальным и вертикальными слоями происходит в
зависимости угла зрения, и оно может быть заблокировано. Слои можно заливать, импортировать
в них карты атрибутов и делать с ними то же самое, что и с плоскими контейнерами.

Совет. Для сглаживания переходов между слоями можно выбрать операцию Smooth
и залить ею весь контейнер.

Как опустошить контейнер


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

Чтобы опустошить контейнер, воспользуйтесь Paint Fluid Tool.


Установите Paintable Attribute=Density, a Value=0.
А затем, убедившись, что Paint Operation=Replace, нажмите кнопку Flood.
Это зальет весь контейнер нулевой плотностью, то есть сделает его пустым. Если вы
подозреваете, что в других сеточных атрибутах, например в скорости, также остались ненулевые
значения, которые могут помешать дальнейшей работе, обнулите их аналогичным способом.

Совет. Вы также можете частично опустошать некоторые области контейнера,


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

Флюиды 1173
Динамическая анимация флюидов
Рассмотрим основные принципы динамики флюидов на примере двухмерного контейнера
- для того, чтобы анимация проигрывалась быстрее, а эксперименты были более интерактивными.
Все атрибуты, а следовательно, и свойства контейнеров, отвечающие за динамическую симуляцию,
совершенно одинаковы для плоских и объемных контейнеров. И все изложенное для первых будет
так же справедливо и для вторых.

Создайте двухмерный контейнер: Fluid Effects=>Create 2D Container.


Он трагически пуст.
Чтобы добавить в него плотности воспользуйтесь Fluid Effects=>Add/Edit Content=>Paint
Fluid Tool.
Выберите PaintableAttribute=DensityAnd Color, a Value=1, нарисуйте несколько разноцветных
пятен, согласившись сделать цвет динамическим атрибутом.
Проиграйте анимацию - пятна поплывут вверх, наподобие нагретого дыма.

Чтобы разобраться в механизмах действия динамики флюидов, придется пристальнее


взглянуть в Attribute Editor на разделы Dynamic Simulation и Contents Detail.
С первым разделом все, более-менее, понятно. Находящиеся в нем атрибуты определяют
общие свойства сплошной среды и параметры численного интегрирования уравнений ее движения.
Величина атрибута Gravity определяет значение встроенной силы гравитации, направленной
вниз.

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

1174 Книга Сергея Цыпцына


получается мед - причем сильно засахаренный и практически не текущий.
Для безумных физиков: единица соответствует числу Рейнольдса, равному 0, при Viscosity=0.5
число Рейнольдса равно 1, а для Viscosity=0 полагается запредельный Рейнольде, типа 100000.
Влияние атрибута Friction можно с трудом заметить в местах взаимодействия среды с объектами
или границами контейнера.

Атрибут Damp соответствует примерно тому же свойству, что и Conserve для частиц.
Его суть заключается в общей «заторморженности» среды и достигается путем небольшого
принудительного понижения скорости в каждом кадре. Такое искусственное торможение, как и в
случае с частицами, иногда можно применять для стабилизации системы с высокими внутренними
скоростями.

Метод (Solver) определяет, каким алгоритмом просчитывать динамику сплошной среды


внутри контейнера.

А вот Grid Interpolator, установленный в Hermite, может повысить точность расчетов и


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

В седьмой версии появился дополнительный атрибут, позволяющий бороться с излишней


диссипацией (перемешиванием) внутри контейнера. Его назвали High Detail Solve, и он слегка
модифицирует вычислительный алгоритм, чтобы препятствовать перемешиванию плотности и
скоростей, получая, таким образом, более «очерченные» изображения. Включайте его постепенно,
самое большое замедление скорости расчетов будет при High Detail Solve=AU Grids.
Start Frame, как и положено для всей динамики, определяет первый кадр для начала
вычислений. А вот Simulation Rate Scale, в отличие от Oversampling для частиц, просто задает
шаг (а не частоту отсчетов) внутренних вычислений. При его увеличении скорость протекания
всех процессов пропорционально ускоряется, однако не надо обольщаться: точность вычислений,
конечно, падает. И наоборот, если ваш флюид «разваливается» под влиянием сильных воздействий
(например, Gravity=1000), уменьшение Simulation Rate Scale позволяет более точно просчитать
процесс, при этом темп анимации, соответственно, уменьшается.

Хотя понятие «точность» здесь, конечно, приобрело весьма расплывчатый смысл. Ведь
требуется максимально точное соответствие творческому замыслу, а не законам физики.

Поэтому я могу только сформулировать следующий вывод: результат просчета ста кадров
с Simulation Rate Scale=1 не совпадает с результатом, полученным за двести кадров с Simulation
Rate Scale=0.5. У них разная математическая точность просчета.

А вот за внутренний шаг вычислений динамики флюидов отвечает атрибут Solver Quality,
появившийся не так давно. Он отвечает именно за точность решения, и его увеличение приводит
к замедлению просчета, но темп анимации остается прежним.

Остальные галки в разделе Dynamic Simulation позволяют немного ускорить просчет, за


счет отключения некоторых дополнительных вычислений.

Так почему же все плывет вверх?


Ведь гравитация направлена вниз. Причина кроется в разделе Contents Details и связана
с математической моделью сплошной среды, используемой в динамике флюидов. Наряду с
вязкостью и внутренней гравитацией, у содержимого контейнера есть еще масса динамических
свойств, которые необходимо не только держать в уме, но и, к сожалению, понимать. Эти
свойства задаются, естественно, через атрибуты и расположены в соответствующих подразделах.
В подразделе Density можно найти некоторое количество атрибутов, связанных с плотностью
среды, и, как следствие, с ее «насыщенностью», «легкостью», «растворяемостью» и другими
физическими свойствами.

Флюиды 1175
Прежде всего, это атрибут Density Scale, позволяющий глобально умножать плотность
всего контейнера на некоторую величину. Распределение плотности в контейнере задается, как
правило, в диапазоне значений от нуля до единицы, а атрибут Density Scale позволяет умножить
или растянуть все значения плотности до нужных пределов.

Увеличьте Density Scale до двух, и вы заметите, как ускорилось движение вверх.

Такое стремительное всплывание связано со следующим свойством, задаваемым атрибутом


Buoyancy (плавучесть). Дело в том, что этот атрибут задает разницу в плотностях между регионами,
где есть ненулевая плотность, и пустыми областями, симулируя, таким образом, выталкивающую
архимедову силу. Если значение Buoyancy больше нуля, плотность вещества в контейнере
считается меньше плотности окружающей среды (представленной пустыми областями). При этом
вещество будет всплывать, подобно легким пузырям в тяжелой воде. И наоборот, если Buoyancy
меньше нуля, содержимое контейнера становится тяжелее окружающей среды и идет на дно.
Задайтеотрицательную плавучесть: Buoyancy=-2. После этого движение напоминает циркулирование
вязкой тяжелой жидкости.

Для того, чтобы получить движение капли воды в воздухе, надо задать очень большую
«антиплавучесть», равную отношению плотности воды к плотности воздуха. При этом возникнут
очень большие внутренние скорости и станет понятно, что данная математическая модель не
совсем подходит для симулирования движения невязких тяжелых жидкостей в разреженной
среде.

Следует понимать, что на скорость всплывания (или падения на «дно») влияют оба
атрибута: Density Scale и Buoyancy. Однако второй определяет только динамическое свойство
среды, связанное с движением, а первый влияет как на движение, так и на внешний вид флюида,
связанный с плотностью и прозрачностью.

Диссипация (Dissipation) и диффузия (Diffusion) - эти термины можно перевести с русского


на русский как «рассеивание». Только первый означает рассеивание по времени, то есть
постепенное уменьшение плотности, подобное исчезновению дымка от сигареты.

1176 Книга Сергея Цыпцына


Диффузия же означает рассеяние по пространству, то есть растекание плотности в
соседние области пространства - стремление распределиться по всему объему.

Диффузия и диссипация присущи также не только плотности, но и цвету и температуре, в


чем можно убедиться, заглянув в нужные подразделы в Attribute Editor. Нет смысла перечислять
остальные атрибуты в разделе Contents Details. Они позволяют как определить дополнительные
физические свойства среды, так и задать искусственные силы, типа турбулентности или
водоворотов (swirl). Дальнейшие эксперименты зависят только от пытливости вашего ума и запаса
настойчивости. Отмечу лишь, что для динамики ключевые атрибуты - это Density Scale и Buoyancy,
без которых невозможно адекватно управлять движением флюидов.

Перед тем, как перейти к вопросам визуализации, обнулите диссипацию и диффузию,


если вы успели их подергать, и сохраните сцену для дальнейших экспериментов.

Взаимодействие флюидов с «нормальной» динамикой


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

Флюиды 1177
Также несложно организовать столкновение среды с геометрическими объектами,
помещенными внутрь контейнера с помощью аналогичной частицам операции Fluid Effects=>Make
Collide. Однако для движущихся внутри контейнера объектов лучше использовать специальное
поле, так как MAYA плохо отслеживает движущуюся геометрию, взаимодейтвующую с флюидом.
Операция Fluid Effects=>Make Motion Field позволяет прикрепить к любому объекту поле, которое
будет действовать как «возмутитель» содержимого контейнера. Сила этого поля будет зависеть от
скорости его перемещения, причем вычисления будут производиться более быстро и точно, чем в
случае столкновения среды с произвольными объектами.

Можно даже организовать обратное взаимодействие - влиять на частицы флюидом, как


полем. Для этого надо выбрать контейнер, затем частицы и выполнить операцию Fields=>Affect
Selected Object.

Возможны и дальнейшие комбинации флюидов и частиц, основанные на обычных


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

Повторюсь, однако: наилучшая отправная точка для изучения динамики флюидов


- примеры, доступные через Fluid Effects=>Get Fluid Example. Среди них есть даже варианты
написания специальных per-point expressions (аналог particle expressions) они позволяют вручную
задавать значения атрибутов в каждой ячейке контейнера.

1178 Книга Сергея Цыпцына


Кэширование флюидов
Для ускорения просчета динамики флюидов можно использовать различные ухищрения.
Можно отключить ненужные вычисления в разделе Dynamic Simulation. Например, если вы не
используете столкновения с поверхностью, можете выключить Use Collisions.

Для того, чтобы еще немного ускорить просчет, можно в разделе Display отключить
отображение как самого флюида (Shaded Display=Off), так и границ контейнера (Boundary
Draw=Bottom).

Но все это полумеры по сравнению с кэшированием, которое позволяет сделать один


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

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

Прежде всего, перед тем, как создавать кэш, сохраните сцену. Имя сцены будет
использовано при создании кэш-файлов, поэтому во избежание путаницы старайтесь давать сцене
имя заранее. Переименование сцены позже может затруднить нахождение нужных кэш-файлов.
Для создания кэша достаточно выбрать контейнер и открыть Option Box операции Create Cache.

Задав диапазон кадров для кэширования в разделе Cache Time Range, следует выбрать,
значения каких динамических атрибутов будут кэшироваться. Естественно, следует выбирать
только те атрибуты, для которых Content Method установлен в Dynamic Grid. Нет смысла кэшировать
атрибуты, которые не вычисляются динамикой.

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

Флюиды 1179
Кстати, можно вручную указать, что некоторые атрибуты не будут использовать данные из
кэша, несмотря на то, что кэш уже посчитан. Для этого надо снять соответствующие галки в At­
tribute Editor, в разделе Grids Cache для контейнера.

После создания кэш-файла в Attribute Editor возникает новая закладка, соответствующая


ноде типа diskCache, которая отвечает за кэширование выбранного контейнера.

В этой закладке есть поле Cache File Name, где можно указать имя ранее сохраненного
кэш-файла для загрузки его содержимого в выбранный контейнер. Когда вы создаете кэш, он
по умолчанию сохраняется в папке data текущего проекта под именем scenename_fluidShapeN.
mcfp. В дальнейшем вы можете его переименовывать, копировать в другое место и повторно
использовать. Часто имеет смысл иметь несколько просчитанных кэш-файлов для дальнейших
экспериментов с визуализацией флюидов.

Комментарий. Начальноесостояние (InitalState) представляетсобой «однокадровый


кэш» и тоже сохраняется в папке data с именем scenename_fluidShapen.mcfi. Его
также можно подгружать в выбранный контейнер, в соответствующей закладке
в Attribute Editor.

Вы должны хорошо понимать, что в кэш записываются только динамические атрибуты типа
плотности или скорости, определяющие значения в ячейках контейнера. Значения «глобального»
атрибута Density Scale в кэш не записывается, их можно изменять и анимировать произвольно,
изменяя общую плотность для уже закэшированного контейнера. Это изменение плотности уже
не будет оказывать влияние на движение среды, так как произведено кэширование скоростей,
однако на внешний вид оно будет иметь самое непосредственное влияние.

Для взрослых. Аналогично частицам и твердым телам, у флюидов есть собственное


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

1180 Книга Сергея Цыпцына


Визуализация флюидов. Поверхности
Рассмотрим методы визуализации флюидов. Попробуем сделать некое подобие жидкости
и, соответственно, представим ее в виде поверхности.
Создайте контейнер с источником и параметрами по умолчанию: Fluid Effects=>Create 3D Container
with Emitter.

Пока контейнер пуст, можно отредактировать его разрешение и размер прямо в Attribute Editor.
Задайте ResolutionY=20 и SizeY=20.
Выберите источник и поднимите его в верхнюю часть контейнера (translateY=8).

Чтобы дымок не поднимался вверх, а наоборот, с бешеной скоростью падал вниз (мы
ведь симулируем движение жидкости), откройте раздел Contents Detail и в подразделе Density
установите сильную «антиплавучесть» (Bouyance=-30) и изрядную плотность (Density Scale=5).

В атрибутах источника установите побольше напор: Density/Voxel/Sec=5, а чтобы струя не


была такая уж толстая, задайте Max Distance=0.3.
Однако вы должны понимать, что для просчета тонких деталей и особенностей разрешение
контейнера должно быть достаточно высоким.

Флюиды 1181
Для экономии времени применим следующий трюк - приблизительный характер движения
можно отладить на грубом разрешении контейнера, а окончательный просчет и кэширование
произвести после увеличения разрешения.

В первый момент из источника вылетает некое облако и падает в виде утолщения вниз.
Отчасти это связано с тем, что для такого тяжелого вещества не хватает точности просчета (то
есть временной шаг вычисления динамики слишком велик). Также это связано с тем, что наша
жидкость врывается в неподвижную среду и пытается об нее затормозиться. Применим небольшой
трюк и проиграем немного анимации, пока жидкость не достигнет дна. В этот момент в контейнере
уже будет распределение скоростей, соответствующее падающей жидкости. Затем сохраним это
состояние как начальное и удалим из контейнера всю плотность. Таким образом, жидкость будет
попадать в контейнер, уже содержащий поле скоростей, соответствующих падению жидкости.
Конечно, реальная жидкость не склонна сильно тормозиться о воздух, но, как я уже упоминал
выше, чтобы симулировать падение реальной тяжелой жидкости, надо применять очень большие
значения для плотности, которые потребуют очень высокой точности просчета и гигантского
времени вычислений. Поэтому будем выкручиваться с помощью трюков.

Проиграйте анимацию примерно до двадцатого кадра.


Остановитесь и сохраните состояние контейнера как начальное: Fluid Effects=>Set Initial
State. Перейдите в первый кадр и вызовите Paint Fluid Tool.

Нажмите кнопку Reset Tool, задайте Value=0 и нажмите Flood.


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

Так как по умолчанию галка Auto Set Initial State включена, это состояние будет сохранено
как начальное.

Выйдите из Paint Fluid Tool и проиграйте анимацию: теперь струя не имеет вызывающего
утолщения в начале.

1182 Книга Сергея Цыпцына


Заметно, что жидкость вытекает некоторыми толчками, это связано с тем, что шаг
вычислений слишком велик, и компьютер не успевает просчитывать такое большое количество
жидкости, испускаемой источником и падающей с высокой скоростью.
В разделе Dynamic Simulation уменьшите Simulation Rate Scale до 0.5.

Совет. Вы можете также позже поэкспериментировать с атрибутом Solver Quality.

Точность просчета улучшится, но для физически корректного моделирования этого не


будет достаточно. Мы, однако, используем этот факт для того, чтобы струя не была совсем гладкой
и имела некоторые возмущения на поверхности. Дополнительно можно добавить возмущений с
помощью атрибутов из раздела Turbulence в Contents Details, но мы пока не будем этого делать.
Скорость просчета упала ровно в два раза, поэтому если вы захотите сохранить прежний
темп анимации, придется рендерить эту сцену через кадр.

Пока заняться визуализацией. Сохраните сцену (liquidStart.ma).

Совет. При работе с таким сложными объектами, как контейнер, периодически


закрывайте все разделы в Attribute Editor. Это поможет быстрее находить нужные
атрибуты и увеличит время жизни мыши.

Откройте раздел Surface и включите опцию Surface Render. Туманная струя превратится в
полупрозрачную поверхность.

Флюиды 1183
Сразу откройте следующий раздел Shading и полностью уберите прозрачность (Transpar­
ency). Это ускорит анимацию и улучшит отображение поверхности.

По какому же принципу строится геометрия на экране? Ключевым свойством для построения


поверхности является плотность среды. MAYA строит поверхность, проходящую через одинаковые
значения плотности. Это пограничное значение плотности задается атрибутом Surface Thresh­
old, равным по умолчанию 0.01. То есть если плотность среды в точке меньше, чем 0.01, мы
находимся снаружи поверхности, а если больше, то внутри. Такой алгоритм построения неявных
поверхностей (Implicit Surfaces) используется в системах метаболов, и к каждом кадре он создает
новую сетку.

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


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

Задайте Surface Threshold до 0.005, и поверхность будет «зацепляться» за точки с совсем


малой плотностью, а следовательно, увеличится.
Важно представлять, что плотность в точках контейнера можно увеличить или уменьшить и
за счет Density Scale, однако это будет оказывать влияние на динамику, поэтому до просчета кэша
проще редактировать Surface Threshold. Оставьте его равным 0.005, чтобы получить насыщенную
струю.
Сейчас струя довольно «квадратная», это связано с недостаточным разрешением
контейнера. Коль скоро мы отладили примерное поведение типа жидкости, теперь можно повысить
разрешение и сразу создать кэш-файл для дальнейших экспериментов с визуализацией.

1184 Книга Сергея Цыпцына


Выберите контейнер.

Встаньте в первый кадр. Это важно!

Зайдите в Option Box операции Fluid Effects=>Edit Fluid Resolution.


Установите X_Resolution=40, Y_Resolution=80, Z_Resolution=40 и нажмите Apply and Close.

Теперь анимация принимает затяжной характер. Чтобы произвольно перемещаться в


любой кадр и не вычислять динамику каждый раз, следует закэшировать данные.

Создайте кэш.
Зайдите в Option Box операции Fluid Effects=>Create Cache.
Выберите для Cache Time Range опцию Start/End и задайте диапазон анимации 1-100.
Отметьте только атрибуты Density и Velocity для записи в кэш.
Нажмите Create и отправляйтесь пообедать. Когда вы вернетесь, кэш, возможно, уже
будет посчитан.

Теперь вы можете проигрывать анимацию в любом направлении и мгновенно вставать в


нужный кадр.

Встаньте в кадр 40 и отрендерите изображение. Поверхность получится слегка «шершавая».


Очевидно, следует улучшить качество рендеринга.

Флюиды 1185
Откройте раздел Shading Quality и выберите Render lnterpolator=Smooth. Это сгладит
поверхность, но не уберет «мохнатые» края.

Чтобы исправить этот недостаток, увеличьте параметр Quality до 9.

1186 Книга Сергея Цыпцына


Совет. Можно использовать IPR Render для отлаживания качества отображения
флюидов. Он будет корректно обновлять изображение даже в разных кадрах. Вы
также можете использовать mental ray для просчета флюидов, это несколько
ускорит скорость и качество рендеринга.

Сохраните файл (liquidFinal.ma). MAYA начнет задумчиво жевать диск. Дело в том, что
в момент сохранения сцены все созданные кэш-файлы переписываются из временной папки в
директорию Data текущего проекта под соответствующими именами.

Далее вы может издеваться над поверхностью, как хотите.

Во-первых, при помощи атрибута Density Scale можно надувать/сдувать поверхность,


просто изменяя общую плотность среды. Так как контейнер закэширован, это будет оказывать
влияние только на внешний вид.

Чтобы задать цвет поверхности, можно воспользоваться градиентом в разделе Color.


После определения цветов градиента следует выбрать с помощью параметра Color Input, как этот
градиент «ляжет» на содержимое контейнера.

В принципе можно назначить обычную трехмерную текстуру на атрибут Selected Color


и получить нужный цвет поверхности. Однако при этом текстура не будет перемещаться с
поверхностью и будет считаться не очень быстро. Для текстурирования флюидов, как правило,
применяют встроенные текстуры, о которых речь пойдет ниже.

Флюиды 1187
К сожалению, на поверхность флюида нельзя назначить обычный материал (по крайней
мере, в текущей версии мне этого не удалось). Поэтому все оптические свойства поверхности
приходится симулировать с помощью атрибутов из разделов Surface и Environment. Мне также не
удалость заставить поверхность преломлять свет, чтобы получить эффект прозрачной жидкости.
Флюиды видны в отражениях и преломлениях, но сами ничего отражать и преломлять не могут.

В разделе Environment можно положить на атрибут Selected Color обычную трехмерную


текстуру, чтобы задать эффект отражающей поверхности. Только имейте в виду, что наибольший
эффект отражения достигается при значении Refractive lndex=1. Этот атрибут симулирует число
Френеля и задает степень отражаемости в зависимости от угла падения взгляда на поверхность.
Задайте Refractive lndex=2 и назначьте на Selected Color текстуру типа Marble или Environment
Sphere с вашей любимой картой отражений.

Запустите IPR Render и подберите эффект отражения по вашему вкусу.

Рендеринг анимации флюидов осуществляется обычным способом, то есть заданием


необходимых параметров в Render Globals и запуском пакетного рендера: Render=>Batch Render. He
забывайте только сохранять сцену перед рендером, чтобы гарантированно обновить кэш-файлы.

11 88 Книга Сергея Цыпцына


Пресеты. Контейнер сыра
Изучить особенности поверхностного рендеринга флюдов можно также с помощью примеров
из Fluid Effects=>Get Fluid Example. Однако мой любимый образец находится в пресетах.
Создайте новый контейнер любого типа.
В Attribute Editor выберите в меню Presets пункт emmenthal=>replace.
Нажмите 6 и отрендерите изображение.

В данном случае использована встроенная текстура для создания отверстий, то есть


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

Конвертирование в полигоны
Некоторые особо внимательные исследователи MAYA обнаружили операцию
Modify=>Convert=>Fluid to Polygons. Действительно, если содержимое контейнера может
отображаться в виде поверхности, то почему бы не сконвертировать эту поверхность в полигональную
сетку. Выбрав контейнер и выполнив указанную операцию, вы получите обычный полигональный
объект (даже с историей), к которому можно применять все стандартные методы полигонального
моделирования (хм..., а ну, попробуйте сделать из него сабдив). Дополнительно его можно будет
рендерить всевозможными способами как обычный объект. Я оставляю за рамками обсуждения
качество и профпригодность такого объекта, полагаясь на ваши оптимистичные эксперименты.
Помните только, что для улучшения качества поверхности необходимо увеличивать разрешение,
со всеми вытекающими отсюда последствиями.

Визуализация объемных флюидов


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

Создайте объемный контейнер следующего разрешения (80, 5, 50) и размера (16, 1, 10).
Коль скоро мы не собираемся использовать динамику, сразу зайдите в раздел Contents
Details и установите Velocity=Off, Density=Gradient, Density Gradient=Y Gradient.
Это выключит всю динамику и зальет контейнер плотностью равномерно убывающей снизу
вверх. Таким образом, в нашей моделиоблака снизу будут выглядеть насыщеннее, чем сверху.

Флюиды 1189
К счастью, можно пропустить кошмарное количество атрибутов, связанных с динамикой, и
сразу перейти в раздел Shading.

Мы не собираемся вылетать за пределы контейнера или смотреть на него сбоку, поэтому


установите Dropoff Shape=None, чтобы убрать затухание по краям контейнера.

Попробуем покрасить контейнер.


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

Ведь у контейнера нет UV-координат, поэтому плоский градиент должен как-то


распределяться внутри него. Закон и направление такого распределения задаются атрибутом
Color Input, где можно указать зависимость градиента не только от пространственных координат
точек, но и от любого атрибута в точке контейнера.
Выберите Color lnput=X Gradient, и цвета распределятся вдоль оси X.

Однако если задать Color lnput=Density, каждый цвет будет зависеть от значения плотности
в точках контейнера. Левый край градиента соответствует нулевому значению атрибута Density,
правый - единичному значению.

1190 Книга Сергея Цыпцына


Конечно, редко нужно делать цвет зависящим от плотности. Ведь от плотности, как
правило, зависит прозрачность, о чем свидетельствует значение по умолчанию атрибута Opacity
lnput=Density в разделе Opacity.
Поэтому удалите все цвета, кроме белого, из градиента Color.
Затем справа создайте темно-серый слой, a Color Input задайте как Y_Gradient.
Это создаст эффект того, что облака сверху светлее, чем снизу, так как солнце находится
над облаками.

Пытливые умы наверняка разгрядели, что градиент самосвечения или раскаленности (In­
candescence) по умолчанию зависит от температуры. Это позволяет делать участки с более высокой
температурой более яркими (желтый цвет справа соответствует большим значениям температуры,
черный слева - меньшим). Таким образом, флюид может окрашиваться по разному в зависимости
от физических свойств, а не только от положения в пространстве. У нас температура не задана, и
мы не будем использовать этот градиент.

В разделе Opacity градиент представлен в виде графика, так как прозрачность в данном
случае представляет из себя числовую величину. Так как Opacity lnput=Density, этот график
трактуется просто: чем больше плотность в точке, тем более непрозрачный объем в этой области. Вы
можете отредактировать график как угодно, и даже задать обратное распределение прозрачности:
где плотнее, там прозрачнее. Однако обычно этот график редактируют для создания более
плотных объемов с четкими границами, когда начало графика сдвигают влево, чтобы исключить
из отображения (сделать прозрачными) области с низкой плотностью. К этому мы еще вернемся.
Чтобы распределение цвета от серого к белому не было столь равномерным и искусственным,
можно назначить на любой из слоев Selected Color обычную текстуру типа Volume Noise или Cloud,
однако мы будем использовать встроенные к любой контейнер фрактальные текстуры, атрибуты
которых располагаются в разделе Texturing.

Особенность применения этих текстур заключается в том, что они назначаются не на сам
контейнер, а на цвета, определенные в разделах Color/lncandescence/Opacity. А еще точнее, на
атрибут Color Input (соответственно Incandescence/Opacity Input). Если это звучит угрожающе,
воспринимайте эти текстуры как добавление шума в градиенты, определенные в разделе Shad­
ing.

Откройте раздел Texturing и включите галку Texture Color.


Чтобы лучше увидеть эффект «загрязнения» цвета, установите усиление Color Тех Gain=2.
Затем в атрибутах текстуры задайте Frequency=5.
Не забудьте нажать 6, чтобы увидеть отображение текстур на экране.

Флюиды 1191
Принципиальным момент здесь в том, что в разделе Color задан бело-серый градиент,
состоящий минимум из двух слоев. Текстура вносит шум не в сами цвета, а в их смешивание,
поэтому если бы в градиенте был только один белый цвет, никакого эффекта текстура бы не
производила.

Можно убрать в разделе Display отображение границ контейнера (Boundary Draw=Off).


Теперь уменьшите Color Тех Gain до 0.5 и включите галку Texture Opacity.
При этом та же самая (да-да, та же самая, одна на всех) текстура назначится и на
прозрачность контейнера (а точнее, на график прозрачности, заданный в разделе Opacity).
По каким-то загадочным причинам для цвета и прозрачности может использоваться только
одна и та же текстура. «Силу» применения этой текстуры можно устанавливать независимо
для цвета и прозрачности с помощью атрибутов Color/Opacity Тех Gain, однако все остальные
параметры этой текстуры настраиваются одинаково.
Задайте Depth Max=4 и включите галку Inflection, чтобы сделать текстуру более «выпуклой».
Можете поэкспериментировать с типами текстур, но имейте ввиду, что Billow - самая медленная
процедурная текстура в мире, соперничающая по времени вычисления с динамикой флюидов. Я
использую стандартный Perlin Noise и вам советую.

Проблема в том, что прозрачность слишком размытая, то есть на экране отображаются и


области с совсем небольшой плотностью и более насыщенные регионы. Сделаем так, чтобы малые
плотности совсем не отображались на экране.

Перейдите в раздел Opacity и отредактируйте график зависимости непрозрачности от


плотности. Сдвиньте вправо начало графика (Selected Position=0.2).

При этом неплотные области исчезнут совсем, так как непрозрачное отображение
начинается с регионов, где плотность не меньше, чем, условно говоря, 0.2.

1192 Книга Сергея Цыпцына


Однако, чтобы визуальная насыщенность возрастала более резко с увеличением плотности,
вставьте дополнительную точку (Selected Position=0.25) и задайте крутой угол для начального
участка графика (Selected Value=0.7).

Границы облаков (то есть места возрастания плотности) станут более четкими и резкими.
Прицельтесь камерой со стороны короткого края контейнера и отрендерите изображение
(используйте mental ray для экономии времени).

Для того, чтобы убрать артефакты в виде черных точек на краях, установите Quality=2 в
разделе Shading Quality.

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

Не залезая пока камерой внутрь контейнера, откройте раздел Texturing и попробуйте


изменять значение атрибута Texture Origin X.

Флюиды 1193
Облака (а точнее, текстура) при этом сдвигаются параллельно оси X. Однако если вы
будете задавать для этого атрибута целочисленные значения (типа 1, 2, 3...), то увидите, что
картина не меняется (это справедливо только для целых значений атрибута Frequency Ratio). To
есть форма облаков периодически повторяется. Поэтому вместо того, чтобы рендерить огромную
последовательность пролета через облака, достаточно просчитать небольшое количество кадров,
задав в первом и последнем необходимые целочисленные (и разные) значения для атрибута
Texture Origin X. В этом случае первый и последний кадр будут визуально совпадать, а между
ними будут летящие на камеру облака. Анимацию после этого можно зациклить и размножить
средствами монтажа.

Задайте в первом кадре Texture Origin X=1 и поставьте на него ключ.


Затем перейдите в сотый кадр и установите Texture Origin X=0 и снова поставьте ключ.

Установите диапазон анимации [1-99] и убедитесь, что анимация зациклена и повторяется


без рывков. Сохраните файл (cloudFly.ma).

Теперь можете нырнуть камерой в гущу облаков и отрендерить анимацию. Не забудьте,


что общую прозрачность можно подрегулировать атрибутом Transparency в разделе Shading.

В дальнейшем поэкспериментируйте со светом и тенями. В разделе Lighting есть галка


Self Shadow, включающая очень адекватное самозатенение. Правда, скорость рендеринга падает
впечатляюще.
С помощью раздела Color можете настроить цвет облаков, превратив их в грозовой фронт
или страну багровых туч.

И не забудьте про Glow в разделе Shading, это позволит вам дополнительно подсветить картинку.

1194 Книга Сергея Цыпцына


Практические советы по работе с контейнерами
Наиболее пытливые умы и склонные к замысловатым экспериментам юннаты наверняка
уже почувствовали, что флюиды - вещь сложная, капризная и своенравная. Об этом можно судить
хотя бы по количеству атрибутов и способам их настройки. Поэтому приведу некоторое количество
практических советов о том, как сберечь некоторое количество нервов и времени при работе с
флюидами.

Хочу выразить огромную благодарность Диме Бойченко за большое количество полезных


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

Прежде всего, общие советы, не касающиеся рендеринга.

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

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

Если в контейнере происходит быстрое движение, например, быстро перемещающийся


источник или сильное поле скоростей, и распределение плотности начинает «рваться» на
куски, уменьшите Simulation Rate Scale или увеличьте Solver Quality. Напротив, если движение
в контейнере неторопливое и вялое, можете увеличить Simulation Rate Scale, чтобы сэкономить
время, ведь симуляция динамики будет считаться быстрее.

Использование динамики горения и распределения температуры - это уже черный пояс


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

Для настройки текстур иногда удобнее задавать средний размер деталей при помощи Tex­
ture Scale, а не выкручивая Frequency. Масштабирование текстуры в этом случае происходит более
предсказуемо.

Атрибут Implode, особенно анимированный, помогает показать, как часть флюида


стягивается в точку или, наоборот, стремительно взрывается из точки, без применения динамики

Флюиды 1195
и полей.

Внутреннее время текстуры Texture Time - это рабочая лошадка в анимации дымов и
облаков. Всяческое клубление, морфинг, неуловимое ощущение движения задаются анимацией
этого атрибута.

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

Основной убийца памяти и процессора - разрешение контейнера. Старайтесь держать его


настолько низким, насколько сможете. Среднестатистического разрешения 50-70 по осям должно
хватать в большинстве случаев. Если вам не надо летать вокруг и камера смотрит только с одной
стороны, разрешение вдоль одной из осей можно сильно сократить, как в примере с облаками.
Если вам все же понадобятся разрешения больше ста, купите отдельный диск под кэш-файлы.
Размер кэш-файла зависит не только от разрешения, но и от Sampling Rate, то есть от того, с
какой частотой в него записываются данные. Следите за этим. Также на размер влияет, какие
именно каналы записаны в кэш, поэтому не запихивайте в него атрибуты, которые не будете
использовать.

Оптимизация визуализации
Некоторые слабохарактерные умы, наверное, отметили, что рендеринг флюидов - это
занятие для очень взрослых мальчиков и больших компьютеров. Для таких морально неустойчивых
пользователей приведу некоторые способы оптимизации рендеринга.
Пользуйтесь mental ray. Начиная с шестой версии, он умеет рендерить флюиды, причем в 6-10
раз быстрее, чем стандартный рендер. (Правда, пока до тех пор, пока вы не включите просчет
теней.)

То, что качество рендеринга (атрибут Shading Quality) надо стараться не задирать слишком
высоко - это слегка банальный совет, но тем не менее держите себя в руках.
Это же касается «рэйтрэйсинга». Прежде чем включить галку Raytracing, подумайте, можно ли
обойтись без него.

Артефакты, возникающие при низком Shading Quality, можно компенсировать общими


настройками качества рендеринга в Render Globals. Обычно это быстрее, чем высокое Shading
Quality и качество по умолчаниию.

В случае статических текстур можно применять следующий трюк: разрешение контейнера


можно делать как можно меньше, а появившееся артефакты и исчезновение деталей компенсировать
повышением Shading Quality и иногда достаточно сильно: при этом просчет будет идти быстрее,
чем при повышении разрешения и понижении Shading Quality, а результат будет похожий.
Используйте встроенный свет, если это возможно, а не обычные источники (Real Light=Off). Это
незначительно, но ускоряет рендеринг. Хотя реальные источники света сильно ускоряют сам
процесс постановки освещения, так что соблюдайте баланс.

Если можете обойтись без теней (Self Shadow=Off) - обходитесь. Они пожирают время
рендеринга со страшной силой. Если не можете, попробуйте сначала обходиться встроенным
тенями (Self Shadow=On). Если все-таки вы хотите бросать тени от объектов на флюиды, используйте
Depth Map тени для источников света. Raytracing-тени убьют ваш рендеринг.

Если вам необходимо отбрасывать тени или отражения от флюидов на окружающие объекты,
попробуйте просто создать обычный геометрический объект, напоминающий по форме флюид
и отбрасывающий тени и отражения вместо него. Можете, если надо, деформировать его при
помощи BlendShape. Как правило, это все равно будет быстрее, чем честные тени и отражения.
Чем сильнее перепады в плотности, тем больше нужно задирать качество, поэтому, если возможно,
распределяйте плотность равномерно. Избегайте жестких краев и границ внутри контейнера.

1196 Книга Сергея Цыпцына


Аналогично, старайтесь не сильно увеличивать частоту шума (Frequency) в текстурах,
это ведет к появлению множества мелких деталей, нуждающихся в проработке с высоким
качеством.

Никогда не берите в руки текстуру Billow: заторможенные реакции, бессвязная речь,


медленные движения и бесконечное время рендеринга вот лишь малая доля последствий
неосторожного обращения с ней. Используйте обычный Perlin Noise или Wispy с включенной
опцией Inflection для крупных надутых облаков, a Volume Wave - для туманов, дымков или перистых
облаков.

За «проработку» текстур отвечает атрибут Depth Max. Он же норовит съесть толику


времени просчета, поэтому не задирайте его без нужды. В среднем значений 4-8 должно хватать
для облаков и взрывов, 2-4 - для туманов и дымов.
Совсем взрослые мальчики могут использовать Shading Samples Overrides в разделе Render
Stats, чтобы изменить частоту сэмплирования контейнера во время просчета. Значения Shading
Samples и Max Shading Samples, равные единице - хорошее начало для экспериментов по снижению
времени рендеринга.

Флюиды как текстуры


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

При работе с контейнерами у некоторых чувствительных умов может возникнуть ощущение,


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

Интуиция вас не подводит, и действительно, контейнеры с флюидами можно использовать


как текстуры. Следует только понять одну маленькую технологическую, а точнее, идеологическую
особенность.

Дело в том, что идеологически контейнеры (плоские и объемные) подразделяются на два


типа: «нормальные» (с которыми мы имели дело выше и которые создаются обычным образом
через меню Fluid Effects) и «текстурные», которые создаются через меню Create в окне Hypershade
(или любым другим способом, создающим текстуры).

Флюиды 1197
И в том и в другом случае на экране создаются совершенно одинаковые контейнеры, для
которых справедливо все описанное выше. С одним маленьким исключением.
Текстурные контейнеры не рендерятся. То есть не отображаются при просчете. Вместо этого, их
можно назначить как текстуру на любой доступный для этого канал. В этом состоит единственное
различие двух типов контейнеров.

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


плоский контейнер и, глядя на свое шедевральное изображение, хотите назначить его как
текстуру на поверхность, например, только что смоделированного телевизора. Проблема в том,
что обычный контейнер (то есть созданный через меню Fluid Effects) не появляется в списке уже
имеющихся текстур. Поэтому следует просто создать текстуру типа Fluid Texture 2D и скопировать
все атрибуты настроенного контейнера в атрибуты созданной текстуры.

Примечание. Так как контейнер и текстура являются объектами разного


типа (fluidShape и fluidTexure2D), то сделать это через механизм пресетов без
дополнительных усилий не удастся. Однако взрослые мальчики могут применить
военную хитрость: сохраните атрибуты контейнера как новый пресет, то же
самое сделайте и для текстуры. Затем вручную скопируйте файл типа fluidShape1.
mel из папки presets\attrPresets\fluidShape в папку presets\attrPresets\fluidTexture2D.
Кроме того, надо открыть его в текстовом редакторе и исправить строчку:
startAttrPreset( "fluidShape" );
на строчку:
startAttrPreset( "fluidTexture2D" );
После этого его надо сохранить и можно загрузить в атрибуты текстуры как
пресет в Attribute Editor.

Если еще немного расширить сознание, можно заметить, что обычный ЗD-контейнер можно
использовать как объемный материал (Volumetric Material), наравне с материалом Particle Cloud, и
назначать его на частицы типа Cloud.

1198 Книга Сергея Цыпцына


Акватория MAYA
Прежде, чем переходить к океаническим исследованиям, разберем, как устроены водоемы
поменьше. Они фигурируют в меню Fluid Effects под названием Pond, а выбрать подходящий
перевод вы можете себе сами, воспользовавшись, например, словарем Lingvo, который предложит
вам следующие варианты: пруд; водохранилище; водоем; запруда; резервуар; бассейн; земляной
отстойник. Преодолевая соблазн излагать материал на примере отстойника, я буду использовать
непереведенный термин Pond, взыскуя к вашему абстрактному мышлению. Равно как и Ocean,
объекты типа Pond предназначены для симуляции поведения водной поверхности. Такая задача
встречается довольно часто в компьютерной графике, а так как вода, в отличие от динозавров и
далеких планет, попадается на глаза практически каждый день, требования к правдоподобности
стоят довольно высокие.

Сначала я никак не мог понять связь «настоящих» контейнерных флюидов и эффектов


водной глади, по крайней мере логику объединения их в одно меню. Однако со временем
связь обнаружилась, и я с удовольствием расскажу, что такое Pond с точки зрения динамики
жидкости.

Создайте обычный плоский контейнер с источником: Fluid Effects=>Create 2D Container


with Emitter.

Сразу откройте раздел Surface и включите опцию Surface Render.

Проиграйте анимацию, только не обращайте внимания, что картинка неполиткорректная.

Контейнер отображается в виде поверхности, проходящей через точки, имеющие


одинаковые значения плотности, определяемые атрибутом Surface Threshold.
Поднимитесь выше и в разделе Container Properties включите галку Use Height Field. Это задаст
отображение контейнера в виде плоскости, имеющей выпуклые деформации в местах скопления
плотности. Причем общая высота выпуклости определяется размером контейнера вдоль оси Z.
Задайте Size_Z=2, чтобы увеличить толщину контейнера.

Флюиды 1199
Примечание. Утилита Height Field применяется для визуального отображения
черно-белых текстур в виде «вспученной» (displacement) поверхности,
деформированной с помощью текстуры. Эта утилита, подобно другим утилитам
для рендеринга, может быть создана независимо и представляет собой обычную
Nurbs-поверхность, которая, однако, не рендерится, а только отображается на
экране. Атрибут Displacement этой утилиты обычно присоединяется к альфа-
каналу нужной текстуры.

Корректно говоря, места наибольшего «вспучивания» располагаются с областях


максимальной плотности и непрозрачности (opacity). Но поскольку атрибут Opacity по умолчанию
имеет вид графика зависимости от плотности, получается так, что распределение плотности
деформирует саму поверхность. Кстати, включение Use Height Field влияет также и на рендеринг-
представление контейнера. В таком виде удобно симулировать всяческие густые субстанции и
процессы на поверхности вязких жидкостей, типа бурления и перемешивания.

Напомню: динамикой движения управляет Sover (решатель), использующий математическую


модель взаимодействия внутри среды. Однако существуют и другие модели, предназначенные для
расчета движений и взаимодействии на поверхности среды. Используя те же исходные данные
(скорость, плотность и др.), они вычисляют движение, происходящее на границе сплошной
среды.

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


алгоритма вычисления движения и распределения плотности.
Откройте раздел Dynamic Simulation и установите Solver=Spring Mesh.
Грубо говоря, это заставит MAYA трактовать контейнер как сетку из пружин, соединяющих
тяжелые точки с разными значениями плотности. Запустите анимацию, и вы увидите, что теперь,
вместо того, чтобы не торопясь растекаться по пространству, плотность мгновенно разбегается в
виде волн по поверхности.

1200 Книга Сергея Цыпцына


Далее вы можете проэкспериментировать с различными вариантами заполнения
контейнера.

Уменьшите напор источника, нарисуйте плотностью небольшие области с помощью Paint


Fluid Tool или импортируйте из Visor новый Initial State. Все эти варианты будут растекаться по
поверхности в виде волн. Не забудьте также попробовать проанимировать движение источника
вдоль поверхности.

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

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


просто изменив некоторые атрибуты контейнера. Посмотрим теперь, что получится, если создать
Pond «легальным путем».

Визуальные свойства поверхности воды


Откройте новую сцену и выполните Fluid Effects=>Pond=>Create Pond.
Возникнет обычный плоский контейнер.
У него довольно высокое разрешение, а также включена галка Use Height Field и задан
большой размер по оси Z (size_Z=3).
Естественно, для него задан Solver=5pring Mesh и небольшое затухание движения
(Damp=0.02).
И, очевидно, включен Surface Render.
Главные отличия от обычного контейнера по умолчанию находятся в разделе Shading.
Следует понимать, что поверхность, получаемая во время рендеринга, не является реальной
геометрией, а строится процедурно, прямо во время просчета. Поэтому на нее нельзя назначить
обычные материалы с привычными отражающе-преломляющими свойствами. Все визуальные
свойства поверхности задаются атрибутами в разделе Shading и не могут быть определены как-то
еще.

Естественно, что в разделе Environment задана карта отражений в виде градиента по высоте.

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

Флюиды 1201
Opacity выступает теперь как высота возмущений на поверхности. А общая прозрачность
определяется атрибутом Transparency.

Хотя поверхность среды может отражаться в окружающих предметах и преломлениях,


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

Рыбалка на озере
Посмотрим теперь, как можно эффективно анимировать поверхность водоема.
Если вам не хватает эстетического антуража, создайте NURBS-плоскость и помните ее с помощью
Artisan, чтобы сделать некое подобие углубления, соответствующее абстрактному водоему. Грубо
говоря, выкопайте котлован.

Затем создайте рыболовный пруд: Fluid Effects=>Pond=>Create Pond.


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

1202 Книга Сергея Цыпцына


Сохраните файл (fishingStart.ma).
Теперь мы хотим возмутить поверхность, бросив на нее что-нибудь вроде поплавка.
Возмущения поверхности делаются с помощью объекта Wake (переводится как «след за телом в
потоке», не путать с «бодрствованием» или «поминками»...).

Выберите контейнер и выполните Fluid Effects=>Pond=>Create Wake.


Возникнет сферический объект, который при тщательном рассмотрении окажется просто
источником (fluidEmitter), испускающим плотность, разбегающуюся во все стороны.

Дабы он не гнал такую сильную волну, просто понизьте для него интенсивность испускания
(Density/Voxel/Sec=2) и уменьшите его размер (scale=0.5).
А чтобы создать эффект от забрасывания поплавка, просто отключите интенсивность после
десятого кадра, поставив два ключа в десятом и одиннадцатом кадре, чтобы источник перестал
возмущать поверхность.

Чтобы волны разбежались и затухли, можно увеличить атрибут Damp самого контейнера,
но проще сильно задрать атрибут Fluid Dropoff для источника.
Установите Fluid Dropoff=10.

Wake применяют не только для бросания всяких глупостей в воду, но и для создания
следов на поверхности воды от движущихся объектов. Для этого положение источника надо просто
анимировать или прикрепить источник к движущемуся объекту. Не забывайте про Fluid Dropoff, a
в случае создания изысканных эффектов попробуйте испускать немного температуры, которая, по
умолчанию, управляет цветом поверхности и позволяет имитировать появление пены.
Кстати, если вы вооружены передовым знанием о природе объекта типа Pond, можете возмущать
поверхность воды не только с помощью «официального» Wake, но и просто изменяя содержимое
контейнера стандартными методами, например, рисуя в нужных местах фронт волны или
импортируя изображение как возмущение поверхности.

Флюиды 1203
Совет. Если будете рисовать плотностью по поверхности, включите в настройках
Paint Fluid Tool опцию Display=As Render. Получается очень зрелищно: рисовать
прямо во время анимации.

Для взрослых. Вы можете «впрыскивать» плотность в контейнер без всяких


источников. Для этого можно использовать expression и команды работы с
атрибутами контейнера. При помощи этих команд можно напрямую устанавливать
значения атрибутов в каждой точке контейнера. Соответственно, если
организовать изменение плотности в случайных точках контейнера в каждом
кадре, можно получить эффект капель, падающих на поверхность воды. Для
выбранного контейнера (PondShape1) достаточно создать простейший expression:
float $mass=0.05;
int $x=rand(0, PondShapel.resolutionW);
int $y=rand(0, PondShapel.resolutionH);
setFluidAttr -xi $x -yi $y -at density -ad -fv $mass PondShapel;
Описание команды setFluidAttr взрослые мальчики могут прочитать в
документации, замечу лишь, что с ее помощью можно изменять любой атрибут
контейнера в любой точке. Так как приведенные команды будут выполняться в
каждом кадре, то небольшие возмушения на поверхности также будут появляться
в каждом кадре.

Буйки и поплавки
Разобравшись, как возмущать поверхность, рассмотрим обратный вопрос: как сама
поверхность может воздействовать на геометрические объекты. Дело в том, что на поверхности
воды имеет обыкновение плавать всякое безобразие, без которого вода уже не будет столь
правдоподобно выглядеть. Да и без поплавка на рыбалке обойтись трудно.
Для того, чтобы заставить объект плавать по поверхности, надо сначала создать что-то
типа «буйка», плавающего на воде, а затем любым подходящим способом прикрепить к этому
буйку реальный геометрический объект. Буйки бывают разных типов, в зависимости от сложности
поведения их на воде. Эти типы перечислены в меню Fluid Effects=>Pond и создаются для выбранного
контейнера.

Самый простой буек - это локатор (Surface Locator), который просто передвигается только
по вертикали, повторяя движение водной глади.

Динамический локатор (Dynamic Locator) дополнительно умеет притапливаться и всплывать,


имея для управления этим процессом дополнительные атрибуты.

Лодочный локатор (Boat Locator), кроме вышеперечисленного, может покачиваться на


воде, поворачиваясь вокруг соответствующих осей.

Для удобства создания плавающих объектов, можно сразу выбрать геометрический объект
и выполнить одну из операций: Float Selected Object, Make Boats, Make Motor Boats. Это создаст
буек-локатор соответствующего типа и привяжет выбранный объект к этому локатору.
Для создания поплавка, который не только притапливается, но и имеет свойство
наклоняться, лучше всего подходит Boat Locator.

Выберите контейнер и выполните меню Fluid Effects=>Pond=>Add Boat Locator.


В начале координат появится локатор, покачивающийся на волнах.

1204 Книга Сергея Цыпцына


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

Рыбалка на море

Перейдем теперь к более широким водным просторам. Понятно, что для отображения
и анимации больших водных пространств нужны некоторые трюки. В случае с океаном (Ocean)
трюк очень прост. Для симуляции огромной водной глади создается простая поверхность (NURBS-
плоскость) и на нее назначается хитрым образом написанный материал. Анимация водной глади
осуществляется за счет displacement, то есть деформации геометрии на этапе рендеринга
с помощью текстуры. Текстура, как и следует ожидать, не простая, а специальным образом
«заточенная» под создание волн и всяческих возмущений водной поверхности.

Немного поэкспериментируем, чтобы узнать, как устроен океан.

Внутреннее устройство океана


Выполните в новой сцене: Fluid Effects=>Ocean=>Create Ocean с параметрами по
умолчанию. Возникнет некая поверхность, на которую, как следует из Attribute Editor, назначен
спецматериал.

Поверхность представляет собой плоский NURBS-объект, и если вы хотите понять получше


его топологию, просто включите отбражение контрольных вершин и подергайте за них. А лучше:

Флюиды 1205
назначьте на эту поверхность обычный материал типа Lambert с текстурой checker на канале
цвета.

Правда, для того, чтобы увидеть отображение текстуры на поверхности, вам придется
выключить галку Enable Overrides в разделе Drawing Overrides для ноды oceanPlaneShape1. Так как
материал для океана довольно сложный, отображение его на экране будет, во-первых, небыстрым,
а во-вторых, неадекватным, то есть неточным. Поэтому по умолчанию для поверхности океана
выключено отображение текстур.

Зачем нужна такая «каракатица»? Дело в том, что при взгляде на водную поверхность важна
проработка деталей только областей близких к камере, регионы же удаленные от наблюдателя
могут быть представлены весьма условно. Поэтому поверхность для симуляции океана имеет
более плотное расположение изопарм ближе к центру. Области ближе к краям поверхности
будут вероятнее всего отображать происходящее на горизонте и, следовательно, могут быть
представлены более грубо.

Поэтому при работе с океаном старайтесь сделать так, чтобы камера, как правило, смотрела
в район центра поверхности. Более того, специально для такого принудительного взгляда в центр
при создании океана предусмотрена галка Attach to Camera в Option Box операции Create Ocean.
Если она включена, то автоматически создается очень простой expression, перемещающий
поверхность океана по горизонтали так, чтобы она всегда была расположена своим центром
перед камерой. Дополнительно этот expression растягивает/сжимает поверхность в зависимости
от высоты камеры по вертикали, это помогает задавать оптимальный размер поверхности по
отношению в визуальному разрешению.

Цитирую:

oceanPlane1.translateX = persp.translateX;
oceanPlane1.translateZ = persp.translateZ;
float $scale = abs(150.0 * persp.translateY) + 10.0;
oceanPlane1.scaleX = $scale;
oceanPlane1.scaleY = $scale;
oceanPlane1.scaleZ = $scale;

Естественно, вы может отредактировать такой expression или создать свой (или даже не
использовать его вовсе), но просто помните о том, что надо целиться в центр океана.

Интерактивная визуализация морской поверхности


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

1206 Книга Сергея Цыпцына


от отстойников, пардон, от объектов типа Pond, океан не есть ни контейнер, ни мягкое тело, ни
вообще объект динамики. Поэтому для визуализации анимированной поверхности применяется
утилита Height Field, о которой уже шла речь выше.

Выберите ваш океан и выполните Fluid Effects=>Ocean=>Add Preview Plane.

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


этот кусочек тряпочки в реальном времени отображает деформацию большой поверхности и,
следовательно, служит визуальным и интерактивным представлением движения океанских волн.
Тряпочка - это стандартная утилита Height Field, автоматически созданная и присоединенная к
соответствующим атрибутам материала oceanShader.

Примечание. Напомню, что утилита Height Field применяется для визуального


отображения черно-белых текстур в виде «вспученной» (displacement) поверхности,
деформированной с помощью текстуры. С моей точки зрения, название Height
Field весьма неудачное, так как путается с динамическими полями или, хуже
того, с телевизионными полуполями. Displacement или Height Preview Plane было
бы удачнее. Поэтому до конца главы я ограничусь скромной «тряпочкой».
Тряпочку можно перемещать по горизонтали, чтобы контролировать поведение
поверхности в различных участках океана. Ее можно также растянуть до нужного
размера, а чтобы она сохраняла необходимую гибкость, можно увеличивать
атрибут Resolution, задающий разбиение ее сетки. При значениях Resolution более
сотни, анимация становится неинтерактивной, поэтому сохраняйте чувство
меры.

Атрибут Height Scale определяет, насколько тряпочка дополнительно растягивается по


вертикали по сравнению с реальным размером волн.

Кстати, включив галку Create Preview Plane в Option Box операции Create Ocean, можно
автоматически создавать Preview Plane для вновь созданного океана.

Флюиды 1207
Динамическая анимация морской поверхности
Буйки, локаторы и прочий водоплавающий мусор создается и анимируется для океана точно
так же, как для объектов типа Pond. Поэтому пункты меню для работы с этими плавсредствами для
Ocean и Pond идентичны.

А вот про реализацию Wake можно поговорить подробнее.

Выберите ваш океан и выполните Fluid Effects=>Ocean=>Create Wake.

Возникнет типичный контейнер, вместе со сферическим источником посередине. Если


анимировать положение источника, на Preview Plane можно увидеть явственный бурун. Вы можете
прицепить источник к любому плавсредству и создавать следы за движущимися объектами.

Идея порождения бурунов в случае океана довольно остроумна.

Если для водоемов поверхность контейнера реально деформировалась в ходе динамической


симуляции и впрыскивания плотности, то в данном случае созданный контейнер представляет собой
текстуру (fluidTexture3D), которая дает дополнительную displacement-деформацию поверхности
океана. Эта текстура анимируется как обычный контейнер, использующий Solver=Spring Mesh, с
источником, который «впрыскивает» плотность и порождает волны, аналогичные рассмотренным в
разделе для Pond. Эти волны передаются на поверхность океана как displacement-текстура. Более
того, если при создании Wake указать порождение пены (Foam Emission), создается еще один
дополнительный контейнер, в который испускается температура, для того чтобы более нагретые
участки текстуры-контейнера давали светлые области на финальной картинке.

Звучит, конечно, несколько угрожающе, однако вы должны понимать, что Wake - это
динамический объект, и для просчета струи или буруна требуется вычисление динамики, так
как используется испускание плотности из источника. За пределами контейнера, естественно,
никаких бурунов не будет, поэтому задавайте размер и положение контейнера относительно
океана заранее.

Те, кто уследил за идеей анимации возмущений поверхности океана с помощью контейнеров,
могут выбрать такой Wake-контейнер и включить у него в разделе Display режим Shaded Display=As
Render, чтобы увидеть, как по текстуре расходятся черно-белые круги из плотности.

1208 Книга Сергея Цыпцына


Зная, как деформация передается от контейнера на поверхность океана, вы можете
анимировать контейнер не только с помощью Wake-источников, но и с помощью всех известных
средств для работы с флюидами.

Для взрослых. Замечу, что хотя текстура выглядит как плоский контейнер, однако реально
это все-таки 3D-контейнер, у которого включили секретный атрибут is2D. Для флюидов-текстур
это имеет значение, так как трехмерная текстура (fluidTexture3D) будет проектироваться на
поверхность, а не «обтягивать» ее, как в случае 2D-текстуры.

Визуализация акватории
Для предварительной настройки визуализации морской поверхности удобно использовать,
во-первых, Preview Plane, а во-вторых, IPR Render. Этот процесс подкупает своей новизной: надо
просто подобрать параметры материала oceanShader, а затем удовлетворенно поставить анимацию
на просчет. Нет смысла перечислять названия и назначения многочисленных атрибутов материала,
они достаточно адекватны. А метод тыка и пристального взгляда на пробный рендер вполне
оправдывает себя в данном случае. Ограничусь лишь некоторыми комментариями.

Флюиды 1209
Общий масштаб (атрибут Scale) действует наоборот: чем больше значение, тем больше
реальных физических метров приходится на клетку экранной сетки и тем больше изображение
мельчает.

Для того, чтобы неистово летать над океаном, не надо крутить и размахивать камерой.
Задайте или даже анимируйте атрибут Observer Speed (скорость наблюдателя), чтобы создать
иллюзию движения над водой. Помните, что не стоит реально улетать камерой от центра
поверхности, симулирующей океан.

Количество волн с промежуточными частотами/длинами (Num Frequencies), конечно,


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

Все графики для атрибутов Wave Height/Turbulence/Peaking представляют собой изменение


высоты от волн с минимальной длиной к максимальным волнам.

Wave Peaking характеризует остроту угла между волнами при их столкновении. Можно
назвать его «плескучесть». Имеет смысл, только если Wave Turbulence не равен нулю.
Foam Threshold определяет высоту волну, на которой начинает образовываться пена. Светлые
участки текстуры, симулирующие пену, можно использовать для всяких дополнительных трюков с
испусканием частиц с поверхности океана.

Поверхность, симулирующая океан, при рендеринге разбирается на полигоны, то


есть подвергается процессу теселляции (tessellation). Если разбиение окажется недостаточно
подробным для ваших задач, его всегда можно изменить в Attribute Editor в разделе Tesselation.
Атрибут Bump Blur может быть удачно использован для размывания поверхности у линии
горизонта, то есть на удаленных от камеры участках. Для того следует создать утилиту samplerlnfo
и задать адекватную связь между атрибутом cameraPointZ и атрибутом Bump Blur.
Последний комментарий следующий: mental ray считает водную поверхность в разы
быстрее. Делайте выводы.

Основной прием при работе с морской поверхностью


Все вышеизложенное относительно океана следует использовать с одной-единственной
целью. Если вам нужен «море-океан» определенного типа, выполните команду Fluid Effects=>Get
Ocean/Pond Example и выберите наиболее подходящие погодные условия. Перетащите их в новую
сцену средней кнопкой мыши и внимательно исследуйте, применяя не только метод тыка, но
и сведения, описанные выше. И хотя примеры не столь многочисленны, как хотелось бы, тем
не менее для изучения и понимания морских эффектов они дают более чем исчерпывающую
информацию.

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

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

История насыщенного контейнера


В прошлой жизни мне довелось работать в Венгрии на строительстве вполне гражданского
объекта - почты. Только что закончив университет и получив диплом, я уехал в международный
стройотряд - так тогда называлось совмещение приятного путешествия за границу с полезным
зарабатыванием денег. Рабочая венгерская неделя имела свои плюсы и минусы. Главный минус
был в том, что рабочий день начинался в семь утра. Везде. Поэтому чтобы успеть на строительство

1210 Книга Сергея Цыпцына


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

В один из выходных наши венгерские товарищи организовали экскурсию в долину


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

Мы довольно быстро промчались сто двадцать километров в аутентичном Икарусе и


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

И тут наши венгерские друзья совершили роковую ошибку. В соответствии с


демократическими принципами постперестроечного периода, всем желающим на обзор
окрестностей и знакомство с достопримечательностями выделили два часа, по истечении которых
следовало благоразумно сесть в автобус и отправиться обратно. Я, человек пытливого ума и
притом малопьющий, отправился исследовать долинный рельеф в компании очаровательной
девушки-переводчицы, а мои друзья как-то незаметно подотстали еще в самом начале. Зайдя
из любопытства в один из погребков, я был молниеносно угощен чем-то типа светлого муската,
изумительного на вкус и цвет. Причем действие его было не менее изумительным: при полной
ясности в голове, мои ноги неожиданно потеряли всяческую устойчивость и стали напоминать по
свойствам свободно катящиеся колеса - в горку идти не было никакой возможности, а вот с горы я
катился с нарастающей скоростью, с удивлением наблюдая за собственными траекториями. И без
того обаятельная спутница превратилась просто в богиню и победительницу межгалактического
конкурса красоты. А жизнь приобрела вкус муската. И это с одного бокала солнечного нектара.
Благо обратный путь ветвился строго под горку и требовалось только отдаться легкому течению
жизни.

Однако задолго до выхода к месту сбора, я уловил над виноградными ландшафтами


знакомую песню. «Задремал под ольхой есаул молоденький» - упруго пульсировало над стоянкой
автобусов и прилегающими территориями. Мои друзья не стали утруждать себя походом по горным
дорогам, а позволили себя угостить в первой же таверне. И не один раз. Венгерские товарищи
поначалу удивленно разгуливали рядом, но когда пришло время отъезжать, на их лицах заиграли
блики растерянности: друзья мои, очевидно, потеряли не только ощущение пространства, но и
чувство времени. Изъять их из объятий дружбы между народами и взаимных угощений оказалось
непросто. Поэтому веселая, бурлящая, поющая человеческая масса перетекла в автобус только
часа через три после наивно запланированного времени. А вот дальше началось самое веселое.
Тогда я был еще бесконечно далек от компьютерной графики и описывал происходящее
в других терминах, однако уже теперь, основательно разобравшись с динамикой флюидов и
сплошной среды, я понял, что это идеальная аналогия, чтобы описать удивительное двухчасовое
путешествие.

Большой и стремительный Икарус напоминал прямоугольный трехмерный контейнер. В


качестве плотности там выступали веселые студенты. Студенты имели постоянно меняющуюся и
явно ненулевую скорость перемещения, жизнь в автобусе кипела так, что, казалось, он с трудом
сохраняет равновесие даже на прямых участках дороги. Следовательно, температура в салоне
тоже не падала ниже определенной отметки. Время от времени откуда-то появлялись новые
запасы fuel, то есть топлива, благоразумно (хотя, скорее, совсем неблагоразумно) прихваченного
веселыми студентами с места дегустации нектара богов. Я никогда не видел, чтобы люди могли
так перемещаться в замкнутом помещении - они были везде - на полу, на потолке, между кресел,
в разных позах, под разными углами к горизонту - и при этом постоянно перемещались. Они пели
песни, играли на гитарах, они рассказывали анекдоты, они спорили и много чего еще делали,

Флюиды 1211
причем одновременно и все сразу. В роли объектов для столкновений с живой массой иногда
проплывали гитары или рюкзаки, но это не вызывало нарушений в общем движении внутри
контейнера. Они попирали все законы физики и являли собой образец броуновского движения
отнюдь не на молекулярном уровне.

Наши венгерские друзья, заняв наиболее безопасные места с наименьшей турбулентностью


в начале салона, удивленно, нет, потрясенно смотрели на эту абсолютно счастливую сплошную
среду.

Иногда сплошной среде становилось нехорошо, тогда автобус останавливался и наименее


стойкие элементы выпадали в придорожную траву. Впрочем через пару минут контейнер снова
принимал свое начальное положение (Initial State) и все начиналось сначала. Пару раз очутившись
в зонах особенно высокой турбулентности и температуры, я прочувствовал атмосферу абсолютного
неуправляемого и беззаботного веселья. В хаосе бурлящей, веселой, перетекающей из угла в угол
сплошной среды царила атмосфера праздника жизни - песни были веселы, вино неиссякаемо, а
женщины неимоверно красивы.

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

Кстати, такой эффект возникновения хаотических движений в ограниченном контейнере,


мне удавалось наблюдать еще пару раз в жизни. Например, когда мы вынуждены были в течение
пяти часов пробираться на маленьком автобусе сквозь снежные заносы, чтобы проникнуть на
болгарский горнолыжный курорт, в салоне оказалась половина склада из магазина duty free, и
я опять наблюдал нарушение законов природы и перемешивание людей, лыж, палок и ботинок в
прямоугольном пространстве контейнера-автобуса.

Подозреваю, что среди скрытых атрибутов объектов типа ftuidShape следует поискать
атрибуты, отвечающие за содержание алкоголя в контейнере и напрямую управляющие скоростью
и турбулентностью среды.

1212 Книга Сергея Цыпцына


Меховая глава
Как ни странно, модуль MAYA Fur попадает у нас в раздел динамики. (А вы-то думали: в
рендеринг?) По крайней мере, в документации он позиционируется именно так, и в разделе Dy­
namics and Effects стоит в конце списка, причем перед модулем AAAYA Live (!). Я же намеренно
поместил его в главу с динамикой, ибо перед тем, как рассказывать про полноценную динамику
движения волос, есть большой соблазн рассказать сначала по мех, чтобы описать общие для
всякой органической растительности понятия и подготовить хорошую почву для следующей главы.
И хотя формально некая динамическая симуляция движения меха может быть реализована,
однако с моей точки зрения - это лишь повод немного удивиться и перейти к динамике волос.
Кроме того, основные понятия и принципы создания растительности для меха и для волос очень
похожи, поэтому если вам все-таки не терпится потаскать вашу модель за волосы, хотя бы мельком
просмотрите эту главу, по крайней мере, первую ее треть.

Меховые применения MAYA Fur и отличия от MAYA Hair


Я буду использовать термин «мех» как перевод слова «fur», прежде всего потому, что
его удобно набирать на клавиатуре. Хотя применения MAYA Fur не ограничиваются пушной
промышленностью и пошивом шуб. С помощью этой технологии также отлично симулируются
всяческая шерсть и подшерсток для разных джульбарсов; в эту же категорию попадают щетина,
ворс и даже трава на газоне. Поскольку довольно значительная часть окружающего живого мира,
как правило, покрыта какой-нибудь растительностью, область применения MAYA Fur довольно
широка. Ее расширяет также отличное свойство меха скрывать ошибки и «косяки», допущенные
при моделировании персонажей.

Основное свойство всех меховых эффектов - это небольшая длина/высота покрова и


довольно сильная плотность. До появления MAYA Hair пользователям приходилось применять всякие
трюки и ужимки, чтобы симулировать растительность значительной длины, имеющую собственную
динамику и склонность к групповому поведению. MAYA Fur плохо подходит для создания длинных
причесок или пушистых хвостов, так как для данной технологии основное движение мехового
покрова всего лишь наследуется от деформаций поверхности, на которой мех произрастает.
Собственные деформации и симуляция тяжелого длинного меха, свисающего и гнущегося под
действием силы тяжести - это не та задача, которую стоит решать с помощью MAYA Fur.

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

Прежде чем садиться за рекламу меховых изделий, оформите свои отношения с


защитниками окружающей среды. Помните их любимый лозунг: «Нужно сорок глупых животных,
чтобы сделать шубу. И только одно, чтобы носить ее.».

К сожалению, в отличие от MAYA Hair, модуль MAYA Fur не был написан с нуля специально
для MAYA, а был приобретен компанией как технология и встроен в MAYA как плагин. Поэтому
способ работы с ним немного (действительно немного) отличается от общей идеологии работы в
MAYA. На внешнем уровне это заметно по структуре меню и отсутствию Option Box, а на внутреннем
определяется как чисто субъективное ощущение.

Для успешной работы с мехом должен быть загружен плагин Fur.mll. Если вы не видите
меню Fur рядом с Paint Effects в режиме Rendering, идите в Windows=>Setting/Preferences=>Plugin
Manager и включите там нужные галки.

Анимация 1215
Устройство MAYA Fur
Как правило, работа с мехом разбивается на несколько этапов. Это прежде всего
подготовка поверхности к созданию на ней меха. Затем идет назначение нового мехового покрова
на подготовленную поверхность и настройка его многочисленных атрибутов. Если деформации
поверхности недостаточно для анимации меха, задается анимация описывающих его атрибутов.
Далее настраиваются параметры визуализации и происходит непосредственный рендеринг.
Забегая вперед, скажу, что для визуализации меха используется специальный рендерер (fur-
Render), который позволяет просчитывать очень насыщенные и плотные меховые покровы.
А то, что вы видите на экране - лишь схематическое представление процедурного описания
меховой растительности, по аналогии с приблизительным отображением процедурных текстур
в окне камеры. Внутри сцены хранится лишь описание меха (Fur Description, то есть значения
соответствующих атрибутов), но никак не набор многочисленных ворсинок. Сам «настоящий» мех
генерируется только на этапе рендеринга.

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

Меховой вывод: мех - это большая процедурная текстура


Подобно текстуре, мех назначается на поверхность или даже сразу на множество
поверхностей. Он также может быть назначен не только на полигоны и NURBS-поверхности, но и
на сабдивы. Назначение нового меха на выбранные объекты производится через меню Fur=>Attach
Fur Description=>New.

Мех назначается на весь объект целиком: к сожалению, нельзя выбрать отдельные грани и
назначить мех только на них. Ненужные участки просто выстригаются позже с помощью инструмента
Paint Fur Attributes Tool, о котором речь пойдет ниже. Альтернативный способ заключается в
удалении UV-координат с тех граней, где меха быть не должно.

Подобно текстуре, меховой покров можно поворачивать на поверхности. Это делается в


тех случаях, когда мех назначен на несколько поверхностей с разным направлением UV, и для
отдельных поверхностей хочется развернуть направления наклона меха. Это больше относится
к NURBS-поверхностям и мультипатчевым моделям и делается через пункт меню Fur=>Offset Fur
Direction by.

Аналогично, чтобы не редактировать нормали самой модели, можно «вывернуть» мех


наизнанку для любой выбранной поверхности при помощи операции Fur=>Reverse Fur Normals.
Помните, что выбирать надо не мех, а саму поверхность.

Так же, как текстуру, мех (а точнее говоря - его описание FurDescription) можно «отдирать»
от поверхностей, переназначать на новые поверхности, удалять или просто дублировать. Все это

1216 Книга Сергея Цыпцына


делается через меню Fur=>Fur Description (more).

На одну поверхность может быть назначено несколько меховых покровов, подобно


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

Создайте полигональный куб (да-да, куб, а не фотореалистичную голову) и назначьте на


него новый мех: Fur=>Attach Fur Description=>New.

Основные атрибуты, определяющие свойства меха, принадлежат всего двум нодам. Это,
как и в случае с Pain Effects или Fluid Effects, сильно упрощает задачу изучения новой технологии,
так как для эффективных экспериментов с мехом нужно начать работать с ограниченным набором
атрибутов и в Attribute Editor, методом тыка, установить их предназначение.

Первая нода (FurFeedback) совсем небольшая, и отвечает только за то, как мех схематически
представлен на экране. Галка Color Feedback Enabled теперь по умолчанию включена, а параметр
Fur Accuracy также по умолчанию равен единице. Это означает, что на экране будет адекватно
отображаться цвет меха, а гибкость «экранных» ворсинок будет примерно соответствовать
реальным ворсинкам на рендере. Атрибуты U/V Samples определяют только количество или
плотность экранного представления меха, и никак не влияют на плотность реального меха при
рендеринге. Это чисто экранное свойство, предназначенное для визуального контроля формы и
цвета меха, но никак не плотности.
А все свойства «реального» меха определяются в закладке для ноды FurDescription.
Она является носителем практически всех свойств меха и вся работа по настройке меховых
особенностей производится в Attribute Editor для этой ноды.

Совет. Некоторые экстремалы, конечно, столь беззаветно любят Channel Box, что
редактируют атрибуты меха там. Однако в случае таких «богатых» атрибутами
объектов, как мех, кисти Paint Effect, флюидные контейнеры или частицы, удобно
работать именно с Attribute Editor, причем открывая его справа, в виде панели, а
не в отдельном окне.

Прежде чем перейти к обсуждению некоторых свойств и атрибутов, я расскажу, почему


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

Подготовка модели к покрытию мехом


Продолжим проводить аналогии с текстурой. Чтобы мех лег на поверхность, на ней должны
быть хоть какие-то UV-координаты. Для NURBS-поверхностей этот вопрос решен изначально и
не представляет проблемы, а вот для полигонов и сабдивов необходимым условием успешного
наложения меха является наличие UV-координат с двумя свойствами: они не должны быть

Меховая глава 1217


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

Стоит только выполнить команду Edit Polygons=>Texture=>Unitize UVs (то есть загнать UV в
единичный диапазон), и мех мгновенно становится на место.

Комментарий. В некоторых случаях вы можете специально выводить UV-


координаты на пределы указанного диапазона, чтобы удалить мех с участков
поверхности, соответствующих этим координатам.

ЕСЛИ ВЫ работаете с полигональными моделями, прежде чем накладывать мех, надо


тщательно проверить модель на наличие неперекрывающихся текстурных координат. Дело в
том, что при назначении меха MAYA не будет ругаться или анализировать UV-маппинг, а просто
положит мех как текстуру, но в процессе редактирования и, тем более, рисования свойствами
меха по поверхности могут вылезти разнообразные артефакты, связанные с перекрывающимися
текстурными координатами. Самый частый их них - проведение многочисленных штрихов в разных
местах при одном движении кистью.

1218 Книга Сергея Цыпцына


Текстурные координаты для меха не обязаны быть «хорошими» с точки зрения обычного
текстурирования. Они всего лишь не должны перекрываться. Автоматический маппинг (Edit
Polygons=>Texture=>Automatic Mapping) во многих случаях дает приемлемые UV-координаты для
наложения меха.

К счастью, мех научился корректно работать с UV-сетами (правда, только для полигонов,
но не для сабдивов). Поэтому можно отдельно создать отдельный UV-set специально для меха, а
затем присоединить к нему существующий мех.

Это делается с помощью редактора отношений врежиме


Fur / UVLinking: Windows=>Relationships => Editors=>Sets.

При работе с полигонами иногда полезно бывает приготовить специальные «плашки» для
покрытия мехом. Эти «плашки» изготавливаются как скопированные с оригинальной поверхности
нужные грани. Сделать это можно операцией Edit Polygons=>Duplicate Faces. Благодаря Construc­
tion History эти плашки будут повторять форму оригинальной поверхности, а сделать для них
необходимый для меха UV-маппинг довольно просто, например, с помощью Planar Mapping.

Причесывание и редактирование меховых свойств


Для дальнейшего изучения меховых свойств займемся реальным парикмахерским делом.
И хотя я уже указывал, что мех не всегда подходит для имитации волос (особенно длинных), в
некоторых случаях он может быть использован эффективнее, чем технология MAYA Hair, особенно
на этапе рендеринга. Все нижеописанное легко переносится на случай меховых зверушек, игрушек
и других мохнатых монстров.

Откройте файл headModel.ma (или любой другой, содержащий вашу любимую модель
джульбарса или другого кандидата на омеховление).

Меховая глава 1219


Выберите поверхность и покройте ее мехом. Fur=>Attach Fur Description=>New.
Абсолютно вся модель покроется мехом.

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

Чтобы мех не выглядел столь куцым, выберите его прямо на экране и задайте в Attribute
Editor для ноды FurFeedback значения U/V samples, адекватные производительности вашей
графической карты, например, 128.

Напомню, что указанные значения определяют лишь «экранную» плотность отображения


меха, но никак не реальную насыщенность мехового покрова.
Перейдите в Attribute Editor, в закладку Fur Description, и перед вами откроются
многочисленные атрибуты меха.

Атрибут Density (плотность) нам пригодится только на этапе рендеринга, а значение Glo­
bal Scale также может быть использовано позже для равномерного увеличения или уменьшения
всех свойств меха, так чтобы общая визуальное восприятие меха просто масштабировалось с
сохранением формы и пропорций.

Задайте значение атрибута Length, определяющего длину меха равным 3.

1220 Книга Сергея Цыпцына


Поиграйте с атрибутом Baldness. Перевод его названия как «плешивость» довольно точно
характеризует его действие, правда, шиворот-навыворот. Когда «плешивость» равна единице, мех
всюду плотно покрывает поверхность, а когда «плешивость» стремится к нулю, мех стремительно
редеет. Оставьте этот атрибут равным единице, сейчас мы используем его для молниеносного
бритья модели с помощью Paint Fur Attributes Tool.

Рисование меховыми атрибутами

Идея этого инструмента очень проста и напоминает способ работы с обычными текстурами
при помощи инструмента 3D Paint Tool. Сначала выбирается поверхность, затем канал/свойство и
производится раскрашивание поверхности этим свойством.

Сохраните вашу сцену (headM.odelFurStart.ma).

Совет. Всегда стоит предварительно сохранять сцену при использовании любого


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

Выберите поверхность, а затем возьмите в руки инструмент Fur=> Paint Fur Attributes Tool.
Наряду с обычными настройками инструмента, проявится также небольшое окошко Paint
Fur Attributes Tool Settings, в котором можно выбирать атрибуты меха для рисования ими по
поверхности.

Комментарий. Помните, что перед рисованием надо выбирать поверхность, а


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

Выберите атрибут Baldness, а в окне Tool Settings задайте Value=0, чтобы рисовать нулевым
значением атрибута. Попробуйте немного побрить персонажа, расширяя области плешивости.

Меховая глава 1221


Однако проще залить всю поверхность нулевым значение Baldness, а затем вырастить мех
только там, где надо.

Нажмите кнопку Flood, и поверхность моментально облысеет.

Затем установите Value=1 и покрасьте либо только верхнюю часть головы (имитируя
прическу), либо всю голову, за исключением лица (моделируя вожака бандерлогов), создавая мех
в нужных местах.

Активно меняйте радиус кисти. А также возьмите третий слева профиль кисти, полностью
заполненный круг, он лучше подходит для рисования четких границ. Подбривайте мех там, где
надо, с помощью Value=0, периодически сохраняя сцену.

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

Выберите вместо Baldness атрибут Length.

Однако после этого весь мех моментально укоротится до длины, равной единице! Ведь
рисовать мы можем только значениями атрибутов от нуля до единицы. Как быть?
Ответ скрывается в Attribute Editor и в том, как MAYA сохраняет значения отрисованных
атрибутов.

Выберите мех и откройте Attribute Editor.

1222 Книга Сергея Цыпцына


Попробуйте пошевелить атрибут Baldness.

Безрезультатно. Точнее, безответно. И это понятно: ведь теперь распределение атрибута


Baldness управляется не одним слайдером, а более сложным образом.

Чтобы понять, каким, спуститесь ниже, в Attribute Editor, и откройте раздел Details.
Там разыщите раздел Baldness и в нем откройте подраздел Maps.

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


Paint Fur Attributes Tool, была создана черно-белая карта, задающая распределение атрибута Bald­
ness по поверхности. Эта карта сохраняется по умолчанию в папке furAttrMap текущего проекта и
может быть без проблем просмотрена, если необходимо - отредактирована, и опять сохранена.

Чтобы избавиться от этой карты и снова перейти к общему управлению атрибутом через
один слайдер, следует просто нажать кнопку Remove Item.
Разрешение карты задавалось при выборе атрибута для рисования в окошке Paint Fur Attributes
Tool Settings и по умолчанию равно 256x256. Соответственно, карта создается только после
использования инструмента Paint Fur Attributes Tool.

Меховая глава 1223


Совет. Часто бывает полезно покрасить поверхность непосредственно под мехом
приблизительно в тот же цвет, что и цвет меха, чтобы не было видно просветов
и проплешин, и чтобы не приходилось дополнительно задирать значение общей
плотности меха. Для этого можно воспользоваться картой распределения
атрибута Baldness как «болванкой» для текстурирования меховой части головы.

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


Hair - это абсолютно процедурный объект. То есть он хранится в сцене просто как
набор значений атрибутов, описывающих свойства меха и карт распределения этих
атрибутов по поверхности. В отличие от волос, которые суть реальные объекты
сцены, мех появляется в виде реальных ворсинок только на этапе рендеринга.

Сразу над разделом Maps есть некоторое количество атрибутов, изменяющих стандартное
применение карты атрибутов. Это прежде всего Map Multiplier, позволяющий умножить значения
черно-белой карты в диапазоне от нуля до единицы на любое число, чтобы можно было адекватно
рисовать атрибутами (например, длиной), имеющими диапазон изменения превосходящий
единичный отрезок.

Теперь понятно, как быть с длиной волос.

Выберите в разделе Details подраздел Length и установите Map Multiplier=3.


Теперь снова выбирайте поверхность и используйте Paint Fur Attributes Tool.
На этот раз при выборе атрибута Length для рисования мех не меняет свою длину, так все
изменения, производимые кистью, автоматически помножаются на 3.

Задайте небольшое значение Value и подстригите, например, щёки, виски или другие
области - по вашему усмотрению. Активно меняйте Value для различных участков. «Снять» немного
длины поможет операция Scale со значением около 0.9. Добавлять - операция Add и значение 0.1.
Не беда, что стрижка получается ступенчатой, как у студента парикмахерского университета.
В конце работы крайне рекомендуется выбрать операцию Smooth и залить (Flood) всю
поверхность этой операцией, причем неоднократно. Это сгладит все ступеньки и разгладит
распределение длины меха вдоль всей поверхности.

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

Аналогично выполняются действия по покраске меха любыми другими свойствами,


достаточно выбрать нужный атрибут и значение Value для него.

1224 Книга Сергея Цыпцына


Совет. После прорисовки карт на экране, стоит взглянуть на них в каком-нибудь
редакторе растровых изображений. Дело в том, что в результате «покраски» на
экране они получаются слегка «дырявыми». Особенно это касается карт для Bald­
ness, ведь для этого атрибута хочется иметь четкие и контрастные черно-белые
карты. Быстро сделать это можно не выходя из MAYA, достаточно нажать клавишу
8 и попасть в режим плоского рисования модуля Paint Effects. Далее достаточно
выбрать в меню этой панели Canvas=>Open Image и загрузить нужную карту. При
помощи черно-белых кистей можно быстро закрасить ненужные дырки в картах.
Хотя аккуратная настройка карт в хорошем разрешении пойдёт быстрее в более
взрослых инструментах, типа «Фотошопа»..

Вы должны также понимать, что размытые края у карты Baldness ведут к «прорежению» меха
на границах, а это, в свою очередь, дает не очень красивый эффект просвечивания. Поэтому всегда
довольно затруднительно получить четкую границу меха, для этого приходится использовать карты
довольно больших разрешений (2048x2048), содержащие всего два цвета. В отличие от текстур,
все методы сглаживания или фильтрации карт ведут, как только что было сказано, к уменьшению
плотности меха на границах и эффекту просвечивания. Благо четкая граница мехового покрова
нечасто встречается в природе, да еще и на крупных планах. Но при работе с картами атрибутов
для меха вы должны понимать, как конкретная черно-белая карта управляет соответствующим
атрибутом. В данном примере я использовал для Baldness карту (2048x2048), которая сохранена в
файле headModelFurStart_Original_Head5hape_FurDescription1_Baldness.iff.

Если вам стало совсем лень красить всю голову или просто ничего не получилось, откройте
файл headModelFurStart.ma. Перед этим вам также необходимо скопировать папку furAttrMap с
диска в папку, содержащую ваш текущий проект, так как карты распределения плотности и длины
лежат именно там.

А сейчас те, кому уже невтерпеж, могут нажать кнопку Render. И получить довольно
плешивую модель в стиле «восставших из ада».

Меховая глава 1225


Настройка формы и внешнего вида меха
По умолчанию реальная плотность меха весьма невысока.
Откройте Attribute Editor для меха и установите значение атрибута Density= 10000.
Просчитайте картинку.

Это даст более плотную картину, но, тем не менее, и этого недостаточно, чтобы получить
плотный мех.

Задайте Density=50000. Это будет стартовая позиция для настройки и отладки остальных
параметров. На финальном просчете можно будет увеличить плотность еще в несколько раз.

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

Подергайте за Inclination (наклон).

Мех начнет наклоняться к поверхности.

Чтобы его хаотично наклонить по всей площади, установите Inclination=0, а затем зайдите
в раздел Details и в подразделе Inclination задайте Noise Amplitude=0.2.
Это немного растреплет мех, правда, в только одном направлении, так как атрибут Inclina­
tion имеет свойство наклонять мех в одну сторону.

1226 Книга Сергея Цыпцына


Чтобы дополнительно растрепать мех, покрутим его вокруг нормали к поверхности. Для
этого в разделе Details выберите Polar и задайте Noise Amplitude=0.3, чтобы хаотично повращать
ворсинки.

Находясь в разделе Details, задайте также неравномерность длины ворсинок: для этого в
разделе Length задайте Noise Amplitude=0.5, a Noise Frequency=40.

По умолчанию ворсинки меха очень тонкие, причем сужающиеся к концам. Но коль скоро в
нашем случае мех похож на волосы (хотя я упорно называю его мехом, чтобы вы помнили, с каким
модулем происходит работа), ничто не мешает сделать его потолще.

В Attribute Editor задайте Base Widht=0.07 и Tip Width=0.04.


Дополнительно «взлохматим» мех, увеличив значение атрибута Scraggle до 0.2.
Имейте в виду, что гибкость, а следовательно, способность меха деформироваться,
зависит от атрибута Segments, определяющего, на сколько условных сегментов разбивается
каждая ворсинка.

Меховая глава 1227


Остальные атрибуты, влияющие на форму меха, легко изучаются методом тыка. Особо
можно выделить атрибут Clamping, позволяющий собирать мех в «пучки» разного размера,
создавая эффект мокрой шерсти или свалявшегося меха.

Главный метод изучения свойств меха


С параноидальной настойчивостью хочу напомнить, что мех, как и большинство «больших»
процедурных объектов типа Paint Effects и Fluid Container, или просто как огромная текстура,
представляет собой немалый список атрибутов, описывающих все его свойства и сосредоточенных
в одном месте (формально говоря, принадлежащих одной ноде). Как правило, для таких объектов
существуют наборы заранее созданных пресетов, то есть комбинаций значений атрибутов,
задающих конкретные примеры, скажем так, из жизни. Мех не исключение - нажав на кнопку Pre­
sets в Attribute Editor, вы увидите некоторое количество меховых примеров, включая, в частности,
панковский мех (Punk) или мокрую ондатру (Wet Otter). Выбрав в этом меню replace, вы можете
загрузить значения в Attribute Editor и методом пристального взгляда изучить, какие атрибуты
используются для задания того или иного вида меха.

Важно понимать, что пресеты содержат лишь значения атрибутов, поэтому, если на вашем
персонаже уже есть карты для некоторых атрибутов (то есть вы успели покрасить, например,
длину меха), то при выборе пресета эти атрибуты не будут заменены на пресетные, а останутся
подсоединенными к текстурам. Также не будут заменяться заблокированные атрибуты.

Причесывание кистями несуществующего атрибута Direction


Хочу обозначить те грабли, на которые наступают практически все начинающие терзать мех.
Проще быстро проиллюстрировать это на новом примере, чтобы не испортить уже настроенную
модель.

Если создать новую сцену, а затем простую поверхность типа плоскости и покрыть ее мехом,
то при первом использовании Paint Fur Attributes Tool, пo умолчанию, предлагается «расчесать»
мех с помощью атрибута Direction, указанного в Paint Fur Attributes Tool Settings.

1228 Книга Сергея Цыпцына


Однако при попытке расчесать, то есть изменить направление меха вдоль поверхности,
ничего не происходит. Более того, усилия по розыску в Attribute Editor атрибута Direction, а также
соответствующего ему раздела Map в разделе Details ни к чему не приводят такого атрибута
вообще не существует!

Дело в том, что для задания направления меха вдоль поверхности используется атрибут
Polar, вращающий ворсины вокруг оси, перпендикулярной поверхности. Но если атрибут Inclina­
tion равен нулю, то все ворсины не наклонены к поверхности, а растут перпендикулярно ей и
следовательно просто вращаются вокруг своей оси при попытке расчесать мех. Если хоть немного
наклонить мех, то есть увеличить значение Inclination (или изменить значение Base/Tip Curl), то
усилия по расчесыванию несуществующим атрибутом Direction сразу станут визуально видны.

Замечу, что такая работа с Direction определяет только направление, а степень наклона
или приглаженности задается значениями Inclination. Никто не мешает вам красить обоими
значениями.

Расчесывание с помощью Direction сохраняется как карта для атрибута Polar. Однако
важно понимать, что рисование с помощью самого атрибута Polar имеет совсем другой результат.
Дело в том, что в режиме Direction работа с кистью не зависит от выбранной операции (Replace/
Add /Scale/Smooth) и от значения Value в настройках инструмента, а служит только для задания
направления и создания карты для атрибута Polar.

Поэтому прежде чем расчесывать любую модель с помощью параметра Direction, наклоните
или раскучерявьте мех хоть немного, иначе ваши усилия не будут видны на экране (хотя карта-
текстура для атрибута Polar будет создаваться в любом случае).

Наиболее любопытные умы даже могут рассмотреть такие карты для Polar и, при достаточно
степени расширенности сознания, пытаться интерпретировать черно-белое изображение как
значения поворотов ворсин вокруг своей оси.

Меховая глава 1229


А сейчас займемся цветовыми свойствами.
Настройка цвета и наложение текстур на мех
Как следует из значений атрибутов Base Color и Tip Color, мех пока абсолютно белый.
Можете задать пока какую-нибудь панковскую раскраску, имея в виду, что для оснований и
кончиков ворсинок можно задавать разные цвета.

Однако пытливые стилисты наверняка захотят положить текстуру на всю поверхность меха
или сделать, например, мелирование. Хорошо, займемся мелированием. Для него подойдет любая
текстура, в том числе и та, которую вы сами нарисуете.
Назначьте на атрибут Tip Color трехмерную текстуру Volume Noise.
Задайте для нее Depth Max=1 и Frequency=0.2, чтобы получить некоторое количество
черно-белых пятен.

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


Просчитайте изображение - так оно и есть: никакого текстурирования кончиков не произошло.
Дело в том, что подобно другим атрибутам, типа Length или Baldness, цвет меха задается либо
фиксированным значением для всей поверхности, либо картой-текстурой, распределяющей цвет
вдоль поверхности. Когда мы назначили процедурную текстуру на атрибут Tip Color, произошло
лишь связывание атрибутов текстуры и меха, но этого недостаточно, чтобы появились карты
распределения цвета, подобно картам распределения Baldness и Length.

1230 Книга Сергея Цыпцына


Для создания такой карты надо нажать кнопку Bake, после этого все процедурные текстуры,
назначенные на атрибуты меха, будут пересчитаны в обычные растровые карты в формате iff.
Возможно, это немного непривычно по сравнению с текстурированием поверхностей, но я напомню,
что мех это полностью процедурный объект, у которого нет поверхности.
Нажмите кнопку Bake и вы увидите, даже на экране, что мех окрасился корректно.

Итак, после каждого назначения текстуры на любой атрибут меха, а также после
каждого изменения атрибутов этой текстуры, следует нажимать кнопку Bake, чтобы текстура
сконвертировалась в нужные карты для соответствующих атрибутов. Эти карты можно всегда
увидеть в Attribute Editor в разделе Details и посмотреть в папке furAttrMap текущего проекта.

Комментарий. Кстати, текстуры можно назначать не только на цвет меха.


С помощью меню на правой кнопке мыши можно назначить текстуру на любой
атрибут, например, на длину, и выстригать проплешины с помощью нарисованной
карты.

ЕСЛИ ВЫ хотите прокрасить полученным узором мех до самых корней, вам надо назначить
эту же текстуру еще и на атрибут Base Color.

Для этого откройте HyperShade, разыщите там текстуру volumeNoise1 и перетащите ее


средней кнопкой прямо на атрибут Base Color в Attribute Editor.

Меховая глава 1231


Чтобы мех не был такой черно-белый откройте Attribute Editor для текстуры volumeNoise и
в разделе Color Balance задайте для атрибута Color Offset любой (например, рыжий) цвет.
После этого надо обязательно снова нажать кнопку Bake для получения карты цвета для
корней ворсинок. Эту карту можно увидеть в разделе Details/Base Color.

Размер конвертируемых из текстур карт задается атрибутами Map Width /Height.


Увеличьте плотность меха (Density=200 000) и просчитайте картинку. Теперь, наверное,
можно заняться светом и тенями.

Комментарий. Мех нельзя затекстурировать вдоль ворсинок. В описании меха


всегда хранятся только две величины - для кончика и основания, поэтому вдоль
длины меха производится просто линейная интерполяция меха. Даже когда на цвет
назначена трехмерная текстура, дающая распределение цвета в пространстве,
ее конвертация кнопкой Bake приводит к появлению двух плоских карт - одной для
концов и второй для оснований меховых ворсинок.

Освещение меха

Прежде всего, обратим внимание на блики, которые могут возникать на поверхности


меха. Их цвет и «блескучесть» определяются атрибутами Specular Color и Specular Sharpness.
По умолчанию блик задан довольно ярким (серый цвет) и большим (50). Дело в том, что блики
для меха считаются немного не так, как для обычных поверхностей. К тому же, многочисленные
ворсинки и из изгибы могут порождать довольно сильный шум в освещении меха, особенно при
использовании атрибут Scraggle.

1232 Книга Сергея Цыпцына


Задайте Specular Sharpness=200, a Specular Color сделайте в два раза темнее. Это сделает
освещение меха более ровным и спокойным.

Кстати, совсем отключить расчет бликов можно, задав Light Model=Ambient+Diffuse.

Теперь разберемся с затенением.

Пытливые умы уже заметили, что в сцене появился источник света defaultLight, хотя
никаких усилии для этого не предпринималось. Дело в том, что для рендеринга меха необходим
хотя бы один реальный источник света. А крики пользователей, отрендеривших сцену без света,
(«Где же мой мех?»), так надоели службе технической поддержки, что по ее просьбе теперь при
попытке просчитать неосвещенный мех автоматически создается новый источник света типа direc-
tionalLight.

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

До сих пор наш мех просвечивался от кончиков до основания, хотя в природе наблюдается
снижение освещенности при погружении в меховые глубины. То есть ворсины находящиеся ближе
к основанию, освещены хуже, чем кончики. Попытка включить тени для источника света ни к чему
не приводит. Однако пытливые умы наверняка нашли в Attribute Editor для источника света раздел
Fur Shading/Shadowing, который, впрочем, безнадежно пуст.

Чтобы заставить мех просчитывать самозатенение, надо указать, какие источники света
при этом будут использоваться. Делается это довольно нетривиально.

Выберите источник света defaultLight и выполните операцию: Fur=>Fur Shadowing


Attributes=>Add to Selected Light.

Меховая глава 1233


После этого в Attribute Editor для источника света в разделе Fur Shading/Shadowing
появится масса атрибутов, управляющих самозатенением, а сам источник света будет учитываться
при расчете теней.

Кстати, исключить его обратно из расчета теней можно, выполнив Fur=>Fur Shadowing
Attributes=>Remove from Selected Light.

Просчитайте изображение. Мех у своего основания появляется практически черным.

Отрегулировать затенение можно несколькими атрибутами источника света.


Общая «затемняемость» настраивается через Self Shade Darkness. А вот атрибут Self Shade
определяет, насколько далеко от основания (по длине ворсины) распространяется затенение.
Задайте Self Shade=0.2, чтобы затенить мех только у самого основания, и немного убавьте Self
Shade Darkness=0.8.

По сравнению с незатененной картинкой, это катастрофически улучшает восприятие меха.


По крайней мере, мне так кажется.

Атрибуты Back Shade определяют, как сильно затеняются участки поверхности, «смотрящие»
в противоположную от источника света сторону.

Совершенно неоценим атрибут Intensity Multiplier. Если вам хочется немного прибавить
освещения для меха, однако освещенность остальных объектов трогать совсем не хочется, можно
«докрутить» интенсивность источника света только для меха.

1234 Книга Сергея Цыпцына


Совет. Можно установить Fur Shading Туре=Nо Shading, но, тем не менее,
пользоваться Intensity Multiplier для индивидуальной настройки источника света
только для меха.

Прелесть использования самозатенения заключается в том, что оно не требует


дополнительного времени рендеринга, а просчитывается с той же скоростью, что и без него. Чтобы
оценить качество затенения и поэкспериментировать с атрибутами затенения можете увеличить
длину меха (Map Multiplier=10..20) и не забыть увеличить общую плотность.

Однако при использовании AutoShading мех отбрасывает тени только сам на себя. Для того,
чтобы получить тень от меха на других объектах, вместо AutoShading надо просчитать реальные
тени от каждой ворсинки методом Depth Maps, при этом не забывая включить просчет теней у
самого источника света. А также купить еды и напитков, ибо за время рендеринга вы успеете пару
раз проголодаться.

К сожалению, считать Depth Map-тени от меха умеют только источники типа Spot Light,
поэтому для нашего defaultLight метод Shadow Maps даже не появляется в параметрах Fur Shading
Type.

На свой страх и риск можете превратить defaultLight в источник типа Spot Light, просто
поменяв его атрибут Туре прямо в Attribute Editor.
А также сдвинув его повыше (Translate=0,70,90).
После этого его надо заново добавить в вычисление затенения меха (Fur=>Fur Shadowing
Attributes=>Add to Selected Light), после чего включив для него галку Use Depth Map Shadows,
задайте для него Fur Shading Type= Shadow Maps.
Если вы забыли выключить Use Dmap Auto Focus в разделе Shadows для источника света,
MAYA выдаст сообщение в Script Editor, но посчитает картинку.

Меховая глава 1235


Теоретическое обоснование необходимости отключения галки Use Dmap Auto Focus выходит
за рамки этой главы, да и книги целиком.

Сохраните цену headModelFurFinal.ma.

Еще немного про визуализацию или взрослый мех


На этом рассказ про рендеринг меха можно было бы и закончить. Однако взрослые мальчики
наверняка захотят понять, что же скрывается в пункте меню Fur=>Fur Globals, а также узнать, как
устроен просчет меха, ибо надписи, возникающие в Script Editor при рендеринге, заинтригуют
кого угодно.

Как правило, вам не придется что-то менять в этих настройках, по крайней мере на
первоначальном этапе работы с мехом.

Напомню, что при просчете родным майским рендерером (MAYA Software), мех считается
специальной программой (furRender) как отдельный файл-изображение, содержащий альфа-канал
и канал глубины (Z-буфер), затем обычным образом просчитываются все остальные поверхности.
После этого два полученных изображения складываются по правилам композитинга с каналом
глубины.

1236 Книга Сергея Цыпцына


Примечание. При использовании mental ray и Renderman for Maya такие безобразия
не используются. Мех считается честно, вместе с остальной сценой. Но долго.

С одной стороны, использование спецпрограммы (furRender) для просчета только меха


позволяет считать огромные количества ворсин за адекватное время. С другой стороны, это
накладывает существенные ограничения на визуальное взаимодействие меха и остальной сцены.
При таком подходе, естественно, что мех не будет виден ни в отражениях, ни в преломлениях,
и о применений эффектов, связанных с трассировкой лучей (Ray Tracing) можно забыть. Чтобы
отражать мех в других объектах, можно, например, просчитать его из камеры, расположенной в
этих объектах, и использовать эти изображения как карты отражений.

Помните о том, что мех - это отдельная картинка, наложенная на основную сцену после
основного просчета. Взрослые мальчики могут осуществлять такое наложение самостоятельно.
Для этого достаточно выключить галку Сотр. Fur (СКОМПОЗИТИТЬ мех с остальной сценой) в
разделе Fur Render Options. После этого просчитанная сцена не будет складываться с мехом после
рендеринга, а отдельно просчитанные меховые изображения всегда можно разыскать в папке
furlmages текущего проекта. Они представляют собой только изображения меха с альфа-каналом.
Там же лежат отдельно просчитанные файлы, содержащие канал глубины.

Взрослые мальчики должны также понимать, что если один и тот же мех назначен сразу
на несколько поверхностей, то в зависимости от площади каждой поверхности, происходит
усреднение или выравнивание плотности. То есть если одна поверхность по площади в четыре
раза меньше другой, и на обе назначен один и тот же мех, плотность меха на первой поверхности
будет в четыре раза меньше. Такое поведение по умолчанию задается значением атрибута Calc.
Area Values=Per Fur Description. Выключить усреднение плотности можно, установив этот атрибут
в Off.

А совсем взрослые мальчики, назначив мех на обычную сферу, должны задаться вопросом:
почему мех не собирается в плотные пучки около полюсов сферы, подобно любой текстуре?
Чтобы предотвратить эффект неравномерного распределения, MAYA дополнительно создает карты
выравнивания (Equalizer Maps) и использует их для компенсации неравномерной параметризации
поверхностей. Как правило, MAYA справляется с такой задачей вполне адекватно, но совсем
неистовые экспериментаторы могут подключить свои карты распределения (Custom Equalizer
Maps). Для вышеотрендеренного вожака банделогов эта карта выглядит так:

М ежовая глава 1237


Меховые проблемы
Было бы, наверное, бесчеловечно не предупредить любителей меха о том, что их ожидает
некоторое количество мелких, но довольно противных проблем.
Самые глазастые умы, наверное, уже разглядели дырки в альфа-канале на просчитанном
изображении. Причин возникновения таких зазоров между мехом и поверхностью может быть, по
крайней мере, три.

Первая кроется в том, что при работе с NURBS-поверхностями для вычисления границы
меха используется отдельное разбиение поверхности на полигоны (Tessellation), отличное от
заданного для самой поверхности в Attribute Editor. При сильном несовпадении этих разбиений
могут возникать такие щели. Для борьбы с ними можно увеличить разбиение самой поверхности
или уменьшить значение атрибута Nurbs Tesselation в разделе Fur Render Options=>Advanced Op-

1238 Книга Сергея Цыпцына


tion. Этот атрибут отвечает за дополнительное разбиение NURBS-поверхности на полигоны при
вычислении границы основания меха.

Уменьшите этот атрибут до двух, щель станет меньше, но не исчезнет совсем.


Следующей причиной может быть то, что край поверхности при рендеринге с высоким
качеством сглаживается методами antialiasing и filtering. Поэтому на этапе композитинга при
складывании с мехом такая сглаженная граница может давать полупрозрачную щель шириной в
один пиксель между краем поверхности и началом меха.

Однако в нашем случае щель возникает между мехом и впередистоящей поверхностью.


Поэтому источник проблем и щелей - то, что при складывании изображений меха и поверхности
используется канал глубины (Z-буфер), а это грубая восьмибитная величина, так что не дает
никакого сглаживания между контрастными областями. Попытаться решить эту проблему можно,
отрендерив изображение с удвоенными или даже учетверенным разрешением, а затем сжав ее до
нормальных размеров. Более дешевым способом может стать обычное складывание изображений
по альфа-каналу.

Еще одно проблемой может стать неадекватная яркость меха по сравнению с остальными
объектами, освещенными теми же источниками света, что и мех. Основным источником такой
яркости обычно являются блики. Возьмите за правило сразу устанавливать Specular Sharpness
минимум в 150, a Specular Color делать лишь немного отличным от черного. Только в случае
мокрого меха, вам могут понадобиться большие значения для цвета блика. Кроме того, атрибут
источников света Intensity Multiplier может помочь «прибрать» освещение только меха и только
для конкретных источников.

Практические рекомендации по оптимизации просчета меха


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

Если избежать теней невозможно, снизить время просчета и катастрофические объемы


памяти, требуемые в этом случае, может помочь уменьшение значения атрибута Hair/Pixels в
разделе Shadow Map Rendering, который можно найти в Attribute Editor если вызвать Fur=>Fur Glo-
bals. Этот атрибут определяет максимальное количество ворсинок, одновременно принимающих
участие в формировании тени от меха в каждой точке изображения.

Меховая глава 1239


Атрибут с таким же именем находится по соседству в разделе Fur Image Rendering. Он
задают максимальное количество ворсинок, одновременно принимающих участие в формировании
изображения самого меха в каждой точке. Уменьшение его также снижает нагрузку на рендеринг,
однако может идти в ущерб качеству картинки.

Использование motion blur также изрядно замедляет рендеринг. Если есть возможность
симулировать его в композитинге, не упускайте такой возможности.

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

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

Плотность меха атрибут не анимируемый. Поэтому задавайте вручную разную плотность


на крупных, средних и дальних планах. Нет смысла рендерить мех, когда камера отъехала
достаточно далеко, можно обойтись обычной текстурой.

Использование Mental Ray для просчета меха


Начиная с шестой версии, мех стало можно рендерить с помощью mental ray. Причем
он просчитывается как честный геометрический материал (geometry shader) и следовательно
может визуально взаимодействовать со все остальной сценой, включая отражения, преломления,
честные тени и прочие прелести.

При попытке просчитать сцену с мехом в mental ray с качеством по умолчанию, картинка
получается, мягко говоря, экзотичная.

i 240 Книга Сергея Цыпцына


Однако надо понимать, что мех в данном случае считается наравне с поверхностями,
в то время как требования по сэмплингу (то есть по количеству отсчетов на единицу экранной
площади) для него должны быть гораздо выше. Поэтому в Render Globals в предустановках качества
рендеринга для mental ray есть специальный вариант Quality Preset=Preview Fur. Если выбрать его,
мех начинает выглядеть более пристойно.

Чтобы включить отражения или преломления меха и управлять свойствами просчета,


следует открыть в Attribute Editor раздел Render Stats для ноды FurFeedbackShape (а не для FurD-
escription) и там выставить необходимые галки.

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

Однако он не умеет делать Auto Shading. К сожалению, даже без теней mental ray считает
мех весьма неторопливо, а при попытке включить тени время просчета становится вызывающе
долгим. Конечно, самозатенение можно симулировать, просто окрашивая основания ворсин
в более темный цвет, однако этот трюк не будет учитывать расположение источников света. Я
надеюсь, что к моменту выхода книги mental ray научится делать самозатенение и некоторые
другие вещи (например, усреднение плотности по площади поверхностей с мехом).

На этом я заканчиваю с визуализацией меха и перехожу к анимации. Такая последовательность


повествования не случайна. Ибо анимация меха реализована в MAYA слегка экзотично.

Немного про Renderman


С появлением Renderman for Maya меховая жизнь стала намного проще. Мех просчитывается
как полноценный участник сцены, качество антиалиазинга более чем хорошее, использование
теней типа DeepShadow дает отличный эффект самозатенения, рейтрейсинговые навороты тоже к
вашим услогам. И все это в адекватное время просчета. Правда, трактовка атрибутов для описания
меха несколько отличается от родной «майской» мех обычно немного светлее и «помятее».
Однако это не является большой проблемой.

Меховая глава 1241


Анимация меха
Прежде всего замечу, что если вам хватает движения меха, унаследованного от деформации
нижележащей поверхности, вам здорово повезло. Старайтесь по максимуму использовать такой
подход, помня о том, что мех - это не длинные волосы, имеющие собственную динамику движения,
а плотный покров, повторяющий форму поверхности. Традиционная анимация атрибутов меха для
ноды FurDescription может задать дополнительные собственные движения меха.

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

Что же такое аттрактор? Это цепочка из двух костей, которую можно вставить в мех, после
чего близлежащие ворсины меха будут гнуться, пытаясь повторить форму этой цепочки. Хотя
форма эта, как вы понимаете, весьма незамысловатая простой «уголок» из двух костей.

1242 Книга Сергея Цыпцына


Вот, в общем-то, и все. Все дальнейшие действия производятся стандартными майскими
средствами. То есть анимировать две эти косточки можно либо с помощью инверсной кинематики,
либо просто руками, ставя ключи или создавая expressions для вращения. Чтобы добавить динамику,
можно вставить в косточки кривую, сделать из нее мягкое тело (желательно с копированием goal-
кривой), дунуть на нее полем, а саму ее использовать как IK Spline Handle для скелета-уголка.
Короче говоря, сделать анимацию двух косточек можно массой способов.

Примечание. Использование аттракторов после выхода седьмой версии


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

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

Позволю себе немного повозмущаться. Совершенно непонятно, почему меховые ворсины,


способные быть как угодно гибкими и состоять хоть из сотни сегментов, управляются всего
двумя, причем весьма странными, объектами. Тем более, что пример для подражания находится
в соседнем меню. Для Paint Effects-объектов реализована довольно удачная идея, когда обычная
кривая (или набор кривых) управляет общей формой кистей, наподобие wrap-деформера. Траву
или деревья, созданные кистями, можно гнуть с помощью кривых, состоящих из любого количества
точек. Так почему же нельзя было организовать такой же подход и для анимации меха? Тем более,
что это бы лишь усилило общее единообразие и сквозную логику разных инструментов.

Примечание. Не скажу, что мои возмущенные эскапады повлияли на содержимое


седьмой версии, но с приходом динамических кривых в качестве аттракторов
жить стало веселее.

Ответ, очевидно, лежит в особенностях реализации. Как я уже упоминал, технология Fur
была когда-то давно куплена у сторонней компании и внедрена, не как родной модуль, а как
плагин - со своими, соответственно, странностями. При покупке технологии забыли купить одну
маленькую деталь - самих разработчиков, поэтому улучшения модуля MAYA Fur уже много лет
носят косметический характер.

Однако приходится мириться с действительностью. Гнуть мех будем двумя экзотическими


костями, называемыми аттракторами. Такие аттракторы можно вставлять в выбранное место
поверхности, на которой растет мех, либо засадить ими эту поверхность в виде сетки. Все это
можно сделать с помощью операции Create Attractor.

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

Создайте полигональную плоскость.

Выберите ее, растяните и засадите ее мехом: Fur=>Attach Fur Descriptions New. Увеличьте
длину меха: Length=4.

Меховая глава 1243


Выполните Fur=>Create Attractor...
Откроется окно для создания аттракторов, причем количество доступных опций зависит от
того, что выбрано на экране.

Если выбрана поверхность, то в разделе Create будет доступна опция создания сетки
аттракторов (A grid of attractors on selected surface).

Чтобы создать один аттрактор в нужном месте поверхности, надо выбрать это нужное
место. В случае полигональной сетки, это грань (face). В случае NURBS-поверхности - surface
point.

Для изучения свойств самого аттрактора создадим сначала всего один такой объект в
начале координат.

Выберите в окне Create Attractors опцию One attractor at the origin, а в качестве типа (Type)
укажите Simple chain with linked joint rotations.

Столь длинное название означает, что вращения второй кости в цепочке будут повторять
вращения первой с некоторой задержкой по времени, указанной в поле Delay. Для такой задержки
используется простой expression.

Нажмите Create,

i 244 Книга Сергея Цыпцына


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

При попытке покрутить вторую кость вас ожидает неудача: для ее вращений был создан
expression, который симулирует запаздывание вращений второй кости относительно вращений
первой.

Можете изучить его на досуге и оценить его профпригодность, а сейчас выключите его
(Modify=>Evaluate Nodes=>Expressions) и согните вторую кость.

Выберите сам мех.


В Attribute Editor появится дополнительная закладка: FurAttractorsl.
Она отвечает за свойства аттрактора (в данном случае, одного, хотя их может быть
несколько, имеющих одинаковые свойства). В отличие от самого меха, количество свойств и
атрибутов невелико. Самые главные из них - это сила и радиус влияния.
Задайте Radius=2, и вы увидите как согнутся только ближайшие к аттрактору ворсины.

Меховая глава 1245


Увеличьте степень влияния: lnfluence=10, и ворсины будут практически повторять форму
аттрактора.

Атрибут Power определяет, насколько основание ворсин менее чувствительно к сгибу по


сравнению с кончиками.

Судя по наличию раздела Details и его содержимому, все атрибуты аттракторов могут быть
распределены по поверхности, точно так же, как и свойства самого меха. Значениями атрибутов
аттракторов можно покрасить поверхность с помощью Paint Fur Attributes Tool, можно задать
хаотическое распределение, используя Noise Amplitude, в общем, использовать ту же идеологию,
что и для свойств меха. Другое дело, что аттракторов бывает не так много, как ворсин у меха, и
потому зачастую проще расставить их руками в нужных местах и в нужном количестве.

Теперь удалим аттрактор.

Несмотря на то, что он всего один, надо удалить не только его, как объект, но и весь набор
(Attractor Set) аттракторов, определяющий их свойства (в данном случае набор состоит из одного
аттрактора).

Выполните Fur=>Attractor Set(more)=>Delete=>FurAttractors1.

Теперь воспользуемся сеткой аттракторов, так как нам надо двигать весь мех.
Выберите плоскость, затем выполните Fur=>Create Attractors и в появившемся в окне
задайте создание сетки аттракторов (A grid of attractors on selected surface).

1246 Книга Сергея Цыпцына


В разделе Туре выберите тип Dynamic Chain, так как это самый сложный тип аттракторов
(все остальные легко изучаются методом тыка). Заметьте, что длина аттрактора по умолчанию
равна пяти и нажмите Create.

Возникнет девять скелетов-аттракторов.

Судя по содержанию Outliner, каждый аттрактор - это сложное хитроумное устройство для
организации взаимодействия между динамикой и деформациями меха.

Сейчас я расскажу об устройстве этого механизма, но сначала создайте простейшую


анимацию на движение самой плоскости.

Поставьте ключи на перемещение в первом и сороковом кадре (Shift-w), затем встаньте


в тридцатый кадр, сдвиньте плоскость (translateX=3) и снова поставьте ключи на перемещение
(Shift-w).

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

Меховая глава 1247


Для того, чтобы движением костей можно было бы управлять с помощью динамики, каждый
аттрактор в данном случае устроен следующим образом:
1. Пара костей управляются с помощью IK Spline Handle. To есть с помощью кривой, которая
состоит из четырех контрольных точек и в первом кадре является просто прямым отрезком.

2. Эта кривая (curveN), кроме того, является мягким телом, то есть ее форма, в свою
очередь, управляется системой из четырех частиц (curveNParticle).

3. Движение этих частиц, в свою очередь, определяется как внешними полями (которых пока
нет), так и наличием goal-объекта, к которому они стремятся. Этот goal-объект - спрятанная копия
кривой, управляющей костями. Эта спрятанная goal-кривая (copyOfcurveN) не деформируется, а
просто торчит перпендикулярно поверхности и передвигается вместе с ней как прямой стержень.
Ее назначение - притягивать к себе частицы «мягкой» кривой. Вы можете показать ее, просто
включив у нее атрибут Visibility.

4. Чтобы частицы сильно не разлетались, между ними натянуты пружины.

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

Когда изменяется или перемещается поверхность, вместе с ней перемещаются торчащие,


как иголки у ежа, невидимые кривые (copyOfcurveN).

За ними пытаются следовать частицы (каждая частица - за своей контрольной вершиной),


а за частицами - «мягкая» кривая.

А за «мягкой» кривой следуют кости, как за своим IK Spline Handle.

Вот такой паровоз.

Вопрос только в том, почему же аттракторы выписывают такие кренделя, ведь в целом
система выглядит вполне работоспособной? А потому, что кто-то (даже пальцем не на кого
показать!..) при задании индивидуальных весов частиц (goalPP), определяющих силу стремления
к goal-кривой для каждой отдельной частицы, установил по умолчанию такие крохотные значения
для всех частиц, кроме первой (находящейся в основании кривой), что частицы практически
не притягиваются к торчащим перепендикулярно goal- кривым и болтаются на пружинках как
веревочки. Следовательно, и аттракторы безвольно болтаются в пространстве, не зная, что такое
настоящая меховая упругость.

Если вы хотите исправить положение, надо отредактировать вес для каждой частицы в
каждом аттракторе. Наименее медленно это можно сделать следующим образом.

1248 Книга Сергея Цыпцына


Перейдите в камеру front.

В меню панели камеры выберите Show=>None.

А затем Show=>Dynamics.
На экране останутся только пружины и частицы.
Выберите только пружины и спрячьте их (Ctrl-h).
Затем выберите частицы и нажмите F8.
После этого выделите только верхний ряд частиц и для редактирования весов откройте
Windows=>General Editors=>Component Editor.

Выберите закладку Particles и убедитесь, что иезуитское значение 0.005 для атрибута goal-
РР действительно присутствует для всех выбранных крайних частиц.
Исправьте его на 0.3 для всех ячеек (для этого достаточно последовательно выбрать все
ячейки, нажимая Ctrl).

Затем выберите на экране следующий ряд ячеек и для них установите goalPP=0.5.
Для третьего ряда задайте goalPP=0.7.
Можете проиграть анимацию прямо сейчас, оценивая упругость колебаний частиц. Если
вас не устраивает движение, настройте веса дополнительно.
Нажмите F8, чтобы вернуться в объектный режим.

Меховая глава 1249


Выберите все частицы и в Channel Box задайте для них conserve=0.9, чтобы частицы не
болтались из стороны в сторону слишком долго.
Выполните в меню панели камеры Show=>All и проиграйте анимацию.

Теперь мех покачивается немного вследствие движения поверхности и благополучно


успокаивается после остановки. Добавить немного хаоса или даже дунуть на мех вы можете
теперь, просто выбрав все частицы и назначив на них нужные поля, типа Turbulence или Air.
Сохраните сцену (attractorFinal.ma).

Самая трудоемкая часть процесса - настройка весов goalPP, и, честно сказать, я не понимаю,
почему до сих пор в окошке Create Attractors не появилось три дополнительных числовых поля для
задания этих весов при создании аттракторов (четвертый вес всегда равен единице и принадлежит
частице в начале «мягкой» кривой).

На этом можно попрощаться с мехом и с его экзотической анимацией.

Примечание. Словно в ответ на вышеприведенные возмущенные комментарии


в седьмой версии MAYA появилась возможность влиять на мех системой волос
НАПРЯМУЮ, без всяких дурацких посредников, типа костей. Таким образом, вы
можете задать динамику движения меха с помощью небольшого количества
динамических кривых, а затем использовать их в качестве аттракторов для любого
уже созданного и настроенного меха. Чтобы это сделать, надо выбрать систему
волос (ноду hairSystem), а затем с помощью пункта меню Fur=>Attach Hair System to
Fur выбрать меховой объект, на который будет влиять эта система волос. После
этого полезно будет также опять выбрать систему волос и выполнить операцию
Fur=>Set Start Position To, чтобы «развернуть» начальное положение стартовых
кривых для системы волос в соответствии с ориентацией меха в первом кадре.

В заключение - небольшая история из жизни с участием одной меховой собаки, пусть и


исполнившей роль второго плана, но сделавшей историю столь запоминающейся.

Я всегда замечал, что сценарии, хоть минимально основанные на реальных событиях или
происшествиях, имеют какую-то дополнительную выпуклость. Поэтому когда с моим приятелем
Андреем Авдеевым приключилась нижеизложенная история, я тут же понял, что это один из
лучших сценариев для анимационного ролика, которые я когда-либо слышал.

Дело в том, что Андрюня - кайтер. А кайтеры - это люди, катающиеся на кайтах. А кайты
- это такие здоровые воздушные змеи, которые болтаются в небе и таскают за собой кайтеров.
Точнее говоря, кайт - это такой микропарашют (или минипараплан), который запускают в небо,
точно так же, как воздушный змей. Стропы кайта крепятся на планку, которую держит кайтер.
Чтобы кайтер совсем не устал, у него на поясе закреплен крюк, которым он цепляется за петлю на
планке, давая рукам отдыхать и управлять движением кайта. При этом безумный кайтер цепляет
на ноги доску типа сноуборда и прыгает в воду. А дальше все происходит очень быстро: кайт
набирает высоту и тащит за собой кайтера, тот извивается всем телом и пытается встать на доску,
находясь при этом в воде. Если ему это удается, он несется по водной глади с квадратными глазами,
пытается управлять кайтом через планку, к которой он прицеплен крюком, и оглушительно визжит
от восторга и избытка адреналина. Все это относится к начинающим и некоторым продолжающим
кайтерам.

При этом кайтера постоянно подстерегают различные опасности. От рыболовных сетей


(если каталка происходит среди браконьеров), до низко висящих зловредных проводов, норовящих
отрезать кайтера от кайта. Даже в море, где нет ни тех, ни других, коварный ветер постоянно
пытается оторвать кайтера от воды и «переставить» его в другое, не всегда покрытое водой
место. При выходе на берег кайт норовит развернуться и со страшным свистом врезаться в крышу
ближайшего кафе, разметав посетителей и официантов. При запуске в сильный ветер кайт стремится
приподнять кайтера, цепляющегося за землю зубами и когтями, и швырнуть его на ближайшую
стройку. В общем, жизнь кайтера полна приключений. Мои приятели-кайтеры неоднократно
предлагали мне сменить доску с парусом на чудо-змея, и даже обещали быстро научить основам
техники, но я вежливо отказывался, памятуя о том, что голова мне еще пригодится хотя бы

1250 Книга Сергея Цыпцына


для того, чтобы закончить эту книгу. Однако я никогда не слышал, чтобы собаки представляли
непосредственную угрозу для кайтеров. Но теперь я знаю, к чему себя готовить.

Итак, одним приятным летним вечером мой приятель Андрюня лихо катался на кайте на
живописном озере, берега которого были облюбованы местными отдыхающими для пикников и
других глупостей. Закладывая очередной вираж-разворот, Андрюня подъехал слишком близко к
берегу, и тут коварный ветер дунул со всей дури. Да так, что Андрюню мигом выволокло на берег
и со скоростью курьерского поезда потащило по особенностям местного рельефа. А на берегу
ничего не подозревавшие люди жарили шашлыки, пили вино, думали о вечном... Стремительным
тараном Андрюня разметал несколько стоянок, сорвал пару тентов и, пытаясь упираться в землю
хотя бы руками, помчался в сторону леса. Теперь представьте мир его глазами, то есть вид из
камеры, пролетающей сквозь костры, палатки, кусты и заросли. И на переднем плане судорожно
растопыренные руки, у которых между пальцев торчат пучки травы и листьев.

Когда, наконец, кайт напутался в окрестных деревьях и бешеная скачка прекратилась,


Андрюня осторожно приоткрыл глаза, увидел свои руки-бульдозеры, проложившие две траншеи на
опушке леса и обнаружил себя совершенно невредимым. Тут необходимо упомянуть, что кайтеры
обычно одевают гидрокостюмы, причем не столько от холода (ведь чувствительность к боли и
холоду у них практически отсутствует), сколько в целях безопасности. Отцепившись от планки,
Андрюня попытался встать, но обнаружил, что это удается ему с большим трудом тело приобрело
какой-то дополнительный вес и в ногах ощущалась непонятная тяжесть. И тут, выпрямившись,
наконец, и оглянувшись, он с изумлением обнаружил, что у него, пардон, на заднице висит
здоровый бультерьер! Причем отцепиться у собаки нет никакой возможности - пятимиллиметровый
слой неопрена, из которого изготовлен гидрокостюм, полностью забил пасть зверя, и без того
яростно сжимающего челюсти. К счастью, Андрюнины тылы не пострадали совсем: весь удар, а
точнее, укус, взял на себя гидрокостюм. Однако пес продолжал болтаться над землей, неистово
вращая глазами и суча лапами.

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

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

Анимация 1251
Волосатый симулятор
Динамику волос в MAYA ждали давно. На фоне уже готовых симуляторов одежды, меха и
«твердотельной» динамики потребность в адекватной технологии для работы с волосами с каждой
новой версией ощущалась все сильнее. Кроме того, персонажная анимация все настойчивее
требовала настоящей динамики волос, утомившись от хитроумных трюков и высокотехнологичных
обманов зрителя в тех случаях, когда требовалось симулировать выразительное движение массы
волос на поверхности персонажа.

До сих пор для симуляции волос использовались разные уловки. Прически на средних
планах моделировались как обычные поверхности с тщательно подобранным материалом и
текстурой. Для более крупных и требовательных планов использовался мех адекватной длины - и
предпринимались героические усилия по его анимации. Технология Paint Effects спровоцировала
технологический скачок в области моделирования и анимации причесок, что способствовало
появлению множества способов симуляции волос с помощью процедурных кистей. Но так как
динамика волос в системе Paint Effects отсутствует, возникла хорошо описанная в Интернете идея
использовать динамику тканей для анимации штрихов Paint Effects с целью создания эффекта
движения волос. Этот действительно красивый подход использует ленты из ткани, движение
которых обеспечивает модуль MAYA Cloth, далее, используя принцип Construction History, края
лент дублируются и превращаются в кривые, а они, в свою очередь, становятся управляющими
объектами, контролирующими деформацию штрихов Paint Effects. К сожалению, при использовании
таких многоступенчатых трюков теряется сама сущность явления, то есть пользователь уже
не оперирует понятием «волосы», а с трудом удерживает в голове все запчасти агрегата для
создания иллюзии работы с волосами. Ближе всех к динамике волос, с моей точки зрения,
подошла динамика мягких тел. Либо сами кривые, превращенные в мягкие тела с частицами,
либо «содранные» изопармы с «мягких» поверхностей дают неплохое базовое движение и даже
позволяют обеспечить столкновение с препятствием. Однако «резиновость» и невозможность
организовать контроль самостолкновений ограничивает возможность применения мягких тел для
динамики волос.

Хочу заметить также, что разработка технологии для работы с волосами - задача, сама по
себе, очень и очень сложная. Ведь волосы, в отличие от поверхностей или скелетонов, объект очень
непростой. С одной стороны, это объект процедурный, то есть описываемый плотностью, длиной,
толщиной, лохматостью, кудрявостью и возникающий окончательно только на этапе рендеринга.
С другой стороны, с волосами хочется работать, как с набором кривых, имеющих вес, упругость,
трение и другие динамические свойства. С третьей стороны, при создании причесок с волосами
было бы неплохо работать, как с едиными объектом, например, как с поверхностью, для придания
ей нужной формы. С четвертой стороны, волосы иногда хочется стричь, то есть осуществлять
массовое тримирование кривых. И так далее. Таким образом, сами технологические требования к
волосам, как к объекту трехмерной графики чудовищно высоки, а пожелания к инструментам для
работы с таким объектом и вовсе фантастичны. Кроме того, для работы с волосами надо решать
некоторое количество внутренних спецзадач: организация взаимодействий между отдельными
участками, формирование констрейнов, специальные быстрые методы рендеринга и т.д. Тем не
менее, такая технология все-таки появилась в шестой версии MAYA, и, с моей точки зрения, это -
произведение искусства. Причем как с технической точки зрения, так и с точки зрения реализации
и встраивания в среду MAYA. С позиции следования общей логике майских инструментов и
соответствия парадигме «объект как набор атрибутов» модуль MAYA Hair является квинтэссенцией
майской идеологии. Похоже я увлекся. Но мне действительно нравится эта технология.

Применения MAYA Hair


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

Да, благодаря быстрой динамике кривых, реализованной в MAYA Hair, стало возможно

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

Все, что связано с динамикой обобщенных веревок, также может быть реализовано
с помощью MAYA Hair. Тросы, провода, канаты, кабели, цепи, лески и даже шнурки - все это
кандидаты в динамические кривые.

Промышленные объекты, напоминающие упругие стержни - типа антенн, удилищ,


небоскребов в сильный ветер или усов гигантского робота-таракана, также легко анимируются с
помощью динамики жестких волос.

Эффект остаточных явлений может быть сделан с помощью анимации динамических


кривых. Для этого достаточно назначить динамическую кривую wrap-деформером для нужного
объекта (или части объекта). При необходимости можно ее также сгруппировать с объектом для
совместных перемещений.

Для задания анимации штрихов Paint Effects можно использовать динамику волос, используя
кривые как Control Curves.

То же самое относится к меху: в меховой главе я описал способ управления движениями


меха с помощью динамики волос.

Для анимации движения всяких тварей, особенно водоплавающих и пресмыкающихся,


прекрасно подойдут динамические кривые при использовании их в качестве IK Spline Handle для
анимации скелета.

Пытливые умы наверняка придумают еще парочку противоестественных применений MAYA


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

Рекомендации по освоению MAYA Hair


Как было упомянуто выше, работа с волосами - дело не сильно простое. Инструменты
и методы MAYA Hair вобрали в себя основные идеи из многих, уже существующих модулей
MAYA. Поверхность надо покрыть волосами аналогично MAYA Fur. Анимации и кэширование часто
напоминают работу с разогнанным (до предельной частоты) MAYA Cloth. Сохранение начальных
положений и наличие коллизий и притягивающих кривых сильно напоминают работу с частицами.
Взаимодействие с полями интегрировано с общей динамикой. Поэтому, если вы уже знакомы в
упомянутыми модулями, освоение MAYA Hair будет для вас источником положительных эмоций и
превратится в переложение новых понятий на старую добрую идеологию. Если вы решили начать с
MAYA Hair, ничего не зная про частицы и динамику, я бы сильно рекомендовал вам предварительно
заглянуть в соответствующие главы, дабы уберечь от технологического шока. Понимать законы и
принципы динамики - абсолютно необходимое условие для адекватного изучения MAYA Hair!

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

Здесь я приведу уже описанные ранее законы майской динамики без комментариев:
это лишь для тех, кто жить не может без симуляции волос, а потому не успел прочесть начало
главы по динамике твердых тел. Однако рекомендую все-таки прочесть обсуждение этих законов
в перерывах между неистовыми экспериментами, если, конечно, вы хотите понимать суть
происходящего перед вами на экране.

1256 Книга Сергея Цыпцына


Закон динамики 1.
Скорость воспроизведения анимации должна быть всегда равна Play Every Frame.

Закон динамики 2.
Анимация должна воспроизводиться всегда только вперед.

Закон динамики 3.
Первый кадр анимации всегда должен быть «начальным» с точки зрения динамики.

Закон динамики 4.
Нельзя безответственно щелкать мышью в TimeLine и так же безнравственно перетаскивать
мышью текущее время. До тех пор, пока вы не разберетесь с кэшированием, нажимайте только
кнопки Play, Stop и возвращайтесь в первый кадр.

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

Неформальный закон динамики.


Большая скорость - главный враг динамики. Для волос это абсолютно справедливо, причем
благодаря наличию упругости, вероятность возникновения быстрых перемещений в системе
весьма высока. Для того, чтобы бороться с ними, для волос есть специальный атрибут Itera­
tions, определяющий точность вычислений и, соответственно, замедляющий просчет для высокой
точности. О нем - немного позже.

Архитектура и устройство MAYA Hair


Я попытаюсь изложить свое понимание динамики волос, основанное на постоянной аналогии
с анимацией частиц. Возможно, этот подход понравится не всем, и особенно пользователям,
у кого аллергия на частицы. Однако, с моей точки зрения, волосы проще всего представить в
виде набора кривых, превращенных в мягкие тела. То есть в виде системы частиц, управляющих
кривыми, для которых наконец-то удалось решить проблему безнадежной растяжимости пружин.
Если же у вас аллергия на частичную пыль, попробуйте представлять волосы как систему
твердотельных микроцилиндров, соединенных с помощью Nail Constraint. В любом случае, волосы
- это динамическая система, поэтому меню Hair расположено в режиме Dynamics(F4).

Чисто терминологически было бы корректно назвать модуль MAYA Hair динамикой кривых,
так как при работе с ним анимируется некоторое (вполне конкретное) количество кривых.
Соответственно, вы должны перестроить свое мышление на работу с отдельными кривыми,
а не с общей массой волос. Дело в том, что никакой суперкомпьютер не способен просчитать
реальную динамику ста пятидесяти тысяч волос, встречающихся в реальной природе на голове
среднелысого персонажа. Поэтому для обмана зрителей и для облегчения жизни технических
директоров используется весьма небольшое количество, скажем так, опорных кривых, задающих
общее движение всей массы волос. Именно с этим конкретным количеством кривых вам и

Волосы 1257
придется работать, как с объектами динамики. И только на этапе рендеринга появляется заданное
и достаточно большое количество волос, заполняющих пространство между опорными кривыми.
Я настоятельно советую вам помнить о такой «двойственной» природе компьютерных волос и
работать с ними, как с динамикой небольшого количества кривых. Чем меньше кривых будет
использоваться для анимации движения, тем быстрее будет обсчитываться динамика и тем
интерактивнее будет проходить работа. Соответственно, основной неформальной задачей будет
искусное заполнение пространства между динамическими кривыми уже на этапе рендеринга. Эта
задача похожа на проблему адекватного текстурирования поверхности, и к ней я вернусь при
обсуждении визуализации волос.

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

Нижеследующее практическое упражнение будет щедро перемежаться объяснениями и


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

Создание системы волос


Создайте полигональный цилиндр. Сожмите его, сделав плашку (Scale=5, 0.2, 5) и
приподнимите (tranlateY=5). Увеличьте количество сегментов (subdivisionsAxis=50). Это - базовый
объект для покрытия его растительностью.

Примечание. На данный момент волосы можно создавать только на сплайновых и


полигональных поверхностях. В случае сабдивов можно применить трюк, описанный
для превращения их в твердые тела: перейти в режим Polygon и создать волосы
для полигональной сетки, окружающей сабдив (не забыв перед этим выполнить
операцию Collapse Hierarchy). На одной поверхности может произрастать несколько
систем волос с различными свойствами. Справедливо и обратное - одна система
волос может покрывать несколько поверхностей.

Выбрав цилиндр, создадим на нем нечто вроде волос.


Откройте Option Box операции Create Hair.

Типы визуализации волос


Первое, на что стоит обратить внимание, это параметр Output, определяющий, в каком виде
волосы будут представлены на экране и на финальной картинке. Это не касается их динамической

1258 Книга Сергея Цыпцына


анимации, но лишь задает, какого рода геометрия будет использоваться для отображения волос.
Если провести аналогию с частицами - это то же, что Particle Render Type.

Если выбрать Output=NURBS Curves, волосы будут представлены в виде обычных NURBS-
кривых. Если вы не собираетесь их визуализировать непосредственно как волосы, а намереваетесь,
например, использовать в виде деформеров или как управляющие кривые для анимации
поверхностей (либо, например, скелетов), это как раз тот самый случай. Или если вы собираетесь
создать вокруг каждой кривой extrude-трубку нужного профиля с адекватной текстурой, чтобы
визуализировать эти кривые как отдельную геометрию. Этот случай также является подходящим,
если вы намереваетесь рендерить кривые в своей любимой системе рендеринга, которая способна
это делать быстро и качественно. В принципе позже можно воспользоваться операцией назначения
кистей Paint Effects на кривые, однако лучше, конечно, заранее продумать способ визуализации
волос.

По умолчанию выбрано Output=Paint Effects, то есть волосы будут визуализированы в виде


штрихов Paint Effects. Такой способ имеет некоторые преимущества, если вам не надо использовать
кривые как объекты воздействия на другую геометрию. Во-первых, отображение сегментов Paint
Effects на экране происходит быстрее, чем отрисовка реальных кривых. Во-вторых, в этом случае
волосы могут отображаться не в виде одиночных кривых, а в виде целых пучков (clumps), растущих
вдоль общей оси, определяемой динамической кривой. Это позволяет радикально сэкономить
время просчета динамики: ведь движение рассчитывается только для одной, центральной формы
волос, а визуализация всех пучков происходит уже после просчета динамики. Кроме того, в этом
случае появляется множество дополнительных атрибутов, позволяющих скручивать волосы в
пучок, задавать толщину и плотность пучка и даже заплетать его в косичку. В общем, не зря этот
вариант выбран по умолчанию.

Если же вам нужно использовать реальные кривые в своих корыстных целях (например,
запустить по ним объект, как по пути) и одновременно вы хотите визуализировать их, пользуясь
преимуществами Paint Effects, можно выбрать вариант Output=Paint Effects and NURBS Curves. Он
также хорошо подходит, когда вы не можете решить, что же вам нужно.

Мы поступим именно так, а потом спрячем штрихи Paint Effects - до нужного момента.

Выберите Output=Paint Effects and NURBS Curves, а затем задайте U Count=50 и V Count=1,
чтобы создать один ряд из пятидесяти кривых, растущих по кругу.
Значения U/V Count определяют разрешение сетки из кривых, которая покроет всю поверхность.
Здесь необходимо остановиться и подумать о том, что на поверхности должны существовать
адекватные UV-координаты. Здесь ситуация полностью аналогична созданию меха.

Требования к поверхности для создания волос


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

Текстурные координаты для создания волос не обязательно должны быть «хорошими» с


точки зрения обычного текстурирования. Они должны всего лишь не перекрываться. Автоматический
маппинг (Edit Polygons=>Texture=>Automatic Mapping) во многих случаях дает приемлемые UV-
координаты.

В тех местах на полигональных поверхностях, где UV-координаты выходят за рамки


единичного диапазона (или просто не определены), волосы-кривые просто не будут создаваться.
Этот факт можно использовать для маскирования части поверхности от создания волос. Тем более,
что специально для назначения волос можно создать новый UV-set и затем привязать к нему уже
созданную систему волос. Это можно сделать с помощью редактора отношений в режиме Hair/UV
Linking: Windows=>Relationships Editors=>Sets. Причем выбирать перед этим нужно полигональную

Волосы 1259
поверхность, на которой расположены волосы.

Вернемся, однако, к окну Create Hair Options, на котором мы застряли.

Оставим без изменений параметр Points Per Hair, определяющий количество контрольных
вершин для кривой, то есть «гнучесть» волоса.
Не будем также трогать длину волос (Length), тем более что эти параметры можно будет
отредактировать после.
Не будем также включать галку Randomization, которая разбросает по поверхности, в
случайном порядке, сетку волос (в нашем случае нужен лишь один ряд).
Галка Equalize действует аналогично картам Equalizer Maps для меха и предназначена для
компенсации неравномерной параметризации поверхностей в областях типа полюсов сферы и для
ровного распределения волос в таких регионах. Ее тоже трогать не надо.
Теперь можно нажать, наконец, кнопку Create Hairs. Вследствие чего возникнет кольцо из
вертикальных кривых, окруженных небольшими пучками. Эти пучки и есть визуализация волос с
помощью штрихов Paint Effects, но, коль скоро мы будем обсуждать форму и внешний вид волос
позже, сейчас спрячем их, чтобы сосредоточиться на динамике и архитектуре системы волос.

Проще всего отключить отображение Paint Effects на экране с помощью меню панели камеры:
достаточно снять галку Show=>Strokes, и в перспективном окне останутся только центральные
кривые.

Пытливые умы, однако, быстро заметят непорядок при расположении волос. Во-первых, в
виде сверху отчетливо видно, что кривые не расположены по центрам сегментов. Во-вторых, их
i 260 Книга Сергея Цыпцына
не пятьдесят, как следовало ожидать. А в-третьих, в Outliner появилось несколько пустых групп,
наводящих на мысль о неудачном создании нескольких кривых. В чем причина неудачи?
Как и в случае с мехом, причина неудачи в ненастроенных UV-координатах.

Выберите цилиндр и откройте Windows=>UV Texture Editor.

Очевидно, при попытке создать один ряд из пятидесяти кривых, MAYA попыталась их
расположить вдоль V-координаты со значением V=0.5, разбивая U-диапазон на пятьдесят шагов.
Однако, как следует из раскладки UV-координат, некоторые значения (например, 11=0.02, V=0.5)
не принадлежат поверхности.

Поэтому, пустые группы результат неудачной попытки создать кривые в точках с UV-
координатами, не принадлежащими поверхности. Отсюда, кстати, следует и принцип, по которому
MAYA располагает сетку из волос-кривых на поверхности: единичный квадрат на плоскости UV-
координат равномерно (или не очень, если включены опции Randomization и Equalize) разбивается
на сетку значений U и V, и в этих местах выращиваются кривые. В принципе, такой алгоритм
работает неплохо, особенно на равномерно распределенных UV-координатах, но вы должны быть
в курсе этого, особенно когда выращиваете кривые на краях поверхностей. Напомню, что все
эти мелкие проблемы вылезают при работе с полигонами. У NURBS-поверхностей осложнений не
возникает.

Совет. Иногда имеет смысл специально для волос создавать «подставки» -


пригруппированные к голове куски сплайновых или полигональных поверхностей
с хорошими UV-координатами. Благо изготовить такие «плашки» несложно как
«отрезанную» часть поверхности головы.

Прямо в окне UV Texture Editor выполните Polygons=>Normalize UV.


Это растянет UV-координаты по вертикали до единичного диапазона, однако потерянные
кривые, увы, не появятся. Придется удалить все волосы и вырастить их заново.

Волосы 1261
Выберите цилиндр и выполните Hair=>Delete Entire Hair System, чтобы удалить все объекты,
относящиеся к волосам. К сожалению, пустые группы придется удалять вручную.

Снова выберите цилиндр и выполните Hair=>Create Hair.

Так как все установки создания сохранились в Option Box и так как значение V=0.5
соответствует теперь середине цилиндра, будут созданы ровно пятьдесят кривых торчащих
горизонтально из боковой поверхности цилиндра. Помните также, что мы спрятали отображение
штрихов Paint Effects в окне камеры.

Запустите анимацию (сразу можете задать диапазон для проигрывания порядка двух тысяч
кадров). Кривые мягко согнутся вниз.

Совет. При работе с волосами исключительно удобно пользоваться стандартной


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

Поэкспериментируйте. Выберите цилиндр, затем Rotate Tool и запустите интерактивное

1262 Книга Сергея Цыпцына


проигрывание анимации (Solvers=>Interactive Playback), позволяющее взаимодействовать с
объектами прямо во время воспроизведения анимации.

Покрутите цилиндр и проследите за движением кривых. Кстати, для Interactive Playback


есть специальная кнопка на полке Hair.

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

Совет. Задайте диапазон анимации, эдак, тысяч в семь кадров. Торопиться


некуда.

Система волос и ее свойства


Как обычно, начнем разбирательство с новым объектом, исследуя его Attribute Editor.
Если выбрать любую кривую на экране, в Attribute Editor появится некоторое количество закладок.
Если первые две закладки вполне предсказуемы (это ноды transform и shape для кривой), то на
остальные стоит взглянуть повнимательнее.

Последняя закладка содержит атрибуты системы волос как единого объекта. То есть
определяет свойства, общие для всех кривых и целиком описывающие характеристики, скажем
так, «прически». Опять по аналогии с частицами, нода hairSystemShape так же определяет свойства
системы волос, как нода particleShape задает общие характеристики системы частиц. Пропустив
пока раздел Clump and Hair Shape, отвечающий за форму прически, откройте раздел Dynamics,
содержащий атрибуты, определяющие динамические свойства волос.

Волосы 1263
Основное «механическое» свойство волос упругость (Stiffness).
Уменьшите значение этого атрибута до нуля, и кривые превратятся в веревки, безвольно
падающие вниз.

Кроме того, подраздел Stiffness Scale позволяет задать распределение жесткости вдоль
длины каждого волоса. Форма распределения по умолчанию симулирует эффект того, что ближе
к основанию волосы жестче, чем на концах.

Атрибут Drag отвечает за эффект сопротивления воздуха или, если посмотреть с другой
стороны, за массу волос. Увеличьте его до 0.1, и вы увидите легкие нити, плавно опускающиеся
вниз.

Задайте Drag=0 и получите динамику тяжелых веревок или даже цепочек, долго
болтающихся, по инерции, но в конце концов останавливающихся.

Аналогом атрибута conserve для частиц является атрибут Damp. Он служит для
искусственного торможения движения кривых. Если представить отдельную кривую в виде цепочки
из стержней и шарниров, то можно сказать, что Damp управляет трением или несмазанностью этих
шарниров. То есть этот атрибут задает внутреннее трение и сопротивление движению. Физическим
аналогом может служить короткий кусок тяжелого каната, который прекращает раскачиваться
не из-за трения о воздух, а в силу внутреннего трения. В случаях, когда в системе возникают
быстрые колебательные процессы, вызванные, например, сильной жесткостью волос или резкими
столкновениями, можно избежать раскачивания и дрожания кривых путем временного увеличения
значения Damp.

Задайте Damp=1, чтобы веревки не раскачивались бесконечно.


Трения при взаимодействии с поверхностями определяется значением атрибута Friction,
который служит аналогом одноименного атрибута ноды geoConnector, возникающей при задании

1264 Книга Сергея Цыпцына


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

Атрибут Length Flex определяет, насколько «резиновыми» (или - растяжимыми) будут


динамические кривые.

А назначение атрибута Iterations близко по смыслу к параметру Oversampling для частиц.


Значение этого атрибута определяет точность вычисления траекторий волос. «По-простому»
можно сказать, что это - подробность просчета динамики в промежутках между кадрами. Чем выше
его значение, тем больше времени будет потрачено на вычисление динамики и тем медленнее
проигрывается анимация. Необходимость в увеличении точности вычислений возникает, когда в
системе появляются быстрые перемещения и колебания, а динамика «не успевает их отловить» с
заданным количеством итераций.

Остальные динамические атрибуты для волос (Dynamic Weight, Start Time, Current Time)
-полный аналог одноименных атрибутов для частиц.

Взаимодействие со стандартными полями


Все стандартные динамические поля могут действовать на волосы. В качестве объекта
для назначения полей нужно использовать саму систему волос - hairSystem. Ее, как объект, легко
выбрать в Outliner. Если после этого создать поле, оно автоматически присоединится и будет
воздействовать на все кривые. Для присоединения системы волос к уже существующим полям
можно воспользоваться окном Dynamic Relationships.

Выберите в Outliner объект hairSystem1 и создайте радиальное поле: Fields=>Radial.


Задайте для него magnitude=-1, чтобы сделать его притягивающей точкой. Все кривые устремятся
к центру поля.

Для взрослых. Для того, чтобы заставить частицы взаимодействовать с волосами,


можно сделать динамические кривые источниками полей и присоединить эти поля
к частицам. Справедливо и обратное: сделав частицы источником поля, можно
назначить это поле на волосы, устроив таким образом бомбардировку волос.
Эффект капель, стекающих с мокрых волос, можно симулировать, сделав кривую
(или кривые) источником, испускающим частицы, и задав испускание только с
крайних точек.

Примечание. На экране вместе с кривыми движется небольшая круглая иконка,


типа манипулятора для поля, которая и обозначает систему волос. Можно,
конечно, выбрать ее на экране, но удобнее сделать это в Outliner или с помощью
операции Convert Selection, к которой я вернусь позже.

Волосы 1265
Редактирование длины волос
Для того, чтобы изменять длину волос, в меню Hair есть очень простой инструмент (Scale
Hair Tool), не имеющий даже собственного манипулятора (курсора) - это, кстати, может быть
причиной «застревания» в этом инструменте, из-за этого его порой путают с Select Tool.
Если выбрать все волосы целиком (объект hairSystem), масштабироваться будут все кривые.
Однако можно выбрать лишь некоторые кривые и применить этот инструмент к только к ним.
Выберите в Outliner объект hairSystem1 и возьмите в руки инструмент парикмахера: Hair=>Scale
Hair Tool.

Теперь, чтобы удлинить волосы, достаточно кликнуть и потащить мышью вправо, а чтобы
укоротить влево.

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

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


клубок и остановятся.

1266 Книга Сергея Цыпцына


Примечание. При увеличении длины кривых они просто масштабируются. Причем
это происходит независимо от вычисления динамики. Количество сегментов из
которых состоят кривые, также не изменяется. Таким образом, получаются
более длинные кривые, перемещающиеся, однако, более определенным образом.
Представьте себе короткий, довольно жесткий кусок веревки. Если его растянуть
чисто визуально, то есть как картинку, не добавляя дополнительных сегментов,
он будет выглядеть, как упругий стержень. Поэтому при удлинении кривых
они визуально становятся более упругими. Соответственно, после изменения
длины, как правило, имеет смысл отредактировать упругость и/или количество
сегментов. В нашем случае упругость кривых равна нулю, а вот вопросом изменения
количества точек/сегментов, из которых состоят кривые, мы займемся немного
позже, при обсуждении столкновений с объектами.

Возмущенный комментарий. Будьте максимально бдительны при использовании


Scale Hair Tool. Во-первых, функция Undo просто не работает с этим инструментом,
так что сохраняйте сцену почаще. Во-вторых, курсор мыши имеет точно такую же
форму, как и у Select Tool, поэтому если вы случайно отвлеклись или забыли, с каким
инструментом работаете, то при попытке чисто рефлекторно (исходя из формы
курсора) выбрать что-либо на экране, вы просто начнете растягивать кривые
непредсказуемым образом. А в условиях неработающего Undo это становится
причиной потери нервных клеток и даже кратковременной депрессии.

Сохранение начального положения


Если теперь удалить притягивающее поле radialFieldl в том положении, когда «узел»
завязан, то кривые «развяжутся» и упадут вниз. Однако проблема в том, что при возвращении
в первый кадр они снова выстроятся горизонтально, по краю цилиндра. Для уже набивших
оскомину частиц есть такая операция, как запоминание текущего состояния в качестве начального
(Solvers=>lnitial State). Для волос существует полностью аналогичная возможность.
Итак, подождите, пока волосы соберутся в пучок.

Выберите объект hairSystem1 и выполните следующую операцию: Hair=>Set Start


Position=>From Current.

Это означает: «задать начальные позиции кривых равными текущей позиции».


MAYA бодро поприветствует вам сообщением «Warning: No hair curves selected». Оказывается, в
данном случае надо выбирать индивидуальные кривые.

Выберите на экране все кривые и повторите операцию Hair=>Set Start Position=>From Cur­
rent. Вернитесь в первый кадр. Затем удалите radialFieldl. Теперь узел развязывается, и кривые
распадаются в стороны.

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

В этом месте лучше сохранить сцену (hairCylinder.ma), ибо дальше будет длинный и
местами скучный разговор о столкновении динамических кривых с поверхностями. MAYA может не
выдержать такого занудства и зависнуть в самый неподходящий момент.

Долгий разговор о коллизиях и взаимодействии с поверхностям


Пытливые умы, конечно, помнят, что частицы, от упоминания о которых кому-то уже
невмоготу, могут довольно весело сталкиваться с поверхностями с помощью операции Make Col­
lide. Исследуем аналогичную возможность для системы волос.

Создайте полигональный тор: Create=>Polygon Primitives=>Torus.


Задайте для него: Radius=3. Чтобы задать столкновение кривых с поверхностью тора,
выберите объект hairSystem1, затем pTorus1 и выполните операцию Hair=>Make Collide.

Запустите анимацию и дайте волю эмоциям. Кривые проходят сквозь поверхность, лишь
слегка покачнувшись при первом соприкосновении. В чем дело?

Тут самое время вспомнить динамику мягких тел, а также опять обратить ваше внимание
на фаворитов нашего хит-парада - частицы. Если кто-то из вас пытался делать тряпки из мягких
тел и сталкивать их с чем-нибудь (или пытался хотя бы выполнить упражнение из соответствующей
главы этой книги), вы помните, что мягкие тела сталкиваются с объектами при помощи
своих частиц, не обязательно лежащих на поверхности мягкого тела. Тоже самое относится к
динамическим кривым. Они взаимодействуют с поверхностями своими контрольными точками, а
никак не сегментами, соединяющими эти точки. Поэтому при настраивании столкновений кривых
с поверхностями всегда следует отчетливо представлять себе, из какого количества точек состоит
каждая кривая и достаточно ли этого количества, чтобы описать как столкновение, так и саму
форму кривой.

Самый простой способ оценить количество точек на кривой - это, естественно, метод
пристального взгляда.

Выберите любую кривую и включите постоянное отображение ее контрольных вершин:


Display=>NURBS Components=>CV.

1268 Книга Сергея Цыпцына


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

Предположим, что количество точек (и, соответственно, сегментов), нас вполне устраивает
с точки зрения движения тяжелых веревок. В этом случае надо повнимательнее разобраться с
параметрами столкновения кривых с поверхностью.

В отличие от частиц (редкий случай), эти параметры определяются атрибутами объекта


hairSystem, а не атрибутами поверхности.

Выберите hairSystem1 и разыщите в Attribute Editor раздел Collisions, отвечающий за


столкновения.

По умолчанию просчет столкновений включен (Collide=On). А вот следующий атрибут


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

Примечание. Оказывается, только значения 1 или 2 просто разбивают отрезки


между контрольными вершинами на дополнительные подсегменты. Пытливые
умы, попробовавшие радостно установить в Collide Over Sample большие значения,

Волосы 1269
наверняка будут разочарованы полученным результатом. Дело в том, что если
задать для этого атрибута значение больше двух, вместо дополнительных
подразбиений, вокруг каждой контрольной вершины будет возникать кольцо
из заданного количества точек-сэмплов. То есть в этом случае используется
принципиально другой метод увеличения точности просчета столкновений. Таким
образом, если у вас не хватает контрольных вершин для столкновений с узкими
или острыми объектами, используйте для Collide Over Sample значения 1 или 2.
Если же вы хотите более точно отслеживать коллизии для широких пучков или
толстых веревок, задавайте значения 3 и выше. Как раз про пучки и пойдет речь
дальше.

Установите Collide Over Sample=1 и запустите анимацию.

Теперь кривые удерживаются тором корректно. Однако у некоторых глазастых умов


непременно возникнут вопросы. Первый их них: отчего существует некоторый зазор между
поверхностью и кривыми.

Здесь необходимо еще подробнее влезть в механизм просчета столкновений. Дело в том,
что на экране мы видим тонкие и бесплотные кривые, а вот при визуализации это будут вполне
конкретные объекты со своей шириной, или лучше даже сказать толщиной. В отличие от вездесущих
частиц, сиротливо сталкивающихся с поверхностями своими центрами, для кривых определен
зазор - цилиндрическая (точнее, конусообразная) окрестность вокруг каждой направляющей
кривой, используемая как толщина веревки или пучка волос.

Если вы помните, мы создавали наш загадочный объект, используя параметр Output=Paint


Effects and NURBS Curves, а затем просто спрятали штрихи Paint Effects до лучших времен. Если
теперь снова их показать в панели камеры (Show=>Strokes), станет ясно, для чего и откуда взялся
зазор между кривыми и поверхностью.

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

Терминологический комментарий. Так как общеупотребительного жаргонизма для


перевода термина «clump» еще не сложилось, я честно пытаюсь перевести его,
ибо выражение «клампы» может быть воспринято как опечатка. Из множества
словарных вариантов а среди них «пряди», «фиксаторы», «клоки», «группы»,

1270 Книга Сергея Цыпцына


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

Ширину пучков дополнительных волос, растущих вокруг центральных кривых, можно


задать в Attribute Editor в разделе Clump and Hair Shape. За это отвечает атрибут Clump Width.
Следующий атрибут (Hair Width) определяет толщину самих волос.

Установите Clump Width=0.01, то есть ширина пучков будет равна толщине самих волос.
Соответственно, и столкновения теперь будут рассчитываться для тонких веревок, а
не для толстых пучков. Особо любознательные умы могут также выровнять графики-профили,
определяющие изменение толщины вдоль направления кривых (Clump/Hair Width Scale).

Запустите анимацию. Зазор исчезнет и кривые будут прилегать к поверхности более


плотно. Спрячьте снова штрихи Paint Effects (Show=>Strokes), чтобы ускорить анимацию.
Коль скоро мы еще не решили, как будем визуализировать кривые, неплохо бы иметь еще один
общий атрибут, который бы просто добавлял ко всем кривым дополнительную толщину при
просчете столкновений. Этим же атрибутом, можно было бы корректировать зазор, независимо
от толщины пучков и волос. Такой атрибут находится в разделе Collisions и называется Collide
Width Offset. Он, как правило, используется для того, чтобы «вытащить» обратно провалившиеся
в поверхность волосы.

Установите Collide Width 0ffset=0.1. Просто так, на будущее.

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


определения толщины кривых при вычислениях коллизий, приведу общую формулу, задающую
такую толщину:

W = Clump Width * Clump Width Scale + Hair Width + Collide Width Offset

Кстати, увидеть эту толщину можно, и не отображая штрих Paint Effects. Два последних
атрибута в разделе Collisions позволяют нарисовать на экране что-то похожее на кружки,
символизирующие динамическую толщину кривых.

Включите Draw Collide Width, и вы увидите вдоль каждой кривой небольшие кружки (а если
вы забыли установить Collide Width Offset=0.1, тогда просто точки). Правда, для того, чтобы они
появились, надо хотя бы немного сдвинуть камеру или перейти в следующий кадр. Чтобы кружков

Волосы 1271
нарисовалось побольше, установите Draw Collide Skip=0. Если они вас раздражают, выключите их
немедленно.

Кстати, вышеприведенная формула используется и при расчетах взаимных столкновений


между кривыми. По умолчанию взаимодействие между отдельными кривыми не вычисляется, и
для того, чтобы его задать, надо включить галку Self Collide в разделе Collisions.

Понятно, что если вычислять взаимодействие между абсолютно всеми кривыми, то не


поможет никакой апгрейд процессора, поэтому атрибут Num Collide Neighbors задает, со сколькими
соседними кривыми будет взаимодействовать каждая кривая в системе волос.

Атрибут Repulsion задает степень отталкивания друг от друга, a Static Cling имитирует силу
притяжения, похожую на прилипание волос друг к другу вследствие статического электричества.
Можете поэкспериментировать с этими атрибутами и отметить, как падает производительность
просчета динамики при включенном взаимодействии кривых. Не забудьте выключить его для
дальнейших экспериментов.

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

Выберите все кривые и выполните операцию: Hair=>Set Start Position=>From Current.


Вернитесь в первый кадр.
Сохраните сцену (hairCylinderTorus.ma).

Примечание. Если вас смущают мелкие биения, пробегающие по кривым, то


помните, что мы работаем с абсолютно неупругими веревками. Если вы хотите,
чтобы они абсолютно застыли на месте, сделайте воздух совсем вязким (Dra$= 1).
Если этот метод вам не нравится, можете вступить на скользкий путь игры с
Iteration и Damp.

Нас дрожание не смущает, но немного конфузит форма кривых. Совершенно очевидно, что
количества контрольных точек на кривых немного не хватает для придания им более гибкой формы.
Однако количество контрольных точек определялось только при создании и не фигурировало среди
атрибутов объекта hairSystem. Оказывается, можно определять количество сегментов для каждой
отдельной кривой, так же, как и ее степень и многие другие свойства. Для того, чтобы изменить
эти свойства, нужно добраться до индивидуальной природы каждой кривой. Этим мы сейчас и
займемся. А я напомню, что мы решили проблему столкновений без дополнительного увеличения
числа точек, и если бы форма и «гнучесть» кривых нас устраивала, не было бы необходимости
увеличивать количество сегментов.

1272 Книга Сергея Цыпцына


Индивидуальные свойства волос
Если в очередной раз, с маниакальной настойчивостью, вернуться к частицам, можно
вспомнить, что у них были индивидуальные (per-particle) атрибуты, определявшие свойства
каждой отдельно взятой частицы. С волосами ситуация очень похожая. Для каждой выбранной
кривой предпоследняя закладка в Attribute Editor определяет ее индивидуальные динамические и
другие свойства.

Если посмотреть на тип ноды в этой закладке, то выяснится, что это follicle (фолликула),
а если нажать в нижней части Attribute Editor кнопку Select, то на экране выберется основание
кривой, этакий корешок. Если немного исхитриться, можно выбирать этот микрообъект прямо на
экране, но всегда проще выбрать кривую и разыскать нужную закладку в Attribute Editor.

Терминологический комментарий. Вот тут, не могу не признать, я в некотором


затруднении. Использовать угрожающе-медицинский термин «фолликула» у меня
не хватает духу. Тем более в оригинале он означает только «луковицу» отдельного
волоса. Однако атрибуты ноды follicle определяют свойства не только основания,
но и всей кривой целиком. Поэтому я буду выкручиваться при помощи термина
«динамическая кривая», с подвариантами: «направляющая», или «центральная»,
или даже «основная» кривая. Иногда, правда, комментируя некоторые пункты
меню, придется упомянуть и о «фолликулах», но в ограниченных дозах.

Таким образом, система волос (hairSystem) состоит из отдельных динамических кривых


(follicles). В отличие от частиц, каждую динамическую кривую можно выбрать как объект и
рассмотреть ее свойства в Attribute Editor или Channel Box.

Соответственно, у каждой динамической кривой в Attribute Editor есть дополнительная


закладка с различными свойствами (аналогично тому, как появляется закладка rididBody у
поверхностей, превращенных в твердые тела).

Примечание. Вспоминая аналогию о превращении поверхностей в твердые тела,


могу посоветовать вам представлять динамические кривые, как обычные
сплайновые кривые, обработанные специальным составом или покрытые слоем
лака, для придания им упругости и других динамических свойств. Соответственно,
свойства такого слоя появляются как атрибуты в дополнительной закладке в At­
tribute Editor для любой выбранной динамической кривой.

Сразу отмечу, что в разделе Dynamics Overrides и Render Overrides находятся атрибуты,
которые позволяют изменить «общепартийные» свойства, заданные для всей системы волос
hairSystem, и дают возможность задать индивидуальные свойства для выбранной кривой. Так,
например, атрибут Stiffness в этом разделе задает индивидуальную упругость для конкретной

Волосы 1273
кривой, не зависящую от значения Stiffness, определенного для всех волос.

Пытливые умы наверняка заметили, что у каждой динамической кривой есть два атрибута
(Parameter U/V), определяющие точное расположение конкретной кривой на поверхности. Причем
эти атрибуты можно, абсолютно без комплексов, редактировать вручную.

Для взрослых. Вы можете использовать эти атрибуты для задания некоторых


свойств динамических кривых с помощью текстуры, лежащей на поверхности.
Например, имея UV-координаты, вы можете прочитать с текстуры цвет в этой
точке и присвоить его на цвет кривой или изменить плотность волос в этой точке
или вообще удалить эту кривую. Читайте об этом подробнее в конце главы.

А вот атрибут Sample Density отвечает за индивидуальное количество контрольных точек на


кривой. Точнее говоря, он действует как умножитель для первоначального количества точек, то
есть если при создании наши кривые имели по десять точек каждая, то задав Sample Density=1.5,
мы увеличим количество точек до 15.

Следующий вопрос состоит таков: как одним махом отредактировать Sample Density для
всех динамических кривых. На ум конечно приходит Channel Box, позволяющий редактировать
атрибуты для всех выбранных объектов, однако если выбрать все кривые на экране, в Channel Box,
к сожалению, появляются только обычные атрибуты кривых, а нужные нам свойства из закладки
follicle отсутствуют. Очевидно, что «корешки» кривых, то есть ноды типа follicle надо выбрать
отдельно. Самый нетворческий путь - начать возиться с Selection Masks. Менее прямолинейное
решение - разыскать в Outliner группу hairSystem1 Follicles и выбрать ее внутреннее содержание.
Однако часто бывает удобно выбирать конкретные кривые прямо на экране и обращаться к их
«динамическим» свойствам непосредственно в Channel Box. Для этого существует операция
конвертации типа выбранных объектов, аналогичная такой же операции для полигональных
компонент (Edit Polygons=>Selection).

Творческий выбор
Самый простой пример наиболее часто встречающей проблемы - как выбрать все
динамические кривые для конкретной системы волос hairSystem? Или наоборот, как для выбранной
кривой быстро выбрать всю систему волос? Для этих целей существует довольно остроумный пункт
меню: Hair=>Convert Selection.

Применительно к нашим целям, выберите объект hairSystem1, а затем выполните операцию


Hair=>Convert Selection=>to Follicles.
Это выберет все динамические кривые, причем за их «основания», то есть за ноды типа follicle.
После этого, если перейти в Channel Box, там можно увидеть и отредактировать индивидуальные
атрибуты всех динамических кривых, принадлежащих системе волос.

1274 Книга Сергея Цыпцына


Совет. Самый быстрый способ выбрать основания (follicles) для всех динамических
кривых состоит в том, чтобы отметить на экране любую кривую, а затем
выполнить две операции: Hair=>Convert Selection => to Hair System u Hair=>Convert
Selection=>to Follicles.

Изменение индивидуальной гибкости кривых


Не забывайте возвращаться в первый кадр.
Задайте в Channel Box для всех выбранных кривых Sample Density=1.6. Запустите анимацию.
Кривые стали более «гибкими», так как количество точек для каждой из них изменилось с десяти
до шестнадцати.
Коль скоро динамические свойства всех кривых доступны в Channel Box, задайте parameterV=0.3.
Это сдвинет все кривые вдоль поверхности цилиндра ближе к краю. Напомню, что с помощью
атрибутов ParameterU/V можно изменять и даже анимировать положение каждой конкретной
кривой на поверхности.

Если некоторые кривые провалились в поверхность вследствие добавления новых


сегментов, просто вернитесь в первый кадр и опустите тор пониже (translateX=-1). Оцените, как
изменилась форма кривых при огибании препятствия.

Как только кривые остановятся, выполните Hair=>Set Start Position=>From Current. Это
должно стать привычкой для сохранения достигнутой в результате анимации формы. Вернитесь в
первый кадр.

Заметьте, что если выбраны все Follicles, нет необходимости выбирать все кривые перед
сохранением начального положения. Однако после этой операции выбранными становятся
так называемые стартовые (или начальные) кривые (Start Curves). Вот о них-то мы сейчас и
поговорим.

Внимание! Следует особо отметить, что в момент сохранения начального положения


произошло не только запоминание позиций всех кривых, но и сохранение количества точек на
кривых в тот момент, когда была выполнена операция Set Start Position. А так как значение Sample
Density было равно 1.6, то для начального положения было сохранено по шестнадцать точек для
каждой кривой. Однако автоматического сбрасывания Sample Density в единицу не произошло, и
для текущего состояния количество точек равно 16x1.6=25!

Поэтому следует обязательно запомнить, что если вы изменили значение Sample Density,
а затем выполнили операцию Set Start Position=>From Current, то следует немедленно установить
Sample Density в единицу, иначе количество точек еще раз увеличится.

Волосы 1275
Снова выберите объект hairSystem1, а затем выполните операцию Hair=>Convert
Selection=>to Follicles, чтобы добраться до индивидуальных свойств всех кривых.
Задайте Sample Density=1. Число точек на каждой кривой должно стать равным шестнадцати.

Стартовые кривые: Start Curves


В отличие от вездесущих частиц, начальное положение динамических кривых сохраняется
в виде реальных кривых, которые по умолчанию невидимы на экране. Они называются стартовые
кривые (Start Curves). Когда в любом кадре выполняется операция Hair=>Set Start Position=>From
Current, то текущее (Current) состояние и форма кривых просто копируется в невидимые стартовые
кривые. При возвращении в первый кадр анимации (точнее, в начальный кадр динамики)
динамические кривые всегда принимают форму стартовых кривых.

Очень важно понимать тот факт, что количество точек на динамических кривых определяется
как количество точек на стартовых кривых, умноженное на значение Sample Density для каждой
кривой. Именно в стартовых кривых, сохраняется количество точек, задаваемое в самом начале
при создании системы волос.

Кроме того, как я только что упоминал, при сохранении текущего (Current) состояния в
качестве начального (Start) с помощью операции Hair=>Set Start Position=>From Current сохраняется
не только форма, но и количество точек. Поэтому если для некоторых (или для всех) кривых
значение Sample Density отлично от единицы, обязательно верните его в единицу после сохранения
начального состояния.

Примечание. В принципе можно не использовать атрибут Sample Density, a


выбирать все стартовые кривые и выполнять операцию Rebuild Curves, задавая
нужное количество точек на стартовых кривых. Результат будет примерно тот
же самый. Однако это, во-первых, более трудоемко, а во-вторых, в результате
операции Rebuild Curve может немного измениться форма стартовых кривых.

Вы также должны понимать, что для одной системы волос hairSystem всегда существует,
как минимум, два набора кривых (как максимум, три - при наличии Rest Curves): текущий (Current)
и стартовый (Start).

Так как в первом кадре форма динамических кривых полностью определяется стартовыми
кривыми, это означает, что начальное состояние (или «прическу») можно задать, просто
отредактировав стартовые кривые всеми легальными и нелегальными методами. Осталось
выяснить, как показать скрытые стартовые кривые.

Примечание. Никогда не редактируйте вручную сами динамические кривые.


Изменять форму можно только для стартовых (Start) кривых или для goal-кривых
(Rest).

Отображение стартовых кривых


Для отображения на экране различных наборов кривых существует меню Hair=>Display.
Его содержимое комментариев не требует. По умолчанию на экране видны только текущие (Cur­
rent) динамические кривые. Чтобы показать также стартовые кривые, следует, очевидно, выбрать
Hair=>Display=>Current and Start.

Удалите тор и проиграйте анимацию, чтобы кривые «упали».


Затем выполните Hair=>Display=>Current and Start, и на экране появятся еще дополнительно
стартовые кривые.

1276 Книга Сергея Цыпцына


Пытливые умы наверняка заметили, что в меню Hair=>Convert Selection были пункты для
выбора отдельно стартовых кривых и даже их компонент. Отредактируем сейчас их форму, чтобы
задать начальное состояние без помощи полей или столкновений.

Редактирование начальной формы


Выберите объект hairSystem1, а затем выполните Hair=>Convert Selection=>to Start Curve
End CV. Это выберет последние контрольные точки для всех стартовых кривых, принадлежащих
системе hairSystem1.

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

Волосы 1277
Однако при попытке смасштабировать или переместить точки возникает резонный вопрос:
а как быть с длиной кривых? - ведь таскание точек неизбежно меняет длину кривой.

В шестой версии MAYA появилась возможность фиксировать длину выбранной кривой


таким образом, что при перемещении одной или нескольких контрольных точек остальные точки
двигаются согласованным образом, обеспечивая сохранение длины кривой. Эта возможность
доступна как при редактировании обычных сплайновых кривых через меню Edit Curves=>Modify
Curves=>Lock Length, так и при работе с динамическими кривыми через меню Hair=>Modify
Curves=>Lock Length. Более того, для этой операции по умолчанию задана горячая клавиша «I»,
действующая как переключатель, то есть фиксирующая длину выбранных кривых только в нажатом
состоянии.

Давайте внимательно поэкспериментируем.


Выберите Scale Tool.
Затем изо всех сил нажмите левой рукой клавишу «I» и держите ее нажатой.
Мышью измените масштаб кольца из выбранных точек.
Отпускайте сначала мышь.
Затем левую руку.
Затем воздух из легких.

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

1278 Книга Сергея Цыпцына


Теперь снова выполните Hair=>Convert Selection=>to Start Curve End CV, для выбора
последних контрольных точек всех стартовых кривых.

Нажмите «I», затем с помощью Scale Tool сожмите немного точки к центру.
Не отпуская «I», выберите Move Tool и поднимите точки вверх, на уровень перегиба в
середине. Вы должны понимать, что после редактирования никакого сохранения начального
состояния не требуется, так как мы непосредственно редактируем стартовое положение кривых.

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


Проиграйте анимацию.
Сохраните сцену (hairCylinderStartCurves.ma).
Остаточные кривые: Rest Curves
Теперь настала пора разобраться еще с одним типом кривых, используемым при работе
с системой волос. По аналогии со стартовыми кривыми их лучше всего назвать финишными
кривыми, однако финишными бывают, как правило, только прямые, поэтому я буду называть их
окончательными, или остаточными кривыми (rest curves). Слово "rest" имеет так много значений,
что подобрать подходящее именно к данной ситуации довольно затруднительно.

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

Однако если вернуться к аналогиям с частицами, можно совершенно четко определить,


что остаточные кривые (rest curves) суть полная аналогия goal-объектов для частиц. (В случае
динамики мягких тел эта аналогия становится особенно адекватной). Как частицы стремятся к
своим goal-объектам, так же и система динамических кривых стремится к форме, задаваемой
остаточными кривыми.

Примечание. С появление в седьмой версии MAYA нового атрибута Start Curve At­
tract необходимость использования остаточных кривых отпала в значительном
большинстве случаев.

Волосы 1279
Попробуем накрахмалить нашу систему веревок.

В отличие от стартовых кривых остаточные кривые не создаются по умолчанию, поэтому


самый адекватный способ их создать - это использовать положение и форму системы динамических
кривых в каком-нибудь кадре, то есть запомнить текущее состояние системы волос как набор
остаточных кривых. (Если продолжать упорствовать и искать аналогии с частицами, это примерно
похоже на дублирование частиц в некотором кадре и на назначение новой копии частиц в качестве
goal-объекта к исходным частицам.)

Проиграйте анимацию примерно до тридцатого кадра (используйте предыдущую сцену,


сохраненную как hairCylinderStartCurves.ma).

Затем выберите все кривые и выполните операцию Hair=>5et Rest Position=>From Current.
Эта операция копирует текущее положение кривых и создает из него остаточные кривые.

Однако при проигрывании анимации никакой разницы с предыдущими вариантами не


наблюдается. В чем дело? Проверим, создались ли остаточные кривые.

Остановите анимацию в любом кадре и выполните операцию Hair=>Display=>All Curves,


после чего все три типа кривых будут отображены на экране.

1280 Книга Сергея Цыпцына


Все кривые на месте, однако никакого влияния остаточных кривых не ощущается. Любители
назойливых частиц, конечно, помнят, что у тех был специальный атрибут goalWeight, отвечающий
за степень стремления к goal-объекту. В данном случае в качестве такого атрибута выступает
упругость динамических кривых. Коль скоро мы установили ее в ноль какое-то время назад, то
никакого стремления к остаточным кривым не наблюдается.

Выберите систему волос hair System1 и в Attribute Editor установите Stiffness=0.15 в разделе Dy­
namics.

Проиграйте анимацию. Теперь веревки выглядят «накрахмаленными» и стремящимися


занять форму, определяемую остаточными кривыми. Однако наличие силы тяжести не дает им
полностью принять такую форму, поэтому в результате получается «компромиссное» положение
между внешними силами и остаточными кривыми.

Поиграйте с упругостью (Stiffness), чтобы убедиться, что она в самом деле управляет
степенью стремления системы веревок к остаточным кривым.

Используя пункт меню Hair=>Convert Selection, можно выбрать концевые точки остаточных
кривых и отредактировать их вручную, аналогично стартовым кривым. Все изменения формы
остаточных кривых немедленно отражаются на анимации.

Использование остаточных кривых (Rest Curves) - довольно полезный способ задания общей
формы для системы волос, особенно в тех случаях, когда речь идет о прическах. Я бы советовал
воспринимать остаточные кривые не как жесткую форму (в отличие от стартовых кривых), а скорее
как силу, которая стремится привести волосы в некоторое состояние и конкурирует с другими
силами.

Посмотрим, как можно быстро удалить остаточные кривые.

Выберите систему hairSystem1, а затем выберите все остаточные кривые, соответствующие


нашей системе волос Hair=>Convert Selection=>To Rest Curves.

Теперь просто удалите выбранные остаточные кривые и запустите анимацию.


Не забудьте установить в ноль упругость (Stiffness) для системы волос hairSystem1, чтобы вернуться
к набору безвольных веревок.

Примечание. Стартовые кривые удалить аналогичным образом нельзя, так как


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

Волосы 1281
Три типа кривых при работе с системой волос
Таким образом, при работе с системой волос мы обычно имеем дело с двумя или тремя
(при наличии Rest Curves) наборами кривых. Существует, правда, еще один тип кривых - пассивные
кривые (Passive Curves), но о них пойдет речь позже.

Прежде всего это сами динамические кривые, которые анимируются под действием
динамики. Они называются Current Curves (или Current Position).

Внимание! Никогда не редактируйте вручную сами динамические кривые. Вы же не


пытаетесь таскать вручную отдельные частицы, поэтому сами волосы тоже трогать не надо.

Стартовые кривые (Start Curves, или Start Positions) задают форму и положение динамических
кривых в начальном кадре. Они автоматически создаются всегда, и их нельзя удалить без удаления
самих динамических кривых. Их можно редактировать вручную. Именно эти кривые определяют
базовое количество точек, из которых состоят динамические кривые.

Остаточные кривые (Rest Curves, или Rest Positions) определяют форму, которую стремятся
занять динамические кривые. Чем больше упругость кривых, тем сильнее и точнее они принимают
эту форму. Остаточные кривые не создаются по умолчанию (но при необходимости могут быть
построены при создании волос). Их также можно и нужно редактировать вручную всеми легальными
и нелегальными методами, однако количество точек на них менять не следует.

Стартовые и остаточные кривые могут быть в любой момент переопределены и заданы,


например, как текущая форма динамических кривых. Все это делается через пункты меню
Hairs=>Set Start(Rest) Position. Для редактирования формы этих кривых «в целом» также существует
специальный пункт меню Hair=>Modify Curves.
По умолчанию на экране отображаются только сами динамические кривые, показать же
стартовые и /или остаточные кривые можно через меню Hairs=> Display. Так как эти кривые - только
вспомогательные и никак не отображаются в процессе рендеринга, они отрисовываются на экране
как кривые первого порядка: ведь важны только позиции контрольных точек этих кривых.

Совет. Напоминаю: если вы собираетесь всерьез экспериментировать с системой


волос, попробуйте разобраться и запомнить, как устроена полка (Shelf) под
названием Hair. Можете перетасовать иконки на ней в удобном для вас порядке. Эта
полка поможет сэкономить массу времени, так как переключение между типами
кривых или преобразование выбора происходит при работе с динамическими
кривыми очень часто.

Для редактирования, точнее для корректирования формы самих динамических кривых


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

Система констрейнов для динамических кривых


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

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


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

1282 Книга Сергея Цыпцына


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

Между волосами (динамическими кривыми) тоже можно натягивать некоторый набор


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

Во-первых, между волосами можно натягивать не только пружины (которые больше


всего напоминают констрейн типа Rubber Band), но и связи других типов - например, упругие
стержни (констрейн типа Stick) или абсолютно жесткие соединения (констрейны типа Transform и
Hair to Hair). Все констрейны имеют общую идеологию (за исключением, пожалуй, Hair Bunch) и
абсолютно одинаковые атрибуты. Так что можно представлять их себе просто как связи разного
типа, накладываемые на контрольные точки динамических кривых прямо во время анимации.

Во-вторых, констрейны-связи накладываются не на произвольно выбранные контрольные


точки динамических кривых, а только на некоторые из них.

Общий принцип наложения связей таков.

Сначала надо выбрать кривые и для них создать констрейн определенного типа
(Hair=>Create Constraint). Этот констрейн определяет в первом кадре (!), какие контрольные точки
для каждой кривой располагаются ближе всего к его центру (визуально констрейн представляется
как локатор), причем этот констрейн выбирает по одной точке с каждой кривой и накладывает
связи только на эти точки.

Поэтому я весьма настоятельно рекомендую создавать констрейны только в первом кадре.


Даже если вы создадите новый констрейн посередине анимации, расстояния от него до ближайших
точек на кривых будут вычислены для первого кадра (а точнее, для стартовых кривых).
Таким образом, выбор точек, на которые накладываются связи, происходит только
в начальном кадре анимации. Поэтому в этом кадре вы можете свободно передвигать центр
констрейна и видеть, как интерактивно обновляется набор ближайших к нему точек (еще раз
напомню: с каждой кривой берется только одна точка). Зафиксировав положение констрейна в
первом кадре, вы запускаете анимацию и видите, как ограничивается движение выбранных в
первом кадре точек. Никто не мешает вам анимировать положение констрейна, просто вы должны
помнить, что набор точек, на которые он влияет, полностью определяется положением констрейна
в первом кадре. В остальных кадрах именно эти точки будут следовать за констрейном, если он
анимирован.

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

После таких теоретических изысканий попробуем потаскать нашу модель за волосы,


точнее, за веревки.

Воспользуйтесь предыдущим файлом (hairCylinderStartCurves.ma).


Встаньте в первый кадр. Спрячьте стартовые кривые, если они присутствуют на экране
(Hair=>Display=>Current Position).

Выберите все кривые и создайте констрейн Rubber Band (резиновая полоска или нить):
Hair=>Create Constraint=>Rubber Band.

В начале координат появится локатор, представляющий положение констрейна, от которого


к концам кривых тянутся пунктирные линии-нити.

Волосы 1283
Если проиграть анимацию, окажется, что эти упругие нити постоянно связывают концы
веревок с локатором.

Вернитесь в первый кадр и попробуйте перемещать локатор вертикально: верх и вниз.


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

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

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

1284 Книга Сергея Цыпцына


Можете «зацепить» констрейном концы кривых и запустить интерактивное воспроизведение
динамики (Solver=>lnteractive Playback).

Выберите затем локатор и хорошенько потаскайте его в пространстве.


Все кривые будут следовать за резиновыми нитями.
Верните локатор на место: Modify => Reset Transformation.
Наиболее экстремальные пытливые умы могут позволить себе следующий фривольный
эксперимент.
В первом кадре выберите фолликулы, то есть ноды, определяющие индивидуальные
свойства каждой динамической кривой: Hair=>Convert Selection=>to Follicies.
Затем откройте Channel Box и установите для всех выбранных объектов pointLock=No Attach.
Запустите анимацию: все кривые выпадут и останутся у вас в руках, точнее в констрейне.
Вы можете даже проанимировать атрибут PointLock, чтобы симулировать выдергивание
кривых в некотором кадре.

Вкратце опишу свойства и назначение каждого констрейна. Так как все констрейны имеют
одинаковую природу и набор атрибутов, вы можете одновременно экспериментировать с разными
типами констрейнов, просто переключая атрибут Constraint Method в Attribute Editor для уже
созданного констрейна.

Rubber Band (резиновые нити) притягивает к себе точки кривых, если расстояние до них
превышает дистанцию, определенную в первом кадре.

Волосы 1285
Transform просто замораживает намертво точки, определенные в первом кадре и
как бы «пригруппировывает» их к себе, так, что они двигаются вместе с ним, как единое
целое. Примечательно, что замороженные точки корректно наследуют все вращения и даже
масштабирование констрейна типа Transform. Его удобно использовать, например, в тех случаях,
когда вы хотите намотать волосы на руку или зафиксировать концы веревок.

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

Hair to Hair просто удерживает выбранные кривые (а точнее, их точки) на фиксированном


расстоянии друг от друга. Причем это расстояние определяется взаимным расположением кривых
в первом кадре.

Hair Banch - единственный констрейн, который может прикладывать силу к точкам кривых
непосредственно в первом кадре. Этот констрейн пытается разбить волосы на пучки, имитируя,
с одной стороны, самостолкновения между кривыми и статическое слипание, с другой стороны.
Если точки кривых находятся ближе, чем значение, определенное атрибутом Clump Width (для
ноды hairSystem), то кривые отталкиваются друг от друга. Если точки подходят совсем близко друг
к другу, они начинают слипаться. Это единственный констрейн, который принимает во внимание
ширину пучков волос (Clumping), определенную для все системы волос. Симуляция взаимодействия

1286 Книга Сергея Цыпцына


между волосами с помощью этого констрейна требует гораздо меньших вычислительных затрат,
чем при использовании опции Self Collide (у ноды hairSystem) для расчета реальных столкновений
между кривыми.

Примечание. Очевидно, что любой констрейн захватывает только по одной


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

Атрибуты констрейнов
Поскольку все констрейны представляют из себя один и тот же объект с разным значением
атрибута Constraint Method, удобно изучить их немногочисленные атрибуты прямо в Attribute Edi­
tor.

Атрибут Stiffness определяет силу, с которой констрейн действует на точки (это не касается
типа Transform).

Волосы 1287
Чтобы почувствовать различие в степени притяжения, задайте, например, Stiffness=0.01
для Rubber Band или Stiffness=5 для HairBunch.

Самое удивительно, что констрейны умеют «обрываться» при очень сильных воздействиях.
Если атрибут Glue Strength равен единице, это означает, что констрейн суперпрочный и никогда
не порвется. Однако значения меньше единицы означают, что если натяжение (или сила) между
точками и констрейном станет достаточно большим, то связь попросту разорвется, и кривая
вырвется на свободу. Причем насколько это самое «достаточно большим», как раз и определяется
значением атрибута Glue Strength.

Естественно, что атрибут Glue Strength можно анимировать, для симуляции разрыва связей
во время анимации.

Если вас смущает, что в первом кадре констрейн авторитарно захватывает ближайшие к
нему точки, вы можете прекратить этот произвол и самостоятельно задать набор точек с некоторым
значением параметра U, который будет прикреплен к констрейну. Для этого достаточно сменить
метод выбора точек в первом кадре (Point Method). Если выбрать Point Method=U Parameter, то с
помощью атрибута U Parameter можно задать набор точек на кривых с одинаковым значением U,
попадающих под воздействие констрейна.

Симуляция столкновений с помощью констрейнов


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

При «честном» просчете столкновений MAYA вынуждена анализировать каждый полигон


поверхности на предмет взаимодействия с кривыми. Разумно было бы подменить сложную
поверхность на что-нибудь, не требующее такого интенсивного анализа. В роли подмены в
MAYA взяты два примитива: сфера и куб. (Я, кстати, не знаю, почему не были выбраны другие
процедурные примитивы, типа цилиндра или тора, поверхность которых вычисляется по формуле,
а не перебором полигонов. Наверное, предполагалось, что персонаж всегда либо кругло-яйце-
головый, либо же имеет квадратную голову.)

Таким образом, в списке констрейнов еще два типа: Collision Sphere и Collision Cube. Они
позволяют создать для выбранных кривых объект для столкновений. Этот объект сферической или
кубической формы можно передвигать, вращать или масштабировать.

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

Типичный способ применения констрейнов такого типа заключается в том, что после
создания волос для отработки столкновений с телом создается несколько констрейнов типа Colli­
sion Sphere, один из которых имитирует столкновения с головой и располагается в соответствующем
месте, другие масштабируются и размещаются (или даже группируются к скелету) в тех местах,
где расположены плечи.

Все это, конечно, трюки и обман, однако если взять хорошополигональную модель и
выполнить Hair=>Make Collide, просчет столкновений будет происходить мало того, что не быстро,
а порой и несколько «неаккуратно», вынуждая увеличивать значение атрибута Collide Over Sam­
ples и, тем самым, еще более растягивать время просчета динамики.

1288 Книга Сергея Цыпцына


Кроме большей точности и скорости просчета, эти два констрейна имеют еще несколько
преимуществ.

Во-первых, кривые никогда не застревают в них, в отличие от реальных поверхностей.

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

Выбор поверхностей и оптимизация столкновений


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

Во-первых, поверхность, из которой растут кривые, не обязана быть объектом для


столкновений. Это может быть лишь её небольшой скопированный участок, расположенный в
нужном месте.

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


коллизий. Никто, как правило, не увидит, что там происходит под покровом массива волос (если
только вы не делаете рекламу шампуня Head & Shoulders). Используйте «подставки».

Острые грани, открытые края поверхностей, мелкие детали - все это «не по вкусу»
динамике кривых. Избегайте их.

Не торопитесь увеличивать количество сегментов на кривых, используйте Collide Over


Sample со значениями 1 или 2. Это не только сэкономит время просчета, но и сохранит упругость
кривых.

И самое главное. Вместо реальных объектов максимально старайтесь, где это возможно,
использовать констрейны типа Collision Sphere и Collision Cube для просчета столкновений.
Аналогично твердым телам, для просчета соударений можно использовать не реальные
поверхности, а процедурные примитивы (типа куба или сферы), если они примерно воспроизводят
форму поверхности. Просчет таких коллизий происходит в разы быстрее и точнее.

Если также вам надо обеспечить столкновение волос с горизонтальной плоскостью, для
этого не надо создавать геометрию. Для этого достаточно в атрибутах системы волос (hairSystem)
в разделе Collisions включить галку Collide Ground и задать высоту плоскости с помощью атрибута
Ground Height. Просчет столкновений с такой горизонтальной плоскостью не требует никаких

Волосы 1289
дополнительных вычислительных затрат.

Избегайте просчета взаимных столкновений между кривыми (Self Collide). Если же этого
не избежать, старайтесь задавать число взаимодействующих между собой соседних кривых (Num
Collide Neighbors) минимально возможным: начните с двух-трех и увеличивайте, пока не добьетесь
нужного эффекта.

Визуализация системы волос


Перед тем, как приступить к практическим экспериментам с рендерингом кривых, хочу
немного порассуждать о природе системы волос и обозначить методы ее визуализации. Прежде
всего, вы должны понимать, что волосы - объект, мягко говоря, экстремальный. Поэтому для
адекватной работы с ними все время приходится сохранять баланс между их количеством и
производительностью компьютера. Понятно, что смоделировать на экране движение «как в жизни»,
то есть ста тысяч волос, не удастся даже при значительных запасах продовольствия. Поэтому на
экране вы всегда будете оперировать с условной массой волос, а окончательный вариант появится
только после рендеринга. Но рендер - тоже сделан человеком, а потому скармливать ему миллионы
волос было бы несколько негуманно.

Оттого на помощь приходят всяческие специальные технологии просчета большого


количества однотипных объектов. Для MAYA это - система Paint Effects и ее методы визуализации
кривых. Для тех пользователей, которые при слове Paint Effects недовольно сморщат нос и
снисходительно пробурчат: «Ах, это же пост-эффект...», замечу лишь, что этот пост-эффект
на сегодняшний день суть быстрейший способ отрендерить гигантские количества кривых, не
израсходовав при этом оперативную память в первую секунду просчета. Технология Multi Streaks
применяемая совместно с Paint Effects, позволяет увеличить количество волос в десятки раз, без
существенного увеличения времени просчета.

Если кто-нибудь заикнется о честных отражениях или преломлениях, я также замечу, что
для использования алгоритма трассировки лучей, вам придется загрузить в память всю геометрию
волос, то есть данные о количестве вершин, их позиции, цвет и прочие атрибуты, собранные с
пары миллионов волос. Я ничего не имею против против Raytracing, но просто хочу обозначить
следующий момент: волосы - не тот объект, который следует рендерить «в лоб». Существуют
методы легального обмана зрителя, так почему бы их не использовать? Пользователи Renderman
десятилетие жили без преломлений и отражений, при этом обманывали народ качественнее всех,
в то же время считая свои сцены быстрее всех.

Примечание. Плагин Renderman for Maya умеет считать майские волосы как
«родной» объект, не используя пост-эффекты.

Для mental ray уже появились коммерческие разработки сторонних компаний, позволяющие
использовать для визуализации волос так называемый «геометрический материал» (Geometry
Shader). Например, решения от компании Provide3d (смотрите на www.provide3d.com) позволяют
отрендерить не только волосы, создаваемые MAYA Hair, но и штрихи Paint Effects с помощью mental
ray, с использованием всех возможностей этого рендерера.

Примечание. Начиная с седьмой версии MAYA, mental ray также умеет считать
майские волосы как «родной» объект, не используя пост-эффекты.

Различные способы визуализации системы волос


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

Напомню: по умолчанию динамические кривые рендерятся с помощью системы Paint


Effects. Ведь родной майский рендер не умеет рендерить кривые напрямую. Как, впрочем, и

i 290 Книга Сергея Цыпцына


mental ray, встроенный в MAYA: без специальных ухищрений он отказывается визуализировать
кривые. Однако, как правило, визуализировать кривые и не требуется. Вы должны понимать,
что сами сплайновые динамические кривые представляют лишь общую форму системы волос и
предназначенны для определения движения системы волос в целом. Было бы нецелесообразно
размножать количество кривых до двухсот тысяч, чтобы потом их честно отрендерить. Во-первых,
поскольку MAYA не «провернет» такую сцену в окне камеры, а во-вторых, «размножать» кривые
логично уже на этапе рендеринга, чтобы не сохранять, вместе со сценой, огромный массив
данных. Соответственно, в сцене должны храниться базовые динамические кривые и процедурное
описание того, как их следует размножить и визуализировать в процессе рендеринга.

Потому-то первый, наиболее адекватный способ - применение системы Paint Effects,


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

Непосредственный рендеринг кривых


Если с помощью системы волос вы делаете движение, например, набора веревок, тросов
или кабелей, вы наверняка захотите визуализировать их как объекты, со своей текстурой и
освещением. Поэтому самым простым (и довольно тупым) способом будет применение операции
Extrude ко всем кривым и текстурирование всех цилиндрических поверхностей вручную.

Другой способ состоит в применении традиционного трюка для визуализации кривых, как
штрихов Paint Effects (это не имеет отношения к встроенным возможностям системы волос).
Вы берете любую кисть, а затем, выбрав кривые и применив операцию Paint Effects=>Curve
Utilities=>Assign Brush to Curve, визуализируете все сплайновые кривые с помощью наложения на
них выбранной кисти.

Волосы 1291
Далее, если вы исповедуете свою хитрую рендеринг-концепцию, то, вероятно, ваш
сакральный рендерер умеет рендерить кривые непосредственно. Поэтому вы можете получать
различные типы эффектов, на которые этот рендерер способен. Однако даже если вы используете
великий и ужасный Renderman, не спешите генерить полмиллиона волос: одна генерация rib-
файла займет у вас грандиозное время, а его размер будет несколько неудобоваримым. Наверняка
вам придется написать собственную dso-процедуру, для генерации волос «на лету», во время
рендеринга.

Примечание. В ноябре 2005 года на свет появился один из самых ожидаемых плагинов
для MAYA - под названием Renderman For Maya. Основное назначение этого плагина:
дать пользователям MAYA возможность просчитать свои уже готовые сцены с
помощью движка Renderman. Причем главное преимущество этого плагина состоит
в отсутствии необходимости настраивать сцены специально для рендеринга: все
материалы, ноды и объекты поддерживаются по умолчанию (кроме MAYA Fluids).
Не нужно писать материалы или делать конвертацию текстур - достаточно лишь
нажать кнопку «Отрендерить». К моему удивлению и восторгу, Renderman For Maya
прекрасно поддерживает и MAYA Hair и MAYA Fur и Paint Effects, причем не как пост­
процесс, а в основном проходе рендеринга, вместе с остальной геометрией сцены.
Все эффекты, связанные с рейтрейсингом, также поддерживаются для MAYA Hair,
MAYA Fur u Paint Effects. Более того, специально для волос и меха идеально подходит
использование фирменной пиксаровской технологии расчета теней DeepShadow,
отлично работающей с «мохнатыми» объектами.

Стандартная визуализация с помощью Paint Effects


Напомню, что при создании динамических кривых всегда требуется выбрать, что будет «на
выходе» (Output) у системы волос. Имеется три выбора: сплайновые кривые, штрихи Paint Effects
или все вместе(кривые и штрихи). Если вы не знаете заранее, что выбрать, создавайте и кривые
и штрихи: потом всегда можно ненужное удалить, а в процессе работы - спрятать. Но коль скоро
речь идет сейчас о визуализации стандартными средствами, надо обязательно создать штрихи
Paint Effects.

1292 Книга Сергея Цыпцына


Для взрослых. А как быть, если были созданы только кривые, а штрихов Paint Ef­
fects нет? Выхода два.

Первый - более программистский: создать ноду pfxHair и соединить ее нужной связью с системой
волос. Это делается с помощью двух команд:

createNode pfxHair; // Result: pfxHairShape1 //


connectAttr -f hairSystemShape1.outputRenderHairs pfxHairShape1.renderHairs;

Второй - более «гуманный», но менее изящный: достаточно выбрать систему волос (hairSys-
tem) и выполнить операцию Hair=>Assign Paint Effects Brush to Hair. (Об этой операции речь пойдет
позже.) Затем надо выбрать созданную ноду pfxHair, разыскать в Attribute Editor кисть Paint Effects
с названием типа brush1 и удалить ее с помощью кнопки Select и клавиши Delete.

Когда вы создаете систему волос, содержащую штрихи Paint Effects, дополнительно


создается нода типа pfxHair. Ее можно рассматривать как один большой штрих, из которого растут
все волосы. Она имеет практические такие же атрибуты, что и нода типа stroke, которые, впрочем,
вам вряд ли понадобится редактировать. Если проводить аналогию с нормальными штрихами
Paint Effects, то параметры кисти (brush), определяющие внешний вид штриха, встроены в ноду
hairSystem. Поэтому чтобы отредактировать цвет или другие визуальные свойства системы волос,
следует работать с атрибутами самой системы волос в разделе Shading.

Если это все звучит сложно и непонятно, скажем так: просто не обращайте внимания на
ноду pfxHair, но рассматривайте атрибуты в разделе Shading для системы волос hairSystem как
параметры текстуры или материала, определяющего внешний вид кривых.

Откройте уже поднадоевший файл hairCylinderStartCurves.ma, чтобы разобраться с


принципами редактирования внешнего вида системы кривых.

Напомню, что динамические кривые были созданы с помощью операции Create Hair
с параметром Output=Paint Effects and NURBS Curves. А затем штрихи Paint Effects были просто
спрятаны в панели камеры.

Теперь покажите их в панели камеры: Show=>Strokes. А вот сплайновые кривые можно


теперь спрятать, поскольку они задают динамику и анимацию, но не участвуют в рендеринге:
Show=>NURBS Curves.

Далее вся работа будет производиться с атрибутами ноды hairSystem. Поэтому сразу
выберите ее и не закрывайте Attribute Editor.

Волосы 1293
Следует выделить две группы атрибутов, одна из которых отвечает за форму системы
волос, а вторая за их цвет (прозрачность, блик и пр.). Первая группа атрибутов располагается в
разделе Clump and Hair Shape и задает количество волос для визуализации (но не для динамики!),
их толщину, гладкость и другие геометрические свойства. Вторая группа атрибутов находится в
разделе Shading и отвечает за цвет, прозрачность, блик и другие визуальные свойства.

Форма системы волос. Химзавивка


Напомню, что в процессе визуализации, кривые искусственно размножаются, то есть
вокруг каждой динамической направляющей кривой выращивается целый пучок (clump), то есть
семейство кривых. С помощью Paint Effects эти пучки визуализируются на экране практически в
том виде, в котором они будут показаны на финальной картинке.

Количество кривых в каждом пучке определяется атрибутом Hair Per Clump и по умолчанию
равно двадцати.

Совет. Когда волос становится очень уж много, MAYA с большим трудом начинает
«ворочать» их на экране. Чтобы показывать на экране только часть волос, у ноды
hairSystem есть атрибут Display Quality. Он задает в процентах, какую часть общей
массы волос отображать на экране. Используйте круглые значения, типа 10, 25,
50, чтобы адекватно представлять, что на экране находится только четверть
или половина всех волос.

Первое, что бросается в глаза, это «ломаность» штрихов Paint Effects. Ведь они не являются
сплайновыми кривыми, а просто представляют собой набор отрезков-сегментов. Поэтому, если вас
смущает угловатость кривых, установите атрибут Sub Segments в единицу. Это увеличит количество
сегментов вдвое, причем не только на экране, но и на финальной картинке.

Совет. Держите в уме общее количество сегментов для системы волос. Оно равно
общему количеству пучков (то есть числу динамических кривых), умноженному на
число волос в пучке, умноженному также на количество точек в каждой кривой и
дополнительно умноженному на количество подсегментов:
N = Num Curves * Hair Per Clump * (Num Points - 1) * (Sub Segments+1)

Это число определяет «тяжесть» системы волос, аналогично количеству граней для

1294 Книга Сергея Цыпцына


полигональной модели.
За ширину пучков отвечает атрибут Clump Width. Увеличьте его до 0.3, и вы получите
довольно плотную массу кривых.

Собственная ширина кривых (Hair Width) на экране никак не отображается и настраивается


уже в процессе рендеринга. Ее удобно настраивать в последнюю очередь, после определения
всех остальных атрибутов.

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

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

Сделать пучки не цилинлрическими, а плоскими можно с помощью атрибута Clamp Flat­


ness. Просто для него установите значение Selected Value в единицу и основания пучков станут
плоскими, как и сами пучки.

Напомню, что все атрибуты типа графиков (Clump Width Scale, Hair Width Scale, Clump Curl,
Clump Flatness) дают распределение свойства вдоль длины волос. Слева находятся основания
кривых, справа - их концы. Поэтому вы можете задавать произвольное изменение толщины пучков
и самих волос вдоль их длины.

Волосы 1295
Остальные атрибуты легко исследуются по аналогии, «методом тыка». Например, для
создания химзавивки следует поколдовать с атрибутом Clump Curl. Следует также помнить об
установленной упругости кривых (Stiffness), которая тоже влияет на форму прически.
К этим атрибутам я еще вернусь, на более «персонажном» примере. А сейчас перейдем к
визуальным характеристикам волос.

Да, чуть не забыл про раздел Displacements! Если вы хотите поиздеваться над формой
волос с помощью всяких бигудей-завитушек (Curl) или просто хотите «помять» волосы (Noise) и
придать им малоухоженный вид, вам никак нельзя пропускать этот раздел. К счастью, атрибутов в
нем немного и разобраться с ними не так уж сложно. Обратите внимание: в отличие от атрибутов
из раздела Hair Shape and Clump, эти деформации воздействуют на индивидуальные кривые, а не
на пучки целиком.

Цвет волос. Мелирование и прочие глупости


Все цветовые характеристики системы волос определяются атрибутами из раздела Shading.

Основной цвет волос задается атрибутом Hair Color. Для изменения основного цвета вдоль
длины волос используется атрибут Hair Color Scale, значение которого просто умножается на Hair
Color. Как правило, Hair Color Scale это черно-белый градиент, который определяет изменение

1296 Книга Сергея Цыпцына


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

Для создания эффекта полупрозрачности и проникания света внутрь массы волос


используется атрибут Translucence. А блики задаются соответствующими атрибутами: Specular
Color и Specular Power.

Как ни банально, но именно в разделе Color Randomization находятся атрибуты,


позволяющие немного «перемешать» цвет среди общей массы волос и добавить случайности в
цветовые характеристики.

Самозатенение и трюки по освещению волос я обсужу позже, а сейчас несколько замечаний


по поводу текстур.

Волосы и текстуры цвета


При попытке наложить текстуру на любой из атрибутов из раздела Shading вас, очевидно,
ждет неудача. Сделать поперек полосатые волосы с помощью текстуры Grid, назначенной на
атрибут Hair Color, просто не получится. Волосы не рассматриваются как объект для безумного
текстурирования. Если вам все же очень приспичит положить любимую текстуру вдоль длины
волос, для этого надо сконвертировать волосы в обычные (или почти обычные) штрихи Paint Ef­
fects и текстурировать их стандартными средствами Paint Effects с оговорками, изложенными в
следующем разделе. Операция конвертации волос в штрихи Paint Effects называется Hair=>Assign
Paint Effects Brush to Hair и будет описана ниже.

Если же озадачиться текстурированием волос не вдоль длины, а вдоль поверхности, из


которой они растут, то придется немного поработать, и даже, как это ни прискорбно, подумать
(результаты размышлений можно найти в разделе «Наследование цвета с текстуры»). Дело в том,
что пытливые умы наверняка помнят: у меха (в MAYA Fur) была отменная кнопка Bake, которая
запросто забирала цвет с текстуры и раскидывала его на мех вдоль поверхности, на которой этот
мех произрастает.

Для волос ничего подобного, по умолчанию, нет, однако у каждой динамической кривой
(определяющей пучок) есть индивидуальные атрибуты. Это прежде всего атрибуты Color Blend
и Color в разделе Render Overrides. Напомню, что добраться до индивидуальных свойств можно
через Hair=>Convert Selection=>to Follicles. Таким образом, у каждого пучка могут быть свои,
«персональные» свойства. Причем атрибут Color Blend определяет, насколько сильно используется
индивидуальный цвет пучка, то есть он определяет степень смешивания общего и индивидуального
цветов.

Волосы 1297
Так что если вы хотите создать отдельные прядки радикально иного цвета или мелировать
отдельные пучки, потребуется добраться до индивидуальных атрибутов отдельных динамических
кривых (которые содержатся в ноде типа follicle, описанной выше) и вручную задать им нужный
цвет и даже толщину. И еще - не забыть установить атрибут Color Blend в единицу.

Здесь хорошую услугу может оказать инструмент Paint Hair Tool. Достаточно выбрать
поверхность, на которой растут волосы, затем взять в руки Hair=>Paint Hair Tool. Затем установить
режим рисования Paint Mode=Edit Follicle Attributes, а в качестве атрибута выбрать Follicle
Attribute=Color Blend. В этом случае станет доступным поле Follicle Override Color, где можно
выбрать индивидуальный цвет волос.

Надо не забыть установить при этом значение Value=1 в параметрах Tool Settings самого
инструмента рисования.

Примечание. В седьмой версии MAYA появилась возможность рисовать текстуру


для цвета волос прямо на поверхности. Причем назначить собственную текстуру
на цвет волос «вдоль» поверхности вы можете, только нарисовав любую
временную текстуру, а затем подменив в соответствующей ноде имя файла.
Могу посоветовать выбирать этот инструмент рисования только через меню
Hair=>Paint Texture Color=>Hair Color, а не через Toolbox или горячие клавиши. Он
довольно капризный и требует выбора системы волос перед рисованием.

Визуализация волос с помощью кистей Paint Effects


Прежде чем переходить к более «персонажным» волосам, я бы хотел завершить
«веревочный» пример рассказом о том, как рендерить систему волос с помощью штрихов Paint
Effects, добиваясь при этом довольно забавных эффектов. Попробуем наложить на волосы какую-
нибудь растительную кисть, типа лианы, чтобы визуализировать наши веревки в виде ползучих
растений.

1298 Книга Сергея Цыпцына


Откройте в последний раз пример с веревками hairCylinderStartCurves.ma.

Покажите штрихи Paint Effects в панели камеры и спрячьте кривые: Show=>Strokes;


Show=>Nurbs Curves.

Выберите систему волос hairSystem1 и задайте для нее атрибуты: Hair Per Clump=1, Clump
Width=0.

Это создаст пучки нулевой толщины, состоящие из одного волоса.

Теперь выберите кисть из библиотеки: Paint Effects=>Get Brush.


Откройте раздел Plants и укажите на кисть fernOrnament.mel.

Этого достаточно, чтобы кисть стала последней выбранной кистью. Теперь можно выбрать
Select Tool, чтобы случайно ничего не нарисовать.

Выберите систему hairSysteml и выполните операцию Hair=>Assign Paint Effects Brush to


Hair. Это превратит каждую кривую в штрих Paint Effects и назначит последнюю выбранную кисть
(fernOrnament) на каждый штрих.

Проблема, однако, состоит в том, что растения растут как бы «из» кривых, а не вдоль

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

Чтобы добраться до атрибутов кисти, выберите объект pfxHair1.

После выполненной операции у него в Attribute Editor появится закладка fernOrnamentl,


содержащая атрибуты кисти.

Откройте раздел Tubes=>Creation и установите Tubes per Step=0; Tube Rand=0 и Start Tubes=1.
Это гарантирует, что из основания кривой будет расти ровно одно растение.

Чтобы удлинить стволы, задайте Length Min=Length Max=4. А чтобы подогнать общий размер
под длину кривых, используйте атрибут Global Scale=3.5.

Чтобы «прижать» поплотнее стволы к исходным кривым, надо открыть раздел


Tubes=>Behaviour=>Forces и увеличить значение атрибута Path Follow до единицы. Это заставит
растения следовать вдоль штрихов, которыми являются исходные кривые.

Проделанные действия позволяют примерно подогнать под форму кривой любую кисть,
содержащую Tubes. Следует помнить, что все деформации (Displacements) или турбулентность будут
отталкивать растения от исходных кривых, поэтому всегда проверяйте значения соответствующих
атрибутов.

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

1300 Книга Сергея Цыпцына


Улучшения которые могут быть сделаны для этой сцены заключаются в следующем:
Увеличьте немного ширину стволов: Tubes=>Creation=>Tube Widthl =0.05; Tube
Width2=0.03.
Откройте Tubes=>Grow=>Leaves и установите Num Leaf Clusters=20; Leaf Start=0.1.
Перейдите в раздел Shading=>Tube Shading и задайте Root Fade=0, чтобы избежать
прозрачности в основаниях.

И в заключение этого раздела приведу несколько замечаний про влияние атрибутов


системы волос на свойства штрихов Paint Effects. Прежде всего замечу, что после операции As­
sign Paint Effects Brush to Hair все кривые системы волос становятся штрихами, из которых и
произрастают все эффекты.

Ширина кисти (Brush Width) игнорируется и вместо нее используется толщина волос (Hair
Width).

Вместо цвета кисти (причем только вместо цвета основания Color1) используется цвет
волос Hair Color. Аналогично и остальные атрибуты из раздела Shading системы волос (Specular

Волосы 1301
Color и др.) заменяют соответствующие свойства кисти из раздела Illumination.

Как я уже упоминал, если вы хотите, чтобы вдоль каждой кривой произрастал только один
ствол (Tube), всегда ставьте Tubes per Step=0; Tube Rand=0 и Start Tubes=1.

Также используйте Elevation Min/Max=0 и не забудьте «прижать» ствол к кривой с помощью


Path Follow.

Длину произрастающих стволов подруливайте с помощью Length Min/Max, а общий размер


задавайте через Global Scale.

И последнее: если вы вдруг захотите отрендерить кривые как бамбуковые палочки или
как макароны с помощью обычных штрихов Paint Effects (с выключенными Tubes), то не забывайте
про толщину (Hair Width), и кроме того вам наверняка придется увеличить атрибут RepeatU раз в
десять-двадцать, чтобы получить тот же вид, что и для оригинальной кисти.

На этом заканчиваю работу с веревочным примером и перехожу к персонажной волосатости,


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

Традиционное применение MAYA Hair


Под традиционным применением я понимаю создание и анимацию волос для персонажа.
Работу с таким применением MAYA Hair можно разбить на несколько этапов. Это прежде всего
создание системы волос. Затем идет укладка, стрижка, причесывание в общем придание волосам
нужной формы. Следующим этапом может быть анимация, если она необходима. Визуализация
естественно завершает работу с таким безумным объектом, как волосы. Если некоторые аспекты
анимации и визуализации я уже обсудил выше, то создание волос и работа с прической требуют
отдельных комментариев.

Создание волос
Первый этап - создание волос. Назовем это созданием, чтобы не путать его со следующим
этапом: моделированием и причесыванием. Дело в том, что главный способ создания волос (во
всяком случае, он по списку первый в меню) предполагает создание волос одним махом, как
некое засеивание поверхности растительностью. Возникающую шапку волос надо будет причесать
и уложить на следующем этапе. Процесс укладки - дело архи-непростое, поэтому старайтесь
сразу создавать волосы так, чтобы они максимально напоминали по форме ту прическу, к которой
вы стремитесь. Для этого существует некоторое количество альтернативных способов создания

1302 Книга Сергея Цыпцына


волос.

Один из традиционных способов - просто смоделировать руками основные направляющие


кривые, определяющие форму прически. Сделать это можно, предварительно создав лишь
несколько динамических «волосин» и отредактировав их начальные положения. Затем можно
применить метод пассивного заполнения (Create Passive Follicles) всей оставшейся поверхности
кривыми, повторяющими среднюю форму направляющих кривых. Таким образом, сначала
создается каркас, а затем он плотно наполняется нужным количеством волос.

Более интеллигентный способ заключается в использовании инструмента Paint Hair


Tool. С его помощью можно нарисовать волосы, то есть «засеять» поверхность волосами только
в местах покраски. Этот же инструмент также позволяет использовать кисти для «выбривания»
(или эпиляции) волос с ненужных участков поверхности. Причем делает это безболезненно и не
требует специальных ухищрений, кроме знания принципов работы с кистями Artisan.

Другой способ создания уже почти причесанных волос заключается в превращении


штрихов Paint Effects в кривые. Если вы уже поднаторели в создании причесок с помощью Paint
Effects и тщательно изучили многочисленные упражнения о том, как их выращивать с помощью
кистей, у вас наверняка возникнет мысль: а не сконвертировать ли такие, процедурные волосы
в обычные кривые и не использовать ли их для дальнейшей анимации? Часть пользователей,
измученная отсутствием системы волос в первых пяти версиях MAYA, научилась довольно ловко
делать прически с помощью системы Paint Effects. Было бы неразумно отбрасывать накопленный
опыт и заготовки, поэтому попросите знакомого скриптописателя написать небольшой код для
конвертации штрихов Paint Effects в обычные кривые или используйте недавно появившийся пункт
меню Modify=>Convert=>Paint Effects to Curves.

Еще один, довольно экзотичный способ заключается в испускании частиц с нужной области
поверхности. Затем с помощью полей и expressions траектории частиц настраиваются так, чтобы
они напоминали форму будущих волос. С помощью небольшого скрипта траектории нужного
количества частиц превращаются в кривые. При необходимости они могут быть дополнены
дополнительными пассивными кривыми. Некоторое количество таких скриптов можно найти на
сайте www.highend3.com. Мне встречалась одна статья в Интернете об использовании динамики
движения жидкости для придания формы волосам. С помощью такого подхода можно использовать
динамику флюидов для задания движения частиц, а траектории последних использовать как ворму
волос. Понимаю: звучит несколько патологически... Но следует помнить: волосы - объект тоже не
совсем нормальный.

Непосредственно перед созданием кривых вы должны продумать ряд моментов, которые


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

Прежде всего определитесь, каким способом вы будете рендерить окончательные кривые.


Будет ли это встроенная визуализация с помощью Paint Effects или написание собственных
шейдеров для просчета в mental ray или Renderman. От решения этого вопроса зависит, нужно ли
вам создавать динамические кривые как объекты или достаточно ограничиться представлением в
виде Paint Effects.

Практическое создание прически


Разберем основные особенности использования Paint Hair Tool для создания системы волос
в нужных местах персонажа - в частности, на голове.

Откройте файл HeadModel.ma. Никаких проблем с UV-координатами возникнуть не должно,


так как модель сплайновая. Особенности подготовки полигональных моделей к пересадке волос я
описал выше.

Волосы 1303
Если попытаться создать систему волос на поверхности с помощью операции Create Hair,
то придется долго избавляться от ненужных волос в различных участках головы. Поэтому куда
логичнее и проще использовать Paint Hair Tool.

Выберите поверхность и выполните Hair=>Paint Hair Tool.

По умолчанию режим рисования установлен в создание новых волос на поверхности: Paint


Mode=Create Follicles.

Так как поверхность параметризована неравномерно, увеличьте плотность волос в


направлении U: Follicle Density=40.

К сожалению, никакой рандомизации расположения волос не предусмотрено, поэтому в


результате покраски будет создаваться равномерная сетка из кривых на поверхности.

Задайте длину волос Hair Length=10.

Количество точек на кривых равно всего шести, но мы можем изменить его позже.

Покрасьте поверхность в тех местах, где, по вашему мнению, могут произрастать волосы.
Пользуйтесь активно Undo, а также для удаления ненужных кривых переключайтесь в режим
удаления Paint Mode=Delete Follicles, чтобы избавиться от конкретных ненужных кривых.

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


сохраняйте результат борьбы с Paint Hair Tool. Я сохранил его как headModelHairStart.ma.

i 304 Книга Сергея Цыпцына


Любопытствующие умы могут тут же включить анимацию и пронаблюдать движение упругих
проволок на голове персонажа. Очевидно, упругость по умолчанию слишком велика.
Выберите объект hairSystem1 и в Attribute Editor откройте раздел Dynamics и установите Stiff-
ness=0.03.

Чтобы анимация проигрывалась в разы быстрее, установите Hair Per Clump=1.


Не забывайте: нас сейчас интересует поведение в целом, а не внешний вид.

Сейчас очень важно задать поверхность для взаимодействия с кривыми: очевидно, волосы
не должны проникать в голову. Если попытаться сделать это позже, то, возможно, некоторые
кривые уже таки проникнут в поверхность - в результате безумных экспериментов с динамикой
и борьбы за прическу. Они, эти кривые, будут, конечно же, застревать в поверхности и начнут
всячески портить вам нервы. Поэтому создадим поверхность для отталкивания кривых прямо
сейчас.

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

Выберите объект hairSystem1 и выполните операцию Hair=>Convert Selection=> to Follicles,


так как создание констрейна требует предварительного выбора кривых.

Затем выполните Hair=>Create Constraint=>Collide Sphere.

Волосы i 305
Это создаст сферу для столкновений - для всех кривых.

Задайте размеры сферы (scale = 5.67; 5.0; 6.5) и ее положение (translate = 0.01; 8.2; 2.75).
К точной настройке размеров мы вернемся позже, а сейчас сохраните сцену (headModeHairCre-
ated.ma).

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

Стрижка, укладывание и прическа


Со стрижкой волос все, более-менее, ясно: для глобальной работы с длиной кривых можно
использовать Scale Hair Tool. Для индивидуального подстригания можно применять Paint Hair Tool
в режиме Paint Mode = Trim Hair/Extend Hair.

А вот процесс укладки и создания причесок - это пока что довольно слабое место у MAYA
Hair. Существует некоторое количество методик и приемов, но все они скорее напоминают трюки
и ухищрения - они имеют мало общего с привычными инструментами парикмахера. Но если уж с
помощью Paint Effects было создано немало причесок, то все же с нынешним инструментарием
жизнь стала еще лучше.

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


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

Во-вторых, создание констрейна типа Transform позволит взять кривые в произвольном


месте и перетаскивать их в нужное положение прямо во время анимации (при использовании
Interactive Playback). Такой подход напоминает создание прически в реальном времени. Другие
типы констрейнов также могут быть использованы. После остановки анимации нужно выполнить
операцию Hair=>Set Start Position=>From Current, чтобы сохранить результат моделирования.

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

По моему опыту, следует быть максимально бесцеремонным и таскать модель за волосы


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

Встаньте в первый кадр и выберите сначала объект hairSystem1, а затем концы всех
стартовых кривых: Hair=>Convert Selection=>to Start Curves End CVs. Возьмите в руки Move Tool,
затем нажмите и удерживайте клавишу «I» для фиксации длины кривых.

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

Оттащите концы стартовых кривых немного назад, не допускайте обратного движения,


тащите только в одну сторону. Если руки дрогнут, откройте сцену еще раз и пробуйте снова - пока
не получится.

1306 Книга Сергея Цыпцына


Далее сожмем концы волос в пучок.
Нажмите Insert (клавишу «I» можно пока отпустить) и оттащите pivot выделения назад, в
район последних концов кривых. Снова нажмите Insert.

Возьмите Scale Tool, затем снова нажмите «I» и сожмите одним (!) уверенным движением
концы к центру.

Сохраните сцену немедленно.

Совет. Перемещать можно не только концевые точки кривых. Выбрав концы,


можно нажимать стрелки вправо-влево, чтобы селектировать и перемещать
ряды внутренних точек на кривых.

Помните, что редактировать можно только стартовые или остаточные кривые.


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

Волосы i 307
Первое, что бросается в глаза: у кривых довольно мало сегментов и оттого они выглядят
излишне упругими и жесткими.

Увеличим количество точек на кривых.

Выберите объект hairSystem1 и выполните Hair=>Convert Selection=>to Follicles.


Откройте Channel Box и задайте для всех выбранных кривых Sample Density=3.
После этого количество точек и сегментов на всех кривых утроится, и, следовательно, они
станут более гибкими.

Примечание. Обратите также внимание, что стартовые кривые (Start Curves)


остались прежними, то есть сохранили первоначальное количество точек.
Атрибут Sample Density влияет только на динамические кривые (Current Curves).
Это в определенной степени хорошо, так как довольно удобно редактировать
стартовые кривые с небольшим количеством точек, а наблюдать движение
на более подробных динамических кривых. Если все же вам хочется увеличить
разбиение именно стартовых кривых, воспользуйтесь для них операцией Rebuild
Curves. А еще лучше установите Sample Density=3, а затем сохраните текущее
положение в первом кадре как стартовое (Hair=>Set Start Position=>From Current) и
тут же установите обратно Sample Density=1.

1308 Книга Сергея Цыпцына


Все-таки нас немного смущают основания кривых. Они пытаются удерживаться
перпендикулярно поверхности. Возможно, иногда это довольно полезно, но сейчас изменим такое
поведение.

В Channel Box установите для всех выбранных кривых Start Direction=Start Curve Base, чтобы
основания волос повторяли форму стартовых кривых, а не торчали по нормали к поверхности.
Теперь волосы довольно безвольно падают вниз и повисают, как веревки. Им немного не хватает
формы и упругости. Для придания некоторой воздушности и наполненности воспользуемся
остаточными кривыми (Rest Curves). Это достаточно стандартный и действенный трюк для
удержания волос в определенной форме. Напомню, что остаточные кривые определяют положение
и форму, к которой стремятся волосы при отсутствии сильных воздействий и динамических полей.
Первый трюк состоит в том, чтобы определить остаточные кривые идентичными стартовым кривым
в данный момент. Сделаем это и посмотрим, как это можно использовать.

Если все кривые до сих пор выбраны (если нет, используйте, как обычно, Hair=>Convert
Selection=>to Follicles), выполните операцию Hair=>Set Rest Position=>From Start.

Запустите анимацию сначала при этом особых отличий в падении волос не видно.
Напомню, что степень стремления волос к остаточным кривым определяется их упругостью.
Поэтому выберите hairSystem1 и поиграйте с атрибутом Stiffness прямо во время анимации.
При значениях Stiffness около 0.3, волосы немного приподнимаются и приобретают
некоторую форму.

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

Пытливые умы наверняка заметят небольшой «всплеск» (или «толчок») в районе оснований
волос в начале анимации. Это может быть связано с размером сферы для столкновений (Collide
Sphere), точнее с тем, что в первом кадре некоторые основания кривых попали внутрь сферы и
стремительно выталкиваются наружу. В данном случае это не очень большая проблема, так как
волосы все равно занимают нужную позицию. Однако в случае необходимости избавиться от такого
толчка можно проделать следующие действия. В первом кадре надо немного сжать сферу так,
чтобы основания кривых не попадали внутрь нее и поставить ключ на размер (Scale) сферы. Затем
запустить интерактивную анимацию (Solvers=>lnteractive Playback) и прямо во время проигрывания
увеличить сферу до прежних (или до нужных) размеров. После этого можно остановить анимацию
и снова поставить ключ на Scale сферы.

Волосы -J3Q9
Примечание. Вы можете управлять трением кривых о сферу через атрибут Fric­
tion. Установите его в единицу, если вам кажется, что волосы скользят по сфере
слишком быстро.

Примечание. В седьмой версии MAYA появился чудовищно полезный атрибут под


названием Start Curve Attract. Он находится в разделе Dynamics и определяет,
насколько текущие кривые стремятся «притянуться» к стартовым кривым. Если
этот атрибут равен нулю, то эффекта притяжения нет, а если равен единице, то
текущие кривые намертво прилипают к стартовым кривым. Степень притяжения
вдоль кривой изменяется в соответствии с кривой Stiffness Scale, так что вы без
труда можете делать кончики более гибкими и «свободными», а основание более
жестким. Использование этого атрибута (анимируемого, притом!) позволяет
избежать многих ухищрений с применением Rest Curves, а также легко делать
жесткие волосы без необходимости увеличивать Stiffness и, следовательно, Itera­
tions, то есть время просчета динамики.

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

Проиграйте анимацию примерно до пятисотого кадра, пока волосы не успокоятся на своих


местах. Выберите кривые (Hair=>Convert Selection=>to Follicles) и выполните операцию Hair=>Set
Start Position=>From Current.

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

Все дело в коварном атрибуте Sample Density, значение которого равно трем. Как только
мы сохранили текущее положение как начальное, все стартовые кривые унаследовали количество
точек с текущего положения. Соответственно, количество точек на стартовых кривых утроилось,
однако значение Sample Density для всех кривых по-прежнему осталось равным трем, поэтому
количество точек на самих волосах еще раз утроилось. Нужно лишь не забыть немедленно вернуть
Sample Density в единицу после определения нового стартового положения кривых.

Выберите hairSystem1, затем Hair=>Convert Selection=>to Follicles, и в Channel Box задайте


Sample Density=1.

Примечание. Количество сегментов на остаточных кривых осталось прежним.

1310 Книга Сергея Цыпцына


Теперь кривые остаются в покое.

Сохраните сцену (headModelHairDress.ma).

Если вас смущает ширина прически (височные области), выберите сферу hairConstraintl и
уменьшите ее размер вдоль оси X (scaleX=5.2).

Не забудьте снова выбрать кривые (Hair=>Convert 5election=>to Follicles) и выполнить


операцию Hair=>Set Start Position=>From Current.

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


Имеет смысл выбирать отдельные кривые и редактировать их длину и, может быть, упругость.
Ничто не мешает воспользоваться приведенным выше бесцеремонным подходом и отредактировать
форму стартовых кривых вручную.

Пассивные кривые. Увеличение густоты прически


Существует два способа увеличивать густоту волосяного покрова.

Первый состоит в увеличении густоты самих пучков, повторяющих форму динамических


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

Поэтому второй способ состоит в увеличении количества волос при помощи пассивных
кривых (Passive Curves). Такими кривыми можно дополнительно «засеять» поверхность между уже
существующими динамическими кривыми. Основная особенность пассивных кривых - в том, что их
не надо анимировать динамикой: они лишь повторяют форму соседних, динамических (активных)
кривых. Их главное преимущество - что их форму не надо моделировать: она автоматически
получается, за счет усреднения формы соседних кривых. Второе преимущество: на просчет их
формы не надо тратить дополнительное время. Их можно отдаленно сравнить с промежуточными
формами blendShape между соседними активными кривыми.

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

Выберите поверхность и возьмите в руки Hair=>Paint Hair Tool. В качестве режима рисования
выберите заполнение пассивными кривыми: Paint Mode=Create Passive Follicles.
Задайте плотность заполнения в два раза больше, чем при предыдущем рисовании, то есть Follicle

Волосы 1311
Density U=80, Follicle Density V=40.

Покрасьте поверхность между существующими кривыми. Помните, что удалить ненужные


или случайно нарисованные кривые можно с помощью Paint Operation=Delete Follicles.

Появляющиеся в результате пассивные кривые будут принимать форму соседей и ловко


заполнять пространство между уже имеющимися волосами.

Визуализация. Настройка формы волос


Настройка внешнего вида волос является довольно нервным этапом, так как действовать
приходится зачастую вслепую. Хотя штрихи Paint Effects довольно точно передают форму прически
вплоть до отдельных волос, но при увеличении их числа до реального количества волос, компьютер
начинает проситься на перекур и никакой апгрейд (по крайней мере в ближайшие пару лет) не
может помочь.

Прежде чем приступить к рендерингу создайте два источника света: основной, direc-
tionaLight (rotate=-10; 10; 0; lntencity=1.4), и заполняющий, pointLight (translate=15; 5; 5; Intenc-
ity=0.5).

Выберите hairSystem1 и задайте Hair Per Clump=20.


Сделайте пробный рендер.

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

Установите Sub Segments=1. Это удвоит количество сегментов при просчете.


По умолчанию пучки волос сужаются к концам. Для мокрых волос это подходит хорошо,
однако нам это не нравится.
Задайте Clamp Width Scale так, чтобы пучки имели равную толщину по все длине.

1312 Книга Сергея Цыпцына


Ширина пучков (Clump Width) является очень важным параметром. Интуитивно понятно,
что пучки должны слегка «перекрываться» по толщине (если только вы не делаете «дреды» или
косички). В тоже время, они не должны быть слишком толстыми, чтобы сохранять густоту и
форму.

Задайте пока Clump Width=0.4.

После увеличения количества сегментов ваша машина (точнее, видеокарта), возможно,


начнет подтормаживать.

Я обычно использую следующий трюк, чтобы не прятать волосы (штрихи Paint Effects) с
экрана совсем, через Show=>Strokes: я выбираю объект hairSystem и устанавливаю атрибут Display
Quality в очень маленькое значение от единицы до пяти. Это позволяет видеть общую форму
прически и в то же время не тормозит интерактивное отображение.

Просчитайте картинку.

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

Во-первых, обычно не хватает визуальной густоты около оснований волос, хотя общая масса
выглядит довольно пристойно. Эту проблему можно решить соответствующим текстурированием
той части поверхности, на которой растут волосы. Например, вы может отрендерить только
волосы (без поверхности) в виде сверху, а потом наложить (как проекцию) это изображение на
поверхность (на один из слоев канала цвета), чтобы закрасить волосистую часть поверхности
текстурой, максимально похожей на сами волосы.

Во-вторых, можно увеличить густоту волос только на граничных областях, там, где сквозь
них просвечивает поверхность. Сейчас мы этим и займемся.
Выберите поверхность и возьмите Hair=>Paint Hair Tool.
Последний использованный режим должен быть Paint Mode=Create Passive Follicles.
Увеличьте плотность заполнения по V: Follicle Density V=80, затем уменьшите радиус кисти
и прокрасьте только переднюю границу волосяного покрова над лбом, затрагивая только два
первых ряда.

Теперь можно уменьшить ширину пучков для задания большей густоты: Clump

Волосы 1313
Width=0.25.

Чтобы волосы выглядели не таким грубыми, уменьшим их толщину: Hair Width = 0.005.
После этого надо обязательно увеличить качество антиалайзинга, так как при работе с такими
тонкими объектами неизбежно появление артефактов.

Откройте Render Global.

В закладке Maya Software в самом низу откройте раздел Paint Effects Rendering Options и
включите опции Oversample и Oversample Post Filter.

Закройте Render Globals.

Установите Hair Per Clump = 50 и запустите рендер.


Выпейте чашку чая, расслабьтесь.

Если вас смущают супертонкие концы волос, вы можете отредактировать их форму через
атрибут Hair Width Scale и сделать их потолще.

Немного поработаем над цветом и бликом. В разделе Shading атрибут Hair Color Scale no
умолчанию задает потемнение цвета ближе к основанию волос, имитируя самозатенение и эффект
выгоревших волос ближе к концам.

Установите его полностью белым, чтобы цвет волос не изменялся вдоль длины, а тени мы
настроим в следующем разделе.
Увеличьте Specular Color примерно до половины и задайте «жесткий» блик Specular Power=10.

Чтобы волосы не были такими «правильными», немного «помните» их.


В разделе Displacements задайте Noise=5 и Noise Frequency=1. Впрочем, любители гладких
причесок могут и не «портить» волосы.

Совет. Легкий «шум» в форме волос помогает бороться с просветами между


волосами. Он также придает немного искусственной густоты.

Просчитайте картинку.

Визуализация. Настройка освещения


Чтобы улучшить внешний вид волос, необходимо, очевидно, чтобы они отбрасывали тени,
в том числе на самих себя. Так как волосы визуализируются с помощью штрихов Paint Effects, то
речь, естественно, идет от тенях типа Depth Map. При настройке теней для волос есть несколько
особенностей, разберем их настроив тени для основного источника света.

1314 Книга Сергея Цыпцына


Выберите directionalLightl и в разделе Shadows включите опцию Use Dmap Shadows.

Так как штрихи Paint Effects не являются поверхностями, то метод Use Mid Dist Dmap для
них не работает, и эту опцию необходимо выключить (Use Mid Dist Dmap=Off).

Кроме того, волосы довольно тонкие объекты, для них требуется довольно высокое
разрешение карт теней.

Установите Dmap Resolution=2048.

Цвет тени Shadow Color сделайте серым, а не чисто черным.


Просчитайте изображение.

О ужас! Все покрылось не то сажей, не то мраком. А дело в том, что при выключенной
опции Use Mid Dist Dmap надо вручную настроить «отступ» начала тени от объекта, иначе тень от
поверхности будет видна на самой поверхности, как это и видно на иллюстрации.

Сдвиньте начало тени от объекта, задав Dmap Bias=0.1.


Дополнительно, чтобы тени не были такими жесткими, задайте Dmap Filter Size=5 это их
немного «размоет».

Волосы 1315
Просчитайте изображение.

Примечание. Еще одним жесткое ограничение для вычисления теней - в области


генерации теней должна быть хоть одна небольшая поверхность отбрасывающая
тени, иначе тени от волос не будут вычисляться. Область генерации теней
для разных типов источников света может различаться. Если для Spot Light это
конус, то для point Light - это шесть пирамид, направленных по осям локальной
системы координат, в каждой из которых должна присутствовать часть реальной
поверхности, отбрасывающей тени.

Таковы основные особенности настройки освещения для волос. Не забывайте размывать


тени и не используйте резко черный цвет.

Сохраните сцену (headModelHairDressForRender.ma).

Глобальное удлинение
Предположим, что вам резко захотелось удлинить всю прическу целиком. Например, чтобы
посмотреть, как она выглядит с новоиспеченным шейдингом и освешением. Приведу пример
одного из возможных путей сделать это. Так как заниматься покраской поверхности с помощью
Paint Hair Tool в режиме Paint Mode=Extend Hairs совсем не хочется, попробуем удлинить напрямую
стартовые кривые с помощью стандартных средств сплайнового моделирования.

Выберите hairSystem1, затем выполните Hair=>Convert Selection=>to Start Curves.

Перейдите в режим моделирования и откройте Option Box операции Edit


Curves=>Extend=>Extend Curves.

Задайте Extension Type=Extrapolate, Distance=10.

Нажмите Extend.

Стартовые кривые удлинятся, а вместе с ними вытянутся и сами волосы. Не забудьте


включить отображение волос, а заодно - всех кривых: Hair=>Display=>All Curves.
Запустите анимацию. Волосы подпрыгнут вверх как ужаленные.

1316 Книга Сергея Цыпцына


Очевидно, удлиненные волос продолжают стремиться к остаточным кривым (Rest Curves),
торчащими по-прежнему назад. Успокоим волосы, задав остаточным кривым форму стартовых
кривых.

Вернитесь в первый кадр. Выполните операцию Hair=>Set Rest Position=>From Start.


Запустите анимацию. Волосы мягко опустятся вниз.

Сохраните это положение как начальное. Можете немного потрясти головой (нет не своей,
a Original_Head), поставив несколько ключей на повороты поверхности.

Просчитайте изображение.

Если вас смущают горизонтальная граница тени на концах волос, вам необходимо еще
немного настроить атрибуты тени у источника света.

Выберите источник света directionalLight1 и снимите опцию Dmap Auto Focus, и задайте
значение атрибута Dmap Width Focus=35, чтобы вручную задать область пространства, в которой
генерится карта теней.

Волосы 1317
Концы волос имеет смысл немного «проредить», а то они обрываются резко и в точности
повторяют форму пучков. Это можно сделать увеличив до 0.5 значение атрибута Thinning для
системы волос hairSystem1. Можете убрать также шум (Noise=0) и посмотреть, что получится.
Просчитайте изображение.

Я оставляю за кадром вопрос создания дополнительных констрейнов типа Collide Sphere,


чтобы волосы не проваливались в скулы и другие части лица модели. В принципе можно выбрать
всю поверхность и выполнить Hair=>Make Collide. Все эти эксперименты вы легко можете выполнить
самостоятельно. Не забывайте только про особенности просчета столкновений, обсуждавшиеся в
первой части этой главы, на «веревочном» примере.

Сохраните сцену (headModeHairDressRenderLong.ma).

Практические методы увеличения визуальной густоты волос


и экономии вычислительного времени
Немного подытожу разные трюки для придания визуального объема волосам. Это касается
только тех случаев, когда вы несколько ограничены в вычислительных мощностях. Если вы
вооружены компьютером будущего и не знаете, что такое ожидание, пропускайте этот раздел.
Прежде всего экономьте активные кривые. Не создавайте их слишком много, это затормозит
просчет динамики и притупит чувство реальности/нереальности анимации.
По этой же причине заполняйте пространство между активными пучками с помощью
пассивных кривых. Это ускорит анимацию и упростит ее отладку.

Когда кривых слишком много, имеет смысл не использовать NURBS Curves в качестве
представления волос. Применяйте Output=Paint Effects, задавайте Hair Per Clump=1 и Clump Width=0
для визуального контроля. Не забывайте про Display Quality. Штрихи Paint Effects отрисовываются
на экране в разы быстрее, чем кривые.

Самые «тяжелые» параметры - это Hair Per Clump и Sub Segments, поэтому старайтесь
держать их минимальными, добиваясь густоты другими методами.

В разделе Multistreaks можно задать эффективное «размножение» волос только на


этапе рендеринга, причем не требующее сильного увеличения времени просчета. Главное - это

1318 Книга Сергея Цыпцына


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

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

Просвечивание поверхности сквозь основания волос на границе роста волос лечится


несколькими приемами. Это прежде всего текстурирование части поверхности под волосами.
Обязательно используйте тени, они «прикроют» поверхность под кривыми. Дополнительные
ряды пассивных кривых вдоль границы роста волос, нарисованные вручную, также могут закрыть
просветы. Легкий шум (noise) или изгиб в районе оснований тоже создаст иллюзию насыщенности,
без увеличения количества кривых.

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

Не забывайте про атрибут Thinning. Он придает концам совершенно шикарный вид, если
только вы не делаете стрижку типа «каре».

Заплетание косичек
Если вы уже начали моделировать мощную косичку с помощью трех сплайновых кривых,
погодите немного. Возможность создания косичек встроена в систему волос изначально, причем,
как это полагается, в виде одной кнопки, точнее галки.

Любой пучок волос (Clump) можно превратить в косичку. Соответственно, должен быть
атрибут, отвечающий за такое превращение. Причем атрибут должен принадлежать не всей
системе волос, а быть индивидуальным, то есть задаваться отдельно для каждого пучка (folli­
cle).

Волосы 1319
Если сцена с длинными волосами еще открыта, проделайте следующие действия, чтобы
заплести все пучки волос в косички.

Выберите hairSystem1, затем выполните Hair=>Convert Selection=>to Follicles.


Откройте Channel Box и задайте braid=on.
Это включит «заплетенность» всех пучков, так как выбраны все кривые.
Включенный атрибут braid отвечает за то, что пучок будет выглядеть, как косичка.
Далее надо сделать некоторые настройки атрибутов всей системы волос, чтобы косички
выглядели нормально. Прежде всего, надо увеличить количество сегментов для нормальной
гибкости волос в косичках: Sub Segments=6.

Затем можно уменьшить ширину косичек: Clump Width=0.2.

При желании, с помощью Clump Width Scale, можно сделать толщину (профиль) косички
резко сужающейся в начале и плавно убывающей в остальной части.
Ширину самих волос можно сделать побольше: Hair Width=0.02, для «уплотнения косичек.
Задайте Thining=0.

Необходимо также убрать любые деформации: Noise=0.


Просчитайте картинку.

Если хотите, можно немного растрепать прическу, чтобы лучше увидеть косички.
Выберите hairSystem1, затем создайте радиальное поле: Fields=>Radial и проиграйте
буквально несколько кадров.

1320 Книга Сергея Цыпцына


Если хотите увидеть более «мясистые» косички, но в меньшем количестве, проделайте
следующее:

Установите Simulatiom Method=Dynamic Follicles Only.

Это уберет с экрана все пассивные пучки. Оставшиеся активные, нужно сделать гуще и толще.
Задайте Hair Per Clump=300; Clump Width=0.7.

Чтобы разворачивать косички вокруг своей продольной оси, можно использовать атрибут
Clump Twist.

Если вы хотите заплести одну огромную косу, для нее имеет смысл создать отдельную
вспомогательную систему волос. Основная система волос должна отвечать за покрытие головы
волосами, концы которых должны заканчиваться у основания косички. Вспомогательная система,
ответственная за саму косу, может состоять только из одного пучка/кривой с очень широким
основанием, что настраивается при помощи Clump Width Scale. Многие атрибуты этих систем
должны совпадать для общего внешнего вида.

Рендеринг волос с помощью mental ray


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

Первая возможность стандартна. Коль скоро волосы представлены штрихами Paint Effects,
их можно сконвертировать в полигональные трубки и делать с ними все, что душе угодно. Правда,
вопрос о размере сцены остается более чем открытым, так вся геометрия будет сохраняться не в
виде описания и набора параметров, а в явном виде.

Для такой конвертации даже существует специальный материал, который автоматически


создается и накладывается на полигональные трубки после конвертации. Он максимально
воспроизводит визуальные свойства волос и представляет собой обычный анизотропический
материал с вполне адекватным набором атрибутов.
Начиная с седьмой версии MAYA mental ray научился рендерить волосы как полноценный

Волосы 1321
объект сцены. Чтобы получить удовлетворительный результат, вам надо сразу выставить довольно
высокое качество антиалиазинга в Render Globals, так как волосы - довольно капризный объект,
состоящий из мелких деталей.

Другая возможность заключается в написании собственного геометрического материала


для просчета волос в mental ray.

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

Работа с кэшированием
Прежде чем закончить с проблемами визуализации, я хотел бы отметить, что перед
рендерингом волосы, как правило, необходимо кэшировать, то есть сохранить их траектории на
диске в специальном файле. Если вас устраивает движение волос и вы хотите, чтобы они двигались
каждый раз именно так, имеет смысл их скэшировать, а не пересчитывать их движение каждый
раз заново. В отличие от твердых тел, траектории волос нельзя «перевести в ключи», поэтому
использование кэширования - единственная альтернатива повторному просчету. Кроме то, вряд
ли у вас получится достойным образом отрендерить волосы с первого раза. Поэтому проще делать
очередные попытки визуализации с уже просчитанными заранее кривыми (если поведение и
траектории волос вас полностью устраивают). Также совершенно очевидно, что motion blur не будет
корректно работать с траекториями кривых, вычисляемыми прямо в процессе рендеринга. В общем
случае, динамика «не знает», что будет в следующем кадре, пока не доберется до него, поэтому
для работы с motion blur всегда необходимо производить предварительное кэширование.

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

Динамические кривые как самостоятельные объекты


Сейчас я бы хотел поговорить об одной из самых интересных возможностей, которой
обладает динамика волос. Она заключается в том, что абсолютно любую сплайновую кривую
можно превратить в динамическую кривую. По-другому можно сказать, что любую кривую можно
включить в систему волос.

Что это может дать? Прежде всего, это широкие возможности по автоматической анимации
формы кривых. Если раньше, для создания эффекта упругой конструкции, типа антенны,
необходимо было превратить кривую в новое мягкое тело, потом назначить оригинальную кривую
в качестве goal-объекта для частиц это мягкого тела и затем назначить для каждой частицы нужный
вес, то теперь сделать упругую кривую можно при помощи всего одной операции: Hair=>Make Se­
lected Curve Dynamic.

Коль скоро любой набор кривых может быть превращен в, назовем их так, «динамические
веревки», то благодаря Construction History, возникает масса возможных использований анимации

1322 Книга Сергея Цыпцына


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

Я выделю особо лишь три из них (это не означает, что остальные применения не заслуживают
внимания):

Во-первых, проведя через динамические кривые поверхность типа Loft, вы получите


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

Во-вторых, использование динамических кривых в качестве IK Spline Handle для управления


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

В-третьих, применение динамических кривых в качестве Wire Deformer позволяет сделать


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

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

В следующем разделе я приведу пример превращения кривой в динамический объект,


а сейчас замечу, что такое превращение лучше делать после того, как вы назначили кривую в
качестве деформера или IK Spline Handle.

Разрезание веревки
Попробуем превратить сплайновый объект в динамическую кривую, а затем разрезать его
пополам.

Создайте половинку окружности: Create NURBS Primitive=>Circle.


Задайте для makeNurbCircle1 значения radius=5; sweep=180.
Поверните окружность: rotateZ=90.
Выберите точку на кривой (RMB=>Curve Point) прямо посередине окружности.

Разрежьте кривую: Edit Curves=>Detach Curves.


Выберите detachedCurve1 и «разверните» ее: Edit Curves=>Reverse Curve Direction.
Выберите обе кривые, удалите историю: Edit=>Delete by Type=>History.
Сохраните файл (ropeCutStart.ma).
Превратите обе кривые в динамические веревки. Выполните операцию Hair=>Make Select­
ed Curve Dynamic.

Волосы 1323
На экране появится дополнительные объекты. Это и есть динамические кривые. Исходные
части полуокружности являются для них стартовыми кривыми.

Примечание. По умолчанию, вновь созданные динамические кривые имеют вторую


степень. Вы можете задать степень динамической кривой, изменив атрибут De­
gree у ноды follicle.

В сцене появится иконка новой системы волос hairSystem1, а также ноды follicle1 и fol-
Ucle2, отвечающие за индивидуальные свойства динамических кривых.

Запустите анимацию. Кривые немного провиснут.

Остановимся на некоторых отличиях динамических кривых, созданных подобным образом


от обычных волос, возникающих «легальным» способом.

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


любой из них (или оба), изменив значение атрибута PointLock в закладке follicleShape1.

Во-вторых, кривая не прикреплена ни к одной из поверхностей. Поэтому и атрибуты Param-


eterU/V равны нулю.

В-третьих, ширина пучка (Clump Width) по умолчанию равна нулю.

Освободим концы обеих кривых.


Выберите hairSystem1, затем выполните Hair=>Convert Selection=>to Follicles.
Откройте Channel Box и задайте Point Lock=Base.

Концы немного провиснут, но все же - так как кривые имеют ощутимую упругость - останутся

1324 Книга Сергея Цыпцына


висеть недалеко от стартовых кривых. Коль скоро мы имеем дело с веревками, зададим нулевую
упругость.

Выберите hairSystem1 и в Attribute Editor задайте в разделе Dynamics значение Stiffness=0.


После этого веревки безвольно повиснут вертикально.

Перейдите в начало анимации. Склеим концы веревок.

Выберите обе веревки на экране. Выполните Hair=>Create Constraints Hair to Hair.


Передвиньте появившийся локатор в место склейки (translateY=-5). Это важно: по положению
локатора в первом кадре определяются точки на кривых (ближайшие к локатору), которые будут
склеиваться.

Запустите анимацию. Чтобы немного сгладить «уголок» в месте склейки, задайте в


атрибутах констрейна Stiffness=0.9.

Проиграйте анимацию.

В любом кадре задайте Stiffness=0. Концы веревок немедленно разъедутся.


Таким образом, задача разрезания веревки сводится к анимации атрибута Stiffness в
нужном кадре.

Анимируя Stiffness, вы также можете подтягивать концы веревок друг к другу.

Сохраните файл (ropeCutFinal.ma).

Далее я хотел бы описать некоторые трюки при работе с волосами, которые не относятся к
стандартным способам создания и редактирования волос. Редкий трюк обходится без использования

Волосы 1325
скриптов, поэтому начнем с тех, что попроще. С наследования цвета волос с текстурной карты.
Дальнейшее изложение будет рассчитано на довольно взрослых мальчиков, а к остальным просьба:
не нервничать.

Наследование цвета волос с текстуры


В этом разделе я бы хотел вернуться к текстурированию волос не вдоль длины, а вдоль
поверхности, из которой они произрастают. Напомню, что у меха (MAYA Fur) есть кнопка Bake,
которая забирает цвет с текстуры и накладывает его на мех вдоль поверхности, на которой этот
мех растет.

Попробуем сделать это же и для волос. Как уже было описано выше, у каждого пучка волос
(или динамической кривой, follicle) есть атрибуты Color Blend и Color. Напомню, что добраться
до индивидуальных свойств можно через Hair=>Convert Selection=>to Follicies. Атрибут Color
Blend определяет, насколько сильно используется индивидуальный цвет пучка, то есть степень
смешивания общего и индивидуального цветов.

Среди индивидуальных свойств динамических кривых (follicle) присутствуют также атрибуты


Parameter U/V, определяющие UV-координаты точки, из которой произрастает конкретный пучок.
Имея эту информацию, можно вычислить цвет текстуры, лежащей на поверхности, из которой
растут кривые (кстати, не обязательно забирать цвет именно с этой текстуры, можно использовать
любую карту), и назначить этот цвет на кривую, то есть на весь пучок.

Как догадались взрослые мальчики, речь идет о небольшом скрипте, поэтому страдающим
аллергией на скрипты читателям настоятельно рекомендуется срочно перейти к следующему
разделу.

Проделаем небольшое упражнение.

Создайте полигональную сферу, задайте радиус равным пяти.


Создайте систему волос на поверхности.
Откройте Option Box операции Create Hair и задайте Output=Paint Effects, U_Count=20,
V_Count=20, Equalize=off.
Это дополнительный (но не обязательный) трюк для выращивания волос точно в центре
граней.
Жмите Create.

Задайте «для красоты» следующие параметры для системы волос hairSystem1:


Hair Per Clump=20; Clump Width=1.2.
Форму Clump Width Scale можно сделать уже к основанию и шире к концам.

1326 Книга Сергея Цыпцына


Выберите сферу и положите на канал Color материала l a m b e r t 1 какую-нибудь цветастую
текстуру, например Ramp. Задайте для текстуры ramp1 значение Noise=1.

Задача состоит в том, чтобы назначить тот же самый цвет и на волосы, растущие на сфере.

Сохраните файл (texturedHairStart.ma).

Выберите hairSystem1, а в Script Editor выполните следующие строки:

// перевод выбранной системы волос в отдельные кривые


convertHairSelection "follicles";
// получение списка кривых
string $list[] = 'ls -sl';
string $it;
// цикл по всем кривым
for ($it in $list) {
// получение UV координат основания кривой
float $u = 'getAttr ($it+parameterU")';
float $v = 'getAttr ($it+parameterV")';
// запрос цвета в точке с такими коодинатами на текстуре rampl
float $col[] = 'colorAtPoint -o RGB -u $u -v $v ramp1';
// назначение полученного цвета на кривую
setAttr ($it+".color") -type double3 ($col[0]) ($col[1]) ($col[2]);
// задание полного индивидуального цвета
setAttr ($it+".colorBlend") 1;
}
Естественно, вместо текстуры r a m p 1 можно использовать любую карту. Следует также
отметить, что цвет унаследовали не отдельные волосы, а целые пучки, внутри которых все волосы
имеют одинаковый цвет. Чтобы написать более изысканный скрипт, окрашивающий отдельные

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

Данный скрипт может быть моментально модифицирован для выполнения следующей


задачи: предположим, что надо удалить все волосы там, где текстура имеет черный цвет, и оставить
там, где цвет белый. Такая возможность аналогична картам для атрибута Baldness системы MAYA
Fur.

Измените зеленый цвет текстуры ramp1 на белый, а синий и красный - на черный. Задайте
lnterpolation=None.

1328 Книга Сергея Цыпцына


Выберите hairSystem1, а в Script Editor выполните новые строки:

// перевод выбранной системы волос в отдельные кривые


convertHairSelection "follicles";
// получение списка кривых
string $list[] = 'ls -sl';
pickWalk -d down;

string $it;
// цикл по всем кривым
for ($it in $list) {
// получение UV координат основания кривой
float $u = 'getAttr ($it+".parameterU")';
float $v = 'getAttr ($it+".parameterV")';
// запрос цвета в точке с такими коодинатами на текстуре rampl
float $col[] = 'colorAtPoint -о RGB -u $u -v $v ramp1';
// удаление кривой, если цвет (красный) меньше 0.9
if($col[0]<0.9) delete ('listConnections -t "nurbsCurve" $ i t ' ) $it;
}

Вместо наследования цвета, кривые просто удаляются, если цвет текстуры около их
основания меньше, чем 0.9 (в черном-белом варианте достаточно сравнивать красный канал
цвета).

Волосы 1329
Замечу, что приведенные скрипты будут работать и в том случае, если выбраны отдельные
кривые, а не только система волос целиком.

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

Примечание. В седьмой версии MAYA появилась встроенная поддержка рисования и


использования текстур для цвета, блика и <лысости» (baldness), чтобы волосы могли наследовать
эти свойства с поверхности. Скажу лишь, что работа с этими инструментами требует определенного
терпения.

Приведенный выше скриптовый подход позволяет моментально наследовать с текстуры


любые свойства системы волос, а не только цвет или «лысость». Это может быть плотность пучков,
их упругость, кучерявость и пр.

Универсальный совет для работы с волосами


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

Аэродинамическая история
Я имею привычку не отмечать Новый год в Москве. Отсутствие снега, солнца, звезд и
других природных явлений делают этот город, по крайней мере зимой, малопригодным не только
для отмечания таких, сезонных праздников, но и для нормальной жизни вообще. Однажды меня
занесло в конце года в Молдавию, в гости к друзьям-музыкантам. Впрочем, история эта касается
не новогодних игрищ, а весьма экзотического возвращения на родину.

Надо сказать, что столица государства, активно наедавшегося независимости, переживала


тогда не лучшие времена. Отсутствие горячей воды, отопления и веерные отключения
электричества не прибавляли зимней прелести Кишиневу. Однако на хорошем настроении и
веселой встрече Нового года это никак не сказалось, хоть и несколько затруднило мой обратный
путь в российскую столицу. А добраться в Москву было крайне необходимо, ведь четвертого января
надо было грузиться с друзьями-горнолыжниками в самолет и лететь исследовать итальянские
склоны. Поэтому я благоразумно взял обратный билет из Кишинева на второе января, имея в виду
непредвиденные задержки. Как я был прозорлив!

Надо сказать, что молдавская зима в том году выдалась необычно лютая. Обнаружив на
градуснике минус двадцать, я решил выехать в аэропорт пораньше. Это была ошибка. Добравшись
до здания аэровокзала, представлявшего собой стеклянную коробку типового проекта, я обнаружил,
что температура снаружи и внутри отличается на два, ну, максимум, на три градуса, все же,
очевидно, подогретая дыханием пассажиров, ожидавших своей участи. Участь, как выяснилось,
не сильно завидная.

Тем не менее, регистрация рейса на Москву началась с несильным опозданием и


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

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


привезли в не менее промороженный самолет, от одного вида которого было как-то не по себе.
Дело в том, что авиакомпания, видимо, решила сэкономить немного денег: обнаружив, что
пассажиров набралось не так и много, заменила и без того некрупный ТУ-134 на совсем дамский
АН-24. Тот самый у которого вход в салон через, пардон, откидывающуюся задницу. Так вот,

1330 Книга Сергея Цыпцына


через эту гостеприимно (и, очевидно, весьма) давно откинутую задницу весь самолет насквозь
проморозило, однако нам не оставалось ничего другого, как занять свои помороженные места.

Вокруг же самолета сновали какие-то странные люди с большими разводными ключами и


что-то говорили в адрес самого самолета, упоминая всуе его возраст, а также генеалогическое
дерево конструктора самолета. Через полчаса сидения и подпрыгивания в нетеплых креслах
появилась стюардесса. Было такое впечатление, что ее только что насильно оторвали от
продолжающегося отмечания Нового года и при этом совсем не дали передохнуть. Она обвела
всех послепраздничным взглядом и хрипло предложила желающим холодной воды. На жалобные
просьбы сделать горячего чайку или хотя бы кипятку, она экспрессивно ответила, что в этом
неработающем самолете не то что кипятку, но даже командира экипажа найти невозможно.

Выяснилось, что командир как-то и в самом деле подзатерялся по дороге от стола в


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

Подъехал все тот же, заиндевевший автобус, и мы, растирая руки и лица, вывалились из
мертвой железной птицы и вскоре покатили в здание аэропорта. Там мы, как взрослые, снова
прошли паспортный контроль, затем таможню, все-таки граница, как-никак, и опять попали в
звенящее от мороза, знакомое нам стеклянное здание. Сплотившись к тому времени в единую
пассажирскую общность, мы бодро стучали в пластиковое окошко офиса авиакомпании с
предложениями немедленно посадить нас на другой самолет. Возникающий из ниоткуда коньяк
практически не помогал от холода и действовал скорее как утолитель жажды и средство стимуляции
жизнедеятельности организма.

Удивительно, но уже через час снова объявили регистрацию, и мы точно разученными


движениями молниеносно прошли регистрацию, паспортный контроль, таможню (граница же!)
и попали в знакомый накопитель. Попрыгав по привычке с полчасика на бетоне, мы опять
погрузились в уже родной, уже навек обледеневший автобус и покатили по летному полю. Но
когда мы остановились, меня охватило неприятное предчувствие. Нас встретила все та же, по-
прежнему гостеприимно распахнутая задница знакомого АН-24. Стюардесса, оказавшаяся на сей
раз в автобусе, великодушно объяснила нам, что пока мы топтались в аэропорту, озверевшим
техникам удалось-таки завести самолет. Да-да, именно так, дословно: «удалось-таки завести этот
... [нехороший] самолет». Так что мы, очевидно, должны были испытать приступ счастья и прилив
нежности к техникам, от того, что сейчас наконец-то упорхнем из этого белого безмолвия. Однако
счастья отчего-то не ощущалось, только жуткий холод, а лететь на ожившем чуде техники совсем
не хотелось, по совершенно неизвестной причине.

Нехорошо улыбаясь, мы, как загипнотизированные, стройными рядами, проследовали из


автобуса в самолет. Смахнув иней с мест, не указанных в билетах, мы вжались в кресла, однако
почему-то не услышали привычной вибрации и гудения. И тут, о чудо, появился командир корабля.
Из его не совсем четких объяснений удалось выяснить следующее (я никогда этого не забуду, ни
один сценарист не смог бы придумать такого поворота событий, хотя это все было на самом деле).
Просто пока мы ехали в автобусе по летному полю, двигатель опять заглох! И теперь его снова
надо было заводить... Бодрые удары в чреве самолета полностью подтверждали слова командира.
Надо признаться, я опять несильно огорчился, узнав, что двигатель заглох. Однако начал очень
сильно бояться того, что он снова заведется. А вообще, я не мог до конца представить, что весь
этот бред происходит со мной и что в жизни такое вообще может случиться.

А свирепые техники всерьез орудовали своими нехитрыми инструментами и решительность


была написана на их новогодних лицах. Однако возраст самолета в союзе с морозом оказался
сильнее, и еще через час командир корабля, выйдя из кабины экипажа, объявил окончательный
приговор: «Не полетит!». Мы все вздохнули с облегчением, но сильно призадумались: что же
будет дальше.

Волосы 1331
А дальше, всего минут через десять, в салоне появился довольно бодрый представитель
авиакомпании, вежливо и доходчиво объяснивший, что компания приносит свои чудовищные
извинения за причиненные неудобства и готова немедленно выплатить всем полную стоимость
билетов прямо в здании аэропорта. Поначалу мы все аж подпрыгнули от радости - от того, что
заводить этого монстра никто больше не будет и что даже деньги нам вернут без потерь. Наиболее
промерзшие даже потянулись к выходу, навстречу морозному вечеру. Однако я, быстро проведя
перебор вариантов, оценил всю безысходность ситуации и буквально завопил на весь салон:
«Господа! Немедленно вернитесь на свои места!». Не знаю, в каком кино я насмотрелся сцен про
стихийные митинги среди мирного, но возмущенного населения, но дальше я пламенно верещал
хорошо поставленным, пусть вконец охрипшим голосом про то, что если мы выйдем отсюда и
получим деньги, никому до нас дела больше не будет. Про то, что следующий рейс на Москву
только через три дня, а где зимовать эти три дня, неизвестно. Про то, что билетов на самолет
через три дня может и не быть. Про то, что нас хотят очень ловко выставить на улицу, всучив нам
наши же деньги и оставив замерзать в ледяном аэропорту. (Про то, что у меня через сутки самолет
в Италию, я почему-то промолчал.) Завершил свою возмущенную речь я призывом немедленно
сесть на свои места и сидеть до полного заиндевения, пока нас не отправят в Москву любым
способом (кроме реанимации АН-24). Напоследок пригрозил представителю компании написать
огромную статью в газету, сотрудником которой я являюсь (это уже был чистой воды кураж, что
правда, то правда).

Удивительно, но моя проникновенная речь произвела впечатление как на пассажиров,


поплюхавшихся в кресла, так и на представителя коварной авиакомпании, который, изменившись
в лице, поспешно скрылся. Далее все продолжало происходить, как в кино.

Командир корабля, запершись в кабине, вел ожесточеннейшие переговоры с невидимыми


собеседниками. Мы извлекали коньяк из того же ниоткуда и все более укрепляли свой мятежный
дух. Наконец командир выбрался из своего укрытия и заявил буквально следующее. Что через час
мимо будет пролетать самолет на Москву (непонятно, правда, откуда над Кишиневом мог взяться
самолет на Москву) и что они будут его сажать, чтобы на нем и отправить нас, мятежников, на
родину. В устах летчика это звучало не сложнее, чем поймать попутку до Киевского вокзала.
Судя по тому, что этот самолет уже был в воздухе (то есть не только завелся, но и не заглох,
хотя уже прошло какое-то время), доверять ему было можно. Посовещавшись, мы согласились и
заученными движениям эвакуировались из самолета, ввалились в уже осточертевший автобус и,
да-да, поехали проходить паспортный контроль, таможню и в очередной раз пересекать границу
двух государств.

В аэровокзале мы свирепо сторожили представителя авиакомпании, благоразумно


укрывшегося в своем пластиковом офисе и вдыхали коньяк прямо из воздуха. Невероятно, но
через час снова (то есть третий раз за этот день) объявили регистрацию на наш рейс. И снова
паспортный контроль и знакомые до боли лица таможников, уже наизусть изучивших все наши
пожитки. И снова накопитель, уже совсем не долго. И опять хрустальный автобус. И вновь лихой
вояж по летному полю.

Невероятно, но в конце этого, эпохального пути нас ожидал хорошо прогретый, исправно
работающий, а главное - совершенно не глохнущий ТУ-134. Мы ввалились в него, как геологи в
баню, и попадали в свободные кресла. Присутствовавшие в салоне пассажиры с опаской смотрели
на наши помороженные, изборожденные духом мятежа лица и жались поближе друг к другу. Но у
нас хватило сил только на то, чтобы поднять тост «За Победу!» и рухнуть лицом в откидывающиеся
столики.

Очнулся я в аэропорту Домодедово. Теплом. Освещенном. Хотелось остаться в нем жить


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

1332 Книга Сергея Цыпцына


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

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

Рендеринг-движки
Не секрет, что встроенный майский рендерер не снискал всеобщей народной любви.
Эта рабочая лошадка была хороша для своего времени, однако потом ее успешно обошли более
резвые и интеллектуальные конкуренты. Проблемы с антиалиазингом, относительно невысокая
скорость, ограниченный рейтрейсинг сделали майский рендерер аутсайдером. Тем более, что
к MAYA за последние годы были «прикручены» все современные рендеринг-движки. Перечислю
лишь некоторые из них.

Обнаружив, что родной майский рендерер безнадежно устаревает, компания Alias сумела
исхитриться и заключила стратегическое соглашение с компанией Mental Images - о встраивании
программы mental ray непосредственно в MAYA. Конечно, это не прошло гладко, и крики о помощи
пользователей пятой версии MAYA до сих пор стоят в ушах службы технической поддержки.
Однако со временем интеграция mental ray и MAYA стала более гладкой, и теперь mental ray даже
рассматривается как основное решения для рендеринга в MAYA. Официально он называется men­
tal ray for maya и иногда пишется как mrfm. Он выполнен в виде самостоятельного плагина и
не является надстройкой над независимым продуктом mental ray standalone, представляющим
собой рендерер из командной строки. Это разные программы с разными возможностями. Для
пытливых умов, наслышанных, что в пакете XSI тоже используется mental ray добавлю, что майская
реализация mental ray несколько отличается от «ксишной», на уровне ядра, и не является с ней
совместимой. Совсем взрослые мальчики, как правило, используют встроенный mental ray for
maya для генерации .mi-файлов, которые затем отправляют на вход для mental ray standalone.
Здесь я отсылаю всех интересующихся на сайт Павла Ледина (http://puppet.cgtalk.ru/), где вы
можете найти соответствующие скрипты и упражнения для адекватного использования mental ray
standalone совместно с MAYA.

В 2005 году компания Pixar выпустила гениальный продукт под названием Renderman for
Maya, или, сокращенно, RfM. Оформленный в виде плагина, он позволяет пользователям MAYA
нажать привычную кнопку Render и просчитать изображение с помощью движка Renderman. Вся
конвертация сцены, майских материалов, текстур, источников света происходит незаметно для
пользователя. Гениальность этого продукта заключается в его простой и понятной интеграции в
MAYA. Как правило, у конечного пользователя не возникает особых вопросов по использованию этого
решения. Однако за простоту надо платить, и поэтому некоторые традиционно сильные технологии
от Pixar не поддерживаются в этом продукте. Среди них генерация rib-файлов и использование
собственных dso-библиотек. Если вы хотите использовать всю техническую мощь Renderman, то
вам следует обратить внимание на пакет Renderman Artist Tools, описанный Алексеем Пузиковым
в соответствующей главе этой книги

Компания Illuminate Labs (www.illuminatelabs.com) выскочила на рынок с со своим


издевательски названным рендерером Turtle совершенно неожиданно. Но «Черепаха» полюбилась
пользователям своей неприхотливостью и отличной интеграцией с MAYA. Пользователям не надо
знать ничего про новый рендерер, он просто получают еще одну кнопку для рендеринга уже
существующих сцен.

В последнее время также набирает популярность новый рендер-движок под названием


Maxwell от компании Next Limit.

Здесь же следует упомянуть такие сильные продукты как finalRender (www.cebas.com),


Brasil (www.splutterfish.com), vray (www.chaosgroup.com). Все эти рендереры давно отлично
интегрированы в 3ds max и слухи об их интеграции в MAYA витают уже несколько лет. В связи с
покупкой Autodesk-ом компании Alias, следует ожидать интересных новостей об этой интеграции.

В главе Алексея Пузикова про Рендерман вы можете найти дополнительную информацию


по альтернативными рендерерам, сотрудничающим с MAYA.

И что же дальше?
Сделав пятиминутный перекур после двухлетней работы по написанию книги и хладнокровно
поразмыслив, я пришел к выводу, что глава, посвященная рендерингу в MAYA либо перерастает в
двухтомный труд «Понимая Рендеринг», либо не имеет смысла вообще, так как устареет, еще до
выхода книги. Немного обосную эти положения.

Если взять хотя бы тему освещения (как локального, так и глобального), то объем
материала, касающегося этой темы, не поместится не то что в главу, а в небольшую книгу. Или
чего стоит один только вопрос просчета теней? Модное глобальное освещение и способы борьбы
с его последствиями в анимации, тоже тянут на отдельное научное исследование. HDRI и IBL,
ambient occlusion и subsurface scattering, Final Gathering и Color Bleeding. Эти новые понятия,
появившиеся в последние годы, только проходят «обкатку» в области «большой анимации» и
«кинопроизводства».

Если говорить о войне рендереров, то есть конкретных решениях для рендеринга в MAYA,
то будущее весьма непредсказуемо.

Интеграция MAYA и mental ray без сомнения будет подвергнута переработке в следующих
версиях MAYA, ибо в данном виде (на момент седьмой версии), она не представляется, скажем
так, удобной и изящной. Следует ожидать упрощения и «дружественнофикации» как самого
интерфейса, так и документации к нему. Кроме того, изменения в следующих версиях mental
ray обязательно наложат отпечаток на способ интеграции его с MAYA. Это делает бессмысленным
описание текущей версии.

Мои личные симпатии на стороне Renderman for Maya, поскольку этот продукт - образец
продуманности и дружественной интеграции в MAYA. Сразу оговорюсь, что это продукт
предназначен прежде всего для конечных пользователей. Он легок в освоении, снабжен
компактной документацией и идеально подходит для начального освоения основ рендеринга.
Его рыночная судьба пока не определена, поэтому описывать его в книжке мне представляется
преждевременным.

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

Рендеринг 1335
1336 Книга Сергея Цыпцына
Renderman
Сношения с внешними рендерерами
или присовокупление к Renderman'y
Сколько я себя помню - всегда хотел написать книжку. В детстве казалось: человек,
который читает много книг, просто обязан уметь их писать. Это занятие я считал настолько легким
и непринуждеенным, что от собственно написания книги меня всегда отделяла какая-то малость
- домашнее задание в школе, например. Так что графоманом я был неправильным - книжек не
писал и не пытался, только думал: вот, когда-нибудь, вот было бы здорово...

Для тех, кому стало неинтересно читать эту главу уже сейчас, после первого абзаца,
сообщаю - продолжение разговора про Maya будет уже скоро, всего через полсотни страниц.

А для всех, кто остался с нами - после небольшой паузы, пока наиболее нетерпеливые
читатели листают страницы в поисках другой главы - лишь скажу: меня зовут Алексей Пузиков, и
моя мечта сбылась! Частично сбылась, конечно - ведь пишу я не целую книгу, а только эту главу.
Поговорим мы в ней только о внешних рендерерах, их связи с MAYA и о Renderman'e.

Так что же пропустят наши неугомонные друзья, кто уже ускакал отсюда на просторы
какой-нибудь другой главы? А вот что:

• рассказ о том, зачем MAYA нужны внешние рендереры;


• и как они работают в связке;
• а еще про Renderman вообще;
• и про Photorealistic Renderman, в частности;
• и про MTOR;
• и даже немножко про Gelato, Jot, GRUNT, MayaMan, Liquid и прочие вкусности, названия и
аббревиатуры;
• и наконец, на десерт, они не прочтут краткое пособие по новому экстремальному виду
спорта - Renderman-читингу.

Уже интересно? Тогда - начнем!

Правда, придется - раз уж мы так весело начали и замахнулись на такой объем информации
- поступить с читателем честно, указав также, чего вы в этой главе не найдете. А не найдете вы в ней
подробных учебников, упражнений и уроков, справочных руководств и перевода спецификаций.
Мир внешних рендереров необъятен, да что там говорить - про один Renderman можно (и нужно!)
написать не одну толстенную книжку - а у нас с вами в распоряжении всего лишь небольшая глава.
Так что ограничимся, для знакомства, неким набором ключевых моментов, опираясь на которые
вы сможете самостоятельно продолжить изучение этого нового мира и выйти на качественно
новый уровень в своей работе.

Зачем?
Почему же вообще возникла необходимость использовать внешние движки визуализации
в MAYA? Возьму на себя смелость высказать основную мысль этой главы уже на ее второй
странице, не углубляясь в дебри объяснений и дискуссий: стандартный MAYASoftware Renderer
попросту непригоден для использования в сколько-нибудь серьезном проекте, а в особенности - в
кинопроекте. Ох, не могу поверить, что я это мог сказать... И нет, еще хуже: что я написал это в
книжке про MAYA. Посмотрите кто-нибудь в окно - там, ненароком, небо в Дунай не упало?
Сказав А, скажем и Б: что, впрочем, рендерить чайники с помощью майского рендерера все
жеможно, но только если их не очень много.

Теперь, когда разгоряченные толпы поклонников MAYA уже занялись моими поисками,
попробуем понять, что же стало причиной такого провала в функциональности, в общем-то, весьма
высококачественного и продуманного продукта. Для начала, обратимся к первоисточникам, а
именно к документу под названием Design and Implementation of the MAYA Renderer , в котором
описываются основные идеи, положенные в основу MAYA Software Renderer. В качестве опорных

Анимация 1339
концепций, ставших краеугольными камнями дизайна этого рендерера, выделены следующие
вещи:

1. Стандартный рендерер MAYA должен быть лучше, чем его предшественники - рендереры
от TDI, Alias и Wavefront. В то же время, на начальных стадиях разработки нового рендерера
вместо него использовалось проверенное старое решение - Alias Renderer - которое затем, по мере
разработки, заменялось готовыми частями нового рендерера.

2. Стандартный рендерер должен быть максимально удобным в использовании и


предоставлять пользователю максимум возможностей для настройки и доступа к "внутренностям".
Поскольку в качестве системы представления внутренних данных в MAYA выбран DAG (прямой
незамкнутый граф), стандартный рендерер также должен быть привязан к этой системе,
предоставлять для нее свои собственные ноды для настройки самого процесса рендеринга и
использовать ноды от HyperShade для настройки свойств материалов.

3. Качество изображения должно быть высоким и предсказуемым.

4. Должно быть сделано все возможное, чтобы ускорить рендеринг.

5. Поскольку рендерер является встроенным в MAYA, в большинстве случаев он будет


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

6. Новый рендерер должен быть по возможности универсальным и допускать расширение


в будущем - без необходимости полного переписывания.
Что же, в результате, получилось у авторов MAYA Software Renderer? Опять-таки, не углубляясь в
ненужные детали, укажем на основные особенности готового продукта:

• Стандартный рендерер MAYA - это адаптивный иерархический сканлайн-рендерер с


возможностью использования рейтрейсинга. В нем, однако, не реализованы модные и потихоньку
начинающие использоваться в производстве Global Illumination, Final Gathering, Ambient Occlusion
Mapping. Данный рендерер - триангулирующий. То бишь в процессе подготовки к рендерингу он
разбивает сцену на части, и каждая часть оценивается по количеству входящих в нее треугольников
- так рендерер пытается не выйти за обозначенные для него рамки доступной памяти.
Хотя было объявлено о наличии у рендера необходимой в работе гибкости, его оказалось
невозможно расширять за счет плагинов, написанных пользователями. Все, что можно сделать,
это реализовать собственные генераторы геометрии и дописать свои материалы для HyperShade
- доступ же к другим возможностям рендерера не обеспечивается (не говоря о, например, замене
модулей или о встраивании в его собственный пайплайн (технологический конвейер). Впрочем, это
- мелкая неприятность: ведь многие современные рендереры не позволяют даже такой гибкости.
Увы, дальше начинаются неприятности покрупнее.

• Для получения сколько-нибудь гладкой поверхности на любых поверхностях - кроме


полигонов - этому рендереру требуется достичь очень высокого уровня тесселяции (разбиения на
полигоны), что сказывается на общей производительности рендерера. Попросту говоря, любая
попытка получить сколько-нибудь качественную картинку с использованием NURBS или Subdivision
Surfaces обречена на долгое ожидание результата.

• Для получения теней рендерер использует по умолчанию технологию shadow


mapping (хотя, как уже говорилось, существует возможность включения рейтрейсинга). А как
показывает опыт, создаваемые с ее помощью карты теней в MAYA имеют ограничение по размеру:
не более 3200 по каждой стороне. Превышение данного ограничения приводит теоретически к
серьезному замедлению рендеринга, а на практике почти всегда роняет рендерер и вместе с ним
- саму MAYA. Такое поведение не позволит получить при помощи shadow maps сколько-нибудь
качественные тени для кино, для high definition video и вообще - для любых изображений высокого
разрешения (например, рекламных плакатов).

• Стандартный рендерер MAYA отвратительно работает с большим количеством

1340 Книга Сергея Цыпцына


объектов и с большими разрешениями (больше 2048x2048). Причем если при попытке отрендерить
кадр с большим разрешением мы получим просто некоторое нелинейное замедление рендеринга
, то при большом количестве объектов мы рискуем просто обвалить процесс.

Следует отметить, что разработчики MAYA приложили уйму усилий для того, чтобы
максимально улучшить свой рендерер и хоть как-то адаптировать его для условий реального
производства . Однако возникает такое впечатление, что успех Bingo и других анимационных
проектов, сделанных исключительно при помощи встроенного движка, настолько повлиял на
умы программистов в Alias, что вместо того, чтобы действительно заняться оптимизацией своего
детища, они пошли на поводу у собственного менеджмента и начали вводить в него новые
возможности (впрочем, они поступили даже еще хуже: начали писать новые рендереры). Таким
образом, в MAYA появились PaintFX Tenderer, vector renderer, volume renderer и другие, не скрою,
приятные расширения стандартного рендерера - но это вовсе не исправило ситуации с основным
движком, а лишь привело к тому, что (автор пригнулся и прикрыл голову руками...) им просто
перестали пользоваться для сколько-нибудь серьезных задач. В конце концов, это увидели и
сами создатели MAYA, но они смирились со своим поражением, встроив в программу в качестве
стандартной опции mental ray. У них это получилось не так ловко, как у разработчиков из Softimage
- что не удивительно, если вспомнить, сколько лет mental ray поставляется в качестве рендерера
для Softimage и XSI. Однако, тем не менее, уже сейчас в стандартной поставке MAYA вы имеете
хороший и стабильный рендерер.

Тем не менее, даже после встраивания MR в MAYA вопрос с использованием внешних


рендереров все еще не закрыт. Отчасти потому, что несмотря на растущую популярность и громкие
пресс-релизы, mental ray пока не стал таким же стандартным инструментом для студий, какой
представляет из себя Renderman. Ну и, конечно же, потому, что очень многие студии используют
для рендеринга свои собственные разработки - достаточно вспомнить Blue Sky Studios со своим
рейтрейсером CGI Production Studio или PDI/Dreamworks с внутренним рендерером (никогда
не угадаете!) PDI Renderer, уж не говоря про многочисленные японские и французские студии,
традиционно использующие для просчета картинок собственные наработки.

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

Прежде чем продолжить свой рассказ, хотелось бы разрешить небольшую неоднозначность


в определении и переводе терминов, чтобы не запутать вас и не запутаться самому. Итак,
существует два различных "интерфейса" - тот, что называется просто interface, и тот, который
обычно принято обозначать как Visual Interface, или GUI. Так вот, на всякий случай договоримся,
что под первым мы будем понимать те параметры, функции, процедуры и объектные сущности,
которые предоставляет MAYA разработчику плагинов или MEL-писателю; а под вторым - те окна,
меню, кнопочки и прочие интерфейсные элементы, которые MAYA отрисовывает.

Так вот, хотя интерфейс внутренний отличался гибкостью и был направлен на реальные
запросы студий, позволяя встроить функциональность вызова внешнего рендерера в MAYA,
интерфейс визуальный, до недавнего времени, не мог уверенно взять установленную планку.
Пользователь, несомненно, мог написать свой плагин, встроить его в MAYA, создать для него окно
настроек с помошью MEL, даже встроиться в главное меню программы - но до пятой версии MAYA ему
не давали возможности встроиться в святая святых рендеринга: окно Render Globals. Запрашивать
значения переменных из этого окна было можно, а встроиться в него - нельзя. (Специально для
любителей теорий видеть во всем тайный сговор упомяну маленькую деталь: эту досадную мелочь
в MAYA исправили только одновременно со встраиванием mental ray...)

Отметим же это торжество справедливости над косностью ума и реализуем возможность


вставить в текст первую в этой главе картинку:

Кое-что про Renderman 1341


Вы, конечно, уже привыкли к таким, некогда страшным словам, как «плагин» и «объектная
сущность», которые я употребил, описывая внутренние интерфейсы MAYA. Более подробно про
внутреннее устройство вы прочитаете в других главах, а сейчас вкратце рассмотрим сам процесс
работы MAYA со внешними рендерерами.

MAYA + внешние рендереры = ?

По вполне понятным, как историческим, так и другим причинам (например, достижения


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

Мы познакомимся с ней подробнее чуть позже, а пока всего лишь отметим, что подавляющее
большинство рендереров запускаются именно из командной строки.

Небольшое отступление для наших читателей, пришедших из мира Autodesk/discreet/Ki-


netix - то есть для пользователей 3dsmax. Подавляющее большинство ВАШИХ рендереров а вы ими,
стоит признать, вовсе не обделены - реализовано в виде плагинов к самому Максу и интерфейса
(вот оно, это слово!) командной строки не реализуют. Очевидно, это имеет множество хороших
сторон, однако, как минимум, одну плохую ваш рендерер так просто к MAYA не подключишь.

1342 Книга Сергея Цыпцына


Впрочем, мы отвлеклись.

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

1. Во-первых, ваш экспортер, то есть тот плагин, который производит экспорт сцены из
MAYA во внешние файлы, итеративно обходит всю сцену и экспортирует ее геометрию и материалы
- обычно в некий новый файл собственного формата. Как известно, MAYA внутри представляет все
свои данные в виде набора нод; некоторые из них связанны в DAG (прямой незамкнутый граф). Наш
плагин должен обойти все ноды в этом графе, передвигаясь от предков к потомкам; для каждой
ноды мы должны определить, с кем она связана и какой тип информации она представляет, и в
зависимости от того, поддерживает ли наш внешний рендерер данную информацию - использовать
ее или пропустить. Задача обхода сцены упрощается тем, что программист может заранее
накладывать фильтр на граф перед тем, как проводить экспорт - например, если ваш рендерер
поддерживает только полигональную геометрию, то и обходить вам нужно только соответствующие
ноды. С другой стороны, в MAYA ОЧЕНЬ много различных типов нод и, скорее всего, вы не захотите
терять информацию только потому, что ваш рендерер не поддерживает тот или иной вид геометрии
или материалов. Это значит, что вашему плагину также придется заниматься преобразованием
информации и приведением ее в тот вид, который подходит для вашего рендерера. Очень многие
рендереры используют свои собственные системы описания материалов, гораздо более простые
или сложные по сравнению с теми, которые используются в MAYA - но все они, как минимум, от
нее отличаются, поэтому «правильный» плагин также должен понимать природу этих различий и
уметь их обходить.

2. Итак, ваш плагин продирается сквозь глубины DAG, сквозь все эти текстуры, материалы,
полигоны, NURBS, SDS, кривые, локаторы, источники света, камеры, объемные примитивы,
трансформы, анимационные кривые и ключи, деформеры, динамику и системы частиц, слои и
глобальные переменные. Некоторые рендереры воспринимают в виде входных данных файл, в
котором описывается как сама геометрия, так и те материалы, которые присоединены к ней.
Другие, напротив, разделяют эти понятия. Некоторые рендереры умеют хранить несколько кадров
в одном файле, другие не умеют - или умеют, но не рекомендуют: просто исходя из того, что
геометрия и материалы в сцене могут быть настолько сложны, что размеры полученных нами
файлов будут очень велики.

3. Все эти сакральные знания спрятаны внутри экспортера, который, пока вы читали
этот абзац, уже закончил экспорт и оставил на диске один или несколько файлов, которые
передаются в рендерер для просчета. Не суть важно, что произойдет в этом случае. Мы можем
просто запустить локальную копию рендерера, передав ей файлы и какие-то другие параметры.
Абсолютно естественно, что в процессе рендеринга может происходить как препроцесинг,
так и постпроцессинг данных, то есть будут выполняться какие-то скрипты, программы или их
комбинации, которые будут преобразовывать ваши данные перед рендерингом или по окончании
оного. Если вы работаете над каким-то большим проектом, то скорее всего вы используете
программно-аппаратное решение (в просторечии - "ферму", официально - "renderfarm"), которое
позволяет распараллеливать ваш рендеринг на несколько машин, находящихся в локальной сети,
будь то рабочие машины сотрудников или специальные компьютеры, выделенные для подобных
расчетов. В таком случае вы не будете вызывать ваш рендерер напрямую, а запустите другую
программу, которая уже и начнет раздачу подпроцессов в вашей ферме.

4. Как результат запуска постороннего движка, будет получена искомая картинка. Многие
современные рендереры имеют возможность рендерить прямо в окно MAYA. Благодаря этому, вы
получаете достаточно удобное средство для предварительного просмотра вашего рендеринга.
Вот, собственно, и все. Волшебство MAYA + умелые руки программистов в сочетании с
опытом работы во всех встречавшихся в процессе продуктах - и мы получаем неплохую основу для
настоящего студийного pipeline, который объединяет в себе сильные черты всех имеющихся на
вооружении продуктов.

Кстати, все хотел у кого-нибудь узнать: какого рода слово "пайплайн"? Считается, что это
очень важное сакральное слово, которое нужно произносить несколько раз в день, особенно глядя
на ошибки в своих «перловых» скриптах или на побитые картинки, оригиналы которых удалил

Кое-что про Renderman 1343


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

Особенно правильным считается употребление слова "пайплайн" в письменном виде, в


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

MAYA + Renderman = хорошо


Теперь, когда мы сугубо поверхностно (а я предупреждал!) рассмотрели теоретические
основы подключения внешних рендереров к MAYA, пришло время обратить внимание на
практический пример, в качестве которого у нас с вами выступит связка MAYA и Photorealistic
Renderman, а именно конкретная реализация такой связки - продукт под названием MTOR.

Почему мы с вами собираемся рассматривать именно эту связку? В последнее время


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

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

В свое время, когда мы (группа единомышленников, объединившаяся в рамках сообщества


Renderman.ru) только начали заниматься Renderman'oM и пропагандой этого стандарта в
русскоязычном интернете, приходилось достаточно часто сталкиваться с обращением новичков
«А где скачать Renderman для MAYA?». Я лично, будучи модератором посвященных Renderman
форумов, потратил многие часы своей жизни ответу на этот вопрос и его широко распространенную
разновидность: «А где скачать Renderman для Макса?» (Как показал опыт, данное упражнение
развивает как мышцы пальцев, так и любовь и терпимость к окружающим.) Оставив в стороне
правовые стороны такой постановки вопроса (а именно ту его часть, которая «а где скачать...»),
остановимся на главном: в его основе лежит широко распространенное заблуждение. Как
оказалось, достаточно просто перепутать два понятия - понятие Renderman как стандарта и понятие
Photorealistic Renderman (prman) как продукта, реализующего этот стандарт. И основная причина
этой путаницы возникла в недрах самой компании Pixar, которая сначала создала стандарт Ren­
derman, а потом начала распространять собственный продукт с очень похожим именем. И что
самое смешное, эта компания продолжает усугублять путаницу, подготавливая к выпуску продукт,
который называется Renderman for MAYA! (Чтобы народ окончательно запутался, можно предложить
Pixar'y анонсировать еще и Renderman for 3dsmax)

Что же такое Renderman? Это - стандарт описания трехмерных данных для их последующей
визуализации. В сборнике часто встречающихся вопросов и ответов ньюсгруппы comp.graphics.
rendering.renderman написано так: "Renderman - стандартный интерфейс между программами
моделирования и рендеринга для создания высококачественного фотореалистического
изображения". Создавая стандарт Renderman (а работа эта началась в доисторические времена
- еще в 1987 году), компания Pixar поставила перед собой достаточно амбициозную цель: пытаясь
воспользоваться идеями формата файлов Postscript как некоей среды для обмена векторными
двухмерными данными (а к тому моменту Postscript был уже широко развит и использовался
повсеместно), сделать аналогичный шаг и создать новый универсальный формат для обмена
информацией между системами для моделирования и анимации и системами для рендеринга,
который был бы достаточно универсален для того, чтобы занять место Postscript в мире трехмерных
приложений.

1344 Книга Сергея Цыпцына


Основная особенность стандарта Renderman в том, что данный стандарт разделяет понятия
геометрии в сцене и материала, который накладывается на данную геометрию. Параметры и
строение сцены описываются посредством Renderman Interface. В первоначальном варианте
спецификации стандарта этот интерфейс был для языка программирования С, используя который
вы могли написать программу, которая бы вызывала рендерер и передавала ему необходимые
параметры. Чтобы отрендерить прямоугольник, было необходимо написать приблизительно такую
программу (текст программы адаптирован из книги RenderMan Companion):

#include <ri.h>
RtPoint Square[4] = { {.5,.5,.5}, {.5,-.5,.5},
{-.5,-.5,.5}, {-.5,.5,.5}};

int main(void)
{
RiBegin(RLNULL);
RiDisplay("RenderMan", RI_FRAMEBUFFER, "rgb", RI_NULL);
RiFormat((Rtlnt) 256, (Rtlnt) 192, 1.0);
RiShadingRate(1.O);
RiWorldBegin();
RiSurface("plastic", RI_NULL);
RiPolygon( (Rtlnt) 4, RI_P, (RtPointer) Square, RI_NULL);
RiWorldEnd();
RiEnd();

return 0;
}

Ничего особо страшного, но и приятного тоже маловато - для человека с непрограммистским


складом ума. В качестве дополнительной возможности первой спецификации значился экспорт
данных в промежуточный формат данных под названием RIB, что расшифровывается как Renderman
Interface Bytestream. Вот как выглядит та же сцена в этом формате (я получил ее, скомпилировав
приведенный выше код на С в исполняемый файл и запустив полученную программу):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 1
WorldBegin
Surface "plastic"
Polygon "P" [0.5 0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5]
WorldEnd

Интуиция вас не подвела: впоследствии окажется, что в большинстве случаев гораздо


удобнее работать именно с форматом RIB, который и стал основной частью Renderman Interface, хотя
возможность использования С-интерфейса по-прежнему существует (для тех случаев, например,
когда вам проще генерировать геометрию процедурно, чем моделировать ее традиционным
путем).

У файлов в формате RIB, описывающих геометрию сцены, обычно (внимание!) такое


расширение: *.rib. В нашем примере вы видели обычное текстовое представление этого формата,
однако стандартом также предусматривается двоичное представление таких файлов. Такие
двоичные файлы занимают гораздо меньше места и хорошо подходят для случаев, когда сцена не
требует дальнейшей обработки и все, что нужно сделать - передать файл рендереру. Как указано
в спецификации формата, RIB изначально предполагался не как средство обмена геометрической
и структурной информацией между различными системами моделирования и анимации, но как
средство передачи данных от таких систем к рендерерам, то есть файлы такого формата не
обязательно должны быть максимально удобными для импорта в программу-моделлер, но должны
представлять максимум информации для последующего рендеринга.

RIB -очень хорошо продуманный расширяемый формат. Это сыграло большую роль в

Кое-что про Renderman 1345


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

Вторая составная часть стандарта Renderman - язык Renderman Shading Language или, в
приблизительном переводе, «язык закраски Renderman». Но не в наших привычках пользоваться
настолько корявым переводом, и потому в дальнейшем будем использовать общепринятую
аббревиатуру: SL.

Язык SL представляет из себя некоторое подмножество языка программирования С,


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

Дабы избежать короткого замыкания в мозгах неискушенных пользователей MAYA, подойдем


к вопросу с другой стороны. В MAYA ведь есть шейдеры? В чем же их отличие от шейдеров в Render-
man?

Ответим на первый вопрос, а заодно определимся с терминологией. Итак, шейдер - это


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

Так вот, с этой точки зрения майские материалы шейдерами не являются. Вы можете
скомбинировать ноды в HyperShade в нужном порядке, получив тот или иной материал - но шейдера
в результате вы не получите.

Очень часто в литературе и в устном общении встречается словосочетание "процедурная


текстура". Исходя из вышесказанного, и шейдеры и материалы - это процедурные текстураы, в
отличие от текстур непроцедурных, или говоря языком родных осин - «картинок».

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


поверхности не была новой даже для 1987 года, когда появился стандарт Renderman. Идея эта
является простой экстраполяцией того факта, что при программировании на низком уровне мы ВСЕ
РАВНО описываем в виде неких алгоритмов и геометрию и визуальные свойства объектов (упомяну
здесь ключевое слово для программистов: OpenGL). Теперь же, когда мы поднялись на более
высокий уровень и для рендеринга картинки уже не нужно писать больших и сложных программ
(а достаточно нажимать большие кнопки с красивыми иконками), оказалось, что процедурное
описание закраски все еще остается полезным, поскольку представляет собой наиболее гибкий
способ такого описания. Процедурные текстуры обладают и другими неоспоримыми достоинствами:
например, малым (по сравнению с обычными) размером файлов; отсутствием зависимости от
разрешения получаемой картинки. Но несмотря на все преимущества этого подхода, до появления
Renderman написание шейдеров носило в основном экспериментальный характер; именно Render-
man сделал шейдеры полноценным индустриальным стандартом; язык написания шейдеров SL
- это, возможно, наиболее известный и распространенный среди других шейдерных языков.

Как мы уже говорили, шейдер на SL- это программа на С-подобном языке программирования,
описывающая алгоритмически визуальное представление объектов, а если выразиться точнее:
описывающая алгоритм расчета интегрированной освещенности и прозрачности для данной точки
поверхности геометрического примитива. Для большего удобства в этом языке были сделаны
некоторые изменения - например, были введены специальные типы данных, которые описывают
цвет и позицию в трехмерном пространстве; синтаксис языка и его стандартная библиотека
процедур были упрощены, оптимизированы и дополнены, по сравнению с оригинальным языком
С, для работы с такими типами данных; был веден набор глобальных переменных, несущих

1346 Книга Сергея Цыпцына


информацию о цвете источников света, положении и ориентации освещаемого сэмпла и так далее,
существенно облегчающих программирование шейдеров.

Простой шейдер на языке SL, реализующий металическую изотропную модель освещения


поверхности, будет выглядеть так:

surface metal (float Ka=1, Ks=1, roughness=.1)


{
normal Nf = faceforward(normalize(N), I) ;
vector V = normalize(-l) ;

Oi = Os;
Ci = Os * Cs * ( Ka*ambient() + Ks*specular(Nf,V,roughness) );
}

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

При помощи шейдеров в Renderman можно контролировать не только модель отображения


поверхности (это задача для Surface shader'a), но и влиять на ее геометрию (через Displacement
shader), управлять поведением источников света (через Light shader), прохождением света через
область сцены (через Volume shader) и общим отображением информации в виртуальной камере
(через Imager shader):

Работа с шейдерами в SL также упрощена путем введения модели "черного ящика". В


переводе на человеческий язык это означает, что в каждый момент времени наш шейдер имеет
дело с одной конкретной точкой в сцене и отвечает на вопрос "Что происходит в данной конкретной
точке сцены"? Об этой точке шейдер знает все: где она находится, какой цвет назначен геометрии
в этом месте по умолчанию, какими геометрическими параметрами она обладает. Шейдер в такой
модели представляет из себя "черный ящик" с некоторым набором "ручек" - вы засовываете
исходные параметры в этот ящик, поворачиваете ручки в нужные позиции и получаете готовые
данные, и так - для каждой точки в вашей сцене. Есть в данном случае и «обратная сторона
медали»: в рамках шейдера вы, в общем случае, не имеете возможности обратиться к данным,
которые относятся к соседней точке этой же сцены, этого же полигона или шарика.

Кое-что про Renderman 1347


Где-то там, наверху, сказано, что в стандарте Renderman две основные части? Пардон,
оговорился: их-таки три, и на закуску я оставил самое интересное.

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

На самом деле стандарт никоим образом не указывает вам, какого рода рендеринг должен
происходить и какого рода обработка должна производиться с вашими файлами. Ваш рендерер
может быть рейтрейсером или использовать технологию сканлайн. Вы можете поддерживать
Global Illumination, можете быть REYES (Renders Everything You Ever Saw) - как prman; можете
быть объемным рендерером, гибридным, использовать A-Buffer, какие-то другие технологии
или их сочетания - стандарт не оговаривает таких подробностей и не ограничивает в деталях
реализации. Если вы хотите, чтобы ваш собственный рендерер стал официально совместимым со
стандартом Renderman, нужно лишь выполнить некий набор специальных требований (описанный
в спецификации стандарта и в книге Renderman Companion), а именно:

• поддерживать некоторое количество стандартных геометрических примитивов и


понимать формат файлов RIB;

• поддерживать шейдеры во всем их разнообразии и, соответственно, файлы SL;

• поддерживать внутри себя иерархическую структуру сцены в соответствии со


стандартом;

• содержать в себе стандартный набор из 15 шейдеров, также описанных в стандарте;


а также делать некоторые другие, не настолько интересные и важные вещи. И это
- все! Любые другие детали реализации движка рендеринга остаются на совести
разработчика; в стандарте, правда, есть небольшой список того, что было бы неплохо
иметь:

• Ray tracing
• Global illumination
• Level of detail
• Depth of field
• Motion blur
• Area light sources

Все это не осталось незамеченным - благодаря подобной гибкости стандарта, вкупе с его
открытостью и продуманностью, а также благодаря массированному продвижению компанией-
прародительницей - Pixar. Семена легли в благодатную почву всеобщего интереса к трехмерной
графике - на тот момент эта область знаний только начала развиваться и была освещающе новой,
а потому вдвойне интересной. А еще возник тогда интерес к специальным эффектам в кино.
Помните: Terminator 21... Jurassic Park?... Ox, как же давно это было!... Добавим в коктейль
отличный референсный продукт от самой Pixar - и получим воистину взрывоопасную смесь, которая
немедленно сдетонировала.

Вокруг стандарта Renderman немедленно образовалась новая ниша продуктов - рендереров,


экспортеров из всевозможных систем анимации и моделирования, вспомогательных программ.
Новичок в индустрии, стандарт сам стал индустрией. На данный момент существует уже больше
десятка рендереров, которые совместимы с Renderman'oм (ссылку на постоянно обновляемый
список смотрите в конце главы); фактически не существует такого пакета ЗD-моделирования,
который бы не выводил в RIB сам или при помощи плагинов.

Более того, благодаря своей открытости и доступности Renderman вошел в программу


обучения многих американских университетов. На крупнейшем мировом форуме, посвященном
компьютерной графике (я имею в виду, конечно же, Siggraph) Renderman'y посвящаются отдельные

1348 Книга Сергея Цыпцына


курсы, проходят собрания групп с особым интересом к этому стандарту - Special Interest Groups
of Renderman, а также группы Birds of Feathers; это - площадка, на которой разработчики и
пользователи стандарта и совместимых с ним продуктов встречаются и обмениваются новыми
идеями. Renderman живет уже своей, отдельной жизнью и пользуется огромной популярностью и
в студиях и среди непрофессиональных пользователей - благо рендереров хватает на любой вкус,
как высококачественных и дорогих, так и бесплатных, с открытым доступом к исходному коду).
Фактически Renderman стал одним из столпов современной индустрии визуальных эффектов.
Я очень хотел бы закончить наш краткий экскурс на этой мажорной ноте, но, как говорится, «в
жизни все не так, как на самом деле».

Историческое развитие индустрии компьютерной графики привело к тому, что Renderman


вместе с тем не стал универсальным стандартом, которого придерживаются все и любые системы
рендеринга. Это абсолютно нормальное явление: конкуренция хороша и нужна везде. Так или
иначе, компания Pixar отказалась от роли технологического лидера и проповедника, а взамен
сконцентрировала свои усилия на анимации, как студия (за что им огромное спасибо). Однако в
результате компания прекратила продвижение стандарта Renderman, перестала выдавать лицензии
на совместимые рендереры и взамен стала продвигать тот самый, референсный рендерер Photore­
alistic Renderman. Эра всеобщего благолепия и братства «людей-цветов» закончилась в августе 2002
года, когда Pixar подала в суд на разработчиков одного из конкурирующих рендереров, компанию
Exluna, с обвинениями в нарушении патентного права. Так руководимая Стивеном Джобсом
компания устранила одного из своих основных конкурентов на рынке Renderman-совместимых
рендереров. Можно долго спорить, кто был прав или виноват в данном случае, но факт остается
фактом: мир изменился навсегда, Renderman повзрослел.

Ну вот, на мажорной ноте закончить не получилось, а обрывать историю на минорной ноте


- не хочу. Да и не нужно ее обрывать, на самом деле, потому что на этом месте заканчивается
история, а начинается сегодняшний день. Когда и prman и стандарт Renderman сам по себе имеют
множество последователей по всему миру, и в том числе среди русскоязычных пользователей. Когда
технологии, описанные данным стандартом, нашли применение и признание как в зарубежных,
так и в отечественных студиях. День, когда историю пишем уже мы.

Не знаю, получилось ли у меня на одном вдохе рассказать о стандарте Renderman.


Рассказать о нем хотелось побольше, но очень многое просто не влезло или не очень соответствует
формату «книжки про MAYA». Нет здесь многого из истории стандарта и продукта, я не приводил
никаких сравнительных таблиц и не публиковал картинок и схем. Все это можно найти в книгах
и на ресурсах в Интернете, ссылки на которые я собрал в конце это главы. Ну, а теперь пришло
время выполнить данное ранее обещание: объяснить, почему именно связку MAYA-Photorealis-
tic Renderman используют в своем пайплайне ведущие студии мира. Не утруждая себя полным
перечислением - вряд ли оно возможно вообще - укажем лишь ILM, Weta Digital, Disney, Sony Pic­
tures Imageworks, Moving Picture Company, Framestore, Tippett Studio, Jim Henson Studios, наконец,
сам Pixar - список уже можно назвать «места, где я бы мечтал работать».

Как только студия принимает решение использовать в своем пайплайне спецэффекты


с использованием того или иного рендерера, к нему предъявляются некоторые, достаточно
специфические требования (в просторечии - он должен «быть production-ready»):

1. Набор возможностей рендерера не должен ограничивать пользователя, это очевидно.


Какие-либо ограничения на количество или качество входных или выходных данных недопустимы.
Даже если вам кажется, что никто никогда не сделает сцену со 100 миллиардами полигонов -
вспомните Билла Гейтса с его знаменитой фразой о 640 килобайтах памяти, которых хватит всем
(1981 год).

2. Рендерер должен понимать множество типов входной геометрии. В современных


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

3. Рендерер должен представлять широкие возможности настройки. Ничто так не радует


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

Кое-что про Renderman 1349


4. Более того, рендерер должен быть гибким. Лучшее доказательство гибкости рендерера
- это когда его можно использовать не по прямому назначению, и он, собака, работает!..
Хороший пример: производство нефотореалистичной анимации при помощи "фотореалистичных"
рендереров (возможность создать так называемый "картун" - cartoon animation).
5. Надежность. Давайте посчитаем. 70 минут среднего полнометражного полностью
трехмерного мультфильма. Вы вряд ли работаете сейчас именно над таким проектом, но помечтать
никто не мешает. Так вот, 70 минут,, или 4200 секунд. 24 кадра в секунду. Чуть больше 100
тысяч кадров - и это только чистового рендерера, но эту цифру можно запросто умножать на
6, если учесть проверочные рендеринги, внесенные по ходу изменения, раздельные рендеры
по слоям и служебные рендеры (текстуры, тени, бейкинг другой информации). Кто-то крикнул
«Какое - на шесть?! Умножай на тридцать!» М-да, вы, видимо, стремитесь к совершенству и у
вас неисчерпаемый бюджет... Мне ваш подход нравится, но давайте останемся хотя бы с нашей
цифрой. Впрочем, нет: семерка всегда и везде считалась счастливым числом, поэтому давайте
умножать на 7. Готово? 700000 кадров. По часу рендеринга, скажем, на кадр - годится? Итог: 80
машино-лет непрерывного рендеринга. Так вот: смысл наших расчетов состоит в том, что produc­
tion-quality renderer не должен падать. Да, софта без ошибок не бывает, в особенности такого
сложного и наукоемкого, каким является рендерер. И тем не менее: падать рендерер не должен.
Каждое падение добавляет новые и новые повторы рендеринга к вашей задаче, а кроме того
забирает и деньги (которых в бюджете всегда и без того мало) и время (которого до срока сдачи
вообще «с гулькин нос»).

6. Надежность. Вы не ошиблись, а я не оговорился. Написать это во второй раз не помешает.


Надежность нужна как воздух, и даже больше...

7. Производительность. Помните цифру наверху? 700 тысяч кадров. Которые вам нужно
отрендерить на вашей старенькой ферме за полгода. И не стоит рассчитывать на закон Мура
(«Мощность вычислительных устройств удваивается каждые 18 месяцев») - в нашей индустрии
действует другой закон, Блинна - «Вне зависимости от скорости компьютера, кадр считается
одинаковое количество времени». Как только вы проапгрейдите свои компьютеры, TD немедленно
найдет, чем занять их новые мощности.

8. Предсказуемость. TD должен быть в состоянии догадаться, насколько увеличится время


рендеринга при добавлении того или другого элемента. Если вы добавили мелкий элемент в сцену
и время обработки увеличилось вдвое - игра не стоит свеч, выбирать это ни к чему.

9. Последовательность. Ваш рендерер умеет рендерить все поддерживаемые примитивы


с применением Motion Blur. В день X авторы программы добавили поддержку нового примитива,
который пока что не понимает MB. В день Х+2 именно с этой проблемой вы столкнетесь в
вашем проекте. Все «навороты» используемого вами решения должны понимать друг друга и
взаимодействовать соответствующим образом - за исключением бессмысленных случаев - и,
возможно, даже в этих бессмысленных случаях.

10. Качество результата. Мы поставили его в конце, и этот параметр иногда сложно
измерить - но на самом деле это самый главный параметр, самое главное требование, основа всех
основ в рендеринге. Если вы делаете кино, то ваши картинки будут показаны на большом (а на
самом деле - на невероятно большом) экране, и каждый грязный и неправильный пиксель будет
иметь размеры, которые можно уже померить с помощью большой деревянной линейки (такие,
знаете, которыми так удобно размахивать, взявшись двумя руками). Любые артефакты, будь то
плохой антиалиасинг, неправильная апроксимация геометрии, ошибки отсечения, полосы Маха
- недопустимы. Более того, скорее всего вы делаете анимацию - а это означает, что также важно
соответствие кадров друг другу во всех деталях. Неподвижные объекты не должны дергаться,
медленно движущиеся - прыгать; антиалиасинг должен быть правильным и одинаковым для
объектов любого размера, находящихся на любой дистанции от камеры.

Ух! Объяснение получилось очень длинное и очень простое -prman полностью удовлетворяет
всем приведенным выше требованиям. А теперь сравните этот список с другим, относящимся к
стандартному рендереру MAYA.

i 350 Книга Сергея Цыпцына


Убедил? Тогда продолжим.

Ужасная история в поезде


Тихий зимний вечер. Мы вместе с классом возращаемся из поездки в Прибалтику. Поезд
проносится мимо темных полей и лесов. Парни внизу играют в карты, на полке напротив тоже что-
то происходит - но мне все равно, я читаю. Мне только что дали почитать СуперПовесть.

Я чуть ли не единственный участник поездки, который еще не успел прочитать эту повесть.
Она хит сезона, она ходит по рукам, от нее невозможно оторваться, очередь выстроилась на
неделю вперед. Класс разделился на тех, кто прочитал Произведение - и со смаком обсуждает
перипетии сюжетных поворотов, и тех, кто еще не успел и может только тупо кивать, слушая эти
обсуждения.

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

И вот оно, счастье: хозяин манускрипта едет со мной в одном купе (или это все-таки был
плацкарт)? Память услужливо подсовывает мне любые детали, кроме этой. Я пользуюсь моментом
- и встреваю без очереди, выпросив эти пожмаканые листики у хозяина и клятвенно пообещав, что
быстренько прочитаю и верну.

О, что это была за повесть! Не обращая внимания на ее содержание (а именно,


борьбу бравого «зеленого берета» за выживание в диких джуглях Амазонии), стоит отметить
исключительно занятный художественный стиль. Ломаное повествование все время бросало
меня из одного ключевого момента в другой. Казалось, что в произведении совсем нет сюжетной
линии, и лишь к тому моменту, когда я осилил примерно половину листков - скрючившись под еле
светящейся лампочкой на второй полке (вспомнил: это был плацкартный вагон!), уже далеко за
полночь, безумно уставший, борясь со сном, со слипающимися и немного слезящимися глазами,
под монотонный стук колес и покачивание вагона разогнавшегося поезда - я наконец-то понял, что
произведение построено наоборот - сюжетная линия ведет меня от конца к началу повествования,
время от времени подбрасывая новые заморочки в своем движении к финалу апофеоза.

Я уже говорил, что на листиках не было номеров страниц? Так вот: их не было...

Всю чудовищность произошедшего я осознал лишь в тот момент, когда увидел на последней
странице ЗАГОЛОВОК повести. Как оказалось, все это время я боролся с сюжетом и плохим
освещением, читая повесть наоборот - от последнего листа к первому...

К чему городить воспоминания школьных лет в книжке про MAYA, спросите вы? Да просто
потому, что, по моему искреннему мнению, начинать рассказ о prman с описания функциональности
Renderman Artist Tools (RAT) - это все равно, что начинать читать интереснейшую книжку с конца.
Нет, не так - это все равно, что начинать читать учебник с конца. Это антипедагогично, антинаучно,
антиморально и вообще неправильно.

И именно это мы собираемся сделать сейчас - начать рассказ с RATa.

Конечно, можно было бы все-таки внять зову сердца и сделать из этой главы академический
учебник: начать с азов, постепенно продвигаясь ко все более и более сложным вещам. Но так
уж получилось, что самое интересное и самое презентабельно выглядящее в prman - это «две
большие разницы». Да и, в конце концов, мы же не ставим себе целью усыпить нашу аудиторию
посреди главы?

Поэтому придется поступиться принципами и построить обзор возможностей комбинации


prman+MAYA в точности так, как я когда-то читал ту самую повесть - то есть задом наперед. Сначала
мы с вами рассмотрим RAT, входящие в него утилиты, их особенности и алгоритм работы с ними.

Кое- что про Renderman 1351


Затем пойдем назад (или, все-таки, вперед?), опустимся чуть поглубже, в потроха рендерера, и
узнаем, как оно все там внутри работает и вызывается.

Кстати говоря, несмотря на то самое происшествие в поезде, я все еще не могу избавиться
от дурной привычки читать с конца журналы. Хотя в последнее время поступаю так все реже и
реже.

RAT, или Рендерим Визуально


Прежде всего, введем в употребление некоторые аббревиатуры, используемые в
пиксаровских продуктах. Итак:

• prman - PhotoRealistic renderMAN или, официально, Pixar's RenderMan - собственно,


рендерер от Пиксар. Я уже использовал это обозначение раньше, теперь просто привожу его для
закрепления.

• RAT - Renderman Artist Tools набор инструментов и плагинов для связи MAYA и prman.
Если кто-то называет его «рэт» (то есть «крысой»), знайте: перед вами новичок. Закоренелый
трехмерщик непременно назовет его "рат" (и уж никак не "Ар-Эй-Ти").

• MTOR MAYA TO Renderman - собственно плагин для MAYA, который позволяет ей рендерить
при помощи Renderman-совместимых рендереров. Входит в состав RAT.

Продуктовая линейка Пиксар на момент написания этих строк включает в себя три продукта:
Renderman Pro Server (включающий в себя prman, Irma и Alfserver), RAT (в составе MTOR, Slim, Al­
fred, "it") и Renderman For MAYA. Нужно было бы, конечно, для лицензионной чистоты расставить
в предыдущей фразе значки ™, в произвольном порядке, ну да ладно.

Еще раз для того, чтобы хоть что-то отрендерить, вам понадобится Pro Server. Для того,
чтобы связать MAYA и Pro Server, нужен RAT:

Renderman for MAYA отдельный новый продукт, боковая ветка эволюции prman и RAT, и он
предназначен для более удобной увязки этих продуктов, причем нацелен, в первую очередь, на
людей, ранее с Renderman'oM не сталкивавшихся. Мы не будем рассматривать Renderman For MAYA
в этой главе детально, поскольку на момент подготовки этой главы продукт все еще не был выпущен
в продажу и не был доступен для бета-тестирования. Для любознательных. Само название Render-
Man имеет любопытную историю. В самом начале основатели Pixar собирались создавать «железо»
- аппаратные решения для рендеринга. В идеале такой микрокомпьютер должен был быть очень
маленьким, чуть ли не карманным. Из таких компьютеров, согласно тогдашней идее, создавались
бы "render walls", так что они объединяли бы свои усилия в рамках одной задачи. Производством
такого железа могли заниматься кто угодно, но оно было бы полностью совместимым, поскольку
подчинялось бы стандарту Renderman. Тогда как раз появился карманный плейер для аудиокассет
фирмы Sony, который назывался Walkman, и вот, по аналогии с ним, будущее устройство назвали
Renderman.

Правда, новый микрокомпьютер так и не появился в продаже, но имя - и стандарт - прижились.

MTOR
Первое, с чем столкнется пользователь MAYA, установивший комплект из Pro Server и RAT
(а работать с ними он будет именно в такой связке) - это MTOR. В интерфейсе MAYA это проявится
вот таким вот образом:

1352 Книга Сергея Цыпцына


то есть в вашем меню появится новый пункт - RenderMan:

Что произойдет после того, как вы (предварительно загрузив какую-нибудь существующую


сцену), выберете пункт меню RenderMan=>Render? Вот что: MTOR последовательно обойдет все
элементы сцены и постарается вывести их в файл формата RIB. Кроме того, он пройдется по
геометрии и источникам света и назначит для них шейдеры в RIB'e - но сделает это очень хитро:
MTOR фактически не будет учитывать текстуры и сложные материалы, эмулируя лишь некоторый
стандартный набор шейдеров (Ambient Light, Directional Light, Point Light, Spot Light, Phong, Blinn,
Lambert - эти шейдеры легко опознать по сигнатуре имени файла mtor*.slo). Наконец, будет
запущен рендеринг, который вызовет окно Alfred и выведет результаты в окне it.

Как видите, все переплелось и взаимосвязалось. Попробуем разобраться в клубке из


аббревиатур и программ, и сделаем это с помощью простого тестового примера.

Набросайте в сцену несколько примитивов и добавьте источники света - пусть это будет
простой майский directLight:

Кое- что про Renderman 1353


В общем, уже можно рендерить. Что мы и делаем: RenderMan=>Render.

Мы только что вызвали на выполнение MTOR - плагин, позволяющий MAYA рендерить с


помощью Renderman-совместимых рендереров. Плагин этот встраивается в интерфейс MAYA, но
поскольку был написан достаточно давно, еще во времена первых версий MAYA (когда встраиваться в
Render Globals и Rendering Window не позволялось), то и проявляется он в виде меню и вызываемого
из этого меню набора собственных окон.

На плечах MTOR лежит задача вывода геометрии в формат RIB и вызова других программ из
набора. Также он осуществляет поддержку совместимых с Renderman'oM сабдивов в интерфейсе
MAYA - видите в меню RenderMan последний пункт: Pixar Subdivs? Это оно.

Сильная сторона MTOR - его программируемость. Встраиваясь в MAYA, MTOR добавляет


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

По моему мнению, RAT - это попытка технарей из Pixar усидеть сразу на двух стульях, а
именно - сделать продукт, который одновременно был бы удобен для неопытного пользователя
и мог бы быть расширяем опытным пользователем. В общем, где-то табурет у них и получился:
пользоваться более-менее удобно, ручки все на месте, настроить под свои требования тоже
можно. С другой стороны, у такого подхода есть и свои проблемы, но о них потом.

Alfred
А у нас тем временем (сцена несложная и много времени на экспорт в RIB не ушло)
появляется окно Alfred:

Alfred система распределения рендеринга по локальной сети. Даже если вы не


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

Alfred - достаточно продвинутый сетевой инструмент, который используют во многих студиях


не только в составе RAT, но и для сетевого рендеринга из MAYA, 3dsmax и даже After Effects, Shake

1354 Книга Сергея Цыпцына


и Nuke, благо под Renderman он не заточен, а в качестве файла задачи в нем выступает обычный
Tcl скрипт с командами. Но несмотря на такую гибкость и на то, что Alfred используется в работе
самими сотрудниками компании Pixar, качество кода этого продукта от релиза к релизу заметно
ухудшается и потому в последнее время появилась тенденция ухода студий на альтернативные (в
том числе и собственной разработки) сетевые диспетчеры.

Раз уж мы заговорили об Альфреде, обозрим и его лучшего друга Альфсервер.

Alfserver
Alfserver - это собственно агент, выполняющий задания Alfred. Название этой программы
несколько сбивает с толку, поскольку мы привыкли, что сервером называется одна головная
программа, к которой подсоединяется множество клиентов. В данном случае центрального
рендеринг-сервера, раздающего задачи клиентам, нет, и применяется обратная аналогия:
клиент-диспетчер задач один (это Alfred), и он сам распределяет задачи по серверам (Alfserv­
er), установленным на рендеринг-машинах в ферме. Очевидно, что клиентов может быть много
(скажем, клиент может быть установлен на компьютере у каждого аниматора и работать по ночам,
пока аниматору снятся анимационные кривые), и все они будут распределять свои задачи по
серверам.

Для продвинутых. Конечно, все не так просто. При работе с Alfred'ом существует
возможность использовать утилиту maitre_d, которая будет выступать в качестве центрального
сервера но основной принцип работы от этого не изменится, поскольку утилита эта сама
распределять задачи не может, а всего-лишь собирает информацию о занятости систем и прочих
метриках и раздает ее всем желающим, а локальные диспетчеры используют эти метрики для
оптимизации нагрузки рендеринг-фермы.

It
А тем временем мы почти сразу же после появления окна Alfred видим новое окно - it, в
котором быстро проявляется наша картинка:

it (от Image Tool) - в оригинале вьюер для графических файлов, в последних версиях
вобравший в себя функциональность просмотрщика последовательностей, каталогизатора файлов
и даже композера. Я более чем уверен, что большинство пользователей RAT не используют даже

Кое-что про Renderman 1355


50% возможностей этой программы - а зря.

По умолчанию it выступает в качестве display target при рендеринге. Это удобно, если вы
хотите посчитать несколько различных картинок подряд, а затем сравнить их или выбрать лучшую
из серии.

Сравним полученную картинку с результатом рендеринга при помощи родного движка от MAYA:

Очень похоже, не правда ли? Ничего, в общем, удивительного сцена примитивная, и


потому нашему крутому рендереру prman негде было развернуться во всей своей красе.
Вы не могли не заметить, что разные размеры у картинок, полученных при рендеринге через RAT
и родным рендерером MAYA. Самое время узнать, каким образом настраивается RAT, а именно,
вызвать RenderMan=>RenderMan Globals.

Подробное описание всех функций этого окна оставим для документации по RAT - кстати

1356 Книга Сергея Цыпцына


говоря, несмотря на некоторую запутанность и огромный размер, она обладает одним немаловажным
преимуществом - в ней есть все.

Пытливый читатель уже обнаружил параметр Display Resolution. На нашем скриншоте этот
параметр уже выставлен в 0, 0 - таким образом, мы всегда будем рендерить в размере выбранного
viewport'a MAYA (по умолчанию же этот параметр выставлен в 640x480). Кстати говоря, обратите
внимание на значки i рядом с именами параметров - это контекстная справка. Про возможность
установки (0,0) я узнал именно из нее.

Для любознательных. Как видите, разрешение рендеринга в MAYA и RAT не сихронизированы.


Оставим для других обсуждение правомерности этого поступка; сами же скажем, что задачу эту
можно достаточно просто решить с помощью механизма скриптования MTOR. Для этого достаточно
немного покопаться в документации в сторону RibBox, mattr и майского нода resolution.

SLIM
Вернемся к MTORy. Чего он делать, к сожалению, не умеет - так это конвертировать
майские материалы в шейдеры Renderman'a. По идее разработчиков RAT, этого от программы и не
требуется, поскольку считается, что все шейдеры будут либо написаны вручную, либо их создадут
с помощью SLIM - визуального конструктора шейдеров.

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

SLIM, как и Hypershade, реализует древовидную схему построения шейдеров из блоков, но


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

На самом деле, когда я занимался историей этого вопроса (чтобы кратко осветить его в
этой вставке, для любознательных), я был буквально ошеломлем тем количеством информации,
которая доступна в Интернете по поводу Визуального Программирования а ведь визуальное
построение шейдеров суть визуальное программирование и есть.

Как оказалось, первая графическая компьютерная система, которую продемонстрировал


в 1963 году Сазерленд (она называлась SketchPad - для тех, кто уже запустил верный Google),
уже была оснащена визуальным редактором для быстрого построения программ - и количество
разработанных с тех пор систем визуального программирования огромно.

Кое-что про Renderman 1357


Так почему же мы до сих пор не строим все наши программы визуально? Почему
программисты шейдеров в той же компании Пиксар до сих пор пользуются vi и emacs, создавая
свои сотни тысяч строк кода шейдеров (цифры реальные)? Этому можно посвятить отдельную
статью, а то и книгу; скажем лишь, что у визуального представления программ есть некий порог
сложности, начиная с которого их становится сложно редактировать и эта возрастающая сложность
редактирования и понимания нивелирует все достоинства метода.

Создаваемые в SLIM материалы назначаются на геометрию в MAYA, добавляя к шейпам


новые собственные атрибуты с необходимой для MTOR информацией.

Более того, таким же образом (через кастомные атрибуты из SLIMa) вы можете добавлять
в сцену свой собственный RIB-код при помощи так называемых RIBbox (мы их уже упоминали в
отступлении для любознательных). Дальше больше: расширяемый SLIM (как и сам MTOR, при
помощи Tcl) позволяет вставлять в сцену TCLbox'ы, которые будут исполняться на этапе экспорта
сцены в RIB и имеют полный доступ как ко внутренним интерфейсам самой MAYA, так и к командам
MTOR и SLIM.

Для любознательных. Основной атрибут шейдера называется slimSurf; короткое имя, под
которым он фигурирует в скриптах и в файлах *.ma sss. В ASCII-файле MAYA это выглядит примерно
так:

createNode nurbsSurface -n "revolvedSurfaceShapel" -p "revolvedSurface1";


addAttr -ci true -sn "sss" -In "slimSurf" -bt "UNKN" -dt "stringArray";
setAttr -k off ",v";
setAttr ".fbd" no;
setAttr ".sss" -type "stringArray" 1 "0ZQ0MmpFLGE00000" ;

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

Не получилось? Не расстраивайтесь, у меня тоже не получилось, поэтому я просто взял


готовую модель (автор модели - Ник Габченко, за что ему отдельное спасибо) из файла sheep.mа
(вы можете найти его на диске).

Эта модель - полигоны, переведенные в сабдивы (subdivision surfaces) при помощи команды
Modify=>Convert=>Polygons to Subdiv. Давайте опробуем SLIM на деле и назначим овечке материалы:
Renderman=>Slim=>New Palette.

1358 Книга Сергея Цыпцына


В меню SLIM выбираем File > Create Appearance > Surface > Velvet - пусть овечкина голова
будет бархатной. Двойной клик по шейдеру Velvet, клик по области Preview, и вот:

Как видите, это довольно сильно напоминает Attribute Editor для стандарных майских
материалов.

Темноватый бархат получился, сделаем-ка его немного светлее. Изменяем Kd, поскольку
амбиентного источника у нас в сцене не будет (говорят, иметь их в сцене вредно), изменяем цвет,
все время проверяем результат, кликая на шарике. Добившись вменяемого результата, назначаем
созданный материал: в MAYA выбираем голову овечки, затем в основном окне SLIMa выбираем Ap­
pearance=> Attach. Рендерим. (А вы уже вынесли на полку пункт меню RenderMan=>Render?)

И чтобы уже совсем сделать наш краткий туториал похожим на все остальные 1327
туториалов для начинающих, заполонивших Интернет, покажем, как собственно делаются в SLIMe
более сложные составные шейдеры.

Для любознательных. Число 1327 выбрано случайно. Кстати, о случайных числах - вот
вы знаете, например, как отличить TIFF файл по сигнатуре? Оказывается, очень просто - у него
третьим и четвертым байтом записано число 42: как сказано в спецификации, «an arbitrary but
carefully chosen number (42) that further identifies the file as a TIFF file» . Я думаю, вопрос о том,
почему выбор не пал на 43 или 41, неправомерен, поскольку они не являются пятым Каталонским
Числом.

Так вот, рядом с Velvet color кликнем на желтом квадратике и в выпавшем меню выбираем
Connection. В этой же строке справа в вываливающемся списке выбираем Noise. Должно получиться
что-то такое:

Кое-что про Renderman 1359


После клика по кнопке Noise мы попадаем в редактор уже самого шума.
И опять для любознательных. Придумал «нойз» и первым реализовал шейдеры в продакшн-
рендеринге один и тот же человек Кен Перлин.
Быстренько задираем величину frequency в заоблачные дали (а именно, где-то в 10), кликом по
диагональной стрелочке возвращаемся к исходному Velvet и сразу же видим результат на нашей
овечке. Исправить ситуацию с UV-маппингом головы овечки, из-за которой нойз так постыдно
размазался, мы оставим в качестве домашнего задания для читателей, а сами закончим наш
туториал на самом интересном месте и продолжим рассматривать программы и утилиты, входящие
в состав RAT. Их осталось не так уж и много. Честно говоря, осталась одна

Irma
Irma - ре-рендерер. В общем, идея проста - вы рендерите один раз с помощью «Ирмы»,
которая кэширует необходимую информацию о сцене, освещении и шейдинге. Все последующие
разы ре-рендеринг использует эту информацию и происходит гораздо быстрее, без перегенерации
RIB-файлов и шейдеров. Irma понимает изменения параметров шейдеров, позиции источников
света и изменения в координатных системах - такие изменения будут просчитаны очень быстро.
Ближайший аналог Irma из мира MAYA - это, конечно же, IPR.

Что бы не говорили, а большую часть интересных новых идей уже кто-то придумал до нас.
Взять, например, ту же «Ирму» с IPROM. Самая первая реализация шейдеров в продакшне - та
самая, которую реализовал на Фортране Кен Перлин - использовала те же идеи: предварительный
рендеринг всего, что можно, в буфер и последующее наложение шейдеров. С другой стороны, с
тех пор утекло очень много воды, и в современных рендерерах большая часть времени тратится
именно на шейдеры. Тем полезнее для вас будет Irma.

prman, или Закапываемся


В 1642 году известный голландский мореплаватель Абель Тасман во главе экспедиции из
двух кораблей отплыл из Джакарты на поиски новой земли на стыке Тихого и Индийского океана.
В ходе своих скитаний путешественник открыл (для европейцев!) Тасманию, Новую Зеландию,

1360 Книга Сергея Цыпцына


острова Фиджи - но при этом умудрился проплыть мимо Австралии!

Я ничего не имею против Новой Зеландии (скорее наоборот), но человек, пытающийся


использовать prman исключительно при помощи RAT, не рассматривая взаимодействие этих
программ, уподобляется славному голландскому первооткрывателю - как Тасман все-таки
открыл Австралию через два года после первого путешествия, так и незадачливый исследователь
Renderman'a все равно откроет для себя командную строку. И вот тогда он, наконец, поймет,
сколько всего интересного скрывал под поверхностью океана айсберг.

К сожалению, не многие проходят этот путь, цепляясь за визуальные инструменты и пытаясь


как можно дольше не погружаться в глубины ЕХЕ-файлов и их параметров. Их позывные слышны
издалека: "Я художник, я не понимаю этого вашего всего, оно мне не нужно, пусть программисты
в этом копаются, а мне пусть сделают мегакнопку".

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

Так что, нещадно перевирая цитаты из блокбастеров, грянем:


- В чем сила, брат?
- В командной строке!
- Да пребудет с тобой сила!

prman.exe
Большинство Renderman-совместимых рендереров состоит из трех программ: собственно
рендерера, компилятора шейдеров и компилятора текстур.

Не столь важно, получилось ли так исторически или просто все рендерерописатели Render­
man-совместимых рендереров смотрели на Pixar в качестве образца - но подобная тройственная
архитектура сохраняется, с теми или иными отклонениями, во всех таких рендерерах. Отчасти в
этом есть некая дань стремлению к максимальной оптимизации процесса и разделению рендерера
на независимые модули. Отчасти - это отклик Unix-овского наследия. Отчасти - это слепок самой
идеи, заложенной в спецификацию Renderman (согласно которой процедурные материалы
(шейдеры) и описание геометрии хранятся в разных файлах, соответственно, в *.SL и в *.RIB). Так
или иначе, тенденция есть, и она сохраняется даже в случае с самыми современными рендерерами
-в их поставке вы тоже обнаружите три ехе-шника: рендерер, компилятор шейдеров и конвертер
текстур.

В этом изысканном трио основная программа , конечно, сам рендерер: prman.

Вызовите свою любимую командную строку (если вы используете Windows, для этого
нужно в стартовом меню Run запустить cmd.exe) и уже в новом окне командной строки запустите
на выполнение prman.exe.

У новичков может возникнуть впечатление, что программа зависла: сразу после запуска
ничего не произошло, и обратно в командную строку мы не вернулись. На самом деле мы
столкнулись еще с одной особенностью программ, изначально написанных в расчете на консоль
Unix - эти программы предназначены, в том числе, и для работы в режиме пайпинга, то есть
передачи данных от одной программы к другой. Так вот, если такую программу запустить на
выполнение, не указав параметров, она будет ожидать, что данные будут поступать на вход от
других программ (для продвинутых: из stdin) или будут набираться с клавиатуры. Значит, нам
нужно это и сделать - запустить программу с параметрами.

Остановим этот экземпляр рендерера при помощи клавиатурной комбинации Ctrl-C.


Возьмем образец текстового RIB-файла из начала нашей главы и сохраним его как test1.rib. Стойте,
не нужно судорожно листать наше повествование в обратном направлении, вот необходимый код
(он также есть на диске):

Кое-что про Renderman 1361


Display "RenderMan" "framebuffer" "rgb"
Format 256 192 1
ShadingRate 1
World Begin
Surface "plastic"
Polygon "P" [0.5 0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5 0.5 -0.5 0.5 0.5]
WorldEnd

Повторим наш экзерсис с рендерером, на этот раз передав программе в качестве параметра
имя test1.rib:

Как видите, в результате получилось... Гм... ничего у нас не получилось. В чем же причина?
Причин на самом деле несколько, и все они достаточно очевидны:

1. В нашей примитивной сцене нет источников света. Поэтому сцена получилась полностью
неосвещенной (умное название для эффекта "ничего не видно")

2. В нашей сцене используется (это не очень очевидно) полигональный объект,


расположенный таким образом, чтобы полностью покрывать видимое пространство (это совсем
неочевидный факт, но можете поверить мне на слово).

Использовать в качестве упражнения на рендеринг в книжке полигон, находящийся в


черной-черной сцене - это, в общем, готично, но при этом не совсем педагогически правильно.
Поэтому нам с вами нужно немножко поработать над нашим RIB'OM, чтобы получить хоть сколько-
нибудь удобоваримую картинку. Я сделал эти исправления вручную в текстовом редакторе, вы
можете просто скопировать текст из книги или из файла test2.rib:

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 1
Translate 0 0 2.7650300856
WorldBegin
TransformBegin
LightSource "ambientlight" 500 "lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] " t o " [0 0 0]

TransformEnd
Surface "plastic"
Sphere 1 -1 1 360
WorldEnd

Записываем этот файл поверх старого и повторяем вызов рендерера:

1362 Книга Сергея Цыпцына


Вот, совсем другое дело. Поздравляю вас с приобщением к великой могучей командной
строке и обществу ее последователей и почитателей.
Если вы хорошо рассмотрели скриншот с командной строкой, то обратили внимание, что
команда, которую мы выполняли, выглядит вот так:

prman test1.rib

Это не единственный возможный способ передачи информации в рендерер; как один из


примеров, мы можем воспользоваться тем самым пайпингом (или «туннелированием», как его
называют некоторые несознательные юниксоиды-русофилы):

type test1.rib | prman

Результат будет в точности такой же. Но это еще не все. Вы же знаете, что «туннелировать»
можно не только две программы, но и целые цепочки программ?
В качестве примера (скриптоненавистники могут пропустить страницу) напишем небольшой
скрипт на Perl, который будет заменять объявление материала Plastic на объявление материала
Stone. Делаем новый файл, называем его magic.pl и пишем нечто вот такое:

foreach (<>) {
s/plastic/stone/;
print;
}

Наша цепочка выполняемых программ в данном случае немного изменится и будет


выглядеть так (я переименовал RIB-файл):

type test2.rib | perl magic.pl | prman

Читаем написанное слева направо: распечатать в консоль файл test2.rib и передать


результат в программу perl, которая выполняет файл magic.pl, который заменяет все нахождения
слова plastic на слово stone и опять печатает в консоль. Вывод этой консоли передается собственно
рендереру:

Кое-что про Render man 1363


Для того, чтобы это сработало на вашей машине (если вы не сидите сейчас за Unix-
терминалом), вам понадобится установить на своем компьютере интерпретатор языка
программирования Perl (например, ActivePerl).

-Лирическое отступление: Perl, по искреннему мнению многих (и я к нему присоединяюсь)


- язык программирования для истинных криптоманьяков. Расшифровывать свои собственные
скрипты через полтора года с момента последнего их использования - занятие, доставляющее
нереальное удовольствие. Так прямо себе и представляю: Блетчли-Парк, Вторая мировая война,
а взломавший «Энигму» Тьюринг никак не может разобраться в перловом скрипте из четырех
строк...

Примечание. Perl - это write-only код (С.Ц.)

Вы уже слышите, как тихонько зазвучало в воздухе исконно русское слово "pipeline"?
Просто подумайте о тех невероятных возможностях, дверь к которым мы только что приоткрыли.
Получается, что геометрию для рендерера совсем не обязательно выводить из MAYA (или 3dsmax,
или Houdini, или откуда угодно еще - на самом деле, неважно, откуда именно) - вы можете сами
писать небольшие программы или скрипты, которые будут или создавать новые файлы RIB или
модифицировать уже существующие. Более того, файлы эти можно запросто открывать в текстовых
редакторах, делать замены, переставлять куски местами, экспериментировать с различными
возможностями - и все это без запуска и использования безумных систем моделирования
и анимации. Да что уж там - изучение текста сгенерированных RIBOB представляет собой
захватывающее интеллектуальное психоделическое путешествие в мир трехмерной графики и во
внутреннее устройство вашего любимого моделлера. Как подействует это изменение в модели на
RIB? Что изменится, если сделать то или это? Какая картинка получится в том или ином случае?

Лирическое отступление. Что уж говорить, я сам прошел через это увлечение


текстовыми рендерерами, но у меня оно началось не с Renderman-совместимых.
Первым рендерером, который я запустил на своем новеньком, свежесобранном
с иголочки 486DX4-100, был Vivid. Где-то в то же время на моем жестком диске
гостили еще и DKB с PovRay'eM в ранних версиях (собственно, PovRay является
развитием DKB, если мне не изменяет память), но Vivid - это было наше все.
Быстрый рейтрейсер, простой входной формат данных, полноцветный выход
- целых 24 бита!

Не один вечер провел я в экспериментах с картинками и скриптами, в попытках сделать


тот или иной элемент, материал, эффект. Рендерер этот был действительно быстрым, быстрее
PovRay чуть ли не в десятки раз (жаль, он не запускается под Windows XP: уж очень хочется
проверить эти мои старые ощущения на новом железе). Такая скорость позволяла мне за вечер
перепробовать множество вариантов, получить множество красивых - и не очень - результатов. В
общем, это была любовь с первого зеркального шарика (стоящего на шахматной доске - а как же
без этого).

Ау, XXX [название удалено по понятным причинам - Автор.], продукт отечественного


трехмерного софтостроения! На совести вашего криво написанного деинсталлятора - все мои
картинки, исходники к ним, равно как и все остальное содержимое моего славного боевого друга
и товарища - диска С! Надеюсь, в славном 199х-ом году вам славно поикалось.

Первый Renderman-совместимый был потом, и был это - BMRT. Но это уже - современная
история: с Интернетом, Амазоном, Пентиумами и ньюсгруппами.

Впрочем, я немного увлекся. Точнее: отвлекся...

i 364 Книга Сергея Цыпцына


Другие RIB'bi
Отметим, что у RIB'OB представление бывает не только текстовое, но и бинарное
(оптимизированное для быстрой загрузки рендерером) и упакованное (оптимизированное для
уменьшения занимаемого дискового пространства - используется библиотека упаковки GZIP).
Объединенного бинарно-упакованного представления нет, но его несложно сымитировать при
помощи той же самой командной строки:

catrib -binary test2.rib | gzip -cq9 > test2.gbin

Слева направо: программа catrib (из поставки Pixar Renderman Pro Server) переводит файл
test2.rib в бинарный формат и результат передает в программу gzip (вам придется скачать ее из
Интернета), которая упаковывает ее и передает дальше, в файл test2.gbin.

Чтобы теперь отрендерить файл test2.gbin, развернем цепочку программ в другом


направлении:

gzip -cd test2.gbin | prman

Что и требовалось доказать.

Для продвинутых. Я вам по секрету скажу - на самом деле можно делать и так:

prman test2.gbin

prman , а также некоторые другие рендереры, понимают такие файлы и отлично с ними
работают.

shader.exe
Вернемся к нашему шарику. Переименовываем файл в test3.rib и вносим небольшие
изменения - убираем строку, определяющую материал (Surface "plastic"):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 1
Translate 0 0 2.7650300856
WorldBegin
Transform Begin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] "to" [0 0 0]

TransformEnd
Sphere 1 -1 1 360
World End

Различия в файле минимальны, но зато какое различие в результате:

Кое-что про Renderman 1365


В отличие от некоторых других рендереров, у prman есть понятие "шейдера по умолчанию"
(этот шейдер хранится в файле с характерным названием defaultsurface.sl; у некоторых рендереров
этот материал встроен в код рендерера - "захардкожен"; аналогом из мира MAYA является lam-
b e r t l , назначаемый на все вновь создаваемые объекты). Даже если вы не назначили материал на
свою геометрию, она все равно отрендерится с использованием материала по умолчанию.

Для продвинутых. В лучших FX-домах иногда в качестве шейдера по умолчанию


устанавливают закраску модели красным цветом. Таким образом, при первом же тестовом
рендеринге будет сразу видно, на какую из моделей вы забыли наложить материалы. Если
геометрии в сцене действительно много - подобный трюк будет очень полезен.

Ранее в своих экспериментах мы использовали шейдеры Plastic и Stone. Вообще


говоря, согласно спецификации стандарта, со всеми Renderman-совместимыми рендерерами
должны поставляться следующие шейдеры (вы помните, что источники света в Renderman тоже
определяются шейдерами):

. null
• constant
• matte
• metal
• shinymetal
• plastic
• paintedplastic
• ambientlight
• distantlight
• pointlight
• spotlight
• depthcue
• fog
• bumpy
• background

Так что поиграть уже есть с чем, но мы хотим сделать что-то свое. Представим себе, что
вы где-то из Интернета скачали шейдер, который обучает вас использованию в Shading Language
функции noise:

surface noisetest ( float freq=10; )


{
Ci = color(noise(freq*s,freq*t));
}

Для продвинутых. Нойз ("шум") - это отличный и обычно первый из приходящих в голову
способов добавить нерегулярности в "стерильную" компьютерную картинку.

Сохраните его в текстовый файл под названием noisetest.si рядом с файлом test3.rib.
Немного правим test3.rib, добавляя в него ссылку на новый материал:

1366 Книга Сергея Цыпцына


Display "RenderMan" "framebuffer" "rgb"
Format 256 192 1
ShadingRate 1
Translate 0 0 2.7650300856
WorldBegin
TransformBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5-1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] " t o " [0 0 0]

TransformEnd
Surface "noisetest"
Sphere 1 -1 1 360
WorldEnd

Запускаем на рендеринг и получаем сообщение об ошибке:

S01001 Cannot load shader "noisetest". (WARNING)

Что происходит? Мы же, вроде бы, все правильно сделали, указали материал, положили
шейдер рядом - что не так? Ан нет, не все так просто. Перед непосредственным использованием
шейдер необходимо привести в состояние, которое будет максимально удобным для рендерера
- а попросту говоря, откомпилировать.

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

Для компиляции используется вторая программа нашего могучего триумвирата - shader.exe.


Возможности и гибкость вызова этой программы абсолютно аналогичны возможностям и гибкости
prman.exe: если мы хотим, можем соорудить цепочку программ, которые будут генерировать
тексты шейдеров на языке SL. Но мы сделаем просто:

shader noisetest.si

Программа отработала, и в нашей директории рядом с файлов noisetest.sl появился noisetest.slo.


Не стоит в него заглядывать - там интересно, но не настолько, чтобы мы отвлекались. Попробуем
отрендерить картинку еще раз и вот:

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

Кое-что про Renderman 1367


достаточно будет одного лишь довода в пользу такого требования - скорость исполнения. Язык
С достаточно сложен для того, чтобы быстро интерпретировать его (выполнить программу без
предварительной компиляции) было почти невозможно. Поэтому создатели рендереров идут на
что угодно, лишь бы ускорить процесс обработки шейдеров внутри своих программ, перенося
эту задачу на компиляторы шейдеров. Prman внутри себя использует архитектуру выполнения
SIMD, для которой компилятор shader генерирует специальный бинарный код. Другие рендереры
поступают по-другому, например, RenderDotC превращает SL-код в минипрограмму на языке
программирования C++, которая затем компилируется уже в файл DLL - и скорость выполнения
шейдера таким, хитрым, образом увеличивается во много раз.
Вернемся к нашему RIB'y. Вот строка из него, которая определяет новый подключенный
материал:

Surface "noisetest"

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

Surface "noisetest" "freq" 100

Дальше - больше. Поскольку язык SL является потомком языка С, нам доступны такие
возможности С, как препроцессор и макросы. Проиллюстрируем это на простом примере. Немного
изменим наш шейдер:

surface noisetest ( float freq=FREQD; )


{
Ci = color(noise(freq*s,freq*t));
}

и строку вызова его компиляции:

shader -DFREQD=2 noisetest.sl

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

1368 Книга Сергея Цыпцына


Учтите, что если бы мы вызвали компилятор без этого параметра, например, так

shader noisetest.sl

то получили бы ошибку - ведь константа останется неопределенной.

Уже вкусно? Сейчас будет еще вкуснее. Поскольку в наших руках почти что язык С, мы
можем вынести куски кода в подключаемые файлы (included files) или, наоборот, использовать
уже готовые подключаемые файлы в своем шейдере. Один из самых интересных для изучения
начинающими include-файлов можно найти в RManNotes, небольшом онлайновом пособии по Ren-
derman Shading Language (его перевод на русский язык доступен на сайте Renderman.ru). Мы же
воспользуемся стандартными возможностями из поставки Renderman Pro Server. Подключаем к
нашему шейдеру библиотеку материалов:

#include "materials.h"
surface noisetest ( float freq=FREQD; )
{
Ci = color(MATERIAL_bronze*noise(freq*s,freq*t));
}

и вызываем компиляцию:

shader -l%RMANTREE%\lib\shaders -DFREQD=2 noisetest.sl

и рендеринг дает нам:

Для продвинутых. -D и -I - это флаги препроцессора языка С. Подробнее о них можно


почитать в справке или в любой книжке по С. Обратим наше внимание на то, что в традиционных
компиляторах препроцессор и компилятор это две разных программы, которые связываются
пайпингом. В некоторых Renderman-совместимых рендерерах используется аналогичный подход,
например, в BMRT и Aqsis. Есть такой препроцессор и у shader; его назвали slpp и спрятали в
поддиректорию %rmantree%\etc.

А как вы смотрите насчет того, чтобы выстроить цепочку из нескольких программ-


генераторов шейдеров? Или, например, написать внутри шейдера небольшую программу на Perl,
затем обработать шейдер еще одной небольшой программой на Perl - и получить таким образом
динамически настраиваемый шейдер? А не изволите ли анимированных шейдеров? Возможностей
- море, нужно только помнить, что вы ничего не можете сделать с самим шейдером после
компиляции - только передать параметры из RIB'a.

txmake.exe
В этом случае все совсем просто. Парадигма тотального ускорения рендеринга и
разумного потребления памяти требует, чтобы все, что поступало на вход рендерера, было
максимально оптимизировано. Для RIB'OB таким вариантом является бинарный формат, для SL
- откомпилированный код. Для текстур, которые вы можете использовать в своих шейдерах, тоже

Кое-что про Renderman 1369


есть такой формат, и перевести текстуру в такой формат можно при помощи последней программы
из нашей шустрой троицы - txmake.exe.

Для продвинутых. Каким образом собственные форматы растровых текстур позволяют


ускорить рендерер - и использовать более гигабайта текстур для одной модели? Все очень
просто:

1. Текстура хранится не сплошным куском, а в виде тайлов - то есть побитой на квадратики.


Соответственно, в память грузится не весь массив данных, а только тот квадратик, к которому
идет обращение.

2. Внутри файла текстуры хранится не одно изображение, а несколько - последовательно


уменьшающихся в размерах и детализации. Для объектов, находящихся на большем расстоянии
от камеры, используется текстура с меньшим разрешением - которая грузится быстрее и занимает
меньше памяти.

3. Прочие хитрости, вроде оптимизации данных под конкретный рендерер - так, например,
prman при конвертации текстур может привести их размеры к величине, кратной степени
двойки.

Таким образом, txmake при конвертации текстур создает многостраничный затайленый


файл формата TIFF - благо формат позволяет. Просмотреть такой файл можно, чем угодно, хоть
ACDSee. Но если вы хотите воспользоваться текстурой размером в 16000x16000 пикселей, а у вас
на машине нет 2 гигабайт памяти - лучше использовать так называемый "старый" формат текстур
Pixar, который можно получить при помощи того же txmake со специальными параметрами вызова
- и который является еще более оптимизированным вариантом.

В Renderman Pro Server растровые изображения используются не только в качестве текстур,


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

Одно небольшое отличие txmake от своих консольных собратьев состоит в том, что текстуры
сами по себе текстовыми файлами не являются, то есть с ними наши фокусы с пайпингом работать
не будут.

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

По причинам, которые мы только что указали, пусть текстура будет квадратной, 512x512
пикселей. Напишем на ней... напишем на ней.... чего бы такого написать, чтобы никого не обидеть
и чтобы литературный редактор пропустил? Вот, придумал:

Надпись
Просто и со вкусом. Добавляем вызов текстуры в наш шейдер (по этому поводу
переименованный в textured_noise.sl):

surface textured_noise ( float freq=100; )


{
Ci = texture("texture.tif", s, t)*noise(freq*s,freq*t);
}

Я несколько упростил наш шейдер по сравнению с последней итерацией (нам сейчас ни к


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

1370 Книга Сергея Цыпцына


Для продвинутых. С педагогической точки зрения, код нашего шейдера следовало бы
переписать несколько иначе:

surface textured_noise ( float freq=100; )


{
color tex = texture("texture.tif", s, t);
float noi = noise(freq*s,freq*t);
Ci = tex*noi;
}

Подход, рекомендуемый некоторыми источниками, состоит в том, что шейдеры необходимо


разбивать на слои в соответствии с накладываемыми эффектами, и затем производить финальные
операции уже над полученными ранее слоями. У этой модели есть свои преимущества и недостатки,
сторонники и противники. Уточним лишь, что оптимизирующий компилятор шейдеров из комплекта
Renderman Pro Server компилирует вышеприведенные шейдеры в почти одинаковый код.
Вносим также некоторые изменения в RIB:

Display "RenderMan" "framebuffer" "rgb"


Format 256 192-1
ShadingRate 1
Translate 0 0 2.7650300856
WorldBegin
TransformBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3-1.2-1.0] " t o " [0 0 0]

TransformEnd
TransformBegin
Rotate 90 1 0 0
Rotate 90 0 0 1
Surface "textured_noise"
Sphere 1 -1 1 360
TransformEnd
WorldEnd

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

Компилируем шейдер:

shader textured_noise.sl

Рендерим картинку:

prman test4.rib

и получаем огромное количество сообщений об ошибках, потому что рендерер не распознал


нашу текстуру как правильный прооптимизированный формат. Строго говоря, какая-то картинка
у нас получилась и так, но поскольку нас интересует академическая правильность процесса,
сделаем два дополнительных действия.

Во-первых, подготовим картинку к рендерингу:

txmake texture.tif texture.tx

Кое-что про Renderman 1371


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

Во-вторых, изменим шейдер:

surface textured_noise ( float freq=100; )


{
Ci = texture("texture.tx", s, t)*noise(freq*s,freq*t);
}

Для любознательных. Вас никто не заставляет называть свои файлы тем или иным образом.
Вы можете хранить свой шейдеры в файлах с расширением *.shader; свою геометрию - в файлах
с расширением *.rib, *.ri или ".renderman; инклуды в файлах *.h или *.inc. Просто стремитесь к
тому, чтобы всегда придерживаться одного и того же логичного и удобного для вас именования
файлов. Система именования, которую я использую в этой главе, считается стандартной и широко
используется в литературе и документации.

Для продвинутых. В процессе обработки текстур RAT включает в название файла параметры
командной строки, которые использовались при вызове txmake. Например, вот так: metal024.tif.
ppu.tx. Расшифровку скрытого в этом имени тайного значения оставим в качестве задания для
самостоятельной работы для вас, продвинутые.

Теперь вроде бы все правильно - компилируем, запускаем рендерер и получаем в результате:

Могучая кучка
Собственно говоря, вычислительное ядро Renderman Pro Server состоит из трех программ:
prman, shader и txmake. Как мы уже говорили раньше, подавляющее большинство Renderman-
совместимых рендереров придерживается такой же архитектуры, просто называя файлы другими
именами. Приведем лишь некоторые из них:

Продукт Рендерер Компилятор Скомпилированный Обработчик


шейдеров шейдер текстур
Prman prman shader *.slo txmake
AIR air shaded *.slb mktex
RenderDotC renderdc shaderdc *.dll texdc
3delight renderdl shaderdl *.sdl tdlmake
Aqsis aqsis aqsl *.slx teqser

1372 Книга Сергея Цыпцына


Ссылку на постоянно обновляющийся список рендереров вы найдете в конце главы, но
уверяю вас - у участников списка все обстоит аналогичным образом.
Для любознательных. Вы ведь знаете, что в комплекте поставки MAYA есть программа под
названием render.exe, которая позволяет рендерить майские сцены из командной строки?Я не
буду проводить аналогии - хотя бы потому, что остальных программ из нашей троицы у MAYA нет,
в силу особенностей ее архитектуры.

А у нас настало время систематизировать наши знания о внутренностях Renderman-


совместимого рендерера. Проще всего будет это сделать в виде схемы, показывающей путь
данных внутри системы:

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


текста в одну простую диаграмму.

Каким же образом в этот процесс встраивается MTOR? Добавим в схему недостающие


элементы (а заодно уберем из нее временные файлы *.ТХ и *.SLO):

Как видно из обновленной диаграммы, майская сцена обрабатывается MTOR'OM И

Кое-что про Renderman 1373


превращается в файлы геометрии *.RIB; а материалы, разработанные в SLIM, конвертируются
в шейдеры *.SL. С текстурами чуть сложнее, но ненамного - вызовы их обработчиков также
настраиваются в SLIM.

Замечание. Для большей простоты мы не указали в этой схеме Alfred.

А как же та самая пресловутая совместимость между рендерерами в рамках стандарта,


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

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

Вы считаете, что и этого мало? Ну, тогда давайте вернемся к нашей схеме и описанию
нашей триады и дополним ее некоторыми немаловажными деталями, которые мы не затронули в
первом заходе.

1. Утилита txmake принимает на входе файлы формата TIFF. На самом деле, список
поддерживаемых форматов гораздо длинее и включает в себя: MAYA IFF, SGI, SUN, TGA, Alias,
GIF, JPEG, LBM, BMP, ICO, форматы систем Х11 (например, майские иконки в файлах ХРМ), Рпо-
toCD, 24битные raw bitmaps и некоторые другие, а начиная с версии 12 - становящийся де-факто
стандартом индустрии OpenEXR.

2. В поставке Renderman Pro Server есть утилита sho.exe, которая позволяет конвертировать
между всеми этими форматами. Кстати говоря, в поставке MAYA есть утилита imgcvt.exe, которая
делает почти то же самое - конвертирует между форматами. Преимущество sho в том, что она может
еще и показывать файлы на экране. Признайтесь честно - когда вы в последний раз заглядывали
внутрь Maya/bin?

3. Язык шейдеров SL можно расширить за счет своих собственных процедур. Сделать это
можно, написав свою собственную DLL (в нашем случае называемую на юниксоидный лад: DSO).
Поверьте мне - это не так сложно, как кажется, и для этого совсем не обязательно знать язык С
или C++.- Я же вообще, с успехом писал DSO на Паскале. Классические примеры расширения SL
- Frankenrender (вызов одного рендерера из шейдера, исполняемого в другом рендерере; именно
так в стародавние времена в prman встраивали raytracing - просто вызывали BMRT) и Vtexture
(использование векторных файлов в качестве текстур).
4. Вы уже знаете, что формат RIB можно генерировать своими собственными программами;
это очевидно, поскольку формат это простой и в основной своей ипостаси - текстовый. О чем
мы в нашей главе не говорили - так это о том, что этот формат также можно расширять при
помощи динамических генераторов RIB-кода, вызовы которых встраиваются непосредственно
в сами RIB'bi. Такие генераторы можно писать как в виде DLL/DSO, так и непосредственно как
исполняемые файлы или даже скрипты на Perl. Комментарий в сторону. Я уже говорил, что Perl
- язык истинных криптоманьяков. Хорошим подтверждением этой гипотезы является тот факт, что
базовым скриптовым языком в ILM и Google избран Python.

5. Начиная с версии 11.5, prman позволяет встраивать ваши собственные фильтры внутрь
рендерера для более глубокого процессинга RIB. Опять-таки, эти фильтры представляют из
себя DLL/DSO с определенной схемой вызовов. Начиная с версии 12.0, эти фильтры описаны в
документации.

6. prman может рендерить во множество файловых форматов: TIFF, MAYA IFF, Softimage,
TGA, SGI, CIN, PIC, Alias. Но этот список можно легко увеличить при помощи своих собственных
плагинов, в этом случае называемых display drivers. Экспериментируя с prman в нашей главе, мы
рендерили сразу в окно просмотра; такая возможность реализуется при помощи плагина d_win-
dows.dll. Пробуя на зуб MTOR, мы считали картинку непосредственно в окно программы it - делается

1374 Книга Сергея Цыпцына


это при помощи драйвера d_socket. Разрабатывая ShaderMan (о нем поговорим чуть попозже, но
уже совсем скоро), я поставил перед собой задачу рендерить напрямую в окно своей программы
- и решил эту задачу, написав специальный display driver. Стандартная для prman 12 возможность
считать в файлы формата OpenEXR может быть реализована и в более старых версиях рендерера
- при помощи таких же драйверов (их можно скачать с сайта OpenEXR или найти через Google).
Хотите считать в PNG, JPEG2000 или свой собственный uber-формат? Просто напишите драйвер.
Почему множество людей, FX-домов и студий во всем мире используют Renderman Pro
Server? Тому есть множество причин.

Сведем все предшествующее описание, все эти десятки страниц, картинок и схем в один список:

1. Стандарт Renderman
2. Скорость работы
3. Соответствие тем нормам, которые мы определили как необходимые для продакшн рендерера
4. Удобство и простота в освоении
5. Расширяемость

Добавим в эту гремучую смесь такие свойства рендерера, как:

• быстрый motion blur - почти не влияющий на скорость рендеринга (сравните с другими)


• настоящий высококачественный displacement
• SL - который сам стоит целого списка

и вы получите тот динамит, который взорвал индустрию спецэффектов. Как выразились


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

Альтернативы?
Почему же множество людей, FX-домов и студий во всем мире НЕ используют Renderman
Pro Server? И тому есть множество причин.

Начнем с очевидной - цены.

На этом можно было бы и закончить, потому что по цене комплект, состоящий из Render-
man Pro Server, RAT + годичной подписки на услуги службы поддержки, почти догнал стоимость
(чуть было не написал - автомобиля) MAYA Unlimited... Надеюсь, вы оценили. Один этот факт ставит
жирный крест на этом продукте для маленьких студий, свободных художников - фрилансеров
и студентов, которые хотят поэкспериментировать с рендерером дома: все они выбирают либо
совместимые альтернативы, либо совершенно другие продукты.
Но я хотел заострить ваше внимание на другом аспекте проблемы. Да, prman - очень универсальный
рендерер. Но, согласно поговорке, когда вы берете в руки молоток, все предметы вокруг вас
начинают казаться гвоздями.

И поэтому мы сделаем небольшой шаг в сторону от нашего магистрального направления


("MAYA+Renderman=счастье") и попытаемся объять необъятное - рассмотреть альтернативные
prman'у рендереры, которые можно использовать совместно с MAYA.

Вообще говоря, говорить о том, что какой-то рендерер не совместим с MAYA, особенно
после того, как вы познакомились с главой, посвященной MEL - глупо. Возможности MEL в области
вывода данных из MAYA настолько велики, что фактически любой рендерер, запускаемый из
командной строки, можно с теми или иными затратами прикрутить к Майе. И это будет работать.
А если вас перестанет устраивать скорость работы скрипта, вы просто перепишете ваш скрипт в
виде плагина (или попросите кого-то переписать ваш скрипт в виде плагина). Это означает, что
MAYA-совместимым является почти любой из существующих на рынке рендереров, запускаемых
из командной строки. Но, как говорил Козьма Прутков, нельзя объять необъятное - у нас здесь не
Большая Советская Энциклопедия, в конце концов. И поэтому мы сделаем небольшую выборку из

Кое-что про Renderman 1375


огромного списка и расскажем вам о нескольких внешних рендерерах.

Примечание. Ситуация на рынке сильно изменилась с выходом «народного» продукта Ren-


derman for Maya, предназначенного для индивидуальных пользователей и небольших студий.

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

Во-вторых, очень часто существующие решения не справляются с поставленными для них


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

Ну, и на закуску остаются исследовательские и студенческие проекты, источник


вдохновения и исходного кода, поток новых идей и инноваций.

Чем же закончился тот вечер, когда я попытался объять необъятное? Простой схемой, на
которой я перечислил все известные мне (пусть только по названию) рендереры и провел между
некоторыми из них связи - будь то родственные, технологические или какие-то еще. Картинка
перед вами.

1376 книга Сергея Цыпцына


Темно-серым цветом на этой схеме обозначены некие ключевые продукты, от которых я
отталкивался в выстраивании системы отсчета - краеугольные камни. Три таких камня очевидны
- это Renderman, mental ray и видеокарты (OpenGL/DirectX и прочее). Но есть и четвертый камень
в этой схеме, и этот четвертый элемент - Gelato.

Gelato
Появления этого продукта ожидали многие. Еще не было достоверно известно, что он
существует, но все понимали, что внутри Nvidia что-то варится. Не могло не вариться - как не
может не взорваться критическая масса внутри атомной бомбы.

Но расскажем по порядку.

В июле 2000-го года три человека - Ларри Гритц, Мэтт Фарр и Крэг Колб (Larry Gritz,
Matt Pharr, Craig Kolb) - объединили усилия, чтобы создать новый Renderman-совместимый
рендерер. Ларри внес в копилку знаний свой рендерер BMRT и опыт работы в Pixar над prman'ом
и интеграцией prman и BMRT (помните, как я, рассказывая о возможностях расширения SL,
кратко упомянул Frankenrender?). Мэтт положил в пул свою идею (и написанную на ее основе
диссертацию) о кардинальном ускорении процесса raytracing'a - и опыт работы в Pixar над prman.
Крэг - опыт, накопленный в ходе разработки рендерера Rayshade. Объединившись под вывеской
Exluna и выбрав в качестве логотипа мультяшный космический кораблик, разработчики сделали
почти невозможное - в августе 2001-го года представили на суд публике новый рендерер - Entro­
py. Качественный, быстрый, Renderman-совместимый рейтрейсер превосходил prman по набору
поддерживаемых алгоритмов рендеринга и стоил всего полторы тысячи долларов (не случайно
считается, что именно после появления Entropy в Pixar серьезно озаботились встраиванием ray
tracer'a в Renderman Pro Server - хотя скорее всего это не так, и работы шли параллельно). А какая
бы ни была продажная цена, стоил продукт гораздо дешевле.

Entropy был хитом и раскупался, как пирожки. Почва под ногами prman зашаталась, и
ответный ход не заставил себя ждать. К сожалению, он был не совсем приятным. Пятого марта
2002-го года Pixar подала на Exluna в суд, обвиняя комнанию в нарушении патентов, а 16-го мая,
во втором иске, обвинила трио основателей в плагиате (ведь два из них ранее работали в Pixar
и видели исходный код prman). Тщетно адвокаты молодой компании пытались бороться: куда
стартапу из 10 человек на втором году жизни тягаться против гиганта Pixar (со студией Диснея
за спиной). И несмотря на то, что причин для судебного разбирательства не было и патенты не
нарушались, наилучшим выходом для Exluna было: прекратить продажи своего продукта, продаться
Nvidia с потрохами и дать победителям урегулировать споры между собой.

К этому моменту сложилась, можно сказать, интересная ситуация - в Nvidia одновременно


оказались несколько разработчиков рендереров: Джакопо Панталеони (Jacopo Pantaleoni), автор
LightFlow; троица из Exluna; Дэниэл Векслер (Daniel Wexler), создатель рендерера, который PDI/
Dreamworks использовали в фильмах Antz и Shrek. По совокупности одновременно находящихся
в компании именитых рендерописателей Nvidia вышла на первое место в индустрии. А это могло
означать только одно: у Entropy готовится преемник.

Таким преемником оказался новый рендерер Gelato, анонсированный 19 апреля 2004-го года.

Основной особенностью Gelato, из-за которой его так любит пресса и так не любят
некоторые разработчики и TD, является то, что это первый продакшн рендерер, который
использует возможности вашей видеокарты для рендеринга - и более того, не работает, если у
вас не установлена определенная видеокарта - конечно же, с чипом от Nvidia. Но чтобы понять,
насколько серьезное преимущество оказывается в руках у тех, кто берет на вооружение этот
новый рендерер, отвлечемся немного и поговорим о процессорах, Законе Мура и современных
реалиях.

Как гласит Закон Мура, число транзисторов на современном компьютерном

Кое-что про Renderman 1377


микропроцессоре удваивается каждые два года. Этот закон был сформулирован в 1965ом году,
работает до сих пор и по оценкам исследователей - будет работать еще с десяток лет. Казалось
бы, все отлично: до недавних пор формулировка закона означала, что каждые два года мы
получаем в свои руки, как минимум, вдвое больше производительности. Но, как показывает опыт,
в последнее время рост производительности центральных микропроцессоров (CPU) практически
прекратился, несмотря на продолжающийся рост сложности их конструкции, числа транзисторов
и тактовой частоты. Производители микропроцессоров (Intel, AMD, Sun, IBM и другие) стараются
изо всех сил, придумывая и воплощая в жизнь новые технологии и идеи, но предложить что-то
кардинально новое, в очередной ускоряющее вычисления в два раза, они, увы, не в состоянии. В
ближайшее время нас ждет нашествие многоядерных решений, в которых за счет фактического
объединения двух процессоров в один будет сделана попытка обмануть закон Мура и опять удвоить
производительность, однако проблема налицо: сделать персональный компьютер с центральным
процессором, в два раза быстрее сегодняшнего, сложно и очень затратно (хотя, как показывает
практика, все-таки можно).

Примечание. Одно время среди компьютерщиков была популярна циничная шутка


о том, что после смерти Версаче вся команда «модных» менеджеров целиком
перешла работать в Intel: ведь именно с этого времени, после смерти Версаче,
стройная и лаконичная продуктовая линейка процессоров (Pentium, Pentium II, III,
IV, вкупе с Celeron) начала разрастаться невнятными и малопонятными модными
расширениями и стало совершенно невозможно разобраться в пестром хаосе
разнообразных моделей.

С другой стороны, в мире процессоров, применяющихся в видеоускорителях (GPU) все


складывается гораздо интереснее: требования по поддержке все новых и новых стандартов (Di­
rectX, OpenGL, шейдеры), по увеличению качества рендеринга во все новых и новых приложениях
и особенно в играх привели к тому, что сугубо специализированные ускорители отрисовки
треугольников превратились в универсальные процессоры данных, позволяющие программировать
себя и обладающие рядом уникальных свойств. При этом для GPU закон Мура не выполняется:
потому что скорость у них каждые два года не удваивается, а чуть ли не удесятеряется - ведь эти
процессоры не отягощает груз совместимости и необходимость запускать операционную систему.
Было бы глупо не попытаться использовать такой мощный дополнительный универсальный
вычислитель для ускорения работы основного процессора - и такие попытки делались и делаются,
и все больше программ умеют использовать "дармовые" мощности. Но первыми, кто смог
оптимизировать для GPU готовый к производству рендерер, стали сотрудники Nvidia.

Итак, для запуска Gelato вам понадобится современный мощный компьютер под управлением
Windows XP или Linux и современная же, мощная профессиональная видеокарта на чипсете
от Nvidia - в частности, Quadra FX. Прежде чем мы попробуем новый рендерер в бою (вы тоже
можете это сделать - тестовая версия Gelato доступна для скачивания на сайте, и единственное
ограничение этой версии - водяной знак на результатах рендеринга), рассмотрим кратко основные
черты этого продукта.

1. Gelato- полноценный production renderer (удовлетворяющий нашему списку требований),


взявший за основу Entropy и BMRT и добавивший в них множество новых свойств.

2. Gelato - современный рендерер. В нем нет поддержки многих устаревших режимов и


видов геометрии, которые не нужны при выполнении реальных задач. Что и говорить, когда такой
геометрический примитив, как сфера, появился в рендерере уже в самом конце бета-теста, да
и то по настоятельным просьбам тестеров: они ведь привыкли к использованию шариков в своих
тестовых сценах. С другой стороны, Gelato поддерживает все современные технологии - ray trac­
ing, ambient occlusion, caustics и многие другие.

3. Gelato не является Renderman-совместимым рендерером (Nvidia решила не играть в


кошки-мышки с Pixar), но взял от былой совместимости все самое лучшее. Например, в этом
рендерере есть свой собственный язык шейдеров GSL - на 90 процентов совместимый с языком
SL и переводимый из него при помощи несложного конвертера (неопытный пользователь может
перепутать шейдеры, настолько они похожи). Возвращаясь к предыдущему пункту - над языком
GSL основательно поработали, улучшив его новыми конструкциями и убрав устаревшие, так что

1378 Книга Сергея Цыпцына


теперь в роли догоняющей оказалась уже Pixar.

Если посмотреть правде аккурат в глаза, то перечислять инновации Gelato вот таким
сухим списком скучновато не только для вас, но и для меня самого. Давайте лучше попробуем
сделать что-нибудь в MAYA и отрендерить в Gelato, а заодно и поговорим о достоинствах этого
рендерера.

В поставке Gelato идет Mango - плагин к MAYA, который встраивается в нее, в отличие от
MTOR, почти без проблем и позволяет использовать всю мощь обоих продуктов.

Создадим новый проект, новую сцену, импортируем нашу овечку (файл sheep.та на
диске). Овечка у нас полигональная, если вы еще не заметили - так что быстренько переводим ее
в Subdivision Surfaces: Modify => Convert => Polygon to Subdiv. Рендерим стандартным движком MAYA
(движок немного притормаживает), и наконец получаем картинку:

Все наши предыдущие картинки с овцой были на черном фоне, который уже немного
надоел - поэтому мы вставили в сцену большой шарик, который и дал нам серенький фон. Надоест
этот фон, уберем и его, и будем опять смотреть на черный задник, но пока нормально и так. Да,
на чем мы там остановились? Ах, да, Gelato...

Если рендерер у вас установился правильно, вам всего лишь нужновключить плагин
обычным способом и вызвать окно Render Globals:

Переключаем рендерер, запускаем просчет опять, слышим, как заработал вентилятор на


видеокарте, ненадолго появилась и сразу же исчезла командная строка - и получаем прямо в
окошке Render View результат:

Не нужно иметь зрение горного орла, чтобы увидеть, что не только рендеринг прошел
гораздо быстрее, но и в результате мы получили гораздо более качественную картинку (не меняя
при этом установок по умолчанию в обоих рендерерах). При этом Gelato подхватил все установки
MAYA и воспроизвел их своими средствами.

Что же произошло за кадром, пока мы слушали песню вентилятора нашей Nvidia GeForce
QuadroFX 3000 (кстати, пока я это писал - вентилятор уже выключился)? Заглянем в директорию
c:\temp - в ней появились 3 новых файла:

gelato. pyg
gelato.bat
gelato_perspShape.pyg

Внутри этих файлов находится самое интересное - геометрия, которую Mango экспортировал
из MAYA B собственный формат Gelato. Правильнее говоря - Mango эскпортировал в формат PYG - один
из форматов, поддерживаемых Gelato. Казалось бы, разница между двумя фразами минимальна,
но она показывает глубокое философское различие между Gelato и другими рендерерами. Это
- одно из тех различий, на которых мы остановимся и которое, возможно, вас удивит.
Различие это состоит в том, что в Gelato нет формата сцены по умолчанию. Формат
шейдера есть (GSL), а формата сцены - нет. Вместо этого пользователю представляется хорошо
документированный программный интерфейс API и возможность написать в соответствии с этим
интерфейсом плагин к рендереру, который и будет заниматься вопросами загрузки геометрии.
Понятное дело, что взять и просто так выпустить на рынок рендерер, в который по умолчанию
нельзя загрузить геометрию вообще - это глупость, поэтому для Gelato придумали свой собственный
формат PYG, представляющий из себя программу на языке Python. В общем, смотрите сами, перед
вами кусочек файла с овечкой:

World ()
PushTransform ()
SetTransform (((0.736097, 0, -0.676876, 0),
(-0.130758, 0.981164, -0.142198, 0),
(-0.664126, -0.193179, -0.722232, 0),

Кое-что про Renderman 1379


(17.6053, 12.845, 21.3661, 1)))
Light ("mayaDefaultLight", "distantlight",
"point to", (0.5,-0.5, 1))
PopTransform ()
PushAttributes ()
Attribute ("string name", "sheep:sheep")
AppendTransform ( ((1, 0, 0, 0),
(0,1,0,0),
(0,0,1,0),
(0,0,0,1)))

Очень похоже на RIB (что неудивительно), но это не обычный текстовый файл, а


минипрограмма. Значит, мы можем взять и сделать из нее настоящую программу: например,
написать цикл, или загрузить данные из другого файла, или прочитать ввод пользователя из
консоли, или даже загрузить данные из Интернета - в нашем распоряжении вся мощь языка
программирования Python!

Энтузиасты Renderman немного скривились - что ж, в их руках такой мощной игрушки нет.
А мы тем временем нанесем им еще один удар - загрузив с сайта Nvidia плагин к Gelato, который
позволяет использовать в качестве файлов геометрии RIB-файлы. Действительно, а почему бы и
нет, если есть открытый API? Попробуем эту возможность в бою: временно откладываем в сторону
MAYA и вызываем командную строку:

gelato test2.rib

и немедленно получаем на экране окно с результатами рендеринга:

Как видно, Gelato без особых проблем справился с RIB'OM, благо шейдер "Plastic", который
мы использовали с нашей тестовой сцене, входит в поставку - равно как и все остальные шейдеры
из стандарта Renderman (сказывается Entropy-шное прошлое).

Это самое прошлое не раз будет напоминать о себе в наших изысканиях. Раз уж мы начали
копаться в командной строке, посмотрим, например, из чего же состоит наш новый друг. Ба!
Налицо уже набившая нам оскомину триада - рендерер, компилятор шейдеров и конвертор текстур,
но на этот раз они называются gelato.exe, gslc.exe и maketx.exe.

Внутри директории gelato/bin еще много всего интересного, например, утилита topyg,
которая позволяет перевести любой из поддерживаемых установленных вами плагинами форматов
геометрии в PYG: с ее помощью можно сравнить одну и ту же сцену в формате PYG и RIB и увидеть
явные аналогии. А мы возвращаемся к нашим баранам я хотел сказать, к нашей овечке и к
Maya.

1380 Книга Сергея Цыпцына


Немножко покрутим камеру, чтобы видеть одну только голову нашей модели -
экспериментировать мы будем именно с головой. Выделяем голову, создаем в Hypershade новый
материал - Create => Materials => Lambert. Назначаем этот материал на голову овцы и начинаем
с ним играть. Я не долго думал над примером и, по аналогии с предыдущими экспериментами,
подключил к ламбертовскому diffuse - Noise:

Снова запускаем рендеринг - а рендерером у нас все так же стоит Gelato - и с удивлением
смотрим на результат:

Gelato подхватил настройки материалов из Hypershade, сконвертировал их в свои и


правильно отобразил новый материал. Оказывается, Mango знает о существовании Hypershade, в
его поставке есть набор шейдеров для многих Hypershade-овских нод, из которых и конструируются
готовые шейдеры для Gelato? Нет, не шейдеры. Мы в очередной раз встретились с инновационным
решением: Gelato позволяет накладывать несколько шейдеров на один объект, объединяя их в
группы и более того позволяя строить из таких шейдеров более сложные конструкции, передавая
параметры и результаты работы из одного шейдера в другой. Давайте еще раз посмотрим внутрь
файла c:\temp\gelato.pyg:

ShaderGroupBegin ()
Shader ( "surface", "maya_place2dTexture", "place2dTexture1" )
Shader ( "surface", "maya_noise", "noisel", "float amplitude", 0.6529, "float depthMax", 4, "float
frequency", 11.57, "float frequencyRatio", 2.1158, "float noiseType", 0, "float ratio", 0.90082, "float
threshold", 0.22316)
ConnectShaders ("place2dTexture1", "outUV", "noisel", "uvCoord")
ConnectShaders ("place2dTexture1", "outUvFilterSize", "noisel", "uvFilterSize")
Shader ( "surface", "mayajambert", "lambert2", "color _color", (0.20932, 0.166365, 0.9091) )
ConnectShaders ("noisel", "outAlpha", "lambert2", "diffuse")
ShaderGroupEnd ()

Кое-что про Renderman 1381


Манго определил, что мы используем три ноды - place2dTexture, noise и lambert. Для этих
нод в поставке Mango есть соответствующие шейдеры (загляните внутрь $GELATOHOME/mango/
shaders, чтобы узнать, какие ноды поддерживаются на данный момент). Далее создается группа
шейдеров, в которой при помощи процедуры ConnectShaders воссоздается то построение, которое
мы с вами только что делали визуально в HyperShade.

Кто-то еще считает, что SLIM - самое удобное для создания шейдеров средство? Тогда пусть
бросает читать на этом месте, а мы тем временем продолжим перестройку сознания и галоп по
возможностям Gelato. Вернемся в директорию c:\temp и покажем, как сделать быстрый рендерер
еще быстрее. Удаляем gelato.bat, а бывшее его содержимое копируем в командную строку и
запускаем:

gelato -iv gelato_perspShape.pyg gelato.pyg

Попутно открылась еще одна возможность - несколько PYG-ов, заданных в качестве


параметров, будут выполнены в той последовательности, в которой вы их задали - удобно для
разделения обших настроек сцены и собственно геометрии. Но мы хотели ускорить просчет сцены.
Запускаем рендерер еще раз, с чуть другими параметрами:

gelato -iv -preview 0.1 gelato_perspShape.pyg gelato.pyg

Результат появился практически мгновенно: мы используем специальный режим


предварительного просмотра в несколько ухудшенном качестве. Можно ли отрендерить еще
быстрее? Да, можно:

gelato -iv -shade defaultsurface


-preview 0.1 gelato_perspShape.pyg gelato.pyg

Мы отключили все шейдеры и вместо них использовали defaultsurface. Результат выглядит


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

Мы могли бы и дальше расписывать особенности Gelato, упрощающие жизнь трехмерщика,


приводя все новые и новые примеры, но вместо этого просто обозначим один факт: этот рендерер
является более расширяемым, чем prman, и вся его философия - это философия расширяемости.
Хотите собственные операторы в GSL, аналогичные таковым в Renderman SL? Есть. Хотите рендерить
в собственные форматы картинок? Есть открытый простой API, с помощью которого можно не только
выводить в ваш формат данных (как в случае с display drivers у Renderman), так и импортировать
эти данные - а изначально поддерживаются TIFF, MAYA IFF, JPEG, PNG, PPM, TGA, HDR, DDS (сжатые
текстуры для использования в DirectX) и, конечно же, OpenEXR. Хотите использовать собственный
формат сцены? Пишите плагин или переводите в RIB или PYG. Хотите встроить рендерер в pipe­
line своей студии? У вас в руках мощнейший язык программирования Python, поддерживаемый
этим рендерером. Хотите рендерить по слоям? Обсчитывать геометрию в shading grid, а потом
использовать Gelato исключительно для решейдинга? Планка, установленная Renderman Pro Serv­
er, поднята на новую высоту этим новым продуктом Nvidia. И индустрия это чувствует - интерес к
рендереру очень высок и, несмотря на молодость и новизну, поддерживающие его конвертеры,
утилиты и плагины появляются, как грибы после дождя.

Должен признаться кое в чем... Вернее, я должен быть признаться в этом еще в начале
нашего рассказа про Gelato. Но лучше поздно, чем никогда: мне нравится этот рендерер. Он мне
действительно очень нравится, почти так же, как и prman (а по-моему, даже больше. - Прим.
редактора). У меня есть видеокарта Quadro FX, и да, я - бета-тестер Nvidia, соответственно,
имеющий доступ к внутренней информации (которая разглашению не подлежит) и бета-релизам
(про которые я вам умудрился не сказать ни слова - хотя очень хотелось). Мне тяжко осознавать,
что я как бы предаю свою искреннюю любовь к Renderman'y, но иногда, по вечерам, я тихонько
закрываю дверь своей комнаты и вместо того, чтобы экспериментировать с prman'ом, исследую
это самое «Джелато». Поэтому - еще раз - мне нужно было признаться с самого начала в том,

i 382 Книга Сергея Цыпцына


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

Что же у нас в сухом остатке? На рынке появился новый продукт, который в полной мере
отвечает обозначенным нами критериям production-качества, он прост для новичков, очень удобен
и гибок в использовании в руках опытных пользователей. Но для того, чтобы воспользоваться
всеми этими преимуществами, вам понадобится современный компьютер, оснащеный мощной
профессиональной видеокартой последнего поколения от Nvidia - то есть денег этой компании
вы заплатите два раза, сначала за рендерер, а потом за видеокарту (а третий раз - за «саппорт»).
Стоит ли этих денег, как минимум, двухкратное ускорение просчета сцены (полученное мной в
ходе антинаучных экспериментов, на одинаковых простых тестовых сценах, на одном и том же
компьютере, с Gelato 1.0R3 в сравнении с prman 11.5.3)? Решать вам.

Для продвинутых. Говорят, индейцы в лесах Амазонии знают, как запустить Gelato на
игровых видеокартах, а также на ноутбуках без Quadra FX. Это сакральное знание передается ими
на закрытых форумах в виде патчей к драйверам Nvidia, которые позволяют обычной видеокарте
эмулировать хай-эндовую - благо элементная база у них одинаковая. Даже и не знаю, что сказать
по этому поводу.

Jot
А первого февраля 2003-го года я оконфузился.

Чувствовал я себя при этом очень глупо, не очень уютно и вообще как-то сугубо некомфортно.
Эту историю я еще никому не рассказывал, потому что немного стыдно до сих пор. По прошествии
нескольких лет я потихоньку начинаю понимать, что все было не так уж и плохо и что зря я так
серьезно отношусь ко всяким мелким происшествиям. Тем более, что стыдиться-то, собственно,
и нечего. Но, как говорится в бородатом анекдоте, ложки-то нашлись, а осадок остался...

И чтобы выветрить осадок, я решил для излития души выбирать только между мегафоном
на набитой народом площади и книгой по MAYA. Сами видите, что выбрал.

А первого февраля 2003-го года Сергей Цыпцын проводила в Москве очередной семинар
по компьютерной графике ViAGra (Visual Art and Graphics). На этом семинаре у меня было
небольшое выступление на тему «Нефотореалистичный рендеринг». Следует отметить, что я уже
давно интересуюсь этой темой и экспериментирую с различными NPR техниками, используя в
своей работе Renderman-совместимые рендереры (а в последнее время и Gelato) как источники
информации для собственных программ и алгоритмов. И для своего выступления на «Виагре» я
подготовил не только доклад, но и небольшой показ своих собственных достижений, которыми
(втайне) очень гордился.

А вот в конце доклада я в качестве обзора вставил в презентацию несколько картинок,


показывающих различные нефотореалистичные техники рендеринга, имитирующие анимационную
закраску, псевдоживопись, чертежные линии, гуашь с акварелью и прочие интересности.
Одна из этих картинок была результатом рендеринга в Jot.
В те времена этот университетский проект еще не назывался Jot, не был выложен в
публичный доступ и не обрел свою микроармию поклонников. Но уже тогда по рукам интересующихся
бродила видеозапись, демонстрирующая все возможности Jot'a в действии.
Признаться, не помню, откуда в моей демонстрации взялся этот файл с видео. Возможно,
я сам его привез. Вполне могло быть, что кто-то подошел и поставил свой диск - я просто не
помню.
Единственное, что я вообще помню сейчас про эти три минуты, пока на экране шел
показ прототипа Jot - это охи и ахи со всех сторон, голос девушки из середины зала, которая
застонала "Дайте мне это, я хочу делать это!" и возглас "Ну вот, это же гораздо круче того, что
вы показывали".
Вот эта последняя фраза меня и доконала. Надеюсь, никто этого не заметил - но я сильно
расстроился. Немного смешно вспоминать это сейчас, честное слово - но это так.

Кое-что про Renderman 1383


Прошло время. Контур и заливку сейчас рендерят все, кому не лень - он есть в стандартной
поставке MAYA, он есть во многих рендерерах (в том числе и Renderman-совместимых) в качестве
дополнительной опции. Студия Disney на одной из последних выставок Siggraph показала свой
внутренний рендерер Inka, рассказала принципы его работы и внутреннего устройства - и с тех пор
только очень ленивый студент не написал идеальный картунный движок. Проблема исчезла сама
собой, вместе с ней ушла эйфория увлечения нерешенными задачами и новыми технологиями,
наступила пора готовых решений. Но даже сейчас, когда я запускаю Jot, внутри меня начинается
какое-то противоречивое шевеление. Я продолжаю восторгаться его возможностями, ужасаться
корявости его интерфейса, и я вспоминаю тот февральский день, когда весь зал ахал и охал,
пусть и не от моих картинок.

Я отлично понимаю, отчего все они так реагировали. Университетский проект, результат
долгих лет исследований студентов и профессоров, Jot - классический нефотореалистичный
рендерер «как в мультфильме», с возможностью работы из командной строки, простым форматом
файла и изюминкой - интерактивным редактором стилей закраски. Да, интерфейс этого
интерактивного редактора ужасен, но стиль его работы и - самое главное - результаты его работы
завораживают. Именно поэтому в качестве второго претендента на обзор в этой главе я избрал Jot
- это, к тому же, хороший пример того, как пристыковать к Майке посторонний специализированный
рендерер.

Скачайте Jot с сайта http://jot.cs.princeton.edu/ и установите на своем компьютере.


Настройка продукта - процесс достаточно сумбурный, но если вы внимательно прочитаете
документацию и всякие там README - доступный и быстрый, поэтому здесь я его незадокументировал.
Нам же интересно - как вывести наши данные, чтобы их понял Jot.

Смотрим в исходный файл одного из примеров:

vertices { {{4.984928608 -4.984928608 -7.771561172е-016} ....


faces { {{160 1 161 }{78 2 79 }{44 4 45 }{26 7 27 }{17 8 19 }...

То есть сцена в формате JOT описывается в виде точек (вершин), из которых затем
собираются треугольники. Ничего военного, очень похоже на формат файла Wavefront 0BJ - и,
похоже, кроме этой геометрии, нас в файле ничего не интересует. Засучив рукава, быстренько
пишем небольшой скрипт на MEL для экспорта данных в нужный формат (текст скрипта любезно
предоставили Егор Чащин и Сергей Цыпцын; он также доступен на прилагаемом диске в файле
export_jot.MEL):

global proc exportjot(string $_filename)


{

string $list[] = 4s -si";

string $item;

for($item in $list)
{
select -hi -r ($item);
string $hi[] = 'Is -si';
string $it;

print ("EXPORTING:\n");
string $filename = $_filename;
int $FP = fopen($filename, "w");

for($it in $hi)
{
string $type = 'nodeType ($it)';
if($type == "mesh")

1384 Книга Сергея Цыпцына


{
fprint $FP "#jot\n\nTEXBODY\t{\n";
fprint $FP ("\tname \t"+$item+"."+""+$it+"(celia) \n");
// code for WTM
fprint $FP "\txform \t{{1 0 0 0 }{0 1 0 0 }{0 0 1 0 }{0 0 0 1 }}\n";
fprint $FP "\tmesh_data { \n\t\tLMESH { \n";
fprint $FP "\t\t\tvertices { {";

int $nv[] = 'polyEvaluate -v $ i t ' ;


int $nf[] = 'polyEvaluate -f $ i t ' ;
int $ii,$jj;
string $varr="";
for($ii=0;$ii<$nv[0];$ii++)
{
float $vt[] = xform -q -ws -t ($it+".vtx["+$ii+"]'V;
$varr+="{"+$vt[0]+ " "+$vt[1]+ " "+$vt[2]+ " } " ;
}
fprint $FP ($varr);
fprint $FP "}} \n";

fprint $FP "\t\t\tfaces \t{ {";


string $farr="";
for($ii=0;$ii<$nf[0];$ii++)
{
string $face[] = 'polylnfo -fv ($it+".f["+$ii+"]")';
string $buf[];
int $nn=tokenize($face[0], " ", $buf);
$farr+="{";
for($jj=2; $jj<$nn-1; $jj++) $farr+= $buf[$jj]+" ";
$farr+="}";
}
fprint $FP ($farr);
fprint $FP "}} \n";

fprint $FP "\t\t\t} } \n\t} \nCREATE \t{ ";


fprint $FP ($item+"."+$it+"(celia)\n\t} " ) ;

}
}
fclose($FP);
}
}

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


выводить исключительно полигональные объекты - помните об этом. Тэ-э-экс, где там наша
многострадальная овечка? Создаем новую сцену, импортируем овцу. Чтобы не очень много ждать
в процессе экспорта, оставляем от бедного животного одну голову, переводим в сабдивы, а затем
сразу же переводим в обратно в полигоны - Modify => Convert => Subdiv to polygon. Объявляем в
MAYA наш скрипт, вызываем его на выполнение командой в Script Editor:

export _jot("sheep. jot");

и получаем файл sheep.jot. Все, что нам осталось сделать - запустить Jot и насладиться
результатом:

Кое-что про Renderman 1385


Как говорится в только что придуманой мною поговорке, овечья голова это еще не вся
овца. Что не дает нам экспортировать всю модель? Излишняя медлительность скрипта, который
вынужден обходить три с половиной тысячи вертексов. Такова природа вещей - писать скрипты
на MEL'e легко и весело, а выполнять тяжело и грустно, поскольку они интерпретируются и
выполняются заведомо медленнее откомпилированного оптимизированного кода на C++ - и
потому хотя и годятся для экспорта больших и сложных моделей, но с большой натяжкой. Дело
мастера боится: закатываем рукава и пишем плагин, который будет делать все то же самое, что
и наш замечательный скрипт, но в десятки раз быстрее. Если с программированием на C++ и
использованием MAYA API у вас туговато - используем план Б и загружаем с диска готовый плагин
(в качестве приглашенного программиста выступил Вячеслав Богданов). Для совсем ленивых я
записал на диск полностью готовую к экспорту сцену sheep_jot.ma. Нам же осталось только
привести готовую картинку:

Для продвинутых и неленивых. Пара советов. Обращайте внимание на то, куда смотрят
нормали вашей поверхности. И помните о том, что при помощи приведенного выше MEL-скрипта
мы можем экспортировать в Jot только один объект - поэтому не забывайте объединять все
полигоны в сцене в единый объект перед экспортом.

1386 Книга Сергея Цыпцына


GRUNT
Пришла пора от овечек перейти к другим животным на ту же букву О - оркам. Мы попробовали
на вкус два рендерера, каждый со своими премудростями, особенностями и сильными сторонами.
Gelato - универсальный продукт, хорошо приспособленный для большинства ставящихся в
реальном продакшне задач. Jot - университетский проект; он умеет рендерить только картунные
линии, но делает это хорошо и включает в себя интерактивный редактор таких линий и их стилей.
Вы можете попробовать применить оба продукта в своей повседневной работе - а теперь я бы
хотел рассказать о рендерерах, применить которые в своей работе вы вряд ли сможете. Это
внутренние разработки иностранных студий, которые используются ими в производстве кино и
рекламы. Почему эти студии занимаются такими разработками? Что их не устраивает в prman'e,
mental ray'e и прочих общедоступных продуктах? Попробуем ответить на этот вопрос.

Надеюсь, все присутствующие смотрели хотя бы один из фильмов трилогии "Властелин


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

Новозеландская студия Weta Digital, автор спецэффектов в трилогии, использует в


качестве основы своего пайплайна две "коробочных" программы - MAYA и Renderman Pro Server.
Но как и всякая другая серьезная студия, Weta Digital старается минимизировать свои расходы
и максимально ускорить производственный процесс - именно поэтому в батальных сценах
использовался специализированный рендерер под названием GRUNT, созданный сотрудником
студии Джоном Эллитом (Jon Allitt).

Этот рендерер (а его название расшифровывается как General Renderer of Unlimited Num­
bers of Things ) имеет одно неоспоримое преимущество перед prman'ом - он использует A-buff-
ег модель рендеринга. В ситуации с батальной сценой с участием десятка тысяч персонажей,
Renderman Pro Server пытается оптимизировать расход памяти и бьет картинку на квадратные
кусочки, каждый из которых будет просчитываться отдельно. На тот случай, если уже обсчитанная
геометрия потребуется в следующем кусочке, информация о ней сохраняется в кэш - иначе
накладные расходы на выгрузку/загрузку/пересчет одного и того же серьезно замедлят процесс.
Для продвинутых. По-научному кусочки эти называются "бакеты". Prman в процессе рендеринга
использует бакеты размером, по умолчанию, 16x16 пикселей и затем обрабатывает сцену не
всю целиком, а по таким вот кусочкам - и по окончании работы с очередным куском занимаемая
им память освобождается. Так вот, проблема в том, что при огромных сценах, в особенности с
полупрозрачными и мелкими объектами, с большим displacement, с применением motion blur и
Depth of field (ну, то есть в типичном кино или телевизионном проекте) - в бакете накапливаются
очень большие объемы информации. Добавьте к этому кэш обработанной геометрии, о котором мы
говорили выше. Конечно, изворотливые пользователи придумали множество различных решений
и обходных маневров - но суть проблемы от этого не меняется.

Для нашей батальной сцены даже на машинах с несколькими гигабайтами оперативной


памяти prman вылетает из-за нехватки оной - просто потому, что кэш становится слишком большим.
GRUNT этого недостатка лишен - он поддерживает в памяти только A-buffer (то есть, Z-buffer, набор
нормалей, координаты точки на поверхности, цвет и некоторую другую информацию для каждого
пикселя картинки) и обходится без кэша моделей, просто подгружая каждого нового орка, рендеря
его, обновляя A-buffer и затем выгружая орка. Чтобы упростить понимание системы - представьте
себе композитинг по Z-буферу - если у вас есть что-то, что находится дальше Z-координаты - вы его
не рендерите и вас слабо интересует, что именно изображено на соответствующем пикселе - если
это не стекло, конечно. Но поскольку орки и эльфы в трилогии Толкиена не ходят в стеклянных
доспехах - считайте, что вам очень сильно повезло.

Любопытно, что GRUNT начинался в 1992 году как универсальный рендерер (и анимационная
система) для операционной системы OS/2 и активно использовался при производстве мультфильмов
и телевизионной рекламы. В 1992-м году 32 мегабайта памяти на персональном компьютере были
огромным размером - и выбор технологии А-буфера дал возможность даже на таком маленьком

Кое-что про Renderman 1387


объеме памяти рендерить очень большие сцены. Позднее, когда Джон присоединился к Weta Dig­
ital, ему пришло в голову, что массовые батальные эпизоды - отличное поле деятельности для его
прежде универсального рендерера.

Итак, основное преимущество специального рендерера - это используемая в его ядре


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

Во-первых, это возможность гибкой настройки для определенных задач. Ведь если у вас в
руках есть исходный код продукта и, более того, если вы - его автор, то никакой prman не даст вам
подобной гибкости. Обратите внимание: я говорю именно о гибкости, а не мощности или скорости
работы.

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


требует расширяемой модели освещения и поддержки Renderman-шейдеров - и шейдеры для него
пишутся на C++ и оптимизируются «по самое немогу». Программой часто пользуются на этапе
настройки сцены - и поэтому встроен специальный механизм, который позволяет сбрасывать
промежуточные результаты рендеринга и сразу же их просматривать. Pipeline компании заточен под
композитинг при помощи Shake - и GRUNT умеет считать в слои. Почти все кадры рассчитываются
с использованием "фермы" - и рендерер умеет делить сложную сцену на несколько простых для
такого просчета.

Основным поставщиком информации и моделей для GRUNT является другой специальный


продукт - Massive, который отвечает за правдоподобное поведение компьютерных персонажей
на поле боя. Massive посредством простых текстовых файлов передает в рендерер как обычную
(для рендерера) информацию (например, направление движения каждого объекта, его размер
и положение), так и необычные вещи - например, в какую одежду нужно одеть того или иного
персонажа. Если бы для всего этого использовались RIB'ы, объем занимаемого дискового
пространства был бы огромным. В данном случае, все необходимые алгоритмы и схемы встроены
непосредственно в рендерер, который анализирует входные данные и на лету собирает необходимую
модель, которую затем рендерит. Ту же самую текстовую начинку умеет генерировать посредством
простых MEL-скриптов и MAYA- и на этом этапе разница между prman и GRUNT для TD, работающих
в Weta Digital, стирается.
Как показывает практика, исчезающе мало число компаний, занимающихся производством
компьютерной графики, анимации и рекламы и при этом имеющих возможность позволить
себе пользоваться своими собственными разработками. Сказывается как себестоимость таких
разработок, которая ставит под вопрос возможность их окупить, так и высокий порог сложности
такой задачи. Появление на рынке MAYA с внутренним языком программирования MEL сильно
уменьшила этот порог - практически невозможно найти пользователя MAYA, который бы не писал
собственных скриптов. Но с собственными рендерерами, несмотря на все преимущества, ситуация
куда сложнее - они остаются вотчиной или крупных студий или отчаянных чудаков, как в нашем
следующем примере.

Spore
Рассказ об этом, не побоюсь громкого слова, революционном рендерере будет одной из
самых сложных для меня частей в главе. Все дело в том, что готовя материал к публикации, я
попытался пообщаться напрямую с людьми, непосредственно связанными с разработкой тех или
иных продуктов. В большинстве случаев мне это удалось - не скрою, многим разработчикам очень
приятно и лестно, когда результат их труда будет освещен в книге (пусть и не англоязычной).
Многим, но не Ричарду Бейли.

Мы общались с доктором Бейли в течение нескольких недель, обменявшись не одним


десятком писем по e-mail. И за все это время я не узнал ничего нового про Spore. To есть -
вообще ничего. Поверьте, я действительно старался! Поэтому все, что вы прочитаете здесь об
этом творении Ричарда, взято исключительно из открытых источников. Впрочем, даже эта горстка
информации впечатляет.

1388 Книга Сергея Цыпцына


Что же делает Spore настолько особенным, чтобы посвятить ему целую главу в этой книге?

Spore - узкоспециализированный рендерер, предназначенный для одного типа геометрии:


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

Результаты работы маленькой студии Ричарда Бейли под названием Image Savant выглядят
немного психоделически - впрочем, это не удивительно, потому что все свои инструменты
- а студия работает исключительно на своих собственных программах и рендерерах - Ричард
рассматривает как пробы в живописи и любительские арт-проекты. Впрочем, для небольшой
студии и психоделически выглядящего "любительского" портфолио у Image Savant неплохой
список заказчиков и фильмов - назовем лишь поверхность планеты Солярис в одноименном
американском римейке или внутренности Земли в фильме The Core.

Поскольку Spore единственный источник существования небольшой студии, все детали


внутреннего устройства этого рендерера доктор Бейли хранит в строгой тайне. Известно лишь, что,
имея полный доступ к исходному коду, Ричард - а он автор этого кода -фактически настраивает
свой продукт для каждого проекта и, возможно, для каждого кадра. В ходе работы над фильмом
Solaris компания Image Savant выдала на-гора 45 минут высококачественной 16ти-битной анимации
в разрешении 2к всего за несколько месяцев (два-три месяца), что говорит об экстраординарной
скорости и гибкости рендерера. Скорее всего, Spore не предусматривает шейдеры в том виде,
к которому мы привыкли после MAYA, Renderman и mental ray, но, как и GRUNT, позволяет
использовать некие, заранее предусмотренные модели закраски. Опять же, полный доступ к коду
продукта позволяет получать промежуточные результаты на любой стадии просчета кадра - мало
какой рендерер похвалится такой гибкостью.

Так о чем же мы могли говорить с Ричардом в ходе нашего онлайнового интервью, спросите
вы, если я ничего не узнал о его рендерере? О многом. Например, о том, что единственная
программа, которую используют в своей работе сотрудники Image Savant и которую они не написали
сами - это Shake, причем версии 1, без визуального интерфейса, исключительно через скрипты.
-И что переходить на более свежие версии эти мазохисты отказываются категорически. О том, что
в современном мире кинопродакшна, оказывается, вполне можно взять и открыть студию из трех
человек, которые займут свою собственную нишу и будут обеспечены работой на многие годы
вперед. Открыть студию, поясню, не имея ни копейки денег и ни одного заказа на старте. О том,
что хорошие, "правильные" программы пишутся чаще всего не программистами. О том, каким
будет следующий рендерер студии и что он позволит сделать (втайне надеюсь, что у них опять
все получится). О том, наконец, насколько сложен в изучении русский язык для англоязычных
- надеюсь, наша книга поможет Ричарду в решении и этой задачи.

Вероятнее всего, мы никогда не увидим Spore продающимся в виде коробочного продукта,


и те из вас, кто не поступит на работу в студию Image Savant, никогда не узнают, есть ли у этого
продукта интерфейс к MAYA. Впрочем, это не так уж и важно. Не знаю, как вам, а мне просто
достаточно знать, что возможность рендерить миллиард партиклов на кадр - есть на этом свете!
Значит, если немного постараться, можно будет обработать и превратить в потрясающе красивый
кинокадр и 10 миллиардов частиц... И кто знает, может, из такой разработки родится и ваша
студия?

Renderman - альтернативы RAT


Возвращаясь к теме Renderman + MAYA, я хотел бы сказать несколько (тысяч) слов о
альтернативах RAT. Ни для кого не секрет (и я попытался передать это ощущение в своей главе),
что связка Renderman Pro Server + RAT + MAYA близка к идеалу. Но ни для кого также не секрет, к
сожалению, что идеальной она все же не является. О некоторых проблемах данной связки мы уже

Кое-что про Renderman 1389


говорили, поэтому сейчас лишь кратко просуммируем сказанное:

высокая цена комплекта;


• ухудшающееся качество кода в последних версиях RAT;
• неудовлетворенность пользователей интерфейсом и возможностями;
и еще раз - высокая цена (увы, для многих этот фактор критичен).

И поэтому неудивительно, что существуют несколько альтернативных RAT'y решений,


позволяющих решать тот же круг задач, но не отягощенных проблемами, присущими продукту
компании Пиксар. В преддверии самой интересной части этой главы, посвященной оптимизации
рендеринга и хитростям, применяемым в реальном продакше, мы не будем тратить ваше время на
подробные описания и уроки, взамен предъявив вам список основных решений, их положительные
и отрицательные черты и наше заключение по каждому из продуктов. Логичным представляется
разделить наш краткий обзор на несколько основных направлений:

1. Рендереры, альтернативные prman'y.


2. Плагины и средства для экспорта геометрии.
3. Программы для работы с шейдерами.

И опять я вас чуток обманул. Потому что сейчас у нас будет еще и пункт номер ноль.

Альтернативные интерфейсы для MTOR


Именно так - альтернативные интерфейсы. Для MTORa. Казалось бы, в чем проблема?
А проблема очень простая - существующий визуальный интерфейс RenderMan Globals, написанный
в закудыкины времена на языке программирования Tel, выглядит чужеродным объектом в теле
MAYA. Более того, для продвинутых пользователей продукта это торжество программирования
со множеством окон и табов не кажется оптимальным. Именно поэтому существуют несколько
различных скриптов на MEL, которые предлагают альтернативный подход к настройкам MTOR
более удобный, скоростной и "родной" - ведь интерфейс самой MAYA тоже написан на MEL. Как
образец творческого подхода к вопросу, можно указать скрипт Юрия Мешалкина под названием
mtorRender (вы можете найти его на диске):

Человеку, только начинающему разбираться с Renderman Pro Server и MTOR, будет полезнее
пока оставаться в знакомом окружении родного интерфейса RenderMan Globals (как минимум, для
того, чтобы не было проблем с прохождением туториалов), но когда его рамки начнут вам мешать
- обратитесь к альтернативным решениям.
1390 Книга Сергея Цыпцына
Альтернативные Renderman-совместимые рендереры
В списке Renderman-совместимых рендереров, находящемся по адресу http://www.
dotcsw.com/links.html и любезно поддерживаемом одним из разработчиков такого рендерера
(Dot С Software, продукт под названием Render Dot С), на апрель 2005-го года находилось 23
продукта, из которых доступны для покупки или (в случае open source) бесплатного скачивания
более половины - 13 штук. Все они обладают теми или иными достоинствами и недостатками,
например, бесплатный Pixie - использует OpenGL и, соответственно, ресурсы видеокарты для
ускорения просчета сцены; недорогой AIR обгоняет всех конкурентов по набору возможностей
и по этому параметру единственный приблизился к prman. Флагманом Renderman-совместимого
рендеростроения с открытым исходным кодом является Aqsis - достаточно медленный, но
старательно пытающийся стать реальным противовесом коммерческим приложениям. Поскольку
все эти продукты Renderman-совместимые (а чтобы называться таким, рендерер должен строго
придерживаться основных положений стандарта), их можно использовать в качестве замены Ren­
derman Pro Server, в особенности если вы не использовали какие-то специфические для prman
особенности SL и RIB - более того, вы можете их использовать вместе с MT0R и SLIM, специальным
образом настроив последние.

Но меня не оставляет мысль, что пока что среди Renderman-совместимых единственным


реальным соперником prman'a является де-юре He-Renderman-совместимый Gelato. Я был бы
счастлив, если бы мог не делиться с вами своим скептицизмом - но таковы факты.

Экспорт из MAYA в RIB - MEL


При всей своей простоте формат файлов RIB в том виде, в котором он описан в спецификации
стандарта, достаточно объемен и включает в себя много различных возможностей и удобств. С
другой стороны, MAYA поддерживает много различных видов геометрии, материалов и эффектов.
Поэтому задача вывода сцены из MAYA в RIB посредством написания скриптов на языке MEL - это
исключительно академическое упражнение: на простых сценах рендерер не может показать себя
во всей своей красе, а на сложных сценах слабым звеном становится сам интерпретируемый скрипт
(выросший к тому моменту до нереальных размеров). Тем не менее, для простых экспериментов
или для случаев, когда пасуют готовые продукты, этот подход хорош.

Экспорт из MAYA в RIB - не MEL


Меня всегда удивляло, сколько всего интересного поставляется в комплекте с MAYA.
Про универсальный конвертер графических файлов мы уже говорили; а вот знаете ли вы, что в
стандартной поставке Майки можно найти плагин для экспорта геометрии в RIB? Удивительно, но
факт: ribExport.mll поставляется со всеми версиями MAYA, начиная с первой, и позволяет делать
простой экспорт геометрии - более того, плагин этот поставляется с полным исходным кодом.
Ни для каких серьезных задач данное решение не предназначено; качество и читаемость RIB'OB,
которые оно производит, оставляет желать лучшего. Тем не менее, такая функциональность в
рамках MAYA существует - и при очень большом желании вы можете взять исходники и попробовать
их модифицировать для своих нужд. Но мой вам совет - при первой же возможности воспользуйтесь
такими плагинами, как МауаМап или Liquid.

MayaMan
Одними из первых, кого не удовлетворили качество и ценовые запросы MT0R, стали
антиподы - австралийцы из студии Animal Logic. Уже одно происхождение продукта по всей
видимости дает ему хорошую фору по отношению к конкурентам - находясь на другой, нижней,
стороне нашего шарика, антиподы все время висят вниз головой, что помимо постоянного притока

Кое-что про Renderman 1391


крови к голове дает немалую раскрепощенность и отсутствие дурных привычек, присущих
голивудской индустрии.

Однако, шутки в сторону. Бесплатная оценочная версия доступна на сайте www.animal-


logic.com. Вы можете попросить временную лицензию, и, скорее всего, вам ее дадут. Мне, как
видите, дали.

Для того, чтобы попробовать МауаМап в деле, откройте свою любимую сцену или создайте
новую и подключите плагин. В главном меню MAYA появился новый пункт:

Как обычно в нашей главе, импортируем бедную овечку, переводим ее в сабдивы и


начинаем искать, как же нам ее отрендерить: МауаМап => МауаМап Globals (имя команды в меню
вам ничего не напоминает?):

Первое же отличие, которое бросается в глаза - это поддержка различных Render-


man-совместимых рендереров. МауаМап изначально разработан с тем расчетом, чтобы быть
совместимым с максимально возможным числом рендереров, предоставляя им одинаковые
возможности - и при этом максимально скрывая разницу между ними. Данная стратегия дала
свои результаты - учитывая различные версии одинаковых продуктов, плагин поддерживает 53
различных рендерера, от самых старых и уже не встречающихся в природе до самых продвинутых
и еще не вышедших из стадии предварительного тестирования.
Для продвинутых. Я получил эти цифры, изучив содержимое директории /mayaman/
Tenderers. Файлы, находящиеся в этой папке, содержат все необходимые настройки для всех

1392 Книга Сергея Цыпцына


поддерживаемых рендереров и представляют из себя весьма увлекательное чтиво.
Нас пока что удовлетворяют настройки по умолчанию, поэтому просто вызываем MayaMan => Pre­
view (я предварительно добавил в сцену большой светлый шарик, чтобы убрать черный фон):

Какой конфуз!.. В отличие от MTOR, MayaMan на данный момент не поддерживает subdivi­


sion surfaces от MAYA Unlimited. Однако мы все равно можем отрендерить полигоны как сабдивы - и
для этого воспользуемся кастомными атрибутами, которые MayaMan позволяет добавить к любому
объекту в сцене.

Для продвинутых. Если не считать конфуз с майскими SDS, официально MayaMan


поддерживает и экспортирует в RIB любую геометрию, кроме PaintFX - впрочем, PaintFX в RIB не
экспортирует ни один из известных плагинов. Этот вопрос - «А как отрендерить Paint Effects в
Renderman?» - в свое время был самым задаваемым в русских форумах, посвященных Renderman:
нам пришлось даже вынести его в FAQ. Впрочем, и у этой проблемы есть возможное решение
ведь вывести данные из PaintFX в виде кривых не составляет особого труда, загвоздка лишь в
применяемых кистях и их отрисовке.

Удаляем из сцены нашу овечку и импортируем ее заново. На этот раз мы не будем


переводить ее в сабдивы штатными майскими средствами; вместо этого, выделяем ту геометрию,
которую нужно отобразить в виде SDS и вызываем пункт меню MayaMan => Add Model Attributes.
Затем в окне редактирования атрибутов в разделе SubDivision Surface выставляем нужную галочку
1Л'

получаем наше животное в целости и сохранности. Но это не так интересно - на протяжении


нашей главы мы уже с дюжину раз различными методами рендерили бедного барашка; попробуем
теперь узнать, какие дополнительные преимущества перед MTOR имеет наш MayaMan. Для этого
назначим на нашу модель любой материал из HyperShade и посмотрим, что произойдет (в данном
случае мы назначили Blinn с присоедененным к каналу цвета brownian):
Кое-что про Renderman 1393
Оказывается, как и Mango, MayaMan поддерживает материалы HyperShade и конвертирует
их в шейдеры RenderMan. Но, в отличие от Mango, MayaMan действительно создает новые шейдеры
- впрочем, делает это очень хитро, давайте посмотрим получившийся у нас шейдер (его можно
найти в поддиректории нашего проекта \mayaman\sheep1\shaders\ - я убрал заголовок шейдера
для краткости):

{
PROFILE("begin");
#pragma nolint
SURFACE_TEMPS;
APPLY_SLICE_PLANE else {

PROFILE("SETUP 0 BLINN");
BLINN_SETUP(v_0_);
if(only_do_opacity == 0) {
PROFILEfSETUP 1 BROWNIAN");
BROWN I AN_SETU P (v_1 _ ) ;
PROFILE("SETUP 2 PLACE3DTEXTURE");
PUCE3DTEXTURE_SETUP(v_2_);
PROFILE("SIMULATE 2 PLACE3DTEXTURE");
PLACE3DTEXTURE_SIM(v_2_);

v_1_placementMatrix = v_2_worldlnverseMatrix[0];
PROFILE("SIMULATE 1 BROWNIAN");
BROWNIAN_SIM(v_1_);

v_0_color = color(v_1_outColor);
}
PROFILE("SIMULATE 0 BLINN");
BLINN_SIM(v_0_);

Ci = v_0_outColor;
Oi = Os;
}
DEEP_SHADOW_OPACITY_HANDLER
PROFILE("end");
SURFACE_DEBUG_HOOK
}

He очень похоже на обычный шейдер, написанный на Renderman SL, правда? Тем не менее,
это обычый шейдер. Вся хитрость в том, что в этом шейдере очень широко используются такие
возможности языка SL, как макросы и подстановка значений. Если мы пропустим этот файл через
препроцессор срр, то сможем увидеть истинное лицо нашего шейдера - впрочем, я не буду сюда
его вставлять из-за достаточно большого размера - книжка-то у нас не резиновая.

Для продвинутых. Те же, кто не поленится заглянуть в получившиеся 40 килобайт (почти


1200 строк) кода на SL, узнают много нового о том, как на Renderman SL сымитировать ноды из
MAYA HyperShade, да и вообще - про внутреннее устройство MAYA и про рендеринг вообще.

Итак, MayaMan конвертирует материалы из MAYA в Renderman SL - и тем самым серьезно


упрощает работу для тех, кто только начинает пробовать на зуб новый рендерер. Кроме того, вы
можете использовать свои собственные шейдеры в качестве материалов - и даже больше, вы
можете встраивать материалы, написанные на языке SL, в виде специальных нод HyperShade - и
эти ноды будут использованы при рендеринге через MayaMan.

Нам же осталось указать, что все возможности и настройки MayaMan доступны как через
MEL (посредством ноды под веселым названием MayaManNugget), так и из командной строки -
при помощи программы mayaman_batch_m6.exe (или mayaman_batch_m65.exe, в зависимости от

i 394 Книга Сергея Цыпцына


используемой вами версии MAYA).

Для продвинутых. Несколько простых скриптов на MEL, которые упростят вашу работу с Maya-
Man. Во-первых, узнаем, какие вообще параметры есть у ноды MayaManNugget - и, соответственно,
у всего плагина:

string $MayaManOptions[ ] = 'jistAttr MayaManNugget';


for ($eachParameter in $MayaManOptions)
print ($eachParameter + "\n");

Во-вторых, небольшой скрипт, который можно вытянуть на полку, чтобы быстро


переключаться в режим предварительного просмотра - и ухудшеного качества (о значении всех
этих устанавливаемых параметров мы будем говорить уже очень скоро):

setAttr "MayaManNugget.ShadingRate" 16;


setAttr "MayaManNugget.PixelSamplesX" 1;
setAttr "MayaManNugget.PixelSamplesY" 1;
setAttr "MayaManNugget.PixelFilterX" 2;
setAttr "MayaManNugget. PixelFilterY" 2;

И в-третьих, антипод скрипта "во-вторых":

setAttr "MayaManNugget.ShadingRate" 1;
setAttr "MayaManNugget.PixelSamplesX" 3;
setAttr "MayaManNugget.PixelSamplesY" 3;
setAttr "MayaManNugget.PixelFilterX" 3;
setAttr "MayaManNugget.PixelFilterY" 3;

Суммируя сказанное: МауаМап специально разработан в расчете на использование с


несколькими Renderman-совместимыми рендерерами, у него более удобный (на мой взгляд)
интерфейс, чем у MTOR, но беднее возможности экспорта геометрии. МауаМап поддерживает
материалы, разработанные в HyperShade, используется в студии Animal Logic в работе над
фильмами и является, по сути, самой сильной альтернативой MTORy из существующих.

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


для 3dsmax и Softimage с соответсвующими названиями - МахМап и SoftMan. Если вы пользуетесь
"максом" или все еще не перешли с "софта" на XSI -хороший повод для того, чтобы попробовать
Renderman, ведь теперь он есть и у вас.

Liquid
Существует целая каста людей, которые по принципиальным соображениям пользуются
исключительно бесплатным программным обеспечением, предоставляемым исключительно с
исходным кодом. Бальзамом на душу таким людям будет наш следующий плагин для MAYA - Liq­
uid.

Разработанный Колином Донкастером (Colin Doncaster), «лИквид» был первоначально


предназначен для нужд студии Weta Digital (мы еще не раз встретим название этой студии в
нашей главе), а именно - для фильма "Властелин Колец". Подобное требование наложило свой
отпечаток на внутреннюю структуру и функциональность плагина, который был максимально
заточен под большие сцены, сложные написанные руками шейдеры и большое количество текстур
- и не очень-то дружествен по отношению к неопытным рендерменщикам.

Впрочем, в 2002-м году Колин покинул студию и забрал Liquid с собой. После долгих
раздумий, он выложил исходный код плагина на сайте http://liquidMAYA.sourceforge.net/ - и с
этого момента фактически прекратил участие в судьбе своего проекта. Впрочем, его программа
попала в хорошие руки, и целая группа разработчиков занялась доводкой и улучшением продукта,

Кое-что про Renderman 1395


выкладывая все новые и новые версии плагина и его исходного кода. Отрадно отметить, что среди
новых родителей Liquid'a есть и русскоязычные программисты.

Из всех рассмотренных нами плагинов для работы с Renderman, Liquid является, по сути,
самым неудобным в повседневной работе. С другой стороны, у этого плагина огромный потенциал
- изначально ориентированная на задачи реального кинопроизводства архитектура, заложенная в
эту архитектуру скорость работы и гибкость дают надежду на дальнейшее развитие этого продукта
- например, некоторые студии вовсю используют Liquid в качестве основы для своих собственных
экспортеров и студийных пайплайнов.

Впрочем, в списке этих студий больше нет Weta Digital. После ухода Колина оказалось,
что второй и третий фильм трилогии "Властелин Колец" серьезно повысили требования к плагину
- а исправлять его было уже некому, да и копирайт на код остался у автора. Поэтому в студии
внедрили новое решение, по иронии судьбы (а скорее, обыгрывая предыдущий продукт - Liquid)
названное Solid (то есть не «жидкость», а «твердость»...).

А мы, тем временем, от средств вывода геометрии перейдем к редактированию шейдеров.


Вот вы, молодой и красивый (а еще лучше - молодая и красивая), сидите перед компьютером, в
плейере загружен последний альбом любимой группы, пакет с соком открыт, вы кладете руки на
клавиатуру - и сталкиваетесь с одной из самых неприятных сторон Renderman Shading Language:
писать на нем шейдеры вручную трудно и долго, в особенности для тех из вас, кто привык к
красивым интерфейсам и большим кнопкам. Множество компаний и просто умельцев прикладывает
массу усилий для того, чтобы облегчить труд шейдерописателя - начиная с модулей для подсветки
синтаксиса SL в самых популярных текстовых редакторах (вот вы смеетесь, а это очень важно
и удобно) и заканчивая визуальными конструкторами, позволяющими создавать шейдеры при
помощи мыши. Наибольший интерес для новичков (равно как и просто очень занятых людей)
представляет именно последняя категория программ. Воспользуюсь служебным положением и
обойду вниманием такие входящие в эту категорию продукты, как ShadeTree, Vshade и Shrimp.
Вместо этого мы поговорим о программе, автор которой ясам и есть - о ShaderMan.

ShaderMan
Когда-то, очень-очень давно, когда деревья не были такими высокими, а в prman еще
не встроили raytracing, я поймал себя на мысли, что в процессе написания шейдеров на SL все
время повторяю одни и те же шаги и постоянно использую одни и те же куски кода в качестве
образцов. Более того, у меня скопилась целая библиотека таких кусков и готовых шейдеров, на
которых я тренировался и учился, изучая чужой код и воплощенные в жизнь идеи (эта библиотека
существует и по сей день, в ней 685 файлов, и у меня сложилось впечатление, что в некоторые
из них я еще ни разу не смотрел). Так вот, я начал подумывать о том, чтобы каким-то образом
автоматизировать свою работу, написав специальную программу, упрощающую создание шейдеров
- но я не был уверен в том, как должна работать такая программа, на какие принципы опираться и
какой визуальный интерфейс наиболее удобный и быстрый.

Примерно в это же время появился новый продукт компании (тогда еще) Softimage
под названием XSI, в котором похожая идея с визуальным редактированием материалов была
воплощена в Render Tree - и после первого же скриншота я понял, в каком направлении мне
следует двигаться.

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

Запускаем ShaderMan. В окошке Welcome, если вы его не закрыли и не отключили, выбираем


кнопку Start New Shader; если все-таки закрыли - то выбираем из меню File=>New... Имя шейдера
по умолчанию (defaultname0) вполне подойдет.

1396 Книга Сергея Цыпцына


В рабочей области программы появился небольшой элемент - в терминологии ShaderMan
он называется кирпичиком (brick).

Аналогия простая: из таких вот кирпичей мы собираемся построить нечто полезное


и красивое. С версией 0.7.0.0 программы поставляется 345 различных кирпичиков. Вполне
естественно, что выводить их все простым списком было бы глупо и некрасиво по отношению к
пользователю, поэтому все элементы рассортированы по тематическим подгруппам - которые вы
и видите в окне слева в виде дерева (или по правому клику на свободном пространстве в окне
ShaderMan - в виде меню).

Для любознательных. Эта древовидная структура всего лишь повторяет структуру


поддиректорий (brick). Все «брики» - это файлы в формате XML с расширением - никогда не
угадаете - *.br.

Чтобы добавить новый элемент в наш шейдер, можно воспользоваться левым деревом
(и перетянуть-бросить в смысле: «дрэг'н'дропнуть» - необходимые элементы из него), а также
контекстным меню рабочего стола или главным меню программы. Не суть важно, как - важно, что
добавим несколько бриков. Какие?

Впервую очередь (поскольку мы не экстремалы, а всего-лишь начинающие шейдерописатели),


это будет готовый шейдер (папка ready shaders) или готовая модель освещения (shading mod­
els). Впоследствии вы сможете сами строить новые модели освещения, пользуясь бриками более
низкого уровня (предоставляется и такая возможность), а пока возьмем на вооружение уже готовые
наработки и добавим в шейдер кирпичик Oren-Nayar.

Для любознательных. В наборе есть и стандартные для MAYA lambert и blinn, но мы


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

Через контекстное меню переводим оба брика в режим с локальными изображениями


(Show local preview) и, если у вас правильно настроен рендерер, видим нечто вот такое:

Кое-что про Render man 1397


Что-то явно не так в датском королевстве... Все элементы на месте, но элемент Surface
- черный, а элемент Oren-Nayar показывает образец шейдера. Вывод логичен необходимо
подсоединить выход из одного брика ко входу из другого, что мы мышкой и делаем, после чего
сразу же тыкаем в картинку на Surface:

Вот, собственно, и все. Окинем взглядом имеющуюся диспозицию:

В правом верхнем углу окна имеем специальную область просмотра результатов рендеринга.
Достаточно выбрать мышкой из списка чего-нибудь нешарообразное, например, чайник (teapot)
и кликнуть в эту область - и сразу появится большое превью, с которым можно делать всякие
разности, например, смотреть по каналам RGB или установить рендеринг не всей картинки, а
только ее части. В общем, имеется в наличии некий мутант, собранный из возможностей fcheck,
it и других просмотрщиков.

Для продвинутых. Чтобы prman мог рендерить сразу в окно ShaderMan, мне пришлось
написать специальный display driver, который затем переписывался еще не раз, в том числе
полностью для Entropy, которая не поддерживала стандартные драйвера дисплея.

1398 Книга Сергея Цыпцына


Внизу под областью просмотра у нас - набор параметров шейдера, настройки для preview и
специальные редакторы для RIB-кода (некий аналог RIBbox из MTOR). В самом низу окна - консоль,
в которую рендереры выводят статусную информацию: иногда полезно поглядывать в это окошко,
чтобы вовремя обнаружить возможные ошибки при рендеринге.

А мы, тем временем, через меню View отключаем все эти навороты и остаемся с голым
рабочим столом программы. При помощи контекстного меню добавляем новый брик: fractal/
fractal. Присоединяем его выход к входу Kd OrenNayar. Кстати, о Kd. Везде, где только можно
было, я старался придерживаться стандартных имен параметров шейдеров, которые приняты на
практике, например, Kd - это коэффициент диффузии. Но в определенный момент, столкнувшись
с вопросами новичков, в особенности пришедших из MAYA HyperShade, я придумал опцию View =>
Friendly Shader Parameters, которая дает параметрам шейдеров более дружественные и понятные
имена:

Кроме визуального, а-ля HyperShade, режима редактирования шейдеров, в ShaderMan


реализован еще один режим, a la Slim. Дабл-кликните (это в смысле - дважды) на любом брике,
например, на достославном Oren-Nayar:

Кое-что про Renderman 1399


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

Каким образом результат нашей работы можно использовать в MAYA? Собственно в MAYA
- почти никак, потому что конечным результатом работы в ShaderMan является шейдер SL. Кроме
этого, вы можете экспортировать темплейты Slim, и уже их непосредственно подключать к MTOR.
Либо экспортировать специальные файлы для Liquid - и использовать их. Ну и, наконец, можно
отрендерить шейдер в текстуру, которую затем подсасывать в майские шейдеры.

На этой мажорной ноте придется оборвать наше повествование. Я много чего не рассказал
вам о ShaderMan. Например, о маркинговом меню (идея которого, когда я впервые увидел ее
в продуктах Alias, поразила меня до глубины души). Или о потенциальной расширяемости
программы, основанной на простом структурированом текстовом формате XML и усиленной языком
программирования Tel. Или о встроенной поддержке более чем десятка Renderman-совместимых
рендереров - и легком добавлении новых (опять с помощью волшебного слова правильно:
XML). Или о дружелюбности продукта, которую способны оценить новички, и, одновременно, его
мощности для опытных пользователей (я тоже раньше думал, что это почти нереально). Или про...
- о, вспомнил! О пункте меню File=> Import.

Найдите на диске один из шейдеров, с которыми мы экспериментировали раньше,


например, textured_noise.sl:

surface textured_noise ( float freq=100; )


{
Ci = texture(texture.tx", s, t)*noise(freq*s,freq*t);
}

Вызываем из главного меню ShaderMan File=>lmport=>Shader source as new brick..., выбираем


только что найденный нами файл и через несколько секунд (в течение которых запускается и
выполняется конвертер из шейдера SL в формат брика BR) на рабочем столе ShaderMan появляется
новый брик - textured_noise. Присоединяем его к Surface Color кирпичика Oren-Nayar и немедленно
получаем:

i 400 Книга Сергея Цыпцына


Таким образом мы можем загрузить в виде нового брика практически любой готовый
шейдер, написанный на языке Renderman SL, и в дальнейшем использовать его как часть своих
собственных шейдеров. Но это еще не все. В том же меню ShaderMan File=>lmport выбираем другой
подпункт - RIB file as template. Находим нашего первенца, testl .rib - это тот самый, неосвещенный,
с единственным одиноким полигоном перпендикулярно камере:

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 -1
ShadingRate 1
WorldBegin
Surface "plastic"
Polygon "P" [0.5 0.5 0.5 0.5 -0.5 0.5 -0.5 -0.5
0.5-0.5 0.5 0.5]
WorldEnd

Пока не случилось непоправимое, быстренько открываем этот файл в тектовом редакторе,


вспоминаем, чему мы учились всю эту главу, и добавляем источники света (для ленивых или тех,
кто читает книжку, только сидя в метро - файл test_shaderman.rib):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192-1
ShadingRate 1
WorldBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] "to" [0 0 0]
AttributeBegin
Attribute "identifier" "name" ["polyShape"]
Surface "plastic"
Polygon "P" [0.5 0.5 0.5 0.5 -0.5 0.5 -0.5
-0.5 0.5-0.5 0.5 0.5]
AttributeEnd
WorldEnd

Кроме источников света мы также добавили аттрибут "identifier", который позволяет нам
дать имя объекту - такие аттрибуты добавляют, в том числе, все экспортеры из MAYA в RIB. И
только теперь импортируем в ShaderMan.

Для продвинутых. Те же самые операции по импорту файлов можно проделать, просто


перетянув их мышкой из Windows Explorer.

Мое- что про Renderman 1401


Вроде бы ничего не поменялось и не произошло, кроме разве что сообщения в консольном
окне (и строке статуса) ShaderMan - \rib_example\test_shaderman.rib : done. Для того, чтобы
понять всю важность произошедшего, включите обратно область preview и попробуйте выбрать в
выпадающем списке объект:

Мы только что загрузили внешний RIB файл в качестве сцены для использования в ShaderMan
- и программа предоставила нам возможность выбрать объект, на котором мы будем тестировать
наш шейдер (не случайно мы дали нашему объекту имя).

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


данных и файлов в рамках RAT. Стоит обратить внимание на то, что некоторые стрелочки в схеме
- двунаправленные; это означает, например, что ShaderMan может как экспортировать, так и
импортировать файлы SL.

Название ShaderMan появилось не сразу. Первые публичные релизы программы (а раздавал


я их сначала только русскоязычным пользователям) назывались TheTool собственно, веб-страница
продукта до сих пор носит такое название - http://www.dream.com.ua/thetool.html. И идея с новым
названием и вообще выкладыванием своего творения на публику тоже пришла не сразу: изначально

1402 Книга Сергея Цыпцына


это был внутренний проект, программа для себя, чтобы сделать свою работу интереснее и проще.
Лишь потом, получив много полезных и приятных откликов от первых пользователей ShaderMan'a,
я озаботился всем тем, что отличает нормальную программу от кустарной поделки - написанием
Help'a, созданием нормальной веб-страницы, инфраструктурой для поддержки пользователей.
И еще - именно из-за того самого первого фидбэка программа осталась бесплатной. В конце
концов, все, что мне было нужно от своего детища - это получить инструмент для дальнейших
исследований, а еще - получить удовольствие от самого процесса написания программы. И если
ShaderMan оказался полезен не только для меня, но и для (многочисленных, насколько я могу
судить по количеству скачивании) пользователей - это очень приятно.
Ведь так?

Трюки, ухищрения, или древнее китайское искусство Chi Ting - в массы

Вы слышали раньше про древнее китайские искусство Chi Ting? Первая информация об
исследованиях этого искусства появилась в 1988 году в статье Джима Блинна (того самого, который
Blinn shading model) под названием " THE ANCIENT CHINESE ART OF CHI-TING" (http://research.
microsoft.com/users/blinn/CHITING.HTM), однако Джим указал, что первенство в придумывании
названия для этого артефакта принадлежит Биллу Этре. Первое же упоминание об использовании
данного искуства в отношении Renderman, надо полагать, появилось в Siggraph-92 Renderman
Course Notes (что-то вроде: «Материалы учебного курса по Renderman во время Siggraph-92»).
/1адно, ладно, я больше не буду издеваться - название Chi Ting, если его прочитать в соответствии
с правилами английского языка, созвучно английскому же слову cheating - то есть, «жульничать»,
«надувать».

Работая в Лаборатории реактивного движения НАСА (NASA Jet Propulsion Laboratory) над
анимационным роликом, рассказывающем о пролете станции исследования дальнего космоса
«Вояджер» над Сатурном (вы наверняка видели этот ролик), Джим заметил, что на самом деле
зрителя мало интересует сам факт, что созданная анимация построена на точных физических
принципах и отображает истинную картину мира. Более того, использовать "взрослую физику"
при производстве такой анимации зачастую попросту невозможно (в силу нашего незнания,
неготовности или физической невозможности проводить расчеты такой сложности). Обратите
внимание - я не говорю про физические эксперименты и визуализацию их результатов, я говорю
про «Вояджер», красиво пролетающий мимо колец Сатурна.

Так почему бы, в таком случае, не срезать несколько углов и не обмануть зрителя,
упростив расчеты или изменив алгоритм, например? Если в стакане красиво плещется вода,
среднестатистическому посетителю кинотеатра (а телерекламосмотрителю - и подавно!) все
равно, настоящая там вода была в стакане, сымитированная на суперкомпьютере, при помощи
суперпродвинутых, метафизических Liber-формул - или это просто "грязный хак", который
выглядит как вода в стакане.

Для любознательных. Буквально на днях прочитал весьма поучительную историю о том,


как делаются рекламные фотографии сухих молочных завтраков - на языке отцов-основателей
они называются crisps, у нас пусть будут по-русски - мюсли. Общеизвестно, что мюсли - штука
катастрофически хрупкая, и обычно на донышке пачки вместо той красотищи, что изображена на
коробке, обнаруживается лишь сухое мелкодисперсное месиво. Так вот для того, чтобы сделать
фотографию для оформления коробки, на пол высыпают целый ящик мюслей, после чего вручную,
ювелирными щипчиками отбирают из огромной кучи 50-60 абсолютно целых, «жирных» кусочков
(обычно к моменту начала ковыряния в куче их где-то столько целых и остается). Берется сосуд,
в него опять же вручную, по одному укладываются отобранные ранее кусочки, затем промежутки
заполняются ярко-белым гелем для волос (в отличие от клея, он не портится от яркого света и
высокой температуры, создаваемых софитами) - это будет видимость молока. В зависимости от
сорта сухого завтрака добавляются всякие вишенки или шоколадки - на самом деле внутри коробки
их нет, но на фотографии они обязательно будут. И вот уже фотографируется эта несъедобная
конструкция. Все - для человека...

Как мне кажется, стандарт Renderman и поддерживающие его рендереры являются


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

Кое-что про Renderman 1403


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

И начнем мы с действительно простых вещей - а именно некоторых особенностей Render-


man-совместимых рендереров.

ShadingRate
В RenderMan существуют несколько настроек качества изображения, которые являются
критическими и без знания о которых вы не сможете добиться нормального баланса между
временем расчета и качеством картинки. Основная такая настройка - это ShadingRate.
Prman, равно как и многие другие рендереры, накладывает шейдеры после тесселяции
объекта на микрополигоны - будем называть их «сэмплами». Если посмотреть на этот вопрос
немного упрощенно, то ShadingRate - это то количество пикселей, которое рендерер будет
просчитывать за один вызов шейдера. Таким образом, вызов

ShadingRate 0.25

означает, что на каждый пиксель картинки шейдер будет вызван приблизительно 4 раза (1/0.25) в
различных точках внутри этого пикселя, а полученные значения будут усреднены и, соответственно,
качество картинки будет гораздо выше. Установка же такого значения:

ShadingRate 20

означает, что вызов шейдера будет производиться один раз на примерно 20 пикселей,
что даст гораздо худшее качество - но рендеринг завершится очень быстро. Так вот, поскольку
именно шейдинг в процессе обсчета картинки занимает большую часть времени (в особенности
для сложных процедурных шейдеров, например, с нойзом), эта настройка чаще всего используется
в Renderman'e.

Давайте рассмотрим несложный пример. Откроем простой RIB с шариком, с которым мы


экспериментировали на протяжение всей нашей главы, и настроим в нем величину ShadingRate
(файл на диске под именем shadingrate025.rib):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 0.25
Translate 0 0 2.7650300856
World Begin
TransformBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] "to" [0 0 0]

TransformEnd
Surface "plastic"
Sphere 1 -1 1 360
WorldEnd

Напускаем prman на этот файл и получаем в результате:

1404 Книга Сергея Цыпцына


Для продвинутых. В этом примере вы использовали ShadingRate, равный 0.25, то есть
4 вызова шейдера для каждого пикселя. По умолчанию, если величину ShadingRate в сцене не
указывать, то она будет выставлена в 0.5. Большинство экспортеров трехмерной сцены в RIB(
и SLIM в их числе) специально выставляют ShadingRate - об этом следует помнить, особенно в
процессе работы в SLIM'e (выставляющем по умолчанию 5.0), если вам вдруг начнет казаться, что
качество картинки в окне предварительного просмотра что-то не очень высокое.

Изменяем значение ShadingRate (файл на диске shadingrate64.rib):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 64
Translate 0 0 2.7650300856
WorldBegin
TransformBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] "to" [0 0 0]

Transform End
Surface "plastic"
Sphere 1 -1 1 360
WorldEnd

После рендеринга видим:

Рендеринг закончился гораздо быстрее, но качество результата оставляет желать лучшего:


шейдер вызывался один раз на 64 пикселя, и теперь вы видим границы между сэмплами.
Существует простой способ сгладить эти неприятные грани, добавив в RIB-файл где-нибудь рядом
с ShadingRate строку

Shadinglnterpolation "smooth"

Кое-что про Renderman 1405


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

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

Option "statistics" "endofframe" [1 ]

или

Option "statistics" "endofframe" [2]

в зависимости от того, насколько детальная информация вас интересует. Для наших двух
примеров оказывается, что количество сэмплов, которое prman создал в процессе рендеринга
для каждой из сцен, равняется 1030 для первой сцены и всего лишь 56 - для второй. Экономия
памяти составила 1 мегабайт; экономия времени - несколько раз (поскольку картинка маленькая
и простая, то сосчитать точно количество раз сложно даже с такой статистикой - для второй сцены
она показала 0 секунд).

Особенностью Renderman'a, которая позволяет очень гибко использовать ShadingRate,


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

ShadingRate 0.25 # Это значение будет работать для всей сцены


AttributeBegin
ShadingRate 4 # Кроме этого шарика, для которого
# определено свое собственное значение
Surface "plastic"
Sphere 1 -1 1 360
AttributeEnd

Таким образом, вы можете установить высокое значение ShadingRate для той части сцены,
которая находится близко к камере, и низкое - для дальних или несущественных объектов. Более
того, используя MEL, это значение можно сделать динамически зависящим от расстояния от
объекта до камеры.

Для продвинутых. Опытные TD советуют использовать для просчета карт теней высокие
значения ShadingRate, вплоть до 32 (хотя все же не больше 8, если используется displacement).
Как оказалось, на видимое качество теней это почти не влияет, а ускорение просчета составляет
до 20 раз.

К сожалению, этот трюк хорошо работает не для всех типов теней; также его не
рекомендуется применять для key light и областей с сильным дисплейсментом из-за возможности
появления "грязи". Сами консультанты из Pixar также советуют при использовании motion blur
увеличивать ShadingRate - поскольку объекты и так будут "разблюрены", то небольшое падение
качества к видимому ухудшению картинки не приведет.

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


у вас не будет большого выбора в значениях ShadingRate, и тому есть несколько причин. Во-
первых, поддержание единого значения ShadimgRate в сцене позволяет избежать разнобоя
в картинке - грубо говоря, артефакты на всех моделях выглядят одинаково. Далее, модели с
высокочастотными текстурами (особенно с большим их количеством) очень требовательны к Shad­
ingRate. И наконец, даже если объект движется (и мы скрываем его при помощи motion blur и, по
совету Pixar, увеличиваем SR), все равно будут несколько кадров, в которых он будет неподвижен.
Именно эти кадры должны показать работу шейдерописателей и текстурных художников во всей

1406 Книга Сергея Цыпцына


красе - потому что именно на этих кадрах (согласно закону бутерброда) будут делать стоп-кадры
на своих DVD-проигрывателях будущие трехмерщики - и изучать, изучать, изучать...

PixelSamples
Архитектура REYES, на которой построен prman, в момент своего создания сильно отличалась
от общепринятых подходов к трехмерному рендерингу, в частности, из-за того, что процесс
шейдинга в ней происходит до определения видимости и вычисления краевого антиалиасинга
поверхностей.

Как это происходит? Получается, что на какой-то стадии шейдеры вызваны, объекты уже
закрашены, а картинка все еще девственно чиста? Что же тогда «красят» шейдеры?

Все очень просто: закраска происходит не в двумерном пространстве картинной плоскости,


а в трехмерном мире сцены. Дело в том, что еще до шейдинга prman производит тесселляцию
(разбиение) видимых поверхностей на микрополигоны, размеры которых приблизительно
определяются числом занимаемых ими на картинной плоскости пикселей - да-да, ShadingRate как раз
тут и говорит свое веское слово! После такой тесселляции в распоряжении рендерера оказывается
сетка из микрополигонов, которые, с одной стороны, представляют собой геометрические объекты
- малюсенькие прямоугольные патчи; а с другой стороны, их можно рассматривать как шейдинг
сэмплы - минимальные кусочки поверхностей, закрашиваемые сплошным цветом.

Вот здесь и начинается собственно шейдинг: для каждого такого патчика будет
сформирован однократный вызов соответствующих шейдеров и каждый патчик получит свой цвет
и прозрачность. А если на поверхность назначен и displacement шейдер, патчики-сэмплы будут
сдвинуты в указанном шейдером направлении. Но повторяю: это все пока происходит в трехмерном
пространстве, и до картинной плоскости дело еще не дошло!

Следующая задача - спроецировать эту трехмерную информацию на пиксели картинки. Тут


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

В реальности же все намного сложнее, в основном, из-за того, что тут мы попадаем в
царство Его Величества Антиалиасинга. Не вдаваясь в подробности, скажу лишь, что для этой
цели алгоритм REYES использует oversampling, то есть многократный точечный сэмплинг. Через
каждый пиксель картинной плоскости (грубо говоря, нашего конечного изображения) к сцене
провешивается несколько лучиков (точнее будет сказать, point samples, или точечных сэмплов,
- не путать с шейдинг сэмплами, с одной стороны, и со световыми лучами при рейтрейсинге
- с другой стороны!), и выясняется, с каким цветом/прозрачностью они уперлись в шейдинг
сэмплы. Эти значения взвешиваются по каждому пикселю, с использованием одной из нескольких
доступных для пользователя фильтрующих функций и в зависимости от удаленности лучиков от
центра пикселя. Результаты взвешивания записываются в пиксель готовой картинки.

Так вот, параметры PixelSamples определяют количество точечных сэмплов на каждый


пиксель - по вертикали и горизонтали. PixelSamples 5 5 заставит prman запросить цвет/прозрачность
шейдинг сэмплов, спроецировааных в каждый пиксель ровно 5 х 5 = 25 раз.

Если копнуть еще глубже, выяснится, что в реальности Prman провешивает лучики, не
разбивая каждый пиксель на регулярную сетку, размером, скажем, 5x5, как в нашем примере, а
случайным образом разбрасывая их в пределах ячеек этой сетки. По науке это называется Stochas­
tic Sampling - именно на эту технологию Pixar получила свой патент, и именно при помощи этого
патента засудила компанию Exluna.

Интересно, что такие эффекты как Motion Blur и Depth of Field prman-ом производятся
как раз при помощи PixelSamples. Все очень просто: направления PixelSample-лучей, опять-
таки, случайным образом изменяются с учетом вектора «движения» шейдинг сэмплов и/или их
удаленности от «точки фокуса» камеры. Собственно, вот вам и объяснение того, что prman держит

Кое-что про Renderman 1407


пальму первенства в скорости рендеринга Motion Blur - там, где другие рендереры при включении
MB замедляются в разы, он теряет всего десяток-другой процентов, потому что продолжает
использовать те же самые алгоритмы, что и до этого. И именно поэтому сцены с motion blur
более требовательны к PixelSamples, чем обычные ведь чем сильнее «блюр» (размазанность),
тем больше может потребоваться сэмплов, чтобы она выглядела равномерно, а не "разбросанной
по экрану".

Ну и последнее уточнение, без которого описанная выше схема рендеринга не имеет


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

Ффух! Отдышались? Поехали дальше.

По умолчанию величина PixelSamples в prman установлена как:

PixelSamples 2 2

Это означает, что на каждый пиксель приходится 4 точечных сэмпла . Если мы изменим эту
величину (файл на диске pixelsamples11.rib):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192 1
ShadingRate 64
PixelSamples 1 1
Translate 0 0 2.7650300856
World Begin
Transform Begin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3 -1.2 -1.0] " t o " [0 0 0]

TransformEnd
Surface "plastic"
Sphere 1 -1 1 360
WorldEnd

то получим картинку без антиалиасинга и с видимыми проблемами с шейдингом - но


получим ее очень быстро:

Управляя двумя переменными - ShadingRate (для любых участков вашей сцены) и Pixel-
Samples (для всей сцены) можно очень гибко настраивать рендеринг, добиваясь максимального

1408 Книга Сергея Цыпцына


качества за минимальное время.

Для продвинутых. Покажем, как управлять этими параметрами при помощи утилиты срр
- как мы отмечали раньше, такая утилита есть в поставке почти всех рендереров, совместимых с
Renderman. Для этого внесем изменения в RIB (вы можете просто открыть cpptest.rib с диска):

Display "RenderMan" "framebuffer" "rgb"


Format 256 192-1
ShadingRate SR
PixelSamples SX SY
Translate 0 0 2.7650300856
WorldBegin
TransformBegin
LightSource "ambientlight" 500
"lightcolor" [0.051 0.051 0.051]
LightSource "distantlight" 501 "from" [1 1.5 -1] " t o " [0 0 0]
LightSource "distantlight" 502 "lightcolor" [0.2 0.2 0.2]
"from" [-1.3-1.2-1.0] " t o " [0 0 0]

TransformEnd
Surface "plastic"
Sphere 1 -1 1 360
World End

Мы определили внутри файла три символьные константы - SR, SX и SY. Теперь вызовем в
командной строке препроцессор:

срр -DSX=2 -DSY=2 -DSR=0.25 cpptest.rib | prman

и получим в результате картинку с необходимыми установками: константы внутри файла


будут заменены на значения, объявленные при вызове срр.

Несколько неожиданный ход - использовать препроцессор языка C++, которым обычно


обрабатываются файлы SL, для работы с файлами RIB. В этом вся соль расширяемости Renderman
- поскольку и те, и другие файлы являются текстовыми, для их обработки годятся одни и те же
утилиты.

LOD
Еще один трюк из арсенала «читинга» в Renderman - это Level of Details, или сокращенно
LOD. Смысл данной настройки состоит в том, что в RIB файле можно указывать не одну
геометрическую модель, а несколько, и при этом указать, начиная с какого расстояния до камеры
использовать ту или иную модель в данном месте сцены. Представьте себе битву с участием
сотен сражающихся. Без LOD все, что вы могли бы сделать - это использовать одну и ту же
высококачественную модель как для бойцов первого плана, так и для статистов на заднем плане и
что совсем печально - для огромной массы бойцов на горизонте, каждый из которых отрендерится
максимум в десяток пикселей. Применяя LOD, вы можете автоматически подставлять для переднего
плана - максимально детальную и проработанную модель; для среднего плана - что-то немного
упрощенное; для массовки на заднем плане - палку-палку-огуречик или вообще один полигон с
наложенной текстурой - и тем самым сильно уменьшить запросы по памяти и времени расчета. А
разницу никто не заметит.

Особенно привлекательным представляется использование LOD в случае большого


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

Кое-что про Renderman 1409


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

Архивы и Замороженные Архивы.


В примере для продвинутых мы показали, что для обработки файлов RIB можно использовать
такую утилиту, как препроцессор языка программирования C++, через который и так проходят все
шейдеры перед компиляцией. Одной из возможностей препроцессора являются так называемые
вложенные файлы (includes) - мы уже пробовали их при рассмотрении шейдеров. Аналогично
вставке кода из файлов *.Н в файлы *.SL при помощи препроцессора, мы можем вставлять RIB-
файлы друг в друга.

Вполне логично предположить, что в стандарте RIB существует аналогичная


функциональность. Так оно и есть - вы можете вставить один RIB в другой (как кусок текста) при
помощи команды ReadArchive, например, вот так:

ReadArchive "templates/teapot.inc"

А в файле teapot.inc, находящемся в директории templates, будет находиться необходимая


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

В MAYA нечто подобное под названием instancing появилось лишь в версии 6.5; в Renderman
эта опция существует уже более 20ти лет.

Но стандарт Renderman не остановился на достигнутом и ввел дополнительную возможность,


под названием DelayedReadArchive.

Procedural "DelayedReadArchive" [ "small.rib" ] [-1 1-11-1 1]

Работает этот вызов в точности как и предыдущий, с одним важным отличием - в нем
указана область нахождения данного объекта в пространстве (в просторечии, bounding box). Так
вот, загрузка объекта в память рендерера произойдет только в том случае, если область объекта
пересечется с видимой областью камеры, и, следовательно, только тогда, когда расчеты сцены
дойдут до этой области.

В точности такой же подход исповедуют и процедурные генераторы RIB-кода, вызов которых


можно осуществлять таким образом:

Procedural "RunProgram" [ "teapot.pl" "some_teapot1_data" ]


[-1 1 - 1 1 - 1 1 ]

Код нашего скрипта на Перле вызовется только в том случае, если он попадет в поле
зрения камеры, и только тогда, когда это необходимо.

Для любознательных. Именно эту технологию применила студия Dreamworks при съемках
мультфильма Shark Tale. В силу производственной необходимости, вся геометрия для этого
мультфильма была подготавлена во внутреннем формате студии, не совместимом с prman (для
совсем продвинутых - это были специальные NURBS'ы). Поэтому был написан процедурный
конвертер из этого формата; вызовы этого конвертера были вставлены в обычные RIB'ы. Таким
образом, на диске геометрия хранилась в удобном для Dreamworks формате и преобразовывалась
в RIB только во время рендеринга - и только в том случае, если в этом была необходимость.

1410 Книга Сергея Цыпцына


Возможности стандарта Renderman в области процедурной генерации геометрии дадут
серьезную фору многим существующим рендерерам. А мы тем временем обратимся к экзотическим
возможностям prman.

Разговаривающие и адаптивные шейдеры


Одной из новых возможностей, реализованных в Renderman Pro Server раньше, чем это
появилось в стандарте, является возможность передавать сообщения между шейдерами (message
passing). В рамках этой функциональности один шейдер может запросить значение переменной,
определенной в другом шейдере, наложенном на эту же модель.

Классический пример использования message passing - получение surface-шейдером


информации из displacement-шейдера о величине отклонения и соответствующая закраска
поверхности - например, более выпуклые области модели закрашиваются более темным цветом.
Связывать таким образом можно любые шейдера, относящиеся к одному объекту - например,
поставив displacement в зависимость от освещенности. Сложная на первый взгляд, передача
сообщений между шейдерами предоставляет еще один метод тонкой настройки отображения
поверхностей, в том числе возможность реализовать адаптивные шейдеры - оптимизирующие
свою функциональность непосредственно во время просчета.

Для продвинутых. Простой пример адаптивного шейдера. В процессе расчета ambient oc­
clusion мы в каждом сэмпле выстреливаем некоторое количество лучиков в полусферу, причем
для того, чтобы в картинке не было грязи и чтобы при анимации она не дрожала, это некоторое
количество обычно является достаточно большим - как минимум, 256. Поскольку говорим мы о ray
tracing, любая оптимизация этого процесса будет к месту. Способ адаптации шейдера к свойствам
поверхности, на которой он вызван, состоит в том, чтобы смотреть на локальную кривизну
поверхности в данной точке (например, спрашивая об этом displacement shader, или просто
вычисляя ее по изменению текстурных координат и их производных) и если кривизна большая - то
в этой точке стрелять лучиков меньше (все равно за мелкими деталями грязи видно не будет), а
если небольшая - то побольше.

Еще один простой пример, чтобы немного взбударажить фонтазию нашего читателя.
Попробуйте поуправлять величиной спекуляра или размером дисплейсмента в зависимости
от расстояния до камеры. Или попробуйте наложить дисплейсмент только на края объекта,
ограничившись в остальной части более примитивным и скоростным бампом.

Для продвинутых-2. MTOR поддерживает мощный механизм для связи майских атрибутов
с шейдерами. Чтобы воспользоваться этим механизмом, достаточно добавить к любому майскому
объекту новый атрибут с именем, например, rmanFmyS. Приставка rmanF (таких приставок несколько
и они подробно описаны в документации) дает MTORy сигнал, что данный атрибут должен быть
обработан специальным образом и его значение должно быть подготовлено к экспорту. Все, что
остается сделать - это использовать полученное значение в шейдере, например, вот так:

surface test( varying float myS = 0; )


{
Ci = color(myS);
}

Ну вот, по внутренностям прошлись - а теперь настало время от оптимизации и ухищрений


на микроуровне перейти к чистой воды читингу на макроуровне, а также просто полезным советам.
Если предыдущие советы имели смысл по большей части только для Renderman-совместимых
рендереров, то теперь мы постараемся быть полезными и для других движков, в том числе для
mental ray и самой MAYA. Настало время для крупнокалиберной артиллерии и грязных трюков.

Только то, что видно (или «Стыдно - когда видно»)

Кое-что про Renderman 1411


Этот прием очевиден, но удивительно, насколько редко он применяется на практике. Не
нужно включать в просчет то, чего все равно никто не увидит!

Если какая-то часть сцены не попадает в камеру и не участвует в отражениях или в ambi­
ent occlusion - удаляйте ее, вручную или при помощи скриптов. Если вместо огромного города,
смоделированного до последнего гвоздика на подоконнике, вполне пройдет текстура или mat­
te-рисунок на заднике - удаляйте город. Считаете тени? Удаляйте все, что не видно из этого
источника света. Считаете отражения? Удаляйте все, что по другую сторону зеркала. В конечном
счете, рендерер это сделает и сам - но зачем заставлять его прокачивать гигабайты мусора, из
которого не получится ни одного полезного пикселя?

Особую пользу этот совет принесет вам в случае, если вы используете RAT. MTOR известен
своей втыкучестью в момент экспорта сцены («втыкучесть»-слово «нехорошее», «нелитературное»,
но зато очень хорошо иллюстрирующее суть процесса); небольшой скрипт на MEL, который
пробежится по сцене перед экспортом и выключит ту геометрию, какая в данный момент из камеры
не видна, ускорит генерацию RIB'OB ДЛЯ действительно сложных сцен на порядки.

По слоям
Рендеринг "по слоям" уже давно стал обязательным требованием работы в продакшн
хаусах. Обычно в отдельные файлы ("слои") выводятся все персонажи; отдельно от них считаются
спецэффекты (огонь, вода и прочие медные трубы); отдельно записываются environment. Затем
все эти отдельные слои сводятся воедино уже на этапе композинга; это снимает ограничения на
всевозможные настройки освещения и удаление-добавление персонажей в сцену, которые так
любят проделывать заказчики в самый последний момент.

Более того, в большинстве студий в отдельные слои выводятся не только персонажи, но


тени от них, карты нормалей для персонажей, Z-buffer - толковые двухмерщики всегда найдут,
где применить эту информацию, благо на время рендеринга сцены это влияет не сильно.

Более того, Renderman дает возможность выводить в отдельные изображения переменные,


определенные внутри шейдеров - как глобальные (например, нормаль поверхности, цвет
поверхности), так и локальные (например, диффузную составляющую освещенности конкретного
персонажа). Остановимся поподробнее на этом «финте ушами».

Откройте в MAYA сцену, которую мы использовали при тестировании RAT'a - ту самую,


с овечкой (файл step2.ma вполне подойдет). Убедитесь, что все в порядке и сцена нормально
рендерится - RenderMan=>Render.

Воспользуемся встроенными возможностями MTOR для того, чтобы показать, как вывести
в отдельный слой информацию о цвете модели, без учета ее освещенности. Для этого вызываем
окно настроек RenderMan=>RenderMan Globals..., в нем в табе Display переключаемся в локальный
таб второго уровня Secondary:

1412 Книга Сергея Цыпцына


Выбираем канал, который мы хотели бы вывести - нажимаем на кнопку New, после этого
настраиваем параметры, как указано на скриншоте:

Что мы с вами только что сделали? Мы указали, что хотим отрендерить в отдельный файл
значение Cs (выбранное из длинного списка доступных переменных в поле Mode), которое в языке
шейдеров соответствует цвету объекта до того, как мы в шейдере применили к нему какие-то
операции. Вызываем рендерер и видим на экране вот это:

Кое-что про Renderman 1413


Обычный результат нашего рендеринга. Куда же подевался запрашиваемый нами
дополнительный слой? Он находится в поддиректории rmanpix вашего проекта. Посмотрим внутрь
файла untitled.new_channel.0001.tif, появившегося в этой директории, при помощи утилиты sho из
поставки Renderman Pro Server:

sho untitled.new_channel.0001.tif

Тот, кто до сих пор шарахается от командной строки, может использовать подростковую
программу, типа ACDSee.

Как видно, перед нами почти готовая заливка для мультипликационного персонажа.
Для продвинутых. Чтобы получить еще и картунную обводку (cartoon outline), выведите в
виде отдельного слоя карту нормалей и преобразуйте ее в любимом композере при помощи фильтра
Sobel. Вы получите достаточно примитивный и не всегда удачный, но вполне качественный контур,
особенно если отрендерите картинку в двойном разрешении, а потом уменьшите ее обратно - это

1414 Книга Сергея Цыпцына


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

Как-нибудь на досуге поиграйте с другими переменными из списка Mode. Особый интерес


представляет переменная uniform float CPUtime, которая в виде картинки покажет вам,
на рендеринг каких части вашей модели тратится больше всего времени. А мы тем временем
собираемся узнать, как вывести в отдельный слой произвольную переменную из нашего шейдера.
Для простоты выберем не самый продуктивный, но зато самый интересный способ.

Итак, находим наш рукописный шейдер textured_noise.sl и переименовываем в aov.sl (AOV


означает Arbitrary Output Variable общепринятое название используемой нами в данном случае
методики):

surface textured_noise ( float freq=100; )


{
Ci = texture("texture.tx", s, t)*noise(freq*s,freq*t);
}

В код этого шейдера нужно внести некоторые дополнения, с тем, чтобы рендерер мог
увидеть внутренние переменные:

surface aov ( float freq=100;


output varying color tex = 0;
output varying float noi = 0;)
{
tex = texture("texture.tx", s, t);
noi = noise(freq*s,freq*t);

Ci = tex*noi;
}

Исправления, которые мы только что внесли, очевидны: мы создали две новые переменные,
которые специальным образом объявили в заголовке шейдера и этим переменным присвоили
значения внутри шейдера.
Дальше начинается самое интересное. Компилируем шейдер, копируем получившийся
файл aov.slo и используемую текстуру texture.tx в папку с майским проектом, прямо в корень
(файл с исходным кодом шейдера aov.sl можно не копировать). Возвращаемся в MAYA, и в окне
Slim делаем File=>lmport Appearance=> Import Appearance... (или нажимаем Ctrl-I). Выбираем наш
aov.slo и вуаля мы только что загрузили написаный руками шейдер в Slim. Импортированый таким
образом шейдер имеет массу ограничений - например, к его параметрам нельзя присоединять
другие темплейты, как мы это делали раньше - но тем не менее, удобство налицо.
Для продвинутых. Аналогичную операцию выполняет утилита командной строки toslim.
Дальнейшая процедура тривиальна - присоединяем шейдер к овечке и рендерим:

Кое-что про Renderman 1415


Во-о-он у нее на ушке наша надпись видна - видите? Но мы сейчас интересуемся совсем
не этим - мы хотим вывести с отдельные слои переменные tex и noi. В очередной раз открываем
RenderMan Globals, удаляем старый слой и добавляем два новых, как показано на скриншоте:

Поскольку мы собираемся использовать не глобальные, а локальные переменные нашего


шейдера, то в списке переменных их нет; соответствующие значения в поле Mode придется
скопировать из заголовка исходного кода шейдера - а именно,

varying color tex

varying float noi

Отправляем на рендеринг и получаем в папке rmanpix 2 новых файла - untitled.noise.0001.tif:

в который вывелось значение переменной noi нашего шейдера (а поскольку шейдер мы


применили только к голове овечки, то и видим мы его только на голове) - в этой переменной мы
сохранили величину нойза до того, как перемножили ее на текстуру - и файл untitled.texture.0001.
tif (в него мы выводили текстуру без нойза):

В этом месте с людьми обычно случается «кондратий Иванович» и начинается вакханалия

1416 книга Сергея Цыпцына


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

Полученные, таким образом, слои можно также использовать в качестве текстуры для
шейдера. Например, вы можете просчитать ambient occlusion для всей сцены один раз, а потом
подмешивать его в качестве текстуры в свой шейдер. Или все-таки делать это в композере - на
ваше усмотрение.

Для любопытных: Среди крупных студий до сих пор нет консенсуса в том, какие именно
слои и значения каких именно переменных нужны и важны для композа. Философия Weta Dig­
ital, например, в этом случае состоит в том, что рендерить нужно в максимально готовом к
композитингу виде, с тем, чтобы композеры не воссоздавали сцену заново из множества слоев,
повторяя фактически работу рендерера. Например, в ходе работы над фильмом " I , Robot" компании
Digital Domain и Weta Digital разделили между собой планы с участием роботов NS5; при этом
Weta считала отдельно только металические и пластмассовые части; DD считал diffuse, specular и
отражение в отдельные файлы, и в результате получая десятки слоев на каждого робота.

Для продвинутых. Рендеринг по слоям - всего лишь один из множества методов борьбы за
уменьшение времени получения конечного результата при рендеринге. Еще один, похожий на него,
прием из той же серии - это всевозможное кэширование значений и последующее использование
этих кэшей рендерером без долгого пересчета. Копайтесь в документации к вашему рендереру
- например, для Prman ключевыми словами будут cache и brick.

Мантра про raytracing


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

При чем здесь рейтрейсинг, спросит наш читатель?

Да при нем, при самом - при результате рендеринга.

Существуют множество способов имитировать raytracing и GI. Например, в случае


зеркального отражения - поставить камеру в необходимую точку, а затем результат рендеринга
наложить как текстурную карту на само зеркало. Или вместо Global Illumination - по-умному
расположить в сцене уйму источников света.

К сожалению, при всей возможной автоматизации этих триков они все равно требуют
больших человеческих затрат опытных сотрудников, а их время стоит - что? Правильно: дороже
машинного. Что еще хуже - очень часто эти трюки не срабатывают или срабатывают не так, как
хотелось бы. И тогда приходится прибегать к честному рейтрейсингу и его родственникам - ambi­
ent occlusion и GI.

Без рейтрейсинга в современном кино- и видео-бизнесе, как говорится - никуда. Трейсить


ambient occlusion придется все равно - это один из основных приемов быстрого достижения столь
желанной фотореалистичности. Но у этой медали есть обратная сторона - простое включение
рейтрейсинга в сцене увеличивает время просчета в разы, каким бы ультраоптимизированным
рендерером вы не пользовались, и prman в этом не исключение, а, скорее, яркий пример. Поэтому,
если вы делаете компьютерную графику в действительно больших количествах - для рекламы,
кино или телевидения, постарайтесь поменьше raytrace'ить (а также ambient occludе'ить, global
illuminate'ить и final gather'ить).

А если уж совсем припекло и стекло не получается стеклянным, а всего лишь тоскливо


стекловидным, воспользуйтесь предыдущим советом и сразу записывайте результаты в отдельные

Кое- что про Render man 1417


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

Для продвинутых. Строго говоря, prman до сих пор не является рейтрейсером, даже
несмотря на то, что подобную функциональность он реализует в полной мере. Основным
алгоритмом, который он использует при рендеринге, является REYES; этот алгоритм полировался
и оптимизировался в течение более чем десятка лет. Поддержка raytracing была добавлена в
Renderman Pro Server не так уж и давно, и, судя по описаниям и опубликованным статьям, в
ядро рендерера она не встроена. Таким образом, если вы не используете эту поддержку, все
еще запускается старый-добрый, ультабыстрый REYES-движок. Если вам страсть как хочется
потрейсить, к нему присоединяется новый: движки интенсивно обмениваются данными и даже
совместно используют некоторые структуры в памяти, но все равно, ядро prman'a до сих пор
остается старым, a raytracing - это всего-лишь добавление к нему, существенно замедляющее
процесс.

Собственное все
Рассказывая о работе студии Digital Domain над фильмом " I , Robot", мы вскользь упомянули
тот факт, что в различные слои рендерятся не только различные части робота, но и различные
части шейдера, в частности diffuse-проход. Как это делается? Рассмотрим на примере стандартного
шейдера plastic:
surface plastic( float Ks=.5, Kd=.5, Ka=1,
roughness=.1; color specularcolor=1 )
{
normal Nf;
vector V;

Nf = faceforward( normalize(N), I );
V = -normalize(l);

Oi = Os;
Ci = Os * ( Cs * (Ka*ambient() + Kd*diffuse(Nf)) +
specularcolor * Ks * specular(Nf,V,roughness) );
}

Как видно из заголовка шейдера, никакие переменные из него вывести в виде отдельного
слоя не получится; для этого придется заниматься модификацией кода. Чтобы получить diffuse в
виде отдельного слоя, шейдер нужно изменить, например, вот таким образом:

surface plastic( float Ks=.5, Kd=.5, Ka=1,


roughness=.1; color specularcolor=1;
output color diffuseC = 0; )
{
normal Nf;
vector V;

Nf = faceforward( normalize(N), I );

V = -normalize(l);

diffuseC = Kd*diffuse(Nf);

Oi = Os;
Ci = Os * ( Cs * (Ka*ambient() + diffuseC) +
specularcolor * Ks * specular(Nf,V,roughness) );
}

1418 Книга Сергея Цыпцына


Как видите, для решения даже простой задачи, которую поставили перед нами
требования реального продакшна, потребовалось пусть небольшое, но изменение стандартного
шейдера. Отсюда и последует наш совет.

Ничто не дает большего чуства контроля над ситуацией, как собственноручно сделанный,
отобранный и настроенный инструментарий. В особенности это касается шейдеров, и в еще
большей особенности - тех самых шейдеров, которые идут в стандартной поставке любого Render-
man-совместимого рендерера.

Эти шейдеры хороши, подробно описаны, по ним хорошо учиться - но потом наступает
момент, когда вы хотите чего-то нового, существующие возможности вас не устраивают: это
означает, что пора начинать писать свое.

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

Для любознательных - пример из жизни


Вы думаете, что все, выше написанное - трудно, тяжело и малоприменимо? Вот вам
реальный пример из реального проекта со слов человека, его делавшего, и пересказаный моими
собственными словами.
Итак, в наличии имеется сцена с внутренностями огромного здания. Изначальная
диспозиция такова: здание смоделировано полигонами в количестве сколько-то там миллионов
штук, при этом постоянно обновляется и достраивается. Генерация RIB'a занимает порядка десяти
минут. Здание буквально купается в ярком солнечном свете, а решетчатая облицовка, колонны и
перекрытия галерей отбрасывают четкие тени на пол и стены. Все остальное освещение в сцене
- отраженный и рассеянный свет от стен и предметов. Посреди холла установлена огромная,
отполированная статуя робота.

Налицо патовая ситуация: явное проявление болезни под названием "nht,etncz глобальное
освещение" с осложнениями в виде невозможно детализированной модели.

Первым делом в таких случаях в руки берется топор и из сцены к такой-то бабушке удаляется
все, что не будет видно камере в конкретном кадре. Имена всех удаленных объектов аккуратно
записываются в отдельный файлик; таким образом нам будет легче убирать их в следующий раз,
когда гигантскую модель здания в очередной раз обновят.

Далее сцена анализируется и разбивается на части. В качестве критерия разбивки


используется материал, из которого изготовлен предмет - пластик, бетон, стекло, металл, мрамор
и так далее. Каждая часть экспортируется в RIB, удаляется из сцены и заново подключается в
сцену с использованием RIBDOX'OB - которые вешаются на простые кубики и шарики. На этом
этапе к сцене вернулась возможность поворачиваться во вьюпорте без натужного скрипа жестким
диском.

На этом этапа начинается работа над освещением. Изначально планировалось использовать


новые возможности Renderman Pro Server - "запечь" отраженный свет в специальный кэш (irradi-
ance cache file), который бы затем использовался в шейдерах. Но оказалось, что для моделей такой
сложности работать с кэшем просто невозможно: его размер быстро превышает все разумные
рамки, и пропорционально падает скорость доступа к нему. Кроме того, любое изменение модели
потребовало бы по крайней мере частичного пересчета кэша. Изменения, которые потенциально
могли внести режиссер или супервайзор проекта, также потребовали бы длительной и трудоемкой
перенастройки параметров global illumination и опять таки пересчета кэша.

Пришлось хитрить. Один раз для сцены было просчитано решение ambient occlusion и
записано в виде отдельного слоя. Этот слой затем аккуратно подмешивался в источники света

Кое- что про Renderman 1419


- а было их в этой сцене не так уж и много, не больше десяти spotlight'oв с разными яркостями,
направлениями и цветом.

Кроме этих слотов, в сцену добавили один источник света с тенью, генерируемой при
помощи raytrace - к сожалению, без него не обошлось; использовались с десяток локальных
источников, которыми подмазывали, подкрашивали и подсвечивали.

Сначала рендерился основной проход - в нем все стекло выключили. В расчете ambient oc­
clusion его тоже не было видно для камеры - но occlusion-лучи, выстреливаемые из каждой точки
сцены, стекло видели и, таким образом, добавили необходимые детали в освещение этажей.

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

Абсолютно естественно, что все роботы и люди, которых вы видели в кадре - тоже считались
отдельно и приклеивались уже на композере.

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

Думайте о неожиданном
Экспериментируйте. Пробуйте. Применяйте новые интересные техники в необычных
ситуациях. Интернет битком набит информацией, новостями, туториалами. Почти каждый год
на сайте renderman.org выкладываются новые PDFы с материалами конференции Siggraph и
учебного курса по Renderman, проходящего на этой конференции. Эти документы - кладезь, это
неисчерпаемый поток знаний, умений и опыта, концентрированное знание множества очень умных
людей, которые оттачивают все эти приемы на каждодневной практике реального кино- и видео­
производства. Их можно читать наискосок, проходить по шагам, постоянно сверяясь с текстом,
пытаться шаблонно использовать в своей работе - а можно подойти творчески и начать пробовать
и задавать вопросы.

Что будет, если в шейдере в diffuse подмешать specular?

А если использовать diffuse в качестве specular?

Что будет, если на вход шейдера Blinn повесить выход шейдера Noise?

А что получится, если в одном шейдере использовать несколько различных спекуляров?

Можно ли использовать карту теней для ускорения просчета сцены? (Ответ: можно.)

Что получится, если выставить источнику света отрицательную величину яркости?

А если связать источник с текстурой, которая бы моделировала освещение из окна -


понадобится ли само окно?

А можно ли сделать такой свет, который был бы синим в тени, и белым в остальных
областях?

А чтобы он содержал только specular-составляющую? А чтобы он светил в одну сторону, а


тени отбрасывал - в другую? А чтобы он мог отбрасывать тени без объекта, сам?

Что вы скажете по поводу анимированных текстур, которые содержат в себе текстурные

1420 Книга Сергея Цыпцына


координаты другого объекта?

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

Можно ли написать шейдер, который покажет, в каком месте кривизна поверхности


максимальна?

Можно ли хранить в текстуре массив - и потом обращаться к нему по индексу?

Можно ли написать шейдер, который в случае ошибки отправит вам SMS?

Как известно, наука - это удовлетворение собственного любопытства за счет заказчика.


Так вот Chi-Ting - это наука. Удовлетворите свое любопытство. Получите удовольствие от своих
открытий. Поделитесь ними с окружающими.

Кинопроектор показывает 24 кадра в секунду; телеэкран - 25. Объем информации,


сваливающийся на зрителя, настолько велик, что если вы его немного обманете, но он не заметит
подвоха и поверит в реальность происходящего - то вы победили.

Мы строили, строили...

Вот и подошло к концу наше путешествие в мир рендеринга. Для того, чтобы дать вам
необходимые для дальнейшего самостоятельного продвижения опорные точки, приведу небольшой
список литературы. Список будет совсем небольшим, ведь у нас тут не библиография. Да и после
появления Google с Амазоном любой может изготовить такой или подобный список за считанные
минуты. Более того, мы, в отличие от остальной книги, приведем наш список здесь, в конце
главы. Раз уж получилось, что мы так себе, потихоньку, прошмыгнули внутрь книжки про MAYA, не
будем требовать себе места еще и в общем списке литературы.

Итак:

• Первым пунктом у нас будет - эта книжка.

Странное пожелание, не правда ли? И тем не менее - дочитайте ее до конца, не бросайте на


середине. Поверьте мне: я видел неотредактированные исходные тексты некоторых ее глав - и
уже они были великолепны. Вы, скорее всего, из оставшихся глав книги больше ничего не узнаете
про внешние рендереры - ну и что?

• Advanced RenderMan: "Creating CGI for Motion Pictures"

Основа основ Renderman. Начиная с азов, достигает нереальных глубин познания. Заставляет мозги
работать в ранее неизведанных направлениях - лично я по прочтении этой книжки заинтересовался
и занялся нефотореалистичным рендерингом. Интересно, в какую сторону повернутся мозги у
вас?

• Renderman Companion

Пока не появился Advanced RenderMan, эта книжка была основой основ. Капитально устарела,
к сожалению. Я долго думал, стоит ли включать эту книгу, настолько она устарела и настолько
она пугающе нацелена в первую очередь на программистов - но тем не менее, вот она, в нашем
списке.

• Texturing and Modeling: A Procedural Approach

И опять основа основ, на этот раз для тех, кто всерьез заинтересовался процедурными текстурами,
историей и современностью этого вопроса. Берите исключительно третье издание, в нем куча
нового материала и все картинки - цветные.

Кое- что про Renderman 1421


Ничего, что все эти книжки - на английском? Ну, тогда продолжим. Вот несколько книжек
для начинающих, но к сожалению, тоже не на русском:

• Essential RenderMan fast


• Rendering for Beginners: Image synthesis using RenderMan

Я не читал ни одну из них, поскольку к моменту их выхода начинающим уже не был, но


хорошо знаком с автором первой и слышал много хорошего об авторе второй, и посему - мои
рекомендации.

Далее - небольшой прыжок в сторону, для тех, кто хочет узнать, как вообще делаются
рендереры:

• Production Rendering, Design and Implementation

Сборник эссе о том, как делаются рендереры вообще и Renderman-совместимые - в


частности. В создании сборника участвовали авторы таких рендереров, как Mantra, RenderDotC,
Air, Aqsis, LightFlow и ART VPS. Отличная книжка; жаль только, что очень уж дорогая.

• Physically Based Rendering: From Theory to Implementation

Учебник для тех, кто хочет написать свой собственный рендерер. В процессе изучения
этого фолианта читатель имеет возможность проследить процедуру создания своего рендерера,
оснащенного под самую завязку самыми современными технологиями, с подробным описанием
используемых алгоритмов - и с полным исходным кодом рендерера, напечатанным прямо в книге
(с использованием Literate Programming). 1000 страниц и почти 2.5 килограмма чистого счастья
для тех, кто понимает.

И под конец нашего списка


• Криптономикон

А это просто книжка, которую я читаю сейчас, в момент написания этого списка литературы.
Она не имеет никакого отношения к предмету разговора; просто она мне понравилась, может,
кому-то из вас тоже понравится. Не перепутайте случайно с Некрономиконом - это совсем разные
вещи.

И это еще, на самом-то деле, не конец. В наш век информационных технологий обойтись
одними книжками в своих исследованиях вам будет, скажем так, трудно. С другой стороны, в наш
век поглощений, закрытий и беспрестанных обновлений страниц, сайтов и компаний, приводить
огромные списки URL тоже, вроде как, неразумно. Так что, обойдемся - сколько там у нас было
книжек, девять? - девятью ссылками:

• renderman.ru

Отбросив ложную скромность, приведем сайт, который я создал и поддерживаю (при неоценимой
помощи и поддержке множества людей). Все о Renderman на русском языке, но в первую очередь
- сообщество, и лишь затем - учебник и помощник.

• renderman.org

Корень всего. Полуофициальный сайт, на котором есть все о Renderman. Бонус-трек: www.render-
man.org/RMR/OtherLinks/blackSIGGRAPH.html - история о закрытии Exluna.

• renderman.pixar.com

Официальный сайт RAT и Prman. Там же - официальный форум поддержки.

1422 Книга Сергея Цыпцына


• C.g.r.r.

Старая добрая конференция сотр.graphics, rendering, renderman в Usenet. В последнее время


не самое активное в плане обсуждения место, но в подавляющем большинстве случаев -
ультраполезный источник информации.

• www.dotcsw.com/links.html

А вот если вы хотите найти список ВСЕХ Renderman-совместимых рендереров, когда-либо


существовавших в природе - вам сюда. Воистину, поучительное чтиво.

• rendermanacademy.com

Академия Renderman. Сайт взял на себя трудную, но почетную обязанность: учить народ
Renderman'y, с чем, в меру сил и умения, справляется.

• film.nvidia.com

Родина Gelato. Официоз и PR, в основном.

• jot.cs.princeton.edu

Домашняя страница рендерера Jot. Что еще сказать? Страница как страница, бывают и
лучше, конечно.
• Google.com

Этот адрес я мог и не писать, конечно. Найдется все, понимаешь. Бонус-ссылка: scholar.google.
com - специализированный поиск по научным работам, диссертациям и исследованиям.

А здесь хочу поблагодарить тех, чья помошь в работе над этой главой невозможно оценить.
Это Александр Сегаль, Сергей Невшупов, Константин Харитонов - без их комментариев, поправок
и советов эта глава не состоялась бы.

Отдельная благодарность Юрию Мешалкину, Егору Чащину, Александру Халявину и


Вячеславу Богданову - за предоставленные скрипты и плагины и за разрешение их опубликовать.
Вы можете найти всех этих людей на сайте нашего community - Renderman.ru.

До встречи - и успехов!
К вопросу о благодарностях.
Здесь я хотел бы поблагодарить всех, кто явно или неявно помогал мне при написании этой
книги. Совершенно очевидно, что осилить данный труд в одиночку мне не удалось бы никогда.
Кроме того, было бы невозможно написать такую книгу, продолжая работать на постоянной
основе на каком-нибудь проекте или в студии. Поэтому прежде всего я благодарен издательству
Арт Хаус Медиа в лице Александра Шишкина и Ивана Пахомова, предоставивших мне возможность
в течение года работать профессиональным писателем, то есть писать книгу и больше ничего не
делать. Спасибо также Михаилу Шатилову за административную поддержку этого проекта.

Самую большую и «жирную» благодарность я хочу выразить Алексею Пузикову, не только


написавшему целую главу, но и принявшему активнейшее участие в редактировании почти всех
глав книги. Леша оказывал мне огромную помощь на протяжении всей работы. Также я хочу
поблагодарить Володю Забелина, въедливо и бескомпромиссно отредактировавшего некоторое
количество глав книги. Как хороший писатель, Володя является превосходным техническим
редактором, не упускающим из виду ни одну мелочь.

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

Хочу поблагодарить Сашу Костина, взявшего на себя огромный труд по подготовке макета
книги.

Далее хотелось бы «пройтись» по тем личностям, которые помогли мне непосредственно с


содержанием книги. Зачастую моей эрудиции не хватало на все аспекты MAYA, поэтому приходилось
активно привлекать признанных авторитетов в той или иной области. Среди них повелитель частиц
Алексей Гусев, мастер флюидов Дмитрий Бойченко. Мастера полигонального дзен помогли
мне систематизировать и упорядочить хаотические и многочисленные средства полигонального
моделирования. Среди этих мастеров: Владимир «Piastro» Панкратов, Саша «Black» Коршунов,
Стае «Stass3D» Глазов, Ниле «Dr.Snake» Блумберг, Ян Зубарев, Сергей Луценко и Миша Бажуткин.
Отдельную благодарность хочу выразить Мише Бажуткину, не только написавшему некоторое
количество уникального материала для книги, но и просветившего меня по многим вопросам.

Очень полезным для написания книги оказалось непосредственное общение или переписка
со многими коллегами по цеху. Явно или неявно, общение с коллегами всегда повышает уровень
эрудиции, поэтому я благодарю Константина Харитонова, Аркадия Дубинина, Сашу Халявина,
Игоря Парщикова, Игоря Леводянского, Анатолия Капчинского, Ивана Тиунова, Армана Яхина,
Михаила Лесина, Игоря Даурова, Дмитрия Чурика, Олега Соловьева, Руслана Огородника и многих
других, кого я наверняка забыл упомянуть.

Спасибо Паше Ледину за просвещение меня во всем, что касается mental ray.

Хочу также поблагодарить Дмитрия Озерца, благодаря которому я попал в мир компьютерной
графики и прочно в нем обосновался. Спасибо также Дмитрию Лаврову за просветительскую
работу и консультации в старые добрые времена Alias Power Animator.

Отдельная благодарность Егору Чащину, за пытливость ума и ширину кругозора.

Спасибо Евгению Ростову за постоянную поддержку и помощь. Также большое спасибо


Paolo Berto и Tom Kluyskens.

Я хочу отчаянно поблагодарить Мишу Лапицкого, не только за модели предоставленные


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

Спасибо Антону Петрову за советы, беседы и частые визиты в Египет. Спасибо Ивану

1424 Книга Сергея Цыпцына


Дзарасову за мудрость.

Я благодарю Владимира Панкратова за безоговорочную, безусловную и бескорыстную


поддержку меня во всех моих начинаниях, включая эту книгу. Спасибо, брат.

Отдельное спасибо Саше и Сереге Сабатовским за веселый нрав, хорошую компанию и за


Шерегеш.

Совершенно особая благодарность Сергею Чупрову, директору виндсерфинг-школы


«Северный ветер» в Хургаде. Большая часть книги была написана на берегу Красного моря.
Благодаря Сергею, я открыл для себя виндсерфинг, как образ жизни, и Египет, как место для
жизни. Также спасибо всем друзьям-серферам, поддерживавшим меня в перерывах между
каталкой.

Спасибо Рустэму Хайретдинову за то, что он есть.

Спасибо всем моим друзьям, поддерживавшим меня всегда: Олегу Булгаку, Стеле Аргату,
Юрию Алябову. Спасибо Людмиле Константиновне Ярославцевой за духовные беседы, дружбу и
веру.

Я также благодарю Сашу Алифанова за Всё.

Мой сын родился, когда я писал введение к книге. Я подозреваю, что получил возможность
написать книгу из-за того, что он собрался прийти в этот мир. Спасибо моей жене Кате за
бесконечную веру в меня и поддержку, поддержку, поддержку.

Я также хочу выразить благодарность всем моим ученикам. В конце прошлого века, в
1999 году, я вернулся из отпуска, где безуспешно охотился за волнами на атлантическом
побережье Испании, и получил предложение от Жени Ландышева прочитать курс по MAYA для
восьми студентов из разных концов страны. Помню, что я сам был увлечен MAYA настолько, что
прочел курс на одном дыхании, без всякой подготовки, импровизируя и полагаясь на интуицию.
Парадоксально, но именно эти пять дней спонтанных лекций легли в основу будущего базового
курса по MAYA и составили его большую часть. Этот курс также в основном вошел в эту книгу,
неявно растворившись на ее страницах. После этого Женя предложил мне организовать школу
по обучению MAYA, а я, недолго думая, предложил модный тогда термин Realtime, после чего
родилась школа Реального времени. Я хочу отдельно поблагодарить Женю за это предложение,
ведь это круто изменило мою жизнь.

Я помню, что вначале я практически удваивал объем своих знаний после каждого курса,
ведь нет лучше способа изучить предмет, чем рассказать о нем кому-нибудь. Тем более, что MAYA
тогда была еще так загадочна и мало изучена, что каждый день работы в ней был источником
новых открытий. Тогда же я понял, что рассказывать про MAYA можно бесконечно, поэтому вскоре
родились новые курсы. И не только по MAYA.

Я приобрел огромный опыт преподавания, я изучил MAYA вдоль и поперек, я преподавал


ночами, студенты стонали от бессонницы, но кричали: «Еще!». Мы ходили со студентами в кино,
ездили в выходные на рыбалку, жарили по ночам шашлыки в саду дома ветеранов кино, разбирали
MAYA на части. Но самый ценный дар, который я приобрел на семь лет преподавания - мои ученики,
многие из которых стали в последствии моими хорошими друзьями. Некоторые теперь преподают в
Школе, некоторые руководят студиями, многие работают за рубежом. Здесь я хочу поблагодарить
именно их, всех моих учеников (и особенно первый состав студии «Классика»). Благодаря вам,
вашему азарту, жажде знаний, пытливости ума я читал курсы с неослабевающим интересом и
увлеченностью. Благодаря вам, в моей голове накопился материал, расположившийся, в конце
концов, на страницах этой книги.

Спасибо всем.

Цыпцын Сергей

Благодарности 1425
Просто учим сложной графике

Мы погружаем студентов в учебу. Занятия начинаются в 10 утра и заканчиваются не раньше 10 вечера.


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

Цыпцын Сергей. Понимая MAYA

Главный редактор: Михаил Шатилов


Литературный редактор: Владимир Болотников
Координатор: Иван Пахомов
Верстка и дизайн: Александр Костин (KostinPublishing)
Корректор: Вера Позднякова

Подписано в печать 05.04.2007


Формат издания 60x90/8
Уч. печ. л. 50. Тираж 3000. Заказ № 70632
Первый завод 1 - 1500
Печать: ООО "Август Борг" 121009, Россия,
Москва, Шубинский пер., д. 2/3

Информационная поддержка: www.cgtalk.ru

Отдельное спасибо: Real Time scool

Издательство: ООО "Арт Хаус медиа", Россия, 115035, г. Москва, а/я 42


Заказ книги: director@protodesign.ru

Все права защищены.


© Цыпцын Сергей, 2006
® 2007 Издательство ООО "Арт Хаус медиа".

Внимание! Книга защищена законом об авторских правах.


Ни одна часть или изображение из этой книги не может быть опубликовано, перепечатано,
отправлено электронным способом или другим любым способом без специального письменного
разрешения издательства! Все эксклюзивные права на ее содержание принадлежат издательству.
О любых нарушениях и незаконных копированиях просьба сообщать в издательство по адресу:
Россия, 115035, г. Москва, а/я 42; email: director@protodesign.ru.

Вам также может понравиться