Радость от деформаций корректами

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

Темой нашего сегодняшнего урока будет использование корректирующих блендшейпов в сложных ситуациях, таких как плечи или бедра. Ввиду специфики данного урока, предполагаю более или менее знающих читателей, разбирающихся в таких понятиях как деформер или блендшейп.
Я рассматриваю только стандартные возможности Maya + дополнительные скрипты и не умаляю достоинств таких интересных инструментов для работы с деформациями как poseDeformer. В конце концов, не все имеют возможность использовать сторонние плагины в своих сценах (например, если над сценой работают много разных людей вне студии или сценку нужно будет передать кому-то неквалифицированному).

Как вы, надеюсь, знаете, основная проблема настройки корректирующих блендшейпов (коррект блендов) сводится к определению веса нужного бленда, то есть нужно четко знать когда он включается, а когда нет.
С локтем, скажем, все более или менее понятно – мы привязываем вес бленда к углу предплечья (локтя), а так как оно у нас вращается всего по одной оси, то и проблем с весом у нас нет – driven key решит все проблемы.

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

Давайте рассмотрим такого вот персонажа.

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

На данный момент мы имеем персонажа и набор поз со сгенерированными корректирующими вариантами.

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

Итак, наша система построена не на привязке к углам, а на анализе расстояния между позами и некой точкой – осью.
Каждая поза идентифицирует положение оси в пространстве и на основании расстояния до оси формирует весовой коэффициент.
Целиком система poseCorrector состоит из оси и набора поз, которые между собой смешиваются. Интепроляция в пределах системы нормализирована, то есть не позволяет вершинам принимать вес > 1 от всех поз (нет наложений блендов).

В сцене система выглядит так.

Общая группа poseCorrector позиционируется на бедренную кость и через orientConstraint (с maintain offset) управляется тазовой костью.
poseCorrector_axis_group через orientConstraint (без maintain offset) управляется костью ноги.
poseCorrector_axis – локатор, который находится в группе и слегка сдвинут в направлении ноги по оси X. Таким образом мы как бы формируем вектор ноги.
Локаторы poseCorrector_side_pose, poseCorrector_forward_pose, poseCorrector_back_pose, poseCorrector_diagonal_pose – собственно позы, которые делались дубликатом poseCorrector_axis в тех положениях ноги, где делались корректирующие бленды.
Каждая поза имеет атрибут radius, который будет управлять областью ее влияния.

Что у нас получилась за ерунда? На самом деле все очень просто. Проще, чем кажется.
Начинаю вращать ногой – poseCorrector_axis точно направлен по бедру и не меняет своего положения при вращении ноги вокруг своей оси.
То есть положение оси точно идентифицирует ногу в данном положении и нам не важно как именно она повернута по каналам rotate.

Теперь нужно получить расстояния от оси до всех поз для построения весовых коэффициентов.
Делается это через ноду distanceBetween: createNode distanceBetween;
Нам нужны расстояния до каждой позы, поэтому дистансБитвинов столько, сколько и поз (в нашем случае 4).
Коннекты такие: point1 – poseCorrector_axis.worldPosition (шейп у локатора смотрите), point2 – worldPosition от позы.

Помимо этого нам понадобятся ноды setRange для каждой позы (тоже 4) для превращения расстояния в весовой коэффициент: createNode setRange;
Соединяем расстояние от оси до позы (distanceBetween.distance) в setRange.valueX.
Также коннектим радиус позы (pose.radius) в setRange.oldMaxX.
Остальные значения такие: oldMinX = 0, minX = 1, maxX = 0.
Что мы получили? Теперь нода setRange для каждой позы возвращает число от 0 до 1 в зависимости от радиуса влияния позы и положения оси (преобразовали диапазон от 0 до radius в диапазон от 0 до 1). Что ж – неплохо.

Не поверите, почти все!!! :-)
Теперь в общем-то можно коннектить setRange.outValueX каждой позы в соответствующий канал корректирующего бленда и деформации будут достаточно контролируемы, но мы пойдем дальше.

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

Данная функция тоже выполняется достаточно просто: суммируем веса всех поз и делим вес нужной позы на эту сумму.
Скажем, у нас такие веса: 0.3, 0.5, 0.8. Если их сложить, то получится 1.6.
Нормализируем: 0.3 / 1.6 = 0.1875, 0.5 / 1.6 = 0.3125, 0.8 / 1.6 = 0.5.
Вот, новые веса, а точнее коэффициенты весов, нам и нужны.

Суммируем веса, к примеру, нодой blendWeighted: createNode blendWeighted;
Коннетим вес каждой позы в свободный инпут blendWeighted ноды:
connectAttr setRange.outValueX blendWeighted.i[0,1 и т.д.]; // Теперь у нас есть сумма весов всех поз.

А что делать, если нога в таком положении, где ни одна из поз не действует? Тогда у нас будет деление на 0. Чтобы этого избежать мы включим проверку на отсутствие включенных блендов.
Делаем через ноду condition: createNode condition;
Операцию у кондишна ставим «greater then» ( > ). Коннектим сумму весов (blendWeighted.output) в каналы firstTerm и colorIfTrueR.
Нода условия теперь возвращает сумму весов, если хотя бы одна из поз включена или 1 (1 – значение по умолчанию в атрибуте colorIfFalseR).

Далее, для каждой ноды необходимо теперь делением получить коэффициент:createNode multiplyDivide;
Операцию ставим «/» (деление). В input1X коннектим вес позы (setRange нода), а в input2X – сумму весов от кондишна (condition.outColorR).
Теперь нода multiplyDivide для каждой позы возвращает весовой коэффициент, но не сам вес. Для получения веса позы умножим этот коэффициент на начальный вес позы (setRange): createNode multDoubleLinear;
В input1 коннектим вес позы (нода setRange), в input2 – весовой коэффициент (multiplyDivide.outputX). Отлично!

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

Очень надеюсь, что вы разобрались с технологией и уже начали использовать корректирующие блендшейпы везде где только возможно :-)

623 0 850 7
12
2013-02-12
Великолепно!!!!! Лучший урок за всё время существования не только render.ru, но и всей компьютерной графики!!!!!! [smile=04] [smile=04] [smile=04]
2013-02-12
[quote]Очень надеюсь, что вы ... начали использовать корректирующие блендшейпы везде где только возможно[/quote] А можно их использовать при катании на лыжах? А для подтягиваний? Может я смогу их прикрутить к своему фотоаппарату?? Посоветуйте, пожалуйста, какие корректирующие блендшейпы подарить девушке на 14 февраля.
2013-02-12
:D
2013-02-12
[quote]А можно их использовать при катании на лыжах? А для подтягиваний?Посоветуйте, пожалуйста, какие корректирующие блендшейпы подарить девушке на 14 февраля. [/quote] Можно. Купи себе парочку корректирующих блендов на свой фотоаппарат! Они будут корректировать твою хреновую съемку :-Д )
2013-02-13
В тему http://circecharacterworks.wordpress.com/2012/08/05/protocol-to-build-a-reusable-deformation-template-ii-a-brute-force-approach/ poseReader кстати считает угол между базиз вектором кости и вектором умноженным на матрицу текущего положения poseReader'а и маппит его от 0 до 180. Очень похоже но он не нормализует вес с друг другом. Еще как вариант, если без плагинов, и просто нужна активация, у меня пока самый лучший результат получается, если мы конвертим ротейт кости в кватернион нодой (благо с 2013 точно она входит в комплект стандартных плагинов), затем используя полученные 4 числа в качестве драйвера считаем RBF для каждого блендшейпа (точки будут наши положения). Полученный результат можно вычислять на addDouble и multiplyDivide нодах на каждый блендшейп.
2013-02-13
[quote=xeash] Еще как вариант, если без плагинов, и просто нужна активация, у меня пока самый лучший результат получается, если мы конвертим ротейт кости в кватернион нодой (благо с 2013 точно она входит в комплект стандартных плагинов), затем используя полученные 4 числа в качестве драйвера считаем RBF для каждого блендшейпа (точки будут наши положения). Полученный результат можно вычислять на addDouble и multiplyDivide нодах на каждый блендшейп. [/quote] Напиши об этом статью, Саня (:-) Взглянул бы. Нужен способ наиболее быстрый и оптимальный с точки зрения большинства пользователей.
2013-02-20
ап
2013-03-12
ап
2013-03-14
ап
2013-03-14
А Володя козел! [smile=18]
2013-03-14
Думаю написать статью об "интерполировании матричных преобразований в деформациях асимметричных систем". Надеюсь тема будет интересна широкому кругу читателей. 
2013-03-19
Всех приветствую. 2 Alexander. У меня к вам вопрос как к специалисту. Вопрос по 3D MAX в ту же тему. При скручивании (twist) плеча персонажа сильно деформируются (скручиваются) вершины в районе плечевого сустава. Пытаюсь устранить данный эффект используя аппараты Gizmos и Skin morph и сетки (цели) в крайних позах. Собственно в них все нормально и форма придается верная, но при анимации в промежуточных ключах (позах) происходят лишние деформации (вертексы как волной ходят) и этот эффект мне устранить не удается. Возможно это проблемы с нормализацией. Если не затруднит, ответьте можно ли применить ваш метод в максе и поможет ли он решить проблему?
RENDER.RU