「Dev:IT/2.5/Py/Scripts/Cookbook/Code snippets/Armatures」の版間の差分
細 (1版 をインポートしました) |
|
(相違点なし)
|
2018年6月29日 (金) 04:43時点における最新版
Armature
Armatura
Questo programma crea un'armatura.
#---------------------------------------------------
# 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 = 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')
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
Questo programma aggiunge un'armatura a una mesh. L'armatura ha tre ossa (Base, Mid, Tip) e vincoli (constraints):
- Un vincolo IK. Mid -> Tip
- Un vincolo Stretch To. Mid -> Tip
- Un vincolo Copy Rotation. Base -> Tip
La mesh è deformata dall'armatura. Quindi un modificatore armatura e i corrispondenti vertex group sono creati.
#----------------------------------------------------------
# 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
Gli attributi delle ossa che agiscono sulla posizione di riposo di un'armatura (head, tail, roll, parent, use connect, etx) sono disponibili solo in Edit Mode (usa un osso in ob.data.edit_bones), mentre gli attributi che coinvolgono il posizionamento richiedono che l'armatura sia in Pose Mode (usa un osso in ob.pose.bones). Per quanto ne so, l'unico modo per passare da Edit Mode a Pose Mode e viceversa, è con una chiamata a un operatore
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='POSE')
Dal momento che gli operatori agiscono sull'oggetto attivo, ci dobbiamo assicurare che l'oggetto corretto è attivo impostando bpy.context.scene.objects.active
.
Questo programma copia l'angolo roll da un rig (chiamato 'SrcRig') a un altro rig (chiamato 'TrgRig'). Entrambe le armature devono avere lo stesso numero di ossa con nomi identici.
#----------------------------------------------------------
# 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'])