Арматуры

Арматура

Эта программа создаёт арматуру.



#--------------------------------------------------- 

# File armature.py

#--------------------------------------------------- 

import bpy, math

from mathutils 
import Vector, Matrix 


def createRig(name, origin, boneTable):

   # Создание арматуры и объекта

   bpy.ops.object.add(

     type='ARMATURE',

     enter_editmode=True,

     location=origin)

   ob = bpy.context.object

   ob.show_x_ray = True

   ob.name = name

   amt = ob.data

   amt.name = name+'Amt'

   amt.show_axes = True


   # Создание костей

   bpy.ops.object.mode_set(mode='EDIT')

   for (bname, pname, vector) in boneTable:

     bone = amt.edit_bones.new(bname)

     if pname:

       parent = amt.edit_bones[pname]

       bone.parent = parent

       bone.head = parent.tail

       bone.use_connect = False

       (trans, rot, scale) = parent.matrix.decompose()

     else:

       bone.head = (0,0,0)

       rot = Matrix.Translation((0,0,0))
 # Матрица идентичности

     bone.tail = Vector(vector) * rot + bone.head

   bpy.ops.object.mode_set(mode='OBJECT')

   return ob


def poseRig(ob, poseTable):

   bpy.context.scene.objects.active = ob

   bpy.ops.object.mode_set(mode='POSE')

   deg2rad = 2*math.pi/360


   for (bname, axis, angle) in poseTable:

     pbone = ob.pose.bones[bname]

     # Установка режима вращения в Euler XYZ (Эйлерово),

     # легче для понимания, чем кватернионы по-умолчанию

     pbone.rotation_mode = 'XYZ'

     # Косяк в документации: Euler.rotate(angle,axis):

     # оси в ['x','y','z'] а не ['X','Y','Z']

     pbone.rotation_euler.rotate_axis(axis, angle*deg2rad)

   bpy.ops.object.mode_set(mode='OBJECT')

   return


def run(origo):

   origin = Vector(origo)

   # Таблица костей в форме (кость, родитель, вектор)

   # Вектор дан в локальных координатах

   boneTable1 = [

     ('Base', None, (1,0,0)),

     ('Mid', 'Base', (1,0,0)),

     ('Tip', 'Mid', (0,0,1))

   ]

   bent = createRig('Bent', origin, boneTable1)


   # Вторая оснастка является прямой линией, то есть кости проходят вдоль локальной оси Y

   boneTable2 = [

      ('Base', None, (1,0,0)),

     ('Mid', 'Base', (0,0.5,0)),

     ('Mid2', 'Mid', (0,0.5,0)),

     ('Tip', 'Mid2', (0,1,0))

   ]

   straight = createRig('Straight', origin+Vector((0,2,0)), boneTable2)


   # Поза второй остнастки

   poseTable2 = [

     ('Base', 'X', 90),

     ('Mid2', 'Z', 45),

     ('Tip', 'Y', -45)

   ]

   poseRig(straight, poseTable2)


   # Поза первой остнастки

   poseTable1 = [

     ('Tip', 'Y', 45),

     ('Mid', 'Y', 45),

     ('Base', 'Y', 45)

   ]

   poseRig(bent, poseTable1)

   return


if __name__ == "__main__":

   run((0,5,0))


Меш с оснасткой

Эта программа добавляет арматуру и меш. Арматура имеет три кости (Base (базовая), Mid (средняя), Tip (конечная)) и ограничения:

1. Ограничение IK Mid -> Tip.

2. Ограничение Stretch To Mid -> Tip.

3. Ограничение Copy Rotation Base -> Tip.

Меш деформируется арматурой. Следовательно, создаются модификатор арматуры и соответствующие группы вершин.



#---------------------------------------------------------- 

# File rigged_mesh.py

#---------------------------------------------------------- 

import bpy, mathutils


def createArmature(origin):

   # Создание арматуры и объекта

   amt = bpy.data.armatures.new('MyRigData')

   rig = bpy.data.objects.new('MyRig', amt)

   rig.location = origin

   rig.show_x_ray = True amt.show_names = True

   # Привязка объекта к сцене

   scn = bpy.context.scene

   scn.objects.link(rig)

   scn.objects.active = rig scn.update()


   # Создание костей

#next two lines by PKHG SVN 36504 W32

   bpy.ops.object.editmode_toggle()

# bpy.ops.object.mode_set(mode='EDIT') 

#original does not work??!! bpy.ops.object.mode_set(mode='EDIT')

   base = amt.edit_bones.new('Base')

   base.head = (0,0,0)

   base.tail = (0,0,1)


   mid = amt.edit_bones.new('Mid')

   mid.head = (0,0,1)

   mid.tail = (0,0,2)

   mid.parent = base

   mid.use_connect = True


   tip = amt.edit_bones.new('Tip')

   tip.head = (0,0,2)

   tip.tail = (0,0,3)


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

   bpy.ops.object.mode_set(mode='POSE')


   # Ограничение IK Mid -> Tip

   pMid = rig.pose.bones['Mid']

   cns1 = pMid.constraints.new('IK')

   cns1.name = 'Ik'

   cns1.target = rig

   cns1.subtarget = 'Tip'

   cns1.chain_count = 1


   # Ограничение StretchTo Mid -> Tip с влиянием 0.5

   cns2 = pMid.constraints.new('STRETCH_TO')

   cns2.name = 'Stretchy'

   cns2.target = rig

   cns2.subtarget = 'Tip'

   cns2.influence = 0.5

   cns2.keep_axis = 'PLANE_X'

   cns2.volume = 'VOLUME_XZX'


   # Ограничение Copy rotation Base -> Tip

   pBase = rig.pose.bones['Base']

   cns3 = pBase.constraints.new('COPY_ROTATION')

   cns3.name = 'Copy_Rotation'

   cns3.target = rig

   cns3.subtarget = 'Tip'

   cns3.owner_space = 'WORLD'

   cns3.target_space = 'WORLD'


   bpy.ops.object.mode_set(mode='OBJECT')

   return rig


def createMesh(origin):

   # Создание меша и объекта

   me = bpy.data.meshes.new('Mesh')

   ob = bpy.data.objects.new('MeshObject', me)

   ob.location = origin

   # Привязка объекта к сцене

   scn = bpy.context.scene

   scn.objects.link(ob)

   scn.objects.active = ob

   scn.update()


   # Список координат вершин.

   verts = [

      (0.5, 0.5,0), (0.5,-0.5,0), (-0.5,-0.5,0), (-0.5,0.5,0),

     (0.5,0.5,1), (0.5,-0.5,1), (-0.5,-0.5,1), (-0.5,0.5,1),

     (-0.5,0.5,2), (-0.5,-0.5,2), (0.5,-0.5,2), (0.5,0.5,2),

     (0.5,0.5,3), (0.5,-0.5,3), (-0.5,-0.5,3), (-0.5, 0.5,3)

   ]

   # Список граней.

   faces = [

     (0, 1, 2, 3),

     (0, 4, 5, 1),

     (1, 5, 6, 2),

     (2, 6, 7, 3),

     (4, 0, 3, 7),

     (4, 7, 8, 11),

     (7, 6, 9, 8),

     (6, 5, 10, 9),

     (5, 4, 11, 10),

     (10, 11, 12, 13),

     (9, 10, 13, 14),

     (8, 9, 14, 15),

     (11, 8, 15, 12),

     (12, 15, 14, 13)

   ]


   # Создание меша из передаваемых списков вершин, рёбер, граней.

   # Или рёбра или грани должны быть [], иначе Вам нужны проблемы

   me.from_pydata(verts, [], faces)


   # Обновление меша с новыми данными

   me.update(calc_edges=True)

   return ob


def skinMesh(ob, rig):

   # Списки вершин в группах, в форме (вершина, вес)

   vgroups = {}

   vgroups['Base'] = [

     (0, 1.0), (1, 1.0), (2, 1.0), (3, 1.0),

     (4, 0.5), (5, 0.5), (6, 0.5), (7, 0.5)]

   vgroups['Mid'] = [

     (4, 0.5), (5, 0.5), (6, 0.5), (7, 0.5),

     (8, 1.0), (9, 1.0), (10, 1.0), (11, 1.0)]

   vgroups['Tip'] = [
(12, 1.0), (13, 1.0), (14, 1.0), (15, 1.0)]


   # Создание групп вершин и добавление вершин и весов

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

   # было назначать несколько вершин сразу

   for name in vgroups.keys():

     grp = ob.vertex_groups.new(name)

     for (v, w) in vgroups[name]:

       grp.add([v], w, 'REPLACE')


   # Добавление меш-объекту модификатора арматуры, с использованием

   # групп вершин, а не envelopes

   mod = ob.modifiers.new('MyRigModif', 'ARMATURE')

   mod.object = rig mod.use_bone_envelopes = False

   mod.use_vertex_groups = True


   return


def run(origin):

   rig = createArmature(origin)

   ob = createMesh(origin)

   skinMesh(ob, rig)


   # Перемещение и вращение кости Tip в режиме позы

   bpy.context.scene.objects.active = rig

   bpy.ops.object.mode_set(mode='POSE')

   ptip = rig.pose.bones['Tip']

   ptip.location = (0.2,-0.5,0)

   rotMatrix = mathutils.Matrix.Rotation(0.6, 3, 'X')

   ptip.rotation_quaternion = rotMatrix.to_quaternion()


   return


if __name__ == "__main__":

   run((0,0,0))


Режим редактирования против режима позы

Атрибуты костей, которые влияют на изначальную позу арматуры (голова, хвост, поворот, родитель, использование соединения, и т.п.), доступны только в режиме редактирования (использование кости в ob.data.edit bones), тогда как атрибуты, которые применяются при позировании, требуют, чтобы арматура была в режиме позы (использование кости в ob.pose.bones). Насколько я знаю, единственный способ переключаться между режимами редактирования и позы — с помощью вызова операторов

bpy.ops.object.mode_set(mode='EDIT')

bpy.ops.object.mode_set(mode='POSE')

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

bpy.context.scene.objects.active
.

Этот скрипт копирует углы поворота

roll
из исходной оснастки (имя объекта 'SrcRig') в целевую оснастку (имя объектна 'TrgRig'). Обе арматуры должны иметь одинаковое число костей с идентичными именами.



#---------------------------------------------------------- 

# File copy_roll.py

#---------------------------------------------------------- 

import bpy 


def copyRolls(src, trg):

   rolls = {} bpy.context.scene.objects.active = src

   bpy.ops.object.mode_set(mode='EDIT')

   for eb in src.data.edit_bones:

     rolls[eb.name] = eb.roll

   bpy.ops.object.mode_set(mode='POSE')


   bpy.context.scene.objects.active = trg

   bpy.ops.object.mode_set(mode='EDIT')

   for eb in trg.data.edit_bones:

     oldRoll = eb.roll

     eb.roll = rolls[eb.name]

     print(eb.name, oldRoll, eb.roll)

   bpy.ops.object.mode_set(mode='POSE')

   return 


objects = bpy.context.scene.objects 

copyRolls(objects['SrcRig'], objects['TrgRig']) 


Загрузка...