def sort_by_parent(pbones):
bones=[]
if len(pbones)<1 : return bones
bone = pbones.pop(0)
while(not bone.name in bones):
bones.append(bone.name)
Затем, мы получаем родителя кости, которую мы только что добавили к нашему списку, и настолько долго, насколько мы можем просматривать цепь родителей, мы включаем такого родителя (или, точнее, его имя) в наш список перед текущим элементом (выделено ниже). Если цепь не может следовать дальше, мы выталкиваем новую кость Позы. Когда больше нет костей, метод pop() вызовет исключение IndexError , и мы выходим из нашего цикла while :
parent = bone.parent
while(parent):
if not parent.name in bones:
bones.insert(bones.index(bone.name),
parent.name)
bone = parent
parent = parent.parent
try:
bone = pbones.pop(0)
except IndexError:
break
return bones
Чем дольше я пытался разобраться с логикой этой функции, чтобы адекватно перевести два предыдущих абзаца, тем сильнее мне это не нравилось, ибо логики я не наблюдал. Тогда я немного потестировал эту функцию в файле peristaltic.blend, и убедился, что она правильно работает не во всех случаях. Цепочка костей в файле по направлению от родительских к дочерним выглядит так: ['Bone', 'Bone.001', 'Bone.002', 'Bone.003', 'Bone.004', 'Bone.005']. Если на вход функции список pbones приходит в таком порядке: ["Bone.001", "Bone.002", "Bone.003", "Bone.004", "Bone.005", "Bone"], то результат получается таким, каким надо, но если на вход придёт, например, список ["Bone.002", "Bone.001", "Bone.003", "Bone.004", "Bone.005", "Bone"] (первые два элемента поменяны местами), то на выходе будет всего 3 кости: ['Bone', 'Bone.001', 'Bone.002']. Вот мой исправленный вариант функции:
def sort_by_parent(pbones):
bones=[]
while True: # Бесконечный цикл гарантирует перебор
# всех костей из входного списка
try:
bone = pbones.pop(0)
except IndexError:
break # Единственное условие выхода из цикла
if not bone.name in bones:
bones.append(bone.name)
parent = bone.parent
while(parent):
if not parent.name in bones:
bones.insert(bones.index(bone.name),
parent.name)
bone = parent
parent = parent.parent
return bones
- Добавление переводчика.
Следующий шаг - это определение самого скрипта. Сначала, мы получаем активный объект в текущей сцене и проверяем, что это - на самом деле арматура. Если нет, мы предупреждаем об этом пользователя с помощью всплывающего сообщения (выделенная часть следующего кода), в противном случае мы продолжаем и получаем связанные с арматурой данные методом getData() :
scn = Blender.Scene.GetCurrent()
arm = scn.objects.active
if arm.getType()!='Armature':
Blender.Draw.PupMenu("Selected object is not an " +
"Armature%t|Ok")
else:
adata = arm.getData()
Затем, мы делаем арматуру редактируемой и убеждаемся, что у каждой кости задана опция HINGE (выделено). Преобразование списка опций в множество (set) и обратно в список после добавления опций HINGE является способом удостовериться, что эта опция появится в списке только один раз.
adata.makeEditable()
for ebone in adata.bones.values():
ebone.options =
list(set(ebone.options)|
set([Blender.Armature.HINGE]))
adata.update()
Поза связана с объектом арматуры, а не со своими данными, так что мы получаем её из объекта arm , используя метод getPose() . Позы кости очень похожи на обычные IPO, но они должны быть связаны с действием (action), которое группирует эти позы. При работе с Блендером интерактивно действие создаётся автоматически, как только мы вставим ключевой кадр в позу, но в скрипте мы должны явно создать действие, если оно ещё не присутствует (выделено):
pose = arm.getPose()
action = arm.getAction()
if not action:
action = Blender.Armature.NLA.NewAction()
action.setActive(arm)
Следующим шагом нужно отсортировать кости Позы в порядке цепи от родительских к дочерним, используя нашу ранее определенную функцию. Всё, что осталось сделать, это двигаться по временной шкале через десять кадров за 1 шаг и задавать ключи для масштаба каждой кости на каждом шаге, увеличивая масштаб, если номер кости в последовательности соответствует нашему шагу и восстанавливая его, если нет. Одна из результирующих кривых IPO показана на скриншоте. Заметьте, что нашей предварительной установкой атрибута HINGE в каждой кости, мы предотвратили распространение масштабирования на детей кости:
Читать дальше