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-07-10 01:52:25 +0400
committerBenjy Cook <benjycook@hotmail.com>2011-07-10 01:52:25 +0400
commitc749a42a8ed77805cf39f9debb508f13313429f9 (patch)
treebf55f773a0b77fd7be7863ae5fff01b8b0705983 /release/scripts
parentdaddbc62df5f8ade39b25acd4e333c5c3bd88b5a (diff)
Some optimizations and coding style improvements across the retargeting and constraint scripts
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/modules/mocap_constraints.py87
-rw-r--r--release/scripts/modules/retarget.py162
-rw-r--r--release/scripts/startup/ui_mocap.py114
3 files changed, 211 insertions, 152 deletions
diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py
index 07ebb01ea3d..f4d96d6a5d0 100644
--- a/release/scripts/modules/mocap_constraints.py
+++ b/release/scripts/modules/mocap_constraints.py
@@ -21,15 +21,11 @@
import bpy
from mathutils import *
from bl_operators import nla
+from retarget import hasIKConstraint
### Utility Functions
-def hasIKConstraint(pose_bone):
- #utility function / predicate, returns True if given bone has IK constraint
- return ("IK" in [constraint.type for constraint in pose_bone.constraints])
-
-
def getConsObj(bone):
#utility function - returns related IK target if bone has IK
ik = [constraint for constraint in bone.constraints if constraint.type == "IK"]
@@ -63,21 +59,18 @@ def addNewConstraint(m_constraint, cons_obj):
real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints))
m_constraint.real_constraint_bone = consObjToBone(cons_obj)
m_constraint.real_constraint = real_constraint.name
- setConstraint(m_constraint)
+ setConstraint(m_constraint, bpy.context)
def removeConstraint(m_constraint, cons_obj):
oldConstraint = cons_obj.constraints[m_constraint.real_constraint]
+ removeInfluenceFcurve(cons_obj, bpy.context.active_object, oldConstraint)
cons_obj.constraints.remove(oldConstraint)
### Update functions. There are 2: UpdateType/UpdateBone
### and update for the others.
-def updateConstraint(self, context):
- setConstraint(self)
-
-
def updateConstraintBoneType(m_constraint, context):
#If the constraint exists, we need to remove it
#from the old bone
@@ -94,10 +87,24 @@ def updateConstraintBoneType(m_constraint, context):
addNewConstraint(m_constraint, cons_obj)
-# Function that copies all settings from m_constraint to the real Blender constraints
-# Is only called when blender constraint already exists
+def setConstraintFraming(m_constraint, context):
+ obj = context.active_object
+ bones = obj.pose.bones
+ bone = bones[m_constraint.constrained_bone]
+ cons_obj = getConsObj(bone)
+ real_constraint = cons_obj.constraints[m_constraint.real_constraint]
+ removeInfluenceFcurve(cons_obj, obj, real_constraint)
+ s, e = m_constraint.s_frame, m_constraint.e_frame
+ s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
+ real_constraint.influence = 1
+ real_constraint.keyframe_insert(data_path="influence", frame=s)
+ real_constraint.keyframe_insert(data_path="influence", frame=e)
+ real_constraint.influence = 0
+ real_constraint.keyframe_insert(data_path="influence", frame=s - s_in)
+ real_constraint.keyframe_insert(data_path="influence", frame=e + s_out)
-def setConstraintFraming(m_constraint, cons_obj, obj, real_constraint):
+
+def removeInfluenceFcurve(cons_obj, obj, real_constraint):
if isinstance(cons_obj, bpy.types.PoseBone):
fcurves = obj.animation_data.action.fcurves
else:
@@ -107,30 +114,24 @@ def setConstraintFraming(m_constraint, cons_obj, obj, real_constraint):
fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA]
#clear the fcurve and set the frames.
if fcurve:
- fcurve = fcurve[0]
- for i in range(len(fcurve.keyframe_points) - 1, 0, -1):
- fcurve.keyframe_points.remove(fcurve.keyframe_points[i])
- s, e = m_constraint.s_frame, m_constraint.e_frame
- s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
- real_constraint.influence = 1
- real_constraint.keyframe_insert(data_path="influence", frame=s)
- real_constraint.keyframe_insert(data_path="influence", frame=e)
- real_constraint.influence = 0
- real_constraint.keyframe_insert(data_path="influence", frame=s - s_in)
- real_constraint.keyframe_insert(data_path="influence", frame=e + s_out)
+ fcurves.remove(fcurve[0])
+
+
+# Function that copies all settings from m_constraint to the real Blender constraints
+# Is only called when blender constraint already exists
-def setConstraint(m_constraint):
+def setConstraint(m_constraint, context):
if not m_constraint.constrained_bone:
return
- obj = bpy.context.active_object
+ obj = context.active_object
bones = obj.pose.bones
bone = bones[m_constraint.constrained_bone]
cons_obj = getConsObj(bone)
real_constraint = cons_obj.constraints[m_constraint.real_constraint]
#frame changing section
- setConstraintFraming(m_constraint, cons_obj, obj, real_constraint)
+ #setConstraintFraming(m_constraint, cons_obj, obj, real_constraint)
#Set the blender constraint parameters
if m_constraint.type == "point":
@@ -176,17 +177,17 @@ def setConstraint(m_constraint):
real_constraint.limit_mode = "LIMITDIST_ONSURFACE"
real_constraint.distance = m_constraint.targetDist
- # active check
+ # active/baked check
real_constraint.mute = (not m_constraint.active) and (m_constraint.baked)
def updateBake(self, context):
if self.baked:
print("baking...")
- bakeConstraint(self)
+ bakeConstraint(self, context)
else:
print("unbaking...")
- unbakeConstraint(self)
+ unbakeConstraint(self, context)
def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj):
@@ -210,14 +211,15 @@ def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj):
return mute_ik
-def bakeConstraint(m_constraint):
- obj = bpy.context.active_object
+def bakeConstraint(m_constraint, context):
+ obj = context.active_object
bones = obj.pose.bones
end_bone = bones[m_constraint.constrained_bone]
cons_obj = getConsObj(end_bone)
- scene = bpy.context.scene
- s_frame = scene.frame_start
- e_frame = scene.frame_end
+ s, e = m_constraint.s_frame, m_constraint.e_frame
+ s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
+ s_frame = s - s_in
+ e_frame = e + s_out
mute_ik = bakeTransformFK(obj.animation_data, s_frame, e_frame, end_bone, bones, cons_obj)
if mute_ik:
ik_con = hasIKConstraint(end_bone)
@@ -232,16 +234,14 @@ def bakeConstraint(m_constraint):
constraintStrip.frame_end = e_frame
-def unbakeConstraint(m_constraint):
+def unbakeConstraint(m_constraint, context):
# to unbake a constraint we need to delete the whole strip
# and rebake all the other constraints
- obj = bpy.context.active_object
+ obj = context.active_object
bones = obj.pose.bones
end_bone = bones[m_constraint.constrained_bone]
cons_obj = getConsObj(end_bone)
scene = bpy.context.scene
- s_frame = scene.frame_start
- e_frame = scene.frame_end
constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"]
constraintStrip = constraintTrack.strips[0]
action = constraintStrip.action
@@ -257,12 +257,3 @@ def unbakeConstraint(m_constraint):
ik_con.mute = False
real_constraint = cons_obj.constraints[m_constraint.real_constraint]
real_constraint.mute = False
-
-
-def hasIKConstraint(pose_bone):
- #utility function / predicate, returns True if given bone has IK constraint
- ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"]
- if ik:
- return ik[0]
- else:
- return False
diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py
index 885a457061a..ef1bc7a1488 100644
--- a/release/scripts/modules/retarget.py
+++ b/release/scripts/modules/retarget.py
@@ -22,40 +22,33 @@ import bpy
from mathutils import *
from math import radians, acos
-#TODO: Only selected bones get retargeted.
-# Selected Bones/chains get original pos empties,
-# if ppl want IK instead of FK
-# Some "magic" numbers - frame start and end,
-# eulers of all orders instead of just quats keyframed
-# dictionary of mapping
-# this is currently manuall input'ed, but willW
-# be created from a more comfortable UI in the future
+def hasIKConstraint(pose_bone):
+ #utility function / predicate, returns True if given bone has IK constraint
+ ik = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"]
+ if ik:
+ return ik[0]
+ else:
+ return False
def createDictionary(perf_arm, end_arm):
- bonemap = {}
- #Bonemap: performer to enduser
- for bone in perf_arm.bones:
- bonemap[bone.name] = bone.map
-
- # creation of a reverse map
- # multiple keys get mapped to list values
- #Bonemapr: enduser to performer
- bonemapr = {}
- for key, value in bonemap.items():
- if not value in bonemapr:
- if isinstance(bonemap[key], tuple):
- for key_x in bonemap[key]:
- bonemapr[key_x] = [key]
- else:
- bonemapr[bonemap[key]] = [key]
- else:
- bonemapr[bonemap[key]].append(key)
+ # clear any old data
+ for end_bone in end_arm.bones:
+ for mapping in end_bone.reverseMap:
+ end_bone.reverseMap.remove(0)
+
+ for perf_bone in perf_arm.bones:
+ #find its match and add perf_bone to the match's mapping
+ if perf_bone.map:
+ end_bone = end_arm.bones[perf_bone.map]
+ newMap = end_bone.reverseMap.add()
+ newMap.name = perf_bone.name
+
#root is the root of the enduser
root = end_arm.bones[0].name
feetBones = [bone.name for bone in perf_arm.bones if bone.foot]
- return bonemap, bonemapr, feetBones, root
+ return feetBones, root
# list of empties created to keep track of "original"
# position data
# in final product, these locations can be stored as custom props
@@ -69,7 +62,7 @@ def createDictionary(perf_arm, end_arm):
# easily while concentrating on the hierarchy changes
-def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene):
+def createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene):
#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
@@ -96,22 +89,17 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr
#determines the type of hierachy change needed and calls the
#right function
def retargetPerfToInter(inter_bone):
- if inter_bone.name in bonemapr:
- perf_bone_name = bonemapr[inter_bone.name]
- #is it a 1 to many?
- if isinstance(bonemap[perf_bone_name[0]], tuple):
- pass
+ if inter_bone.bone.reverseMap:
+ perf_bone_name = inter_bone.bone.reverseMap
# 1 to many not supported yet
- 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)
+ if len(perf_bone_name) > 1:
+ performer_bones_s = [performer_bones[map.name] for map 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].name]
+ inter_bone.matrix_basis = singleBoneRetarget(inter_bone, perf_bone)
inter_bone.keyframe_insert("rotation_quaternion")
for child in inter_bone.children:
@@ -140,7 +128,7 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr
inter_bone = inter_bones[root]
retargetPerfToInter(inter_bone)
- return inter_obj, inter_arm
+ return inter_obj
# this procedure copies the rotations over from the intermediate
# armature to the end user one.
@@ -176,7 +164,13 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene):
rest_matrix_inv.invert()
bake_matrix = rest_matrix_inv * bake_matrix
trg_bone.matrix_basis = bake_matrix
- end_bone.keyframe_insert("rotation_quaternion")
+ rot_mode = end_bone.rotation_mode
+ if rot_mode == "QUATERNION":
+ end_bone.keyframe_insert("rotation_quaternion")
+ elif rot_mode == "AXIS_ANGLE":
+ end_bone.keyframe_insert("rotation_axis_angle")
+ else:
+ end_bone.keyframe_insert("rotation_euler")
for bone in end_bone.children:
bakeTransform(bone)
@@ -193,13 +187,13 @@ def retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene):
# (they don't move, despite root moving) somewhere in the animation.
-def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat):
+def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame, scene, enduser_obj_mat):
perf_bones = performer_obj.pose.bones
end_bones = enduser_obj.pose.bones
- perfRoot = bonemapr[root][0]
- endFeet = [bonemap[perfBone] for perfBone in perfFeet]
+ perfRoot = end_bones[root].bone.reverseMap[0].name
+ endFeet = [perf_bones[perfBone].bone.map for perfBone in perfFeet]
locDictKeys = perfFeet + endFeet + [perfRoot]
def tailLoc(bone):
@@ -208,7 +202,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo
#Step 1 - we create a dict that contains these keys:
#(Performer) Hips, Feet
#(End user) Feet
- # where the values are their world position on each (1,120) frame
+ # where the values are their world position on each frame in range (s,e)
locDict = {}
for key in locDictKeys:
@@ -231,10 +225,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo
for key in locDict.keys():
graph = locDict[key]
- for t in range(len(graph) - 1):
- x = graph[t]
- xh = graph[t + 1]
- locDeriv[key].append(xh - x)
+ locDeriv[key] = [graph[t + 1] - graph[t] for t in range(len(graph) - 1)]
# now find the plant frames, where perfFeet don't move much
@@ -244,7 +235,7 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo
for i in range(len(locDeriv[key]) - 1):
v = locDeriv[key][i]
hipV = locDeriv[perfRoot][i]
- endV = locDeriv[bonemap[key]][i]
+ endV = locDeriv[perf_bones[key].bone.map][i]
if (v.length < 0.1):
#this is a plant frame.
#lets see what the original hip delta is, and the corresponding
@@ -268,18 +259,16 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo
return stride_bone
-def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene):
+def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene):
end_bones = enduser_obj.pose.bones
for pose_bone in end_bones:
- if "IK" in [constraint.type for constraint in pose_bone.constraints]:
+ ik_constraint = hasIKConstraint(pose_bone)
+ if ik_constraint:
target_is_bone = False
# set constraint target to corresponding empty if targetless,
# if not, keyframe current target to corresponding empty
- perf_bone = bonemapr[pose_bone.name]
- if isinstance(perf_bone, list):
- perf_bone = bonemapr[pose_bone.name][-1]
+ perf_bone = pose_bone.bone.reverseMap[-1].name
orgLocTrg = originalLocationTarget(pose_bone)
- ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0]
if not ik_constraint.target:
ik_constraint.target = orgLocTrg
target = orgLocTrg
@@ -314,8 +303,8 @@ def turnOffIK(enduser_obj):
#pose_bone.ik_stiffness_x = 0.5
#pose_bone.ik_stiffness_y = 0.5
#pose_bone.ik_stiffness_z = 0.5
- if "IK" in [constraint.type for constraint in pose_bone.constraints]:
- ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0]
+ ik_constraint = hasIKConstraint(pose_bone)
+ if ik_constraint:
ik_constraint.mute = True
@@ -350,45 +339,38 @@ def originalLocationTarget(end_bone):
return empty
-def totalRetarget():
- print("retargeting...")
- enduser_obj = bpy.context.active_object
- performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj]
- if enduser_obj is None or len(performer_obj) != 1:
- print("Need active and selected armatures")
- else:
- performer_obj = performer_obj[0]
- perf_arm = performer_obj.data
- end_arm = enduser_obj.data
- scene = bpy.context.scene
- s_frame = scene.frame_start
- e_frame = scene.frame_end
- bonemap, bonemapr, feetBones, root = createDictionary(perf_arm, end_arm)
- perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj)
- turnOffIK(enduser_obj)
- inter_obj, inter_arm = createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_frame, e_frame, scene)
- retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene)
- stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, bonemap, bonemapr, root, s_frame, e_frame, scene, enduser_obj_mat)
- IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene)
- restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone)
- bpy.ops.object.mode_set(mode='OBJECT')
- bpy.ops.object.select_name(name=inter_obj.name, extend=False)
- bpy.ops.object.delete()
+def NLASystemInitialize(enduser_obj, s_frame):
anim_data = enduser_obj.animation_data
mocapAction = anim_data.action
- mocapAction.name = "Base Mocap Action"
+ mocapAction.name = "Base Mocap"
anim_data.use_nla = True
mocapTrack = anim_data.nla_tracks.new()
mocapTrack.name = "Base Mocap Track"
- mocapStrip = mocapTrack.strips.new("Base Mocap Action", s_frame, mocapAction)
+ mocapStrip = mocapTrack.strips.new("Base Mocap", s_frame, mocapAction)
constraintTrack = anim_data.nla_tracks.new()
constraintTrack.name = "Mocap constraints"
- constraintAction = bpy.data.actions.new("Mocap constraints Action")
- constraintStrip = constraintTrack.strips.new("Mocap constraints Action", s_frame, constraintAction)
- #constraintStrip.frame_end = e_frame
+ constraintAction = bpy.data.actions.new("Mocap constraints")
+ constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction)
anim_data.nla_tracks.active = constraintTrack
anim_data.action = constraintAction
+def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame):
+ perf_arm = performer_obj.data
+ end_arm = enduser_obj.data
+ feetBones, root = createDictionary(perf_arm, end_arm)
+ perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj, enduser_obj)
+ turnOffIK(enduser_obj)
+ inter_obj = createIntermediate(performer_obj, enduser_obj, root, s_frame, e_frame, scene)
+ retargetEnduser(inter_obj, enduser_obj, root, s_frame, e_frame, scene)
+ stride_bone = copyTranslation(performer_obj, enduser_obj, feetBones, root, s_frame, e_frame, scene, enduser_obj_mat)
+ IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene)
+ restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone)
+ bpy.ops.object.mode_set(mode='OBJECT')
+ bpy.ops.object.select_name(name=inter_obj.name, extend=False)
+ bpy.ops.object.delete()
+ NLASystemInitialize(enduser_obj, s_frame)
+
+
if __name__ == "__main__":
totalRetarget()
diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py
index d750489191f..b09f9705a56 100644
--- a/release/scripts/startup/ui_mocap.py
+++ b/release/scripts/startup/ui_mocap.py
@@ -42,7 +42,7 @@ class MocapConstraint(bpy.types.PropertyGroup):
name = bpy.props.StringProperty(name="Name",
default="Mocap Constraint",
description="Name of Mocap Constraint",
- update=updateConstraint)
+ update=setConstraint)
constrained_bone = bpy.props.StringProperty(name="Bone",
default="",
description="Constrained Bone",
@@ -50,33 +50,33 @@ class MocapConstraint(bpy.types.PropertyGroup):
constrained_boneB = bpy.props.StringProperty(name="Bone (2)",
default="",
description="Other Constrained Bone (optional, depends on type)",
- update=updateConstraint)
+ update=setConstraint)
s_frame = bpy.props.IntProperty(name="S",
default=1,
description="Start frame of constraint",
- update=updateConstraint)
+ update=setConstraintFraming)
e_frame = bpy.props.IntProperty(name="E",
default=500,
description="End frame of constrain",
- update=updateConstraint)
+ update=setConstraintFraming)
smooth_in = bpy.props.IntProperty(name="In",
default=10,
description="Amount of frames to smooth in",
- update=updateConstraint,
+ update=setConstraintFraming,
min=0)
smooth_out = bpy.props.IntProperty(name="Out",
default=10,
description="Amount of frames to smooth out",
- update=updateConstraint,
+ update=setConstraintFraming,
min=0)
targetMesh = bpy.props.StringProperty(name="Mesh",
default="",
description="Target of Constraint - Mesh (optional, depends on type)",
- update=updateConstraint)
+ update=setConstraint)
active = bpy.props.BoolProperty(name="Active",
default=True,
description="Constraint is active",
- update=updateConstraint)
+ update=setConstraint)
baked = bpy.props.BoolProperty(name="Baked / Applied",
default=False,
description="Constraint has been baked to NLA layer",
@@ -84,18 +84,18 @@ class MocapConstraint(bpy.types.PropertyGroup):
targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3,
subtype="XYZ", default=(0.0, 0.0, 0.0),
description="Target of Constraint - Point",
- update=updateConstraint)
+ update=setConstraint)
targetDist = bpy.props.FloatProperty(name="Dist",
default=1,
description="Distance Constraint - Desired distance",
- update=updateConstraint)
+ update=setConstraint)
targetSpace = bpy.props.EnumProperty(
items=[("WORLD", "World Space", "Evaluate target in global space"),
("LOCAL", "Object space", "Evaluate target in object space"),
("constrained_boneB", "Other Bone Space", "Evaluate target in specified other bone space")],
name="Space",
description="In which space should Point type target be evaluated",
- update=updateConstraint)
+ update=setConstraint)
type = bpy.props.EnumProperty(name="Type of constraint",
items=[("point", "Maintain Position", "Bone is at a specific point"),
("freeze", "Maintain Position at frame", "Bone does not move from location specified in target frame"),
@@ -148,7 +148,14 @@ def toggleIKBone(self, context):
if not bone.is_in_ik_chain:
bone.IKRetarget = False
+
+class MocapMapping(bpy.types.PropertyGroup):
+ name = bpy.props.StringProperty()
+
+bpy.utils.register_class(MocapMapping)
+
bpy.types.Bone.map = bpy.props.StringProperty()
+bpy.types.Bone.reverseMap = bpy.props.CollectionProperty(type=MocapMapping)
bpy.types.Bone.foot = bpy.props.BoolProperty(name="Foot",
description="Marks this bone as a 'foot', which determines retargeted animation's translation",
default=False)
@@ -225,6 +232,7 @@ class MocapPanel(bpy.types.Panel):
else:
row.label(" ")
row.label(" ")
+ self.layout.operator("mocap.savemapping", text='Save mapping')
self.layout.operator("mocap.retarget", text='RETARGET!')
@@ -283,9 +291,49 @@ class OBJECT_OT_RetargetButton(bpy.types.Operator):
bl_label = "Retargets active action from Performer to Enduser"
def execute(self, context):
- retarget.totalRetarget()
+ enduser_obj = context.active_object
+ performer_obj = [obj for obj in context.selected_objects if obj != enduser_obj]
+ if enduser_obj is None or len(performer_obj) != 1:
+ print("Need active and selected armatures")
+ else:
+ performer_obj = performer_obj[0]
+ scene = context.scene
+ s_frame = scene.frame_start
+ e_frame = scene.frame_end
+ retarget.totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame)
+ return {"FINISHED"}
+
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature)
+ performer_obj = [obj for obj in context.selected_objects if obj != context.active_object]
+ if performer_obj:
+ return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature)
+ else:
+ return False
+
+
+class OBJECT_OT_SaveMappingButton(bpy.types.Operator):
+ bl_idname = "mocap.savemapping"
+ bl_label = "Saves user generated mapping from Performer to Enduser"
+
+ def execute(self, context):
+ enduser_obj = bpy.context.active_object
+ performer_obj = [obj for obj in bpy.context.selected_objects if obj != enduser_obj][0]
+ retarget.createDictionary(performer_obj.data, enduser_obj.data)
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature)
+ performer_obj = [obj for obj in context.selected_objects if obj != context.active_object]
+ if performer_obj:
+ return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature)
+ else:
+ return False
+
class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator):
bl_idname = "mocap.samples"
@@ -295,6 +343,10 @@ class OBJECT_OT_ConvertSamplesButton(bpy.types.Operator):
mocap_tools.fcurves_simplify()
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ return context.active_object.animation_data
+
class OBJECT_OT_LooperButton(bpy.types.Operator):
bl_idname = "mocap.looper"
@@ -304,6 +356,10 @@ class OBJECT_OT_LooperButton(bpy.types.Operator):
mocap_tools.autoloop_anim()
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ return context.active_object.animation_data
+
class OBJECT_OT_DenoiseButton(bpy.types.Operator):
bl_idname = "mocap.denoise"
@@ -313,6 +369,14 @@ class OBJECT_OT_DenoiseButton(bpy.types.Operator):
mocap_tools.denoise_median()
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ return context.active_object
+
+ @classmethod
+ def poll(cls, context):
+ return context.active_object.animation_data
+
class OBJECT_OT_LimitDOFButton(bpy.types.Operator):
bl_idname = "mocap.limitdof"
@@ -321,6 +385,16 @@ class OBJECT_OT_LimitDOFButton(bpy.types.Operator):
def execute(self, context):
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ activeIsArmature = isinstance(context.active_object.data, bpy.types.Armature)
+ performer_obj = [obj for obj in context.selected_objects if obj != context.active_object]
+ if performer_obj:
+ return activeIsArmature and isinstance(performer_obj[0].data, bpy.types.Armature)
+ else:
+ return False
+
class OBJECT_OT_RotateFixArmature(bpy.types.Operator):
bl_idname = "mocap.rotate_fix"
@@ -330,8 +404,10 @@ class OBJECT_OT_RotateFixArmature(bpy.types.Operator):
mocap_tools.rotate_fix_armature(context.active_object.data)
return {"FINISHED"}
- #def poll(self, context):
- # return context.active_object.data in bpy.data.armatures
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ return isinstance(context.active_object.data, bpy.types.Armature)
class OBJECT_OT_AddMocapConstraint(bpy.types.Operator):
@@ -344,6 +420,11 @@ class OBJECT_OT_AddMocapConstraint(bpy.types.Operator):
new_mcon = enduser_arm.mocap_constraints.add()
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ return isinstance(context.active_object.data, bpy.types.Armature)
+
class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator):
bl_idname = "mocap.removeconstraint"
@@ -362,6 +443,11 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator):
m_constraints.remove(self.constraint)
return {"FINISHED"}
+ @classmethod
+ def poll(cls, context):
+ if context.active_object:
+ return isinstance(context.active_object.data, bpy.types.Armature)
+
def register():
bpy.utils.register_module(__name__)