Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjy Cook <benjycook@hotmail.com>2011-06-02 21:19:07 +0400
committerBenjy Cook <benjycook@hotmail.com>2011-06-02 21:19:07 +0400
commitfbff066a70c23077c16899a74feb29096ce5a2e9 (patch)
tree2d9c8982d619b09a5e28b6a0e49fd8f1e2e69535 /release
parente3a46d05a77582ce8c86bff4f0d2c76cea0dac4e (diff)
2nd commit of mine. Contains retarget.py, which has functions for retargeting an animated armature to a second one, given a user mapping of the hiearchy. Currently creates an intermediate skeleton that solves some of the major issues. WIP
Diffstat (limited to 'release')
-rw-r--r--release/scripts/modules/retarget.py136
1 files changed, 136 insertions, 0 deletions
diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py
new file mode 100644
index 00000000000..c7a482659ef
--- /dev/null
+++ b/release/scripts/modules/retarget.py
@@ -0,0 +1,136 @@
+import bpy
+from mathutils import *
+from math import radians, acos
+performer_obj = bpy.data.objects["performer"]
+enduser_obj = bpy.data.objects["enduser"]
+scene = bpy.context.scene
+
+# dictionary of mapping
+bonemap = { "LeftFoot": ("DEF_Foot.L","DEF_Toes.L"),
+ "LeftUpLeg": "DEF_Thigh.L",
+ "Hips": "DEF_Hip",
+ "LowerBack": "DEF_Spine",
+ "Spine": "DEF_Torso",
+ "Neck": "DEF_Neck",
+ "Neck1": "DEF_Neck",
+ "Head": "DEF_Head",
+ "LeftShoulder": "DEF_Shoulder.L",
+ "LeftArm": "DEF_Forearm.L",
+ "LeftForeArm": "DEF_Arm.L",
+ "LeftHand": "DEF_Hand.L",
+ "RightShoulder": "DEF_Shoulder.R",
+ "RightArm": "DEF_Forearm.R",
+ "RightForeArm": "DEF_Arm.R",
+ "RightHand": "DEF_Hand.R",
+ "RightFoot": ("DEF_Foot.R","DEF_Toes.R"),
+ "RightUpLeg": "DEF_Thigh.R",
+ "RightLeg": "DEF_Shin.R",
+ "LeftLeg": "DEF_Shin.L"}
+# creation of a reverse map
+# multiple keys get mapped to list values
+bonemapr = {}
+for key in bonemap.keys():
+ if not bonemap[key] in bonemapr:
+ if type(bonemap[key])==type((0,0)):
+ for key_x in bonemap[key]:
+ bonemapr[key_x] = [key]
+ else:
+ bonemapr[bonemap[key]] = [key]
+ else:
+ bonemapr[bonemap[key]].append(key)
+
+# list of empties created to keep track of "original"
+# position data
+# in final product, these locations can be stored as custom props
+
+constraints = []
+
+#creation of intermediate armature
+# the intermediate armature has the hiearchy of the end user,
+# does not have rotation inheritence
+# and bone roll is identical to the performer
+# its purpose is to copy over the rotations
+# easily while concentrating on the hierarchy changes
+def createIntermediate():
+
+ #creates and keyframes an empty with its location
+ #the original position of the tail bone
+ #useful for storing the important data in the original motion
+ #i.e. using this empty to IK the chain to that pos.
+ def locOfOriginal(inter_bone,perf_bone):
+ if not perf_bone.name+"Org" in bpy.data.objects:
+ bpy.ops.object.add()
+ empty = bpy.context.active_object
+ empty.name = perf_bone.name+"Org"
+ empty = bpy.data.objects[perf_bone.name+"Org"]
+ offset = perf_bone.vector
+ scaling = perf_bone.length / inter_bone.length
+ offset/=scaling
+ empty.location = inter_bone.head + offset
+ empty.keyframe_insert("location")
+
+ #Simple 1to1 retarget of a bone
+ def singleBoneRetarget(inter_bone,perf_bone):
+ perf_world_rotation = perf_bone.matrix * performer_obj.matrix_world
+ inter_world_base_rotation = inter_bone.bone.matrix_local * inter_obj.matrix_world
+ inter_world_base_inv = Matrix(inter_world_base_rotation)
+ inter_world_base_inv.invert()
+ return (inter_world_base_inv.to_3x3() * perf_world_rotation.to_3x3()).to_4x4()
+
+ #uses 1to1 and interpolation/averaging to match many to 1 retarget
+ def manyPerfToSingleInterRetarget(inter_bone,performer_bones_s):
+ retarget_matrices = [singleBoneRetarget(inter_bone,perf_bone) for perf_bone in performer_bones_s]
+ lerp_matrix = Matrix()
+ for i in range(len(retarget_matrices)-1):
+ first_mat = retarget_matrices[i]
+ next_mat = retarget_matrices[i+1]
+ lerp_matrix = first_mat.lerp(next_mat,0.5)
+ return lerp_matrix
+
+ #determines the type of hierachy change needed and calls the
+ #right function
+ def retargetPerfToInter(inter_bone):
+ if inter_bone.name in bonemapr.keys():
+ perf_bone_name = bonemapr[inter_bone.name]
+ #is it a 1 to many?
+ if type(bonemap[perf_bone_name[0]])==type((0,0)):
+ perf_bone = performer_bones[perf_bone_name[0]]
+ if inter_bone.name == bonemap[perf_bone_name[0]][0]:
+ locOfOriginal(inter_bone,perf_bone)
+ else:
+ # then its either a many to 1 or 1 to 1
+
+ if len(perf_bone_name) > 1:
+ performer_bones_s = [performer_bones[name] for name in perf_bone_name]
+ #we need to map several performance bone to a single
+ inter_bone.matrix_basis = manyPerfToSingleInterRetarget(inter_bone,performer_bones_s)
+ else:
+ perf_bone = performer_bones[perf_bone_name[0]]
+ inter_bone.matrix_basis = singleBoneRetarget(inter_bone,perf_bone)
+
+ inter_bone.keyframe_insert("rotation_quaternion")
+ for child in inter_bone.children:
+ retargetPerfToInter(child)
+
+ #creates the intermediate armature object
+ bpy.ops.object.select_name(name="enduser",extend=False)
+ bpy.ops.object.duplicate(linked=False)
+ bpy.context.active_object.name = "intermediate"
+ inter_obj = bpy.context.active_object
+ bpy.ops.object.mode_set(mode='EDIT')
+ #resets roll
+ bpy.ops.armature.calculate_roll(type='Z')
+ bpy.ops.object.mode_set(mode="OBJECT")
+ performer_bones = performer_obj.pose.bones
+ inter_bones = inter_obj.pose.bones
+
+ #clears inheritance
+ for inter_bone in inter_bones:
+ inter_bone.bone.use_inherit_rotation = False
+
+ for t in range(1,150):
+ scene.frame_set(t)
+ inter_bone = inter_bones["DEF_Hip"]
+ retargetPerfToInter(inter_bone)
+
+createIntermediate() \ No newline at end of file