Multi Constraint

Сразу оговорюсь, что данный материал не претендует на то, чтобы описанные в нем методы использовались в производстве, т.е. он не является "истиной в последней инстанции". Это не урок в традиционном варианте, а скорее статья-исследование. Её цель продемонстрировать на примерах особенности устройства и работы Maya,
обсудить некоторые вещи, и дать пищу для ума. Я старался писать материал в таком стиле, чтобы её смог прочитать человек, ещё не имеющий большого опыта в сетапе. Для этого в тексте будут вставки, подробно объясняющие все действия в программе, и дополнительные советы, в желтых блоках. Помимо словесного описания, каждый шаг, будет также продублирован на MEL. И, наконец, будут ссылки на файлы (в формате MA), демонстрирующие каждый этап работы.

Теперь перехожу собственно к теме. Каждый год Maya улучшают, но до сих пор, в ней нет некоторых вещей, которые еще больше облегчили бы жизнь аниматора. Например, при работе с объектами, где нужно часто менять точку вращения или несколько раз за сцену менять их "родителя". Казалось бы, проблема лежит на поверхности, но разработчики по-прежнему обходят её стороной. За это время в Maya доработали сами констрейнты, например, появилась долгожданная система микширования анимации с работой констрейнта (нода pairBlend), анимационные слои, но нужного констрента так и не появилось. Страшно представить, но ведь в первых версиях Maya не было даже parent-констрейнта! Но что из себя представляет этот “Multi Constraint”?

Возьмем для примера объект, имеющий несколько точек вращения, например, трость. В свободном полёте она вращается относительно своего центра массы, но в руке персонажа трость уже будет вращается относительно точки, в которой он её держит. Есть также точка соприкосновения с землёй, при ударе, или когда персонаж опирается ей о землю. Если на протяжении одной сцены трость будет несколько раз менять свои точки вращения, то аниматору придется что-то предпринять для того, чтобы сделать все необходимые переходы из одного состояния в другое.
Вариантов может быть несколько: это может быть набор локаторов, к которым будет приконстренена палка, или несколько вложенных в друг друга трансформ-групп, с разными pivot, или специальный инструмент, типа ZV Parent Master с удобным функционалом для подобных операций. Но все равно, каждый раз определяя новую точку вращения, аниматор должен будет устанавливать её вручную.

В идеале нужна такая система, чтобы аниматор мог в любой момент переключить ведущий контрол и, соответственно, новую точку вращения объекта, без необходимости вручную двигать контролы для их синхронизации. В этой системе, в один момент времени, только один контрол будет ведущим (назовем его driver-контрол), а остальные будут ведомыми, т.е. будут пассивно следовать за ведущим, сохраняя свои начальные позицию и ориентацию относительно ведущего контрола. И конечно же, у этой системы должен быть атрибут для переключения ведущего контрола. Такую систему и можно будет назвать мульти-констрейнтом.
Теперь перейдем к реализации задуманного. И прежде чем пускаться "во все тяжкие", я имею в виду написание нового плагина, нужно сначала подумать над возможностью решить эту задачу средствами Maya, не прибегая к программированию. Сразу скажу, что существуют несколько решений этого вопроса. И все они будут описаны в этой статье. Начнем с первого, показательного, но не самого оптимального.

Рассмотрим простой пример с двумя контролами. Создадим их в виде локаторов (меню Create > Locator) и сразу сделаем второй локатор синего цвета (Display >Wireframe Color...). В дальнейшем это нам поможет лучше их различать.

// создаем локаторы и меняем их позицию:
spaceLocator;
move -rpr -2 2 2;
spaceLocator;
move -rpr 2 2 -2;

// меняем цвет второго локатора на синий:
setAttr "locatorShape2.useObjectColor" 1;
setAttr "locatorShape2.objectColor" 5;

Но при попытке их связать двумя parent-констрейнтами в обе стороны, мы сталкиваемся с классической проблемой цикла в графе зависимости (Dependency Graph, или сокращенно, DG), о чем нам Maya незамедлительно сообщает соответствующим предупреждением в Script Editor, так как в ней заложен механизм обнаружения подобных случаев.

// создаем два parent-констрейнта с сохранением позиций, относительно друг друга:
parentConstraint -mo "locator2" "locator1";
parentConstraint -mo "locator1" "locator2";

Откроем Hypergraph (меню Window > Hypergraph: Connections или переключим Panel Layout как на скриншоте) и отобразим все связи между локаторами (кнопка или меню окна Graph > Input and Output Connections).

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

У всех констрейнтов в Maya имеются атрибуты веса влияющих объектов, но отключение веса (установкой его значения в ноль), увы, не отключает работу констрейнта, а только меняет режим и математику его работы. Но у каждой ноды в Maya имеется особенный атрибут nodeState, который в режиме “Blocking” может полностью отключить работу ноды, и таким образом, сможет прервать цикл "порочной" зависимости. Значит наш атрибут, переключающий ведущий контрол, должен управлять атрибутами nodeState всех констрейнтов, и в один момент времени, у одного из локаторов констрейнт будет включен, а у другого выключен, и наоборот. Отменим последние действия по созданию констрейнов, и проделаем эти операции снова, но уже со знанием дела. Сначала сделаем parent-констрейнт для первого локатора и переключим его атрибут nodeState в значение “Blocking”, а затем уже сделам parent-констрейнт для второго локатора. Убедимся в том, что система работает без цикла и в одном направлении, т.е. при движении зеленого локатора, второй (синий) локатор должен следовать за ним. Тут следует отметить, что этот атрибут (nodeState) имеет тип enum, т.е. когда мы переключаем его значение, на самом деле, мы меняем целочисленное значение и в данном случае “Normal” — это 0, так как нумерация идет с нуля, а “Blocking” — это 2.

// создаем parent-констрейнт для первого контрола:
parentConstraint -mo "locator2" "locator1";

// отключаем констрейнт первого локатора:
setAttr "locator1_parentConstraint1.nodeState" 2;

// создаем parent-констрейнт для второго контрола:
parentConstraint -mo "locator1" "locator2";
Maya, как правило, практически все действия пользователя отображает в Script Editor в виде MEL-команд. Именно там можно увидеть всю “истину” происходящего и прочитать об ошибках, если что-то пошло не так.

Создадим еще один локатор с именем switcher, и добавим ему атрибут с названием driver, типа enum, не меняя его значения в списке по умолчанию: “Green и “Blue. Кстати, этот локатор также стоит перекрасить в другой цвет, например, желтый.

// создаем локатор для выбора ведущего контрола и меняем его цвет на желтый:
spaceLocator -n "switcher";
move -rpr 4 0 0;
setAttr "switcherShape.useObjectColor" 1;
setAttr "switcherShape.objectColor" 1;

// добавляем атрибут “driver”:
addAttr -k 1 -ln "driver" -at "enum" -en "Green:Blue:" "switcher";
Используя цвет для идентификации контролов, мы тем самым упрощаем себе задачу универсальности сетапа. Таким образом, где бы мы эти локаторы потом не использовали, не нужно будет думать о том, как их лучше переименовать по смыслу, в зависимости от базового расположения, относительно объекта, или задачи. К тому же, такие контролы можно будет легко различить во вьюпорте.

Для данного случая, вместо того, чтобы сделать зависимость атрибута driver с атрибутами nodeState используя технику Driven Key, я предлагаю использовать ноду condition, работу которой можно отобразить в виде следующего кода:

if (firstTerm operation secondTerm)
then
outColor = colorIfTrue
else
outColor = colorIfFalse

Т.е. она сравнивает два входящих атрибута, используя то условие, что задано в атрибуте operation, и если оно выполняется, то нода возвращает значение заданное в атрибуте colorIfTrue, в противном случае, берётся значение из атрибута colorIfFalse.

Пусть вас не смущает то, что её атрибуты имеют названия, явно указывающие на свою принадлежность к цвету. Действительно, с первой версии Maya, большинство нод, выполняющие математические операции, входящие в раздел рендера Utilities, были по задумке разработчиков предназначены в первую очередь для создания сложных шейдеров. Но этим их применение совсем не ограничено. Вы можете смело их использовать для других операций тоже. Так как у атрибута цвета color имеются три компоненты (RGB), то они отлично подходят для работы с другими трехкомпонентными атрибутами, типа translate (XYZ).

Создать её можно с помощью команды createNode с указанием типа создаваемой ноды:

createNode condition;
Очень удобно эти ноды создавать через меню: Window > Create Node, далее выбираем в разделе Utilities ноду Condition. Но сразу замечу, что создавая ноду этим способом,Maya автоматически связывает её атрибут message со служебной нодой defaultRenderUtilityList1, для того, чтобы она была в списке используемых рендер-нод в закладе Utilities окна Hypershade. Хотя эту связь после создания ноды можно разорвать и, в общем-то, она ни на что не влияет, для "чистоты", все-таки будет лучше создавать эти ноды командой createNode, если они не используются в шейдинге.

Перетянем средней кнопкой мыши в окне Hypergraph ноду switcher на ноду condition1, зажимая клавишу Shift (автоматически должно открыться окно Connetion Editor с атрибутами этих нод), и свяжем driver-атрибут с атрибутом firstTerm ноды condition1.

