Чтение онлайн

ЖАНРЫ

Написание скриптов для Blender 2.49

Anders Michel

Шрифт:

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 в каждой кости, мы предотвратили распространение масштабирования на детей кости:

bones = sort_by_parent(pose.bones.values)

for frame in range(1,161,10):

index = int(frame/21)-1

n = len(bones)

for i,bone in enumerate(bones):

if i == index :

size = 1.3

else :

size = 1.0

pose.bones[bone].size=Vector(size,size,size)

pose.bones[bone].insertKey(arm,frame,

Blender.Object.Pose.SIZE)

Полный код доступен как peristaltic.py в файле peristaltic.blend.

Применение peristaltic.py к арматуре

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

Поделиться с друзьями: