From BlenderWiki
Armatures
Armature
This program creates an armature.
#--------------------------------------------------- # File armature.py #--------------------------------------------------- import bpy, math from mathutils import Vector, Matrix def createRig(name, origin, boneTable): # Create armature and object 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 # Create bones 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)) # identity matrix bone.tail = rot * Vector(vector) + 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') for (bname, axis, angle) in poseTable: pbone = ob.pose.bones[bname] # Set rotation mode to Euler XYZ, easier to understand # than default quaternions pbone.rotation_mode = 'XYZ' # Documentation bug: Euler.rotate(angle,axis): # axis in ['x','y','z'] and not ['X','Y','Z'] pbone.rotation_euler.rotate_axis(axis, math.radians(angle)) bpy.ops.object.mode_set(mode='OBJECT') def run(origo): origin = Vector(origo) # Table of bones in the form (bone, parent, vector) # The vector is given in local coordinates boneTable1 = [ ('Base', None, (1,0,0)), ('Mid', 'Base', (1,0,0)), ('Tip', 'Mid', (0,0,1)) ] bent = createRig('Bent', origin, boneTable1) # The second rig is a straight line, i.e. bones run along local Y axis 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) # Pose second rig poseTable2 = [ ('Base', 'X', 90), ('Mid2', 'Z', 45), ('Tip', 'Y', -45) ] poseRig(straight, poseTable2) # Pose first rig poseTable1 = [ ('Tip', 'Y', 45), ('Mid', 'Y', 45), ('Base', 'Y', 45) ] poseRig(bent, poseTable1) if __name__ == "__main__": run((0,5,0))
Rigged mesh
This program adds an armature and a mesh. The armature has three bones (Base, Mid, Tip) and constraints:
- An IK constraint Mid -> Tip.
- A Stretch To constraint Mid -> Tip.
- A Copy Rotation constraint Base -> Tip.
The mesh is deformed by the armature. Hence an armature modifier and the corresponding vertex groups are created.
#---------------------------------------------------------- # File rigged_mesh.py #---------------------------------------------------------- import bpy, mathutils def createArmature(origin): # Create armature and object 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 # Link object to scene scn = bpy.context.scene scn.objects.link(rig) scn.objects.active = rig scn.update() # Create bones #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) # Bone constraints. Armature must be in pose mode. bpy.ops.object.mode_set(mode='POSE') # IK constraint 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 constraint Mid -> Tip with influence 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 constraints 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): # Create mesh and object me = bpy.data.meshes.new('Mesh') ob = bpy.data.objects.new('MeshObject', me) ob.location = origin # Link object to scene scn = bpy.context.scene scn.objects.link(ob) scn.objects.active = ob scn.update() # List of vertex coordinates 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) ] # List of faces. 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) ] # Create mesh from given verts, edges, faces. Either edges or # faces should be [], or you ask for problems me.from_pydata(verts, [], faces) # Update mesh with new data me.update(calc_edges=True) return ob def skinMesh(ob, rig): # List of vertex groups, in the form (vertex, weight) 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)] # Create vertex groups, and add verts and weights # First arg in assignment is a list, can assign several verts at once for name, vgroup in vgroups.items(): grp = ob.vertex_groups.new(name) for (v, w) in vgroup: grp.add([v], w, 'REPLACE') # Give mesh object an armature modifier, using vertex groups but # not envelopes mod = ob.modifiers.new('MyRigModif', 'ARMATURE') mod.object = rig mod.use_bone_envelopes = False mod.use_vertex_groups = True def run(origin): rig = createArmature(origin) ob = createMesh(origin) skinMesh(ob, rig) # Move and rotate the tip bone in pose mode 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() if __name__ == "__main__": run((0,0,0))
Edit mode versus pose mode
Bone attributes which affect the rest pose of an armature (head, tail, roll, parent, use connect, etc.) are only available in edit mode (using a bone in ob.data.edit bones), whereas attributes which involve posing require the the armature is in pose mode (using a bone in ob.pose.bones). To my knowledge, the only way to switch between edit and pose mode is with the operator calls
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='POSE')
Since operators act on the active object, we must ensure that the right object is active by setting bpy.context.scene.objects.active.
This script copies the roll angles from a source rig (object name 'SrcRig') to a target rig (object name 'TrgRig'). Both armatures must have the same number of bones with identical names.
#---------------------------------------------------------- # 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') objects = bpy.context.scene.objects copyRolls(objects['SrcRig'], objects['TrgRig'])