// соединяем управляющий атрибут с входным атрибутом ноды condition:
connectAttr "switcher.driver" "condition1.firstTerm";

Атрибут secondTerm оставим со значением 0, это будет соответствовать состоянию системы, когда driver имеет значение “Green”. Атрибут operation также менять не будем, по умолчанию он установлен в нужную для нас операцию сравнения значений — “Equal”.
Откроем Attribute Editor и установим выходные значения ноды condition1. Когда зеленый локатор активен, его констрейнт не должен работать. Значит в colorIfTrueR мы должены установить значение 2 (“Blocking”), а в атрибут colorIfFalseR — значение 0 (“Normal”). Несмотря на то, что эти атрибуты трехкомпонентные (RGB), мы будем использовать только первую компоненту R, остальные просто не будут задействованы.

// меняем выходные значение ноды condition:
setAttr "condition1.colorIfTrueR" 2;
setAttr "condition1.colorIfFalseR" 0;

Теперь загрузим в Connection Editor ноду констрейнта зеленого локатора (locator1) и соединим атрибут condition1.outColoR с атрибутом locator1_parentConstraint1.nodeState.

// соединяем выходной атрибут ноды condition c атрибутом nodeState констрейнта:
connectAttr "condition1.outColorR" "locator1_parentConstraint1.nodeState";

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

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

Далее мы проделаем всё тоже самое со вторым констрейнтом, но, чтобы сэкономить время, воспользуемся меню Edit > Duplicate Special в режиме Duplicate input connections. Продублировав таким образом ноду condition1, нам не придется снова соединять её входной атрибут с атрибутом switcher.driver.

// дублируем ноду condition1, сохраняя входящие связи:
duplicate -rr -ic "condition1";

Но, прежде чем мы свяжем выходной атрибут продублированной ноды condition2.outColorR с locator2_parentConstraint1.nodeState, сначала поменяем значение её атрибута secondTerm в значение 1 (что соответствует значению “Blue” атрибута driver). Т.е. эта нода будет выполнять те же функции, но уже для констрейнта второго локатора и при тех же самых значениях в остальных атрибутах. В этом собственно и заключается удобство использования этой ноды для управления однотипными данными от одного переключателя.

// меняем значение атрибута новой ноды condition:
setAttr "condition2.secondTerm" 1;

// и связываем со констрейнтом второго контрола:
connectAttr "condition2.outColorR" "locator2_parentConstraint1.nodeState";

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

// создаем куб с длиной граней, равной четырем единицам:
polyCube -w 4 -h 4 -d 4 -sx 1 -sy 1 -sz 1 -ax 0 1 0 -cuv 4 -ch 1;

// констрейнтим его к первому локатору
parentConstraint -mo "locator1" "pCube1";

// констрейнтим переключающий локатор к первому локатору;
parentConstraint -mo "locator1" "switcher";

Я специально сделал куб с длиной граней в четыре единицы, чтобы позиции локаторов совпали с его вершинами.
Да, чуть не забыл, осталось сделать последнюю мелочь. Уберём из Channel Box все ненужные для анимации атрибуты локаторов: масштабирования и видимости. Для этого выделим атрибуты обоих локаторы в Channel Box и воспользуемся его меню Edit > Hide and Lock (кроме всего прочего, мы еще и блокируем эти атрибуты от случайного изменения). А на переключающем локаторе switcher скроем все атрибуты, за исключением атрибута driver.

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

setAttr -lock true -keyable false -channelBox false "locator2.sx";
setAttr -lock true -keyable false -channelBox false "locator1.sx";
setAttr -lock true -keyable false -channelBox false "locator2.sy";
setAttr -lock true -keyable false -channelBox false "locator1.sy";
setAttr -lock true -keyable false -channelBox false "locator2.sz";
setAttr -lock true -keyable false -channelBox false "locator1.sz";
setAttr -lock true -keyable false -channelBox false "locator2.v";
setAttr -lock true -keyable false -channelBox false "locator1.v";

setAttr -lock true -keyable false -channelBox false "switcher.tx";
setAttr -lock true -keyable false -channelBox false "switcher.ty";
setAttr -lock true -keyable false -channelBox false "switcher.tz";
setAttr -lock true -keyable false -channelBox false "switcher.rx";
setAttr -lock true -keyable false -channelBox false "switcher.ry";
setAttr -lock true -keyable false -channelBox false "switcher.rz";
setAttr -lock true -keyable false -channelBox false "switcher.sx";
setAttr -lock true -keyable false -channelBox false "switcher.sy";
setAttr -lock true -keyable false -channelBox false "switcher.sz";
setAttr -lock true -keyable false -channelBox false "switcher.v";
Всегда, в процессе сетапа, и по его окончанию, следите за тем, чтобы все ненужные (а иногда и нарушающую работу сетапа) атрибуты были скрыты в Channel Box. Хотя бы потому, что такие атрибуты отвлекают внимание аниматора и создают лишние графики в Graph Editor.

Теперь, когда мы закончили сетап, настало время проверить работу полученной системы в режиме “Green” и “Blue”.

Файл two_constrained_locators_1.ma.

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

// устанавливаем ключи на все локаторы системы:
setKeyframe -breakdown 0 -hierarchy none -controlPoints 0 -shape 0 {"locator1", "locator2", "switcher"};

Как и должно было произойти, Maya автоматически добавила на первый и второй локаторы атрибут blendParent1 со значением ноль. Также в графе зависимости появились две ноды типа pairBlend. Эта нода отвечает за микширование анимации и результата работы констрейнта.

Когда атрибут blendParent1 равен нулю, то локатор движется, используя данные анимационных кривых, т.е. ключей, а при единичном значении — констрейнта. Следовательно, теперь, аналогично атрибуту nodeState, нужно создать управление атрибутом blendParent1. Но так как атрибут blendParent1 соединен с атрибутом weight ноды pairBlend, то этот атрибут, по идее, можно удалить и управлять напрямую, зачем нам лишние посредники. Выделяем два локатора и их атрибуты blendParent1 в Channel Box и удаляем их с помощью его меню Edit > Delete Attributes.

// удаляем атрибуты "blendParent1" на двух локаторах:
deleteAttr -attribute "blendParent1" "locator1" "locator2";

Для управления атрибутами weight не будем создавать новые ноды condition, так как ещё остались незадействованные компоненты G и B, у тех нод condition1 и condition2, что были созданы ранее. Нам даже не придется изменять их значения, так как те, что уже стоят по умолчанию, точно подходят под наше условие. Для активного локатора значение атрибута weight как раз должно быть равно нулю, а в противоположном случае — единице.
Теперь свяжем атрибут condition1.outColorB с атрибутом pairBlend1.weight и атрибут condition2.outColorB с атрибутом pairBlend2.weight.

// соединяем выходные атрибуты нод condition с нодами pairBlend:
connectAttr "condition1.outColorG" "pairBlend1.weight";
connectAttr "condition2.outColorG" "pairBlend2.weight";

Чтобы упростить одновременную установку ключей на все контролы системы, создадим, так называемый, персонажный сет. Для этого выберем все локаторы и вызовем меню Character > Create Character Set.

// создаем персонажный сет:
character "locator1" "locator2" "switcher";
В Maya встроен механизм автоматического удаления всех нод в истории графа зависимости, связанных с удаляемой нодой. И если Character Set не был сделан, то нода pairBlend автоматически удаляется при удалении анимации с контрола. Ещё один способ защитить ноду от удаления — это команда: lockNode -lock 1
Но пользоваться ей нужно в крайнем случае, так как после удаления объектов, с которыми была связана заблокированная нода, она будет оставаться в сцене в виде “мусора”.
Более продвинутый и гибкий способ защитить свои ноды от удаления — это использование ассетов (контейнеров с включенным режимом “Black Box”).

Теперь попробуем сделать анимацию локаторов в полученной системе. Для того, чтобы в момент перехода с одной точки вращения на другую, т.е. смены driver-контрола, была полная синхронизация позиции и ориентации всех контролов, нужно установить ключи на все контролы в кадре, где происходит эта смена. Затем нужно переключить атрибут switcher.driver, и снова поставить ключ (последнее действие будет происходить автоматически, если в Maya включить режим Auto Key).

Файл two_constrained_locators_2.ma

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

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

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

Так сложно выглядит граф связей, всего лишь между 4-я элементами.

А так это выглядит в Hypergraph для 4-х локаторов и их констрейнтов.

Но как это не странно звучит, эту задачу нам поможет решить... “цикл”! Мы можем оставить принцип, когда один контрол соединен только с одним другим контролом, соединив все контролы по кругу. Но не получим ли мы опять цикл в графе зависимости? Нет, не получим, если в этой цепочке всегда будет один разрыв, в том месте, где мы будем отключать констрейнт у активного driver-контрола.

Граф связей последовательно связанных между собой 4-х элементов.

Та же схема в Hypergraph выглядит значительно проще, чем в прошлый раз.

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

Результат такого сетапа с тестовой анимацией можно посмотреть в файле three_constrained_locators_1.ma.

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

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

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

Атрибуты объекта, зависимые от
контрейнта и одновременно имеющие ключи,
не информируют о наличие ключей
в текущем кадре, и вообще, о наличие или
отсутствии анимации.


Атрибуты свободного от констрейнтов
анимируемого объекта отображают
информацию о наличии ключей на его
атрибутах и об их наличии в текущем кадре
(последнее, начиная с версии Maya 2015
Extension 1)

Тогда придется поискать другой способ передачи информации на объект, такой, чтобы атрибуты контролов не были связаны с управляющими ими объектами. Подобным образом в Maya работают с костями IK-солверы. Обычно солверы занимаются тем, что вращают кости, но только один солвер в Maya может также и перемещать их. Речь идет об IK Spline Solver. Его основная задача ориентировать цепочку костей вдоль кривой (NURBS-spline). Но он также может двигать базовую первую (root) кость вдоль кривой. В ikHandle этого солвера имеется атрибут rootOnCurve, который отвечает за функцию констрейнта к кривой. Получается, если построить анимационный контрол на основе ноды joint, то мы сможем его констрейнтить к кривой. Самую кривую с помощью функции parent привяжем к другому такому же контролу. А проблему с циклом будем решать тем же методом, что и в прошлый раз, только в этом случае нужно будет управлять только атрибутом ikBlend каждого ikHandle системы.

В качестве кривой подойдет самая простая кривая первого порядка, состоящая из двух точек. Создадим такую кривую вдоль оси X (так нужно, чтобы правильно заработал ещё один очень важный режим солвера), с координатами точек {0, 0, 0} и {1, 0, 0}.

// создаем кривую первого порядка и единичной длинны вдоль оси X:
curve -d 1 -p 0 0 0 -p 1 0 0 -k 0 -k 1;

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

// убираем выделение с кривой, иначе кости будут создаваться как “дети” по отношению к ней:
select -cl;

// создаем кость единичной длинны вдоль оси X:
joint -p 0 0 0;
joint -p 1 0 0;

Полученную кость и кривую свяжем, создав IK Handle, отключив в настройках инструмента опцию автоматического создания кривой “Auto create curve”.

// создаем IK Handle:
ikHandle -sol ikSplineSolver -ccv 0 -sj "joint1" -ee "joint2" -c "curve1";

Если теперь для проверки "припарентить" к кости проверочный кубик и покрутить кривую, то можно заметить, что кость поворачивается, но не улавливает twist-вращение кривой вдоль её оси.

811 0 850 9
4
2015-01-30
хорошая статья. прям порадовала.
2015-01-30
Тоже как-то занимался этим вопросом. Была изначальная идея это реализовать через отключение нод, чтобы избежать зацикливания, но как-то не доделал в итоге. Остановился на варианте с обновлением нод parentConstraint через scriptJob + expressions, все в рамках возможностей parentConstraint (без стандартных обновлений через матрицы трансформации). А довести этот метод удалось благодаря идеям Deniseich 0-1, за что ему отдельное спасибо.
2015-02-02

Отличная статья, дает пищу для размышления. Я в этом вопросе так глубоко не копал. Единственное, что на практике, есть пара неудобных моментов при анимации данным способом: Первое, аниматор должен обязательно, прямо вот 100%, не забывать ставить ключи на все контроллеры, включая "switch", а не только на тот контроллер за который анимирует в данный момент. Иначе персонаж возвращается к предыдущему положению контроллера, на который аниматор переключился. Т.е. просто слетает. В принципе это можно поправить, написав "scriptJob" на автоматическое прокеивание всех контроллеров, при смене положения атрибута "switch", чтобы исключить человеческий фактор. Второй момент возникает при внесении правок в уже сделанную анимацию, а они 100% будут. ; ) Если перейти на любой промежуточный ключевой кадр, для внесения правок, то анимация в этом кадре была сделана, например, контроллером "blue",  а атрибут "switch" в этом кадре стоит уже в положении "red", т.е. необходимо посмотреть в каком режиме был "switch" в предыдущем ключевом кадре, вернуться в текущий кадр, переключить "switch" , поправить позу, и вернуть "switch" к изначальному положению. Вроде бы звучит не так сложно, но на практике при правке даже 5-6 ключей, довольно гемморойно, учитывая еще то, что плюс к этому нужно не забывать ставить ключи на всё. Хотя в целом, даже несмотря на неудобство, способ работает и возможно он того стоит, потому что это первый настолько функциональный способ, реализованный без плагинов и скриптов, стандартными средствами майи, который я вижу.

2015-12-28

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

RENDER.RU