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-14 17:26:23 +0400
committerBenjy Cook <benjycook@hotmail.com>2011-07-14 17:26:23 +0400
commitb3714ec8ed1718979394615cadddbb39bff17951 (patch)
tree01f30ef52b299269eba0fb90087d391635e467f1 /release/scripts/modules
parentad08de4c2afda4456585f6e9bb462be1143f9c14 (diff)
Bugfix: Baking mocap constraints now works for user created IK bones
Diffstat (limited to 'release/scripts/modules')
-rw-r--r--release/scripts/modules/mocap_constraints.py150
-rw-r--r--release/scripts/modules/retarget.py25
2 files changed, 109 insertions, 66 deletions
diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py
index f4d96d6a5d0..56589403ce2 100644
--- a/release/scripts/modules/mocap_constraints.py
+++ b/release/scripts/modules/mocap_constraints.py
@@ -40,6 +40,7 @@ def getConsObj(bone):
def consObjToBone(cons_obj):
+ #Utility function - returns related bone from ik object
if cons_obj.name[-3:] == "Org":
return cons_obj.name[:-3]
else:
@@ -49,26 +50,31 @@ def consObjToBone(cons_obj):
def addNewConstraint(m_constraint, cons_obj):
+ #Decide the correct Blender constraint according to the Mocap constraint type
if m_constraint.type == "point" or m_constraint.type == "freeze":
c_type = "LIMIT_LOCATION"
if m_constraint.type == "distance":
c_type = "LIMIT_DISTANCE"
if m_constraint.type == "floor":
c_type = "FLOOR"
+ #create and store the new constraint within m_constraint
real_constraint = cons_obj.constraints.new(c_type)
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
+ #set the rest of the constraint properties
setConstraint(m_constraint, bpy.context)
def removeConstraint(m_constraint, cons_obj):
+ #remove the influence fcurve and Blender constraint
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.
+### Update functions. There are 3: UpdateType/Bone
+### update framing (deals with changes in the desired frame range)
+### And setConstraint which deals with the rest
def updateConstraintBoneType(m_constraint, context):
@@ -93,7 +99,9 @@ def setConstraintFraming(m_constraint, context):
bone = bones[m_constraint.constrained_bone]
cons_obj = getConsObj(bone)
real_constraint = cons_obj.constraints[m_constraint.real_constraint]
+ #remove the old keyframes
removeInfluenceFcurve(cons_obj, obj, real_constraint)
+ #set the new ones according to the m_constraint properties
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
@@ -105,12 +113,14 @@ def setConstraintFraming(m_constraint, context):
def removeInfluenceFcurve(cons_obj, obj, real_constraint):
+ #Determine if the constrained object is a bone or an empty
if isinstance(cons_obj, bpy.types.PoseBone):
fcurves = obj.animation_data.action.fcurves
else:
fcurves = cons_obj.animation_data.action.fcurves
-
+ #Find the RNA data path of the constraint's influence
influence_RNA = real_constraint.path_from_id("influence")
+ #Retrieve the correct fcurve via the RNA data path and remove it
fcurve = [fcurve for fcurve in fcurves if fcurve.data_path == influence_RNA]
#clear the fcurve and set the frames.
if fcurve:
@@ -131,7 +141,7 @@ def setConstraint(m_constraint, context):
real_constraint = cons_obj.constraints[m_constraint.real_constraint]
#frame changing section
- #setConstraintFraming(m_constraint, cons_obj, obj, real_constraint)
+ setConstraintFraming(m_constraint, context)
#Set the blender constraint parameters
if m_constraint.type == "point":
@@ -154,7 +164,7 @@ def setConstraint(m_constraint, context):
real_constraint.owner_space = m_constraint.targetSpace
bpy.context.scene.frame_set(m_constraint.s_frame)
if isinstance(cons_obj, bpy.types.PoseBone):
- x, y, z = cons_obj.center + (cons_obj.vector / 2)
+ x, y, z = cons_obj.bone.center + (cons_obj.bone.vector / 2) + obj.matrix_world.to_translation()
else:
x, y, z = cons_obj.matrix_world.to_translation()
@@ -178,82 +188,100 @@ def setConstraint(m_constraint, context):
real_constraint.distance = m_constraint.targetDist
# active/baked check
- real_constraint.mute = (not m_constraint.active) and (m_constraint.baked)
-
+ real_constraint.mute = (not m_constraint.active)
-def updateBake(self, context):
- if self.baked:
- print("baking...")
- bakeConstraint(self, context)
- else:
- print("unbaking...")
- unbakeConstraint(self, context)
-
-def bakeTransformFK(anim_data, s_frame, e_frame, end_bone, bones, cons_obj):
- mute_ik = False
+def locBake(s_frame, e_frame, bones):
+ scene = bpy.context.scene
+ bakeDict = {}
+ for bone in bones:
+ bakeDict[bone.name] = {}
+ for t in range(s_frame, e_frame):
+ scene.frame_set(t)
+ for bone in bones:
+ bakeDict[bone.name][t] = bone.matrix.copy()
+ for t in range(s_frame, e_frame):
+ for bone in bones:
+ print(bone.bone.matrix_local.to_translation())
+ bone.matrix = bakeDict[bone.name][t]
+ bone.keyframe_insert("location", frame=t)
+
+
+# Baking function which bakes all bones effected by the constraint
+def bakeAllConstraints(obj, s_frame, e_frame, bones):
for bone in bones:
bone.bone.select = False
- ik = hasIKConstraint(end_bone)
- if not isinstance(cons_obj, bpy.types.PoseBone) and ik:
- if ik.chain_count == 0:
- selectedBones = bones
+ selectedBones = [] # Marks bones that need a full bake
+ simpleBake = [] # Marks bones that need only a location bake
+ for end_bone in bones:
+ if end_bone.name in [m_constraint.real_constraint_bone for m_constraint in obj.data.mocap_constraints]:
+ #For all bones that have a constraint:
+ ik = hasIKConstraint(end_bone)
+ cons_obj = getConsObj(end_bone)
+ if ik:
+ #If it's an auto generated IK:
+ if ik.chain_count == 0:
+ selectedBones += bones # Chain len 0, bake everything
+ else:
+ selectedBones += [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1] # Bake the chain
else:
- selectedBones = [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1]
- mute_ik = True
- else:
- selectedBones = [end_bone]
- print(selectedBones)
+ #It's either an FK bone which we should just bake
+ #OR a user created IK target bone
+ simpleBake += [end_bone]
for bone in selectedBones:
bone.bone.select = True
- anim_data.action = nla.bake(s_frame,
- e_frame, action=anim_data.action)
- return mute_ik
-
-
-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)
- 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)
- ik_con.mute = True
- real_constraint = cons_obj.constraints[m_constraint.real_constraint]
- real_constraint.mute = True
constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"]
constraintStrip = constraintTrack.strips[0]
constraintStrip.action_frame_start = s_frame
constraintStrip.action_frame_end = e_frame
constraintStrip.frame_start = s_frame
constraintStrip.frame_end = e_frame
+ if selectedBones:
+ #Use bake function from NLA Bake Action operator
+ nla.bake(s_frame, e_frame, action=constraintStrip.action, only_selected=True, do_pose=True, do_object=False)
+ if simpleBake:
+ #Do a "simple" bake, location only, world space only.
+ locBake(s_frame, e_frame, simpleBake)
-def unbakeConstraint(m_constraint, context):
- # to unbake a constraint we need to delete the whole strip
- # and rebake all the other constraints
+#Calls the baking function and decativates releveant constraints
+def bakeConstraints(context):
+ obj = context.active_object
+ bones = obj.pose.bones
+ s_frame, e_frame = context.scene.frame_start, context.scene.frame_end
+ #Bake relevant bones
+ bakeAllConstraints(obj, s_frame, e_frame, bones)
+ for m_constraint in obj.data.mocap_constraints:
+ end_bone = bones[m_constraint.real_constraint_bone]
+ cons_obj = getConsObj(end_bone)
+ # It's a control empty: turn the ik off
+ if not isinstance(cons_obj, bpy.types.PoseBone):
+ ik_con = hasIKConstraint(end_bone)
+ if ik_con:
+ ik_con.mute = True
+ # Deactivate related Blender Constraint
+ m_constraint.active = False
+
+
+#Deletes the baked fcurves and reactivates relevant constraints
+def unbakeConstraints(context):
+ # to unbake constraints we delete the whole strip
obj = context.active_object
bones = obj.pose.bones
- end_bone = bones[m_constraint.constrained_bone]
- cons_obj = getConsObj(end_bone)
scene = bpy.context.scene
constraintTrack = obj.animation_data.nla_tracks["Mocap constraints"]
constraintStrip = constraintTrack.strips[0]
action = constraintStrip.action
+ # delete the fcurves on the strip
for fcurve in action.fcurves:
action.fcurves.remove(fcurve)
- for other_m_constraint in obj.data.mocap_constraints:
- if m_constraint != other_m_constraint:
- bakeConstraint(other_m_constraint)
- # It's a control empty: turn the ik back on
- if not isinstance(cons_obj, bpy.types.PoseBone):
- ik_con = hasIKConstraint(end_bone)
- if ik_con:
- ik_con.mute = False
- real_constraint = cons_obj.constraints[m_constraint.real_constraint]
- real_constraint.mute = False
+ # reactivate relevant constraints
+ for m_constraint in obj.data.mocap_constraints:
+ end_bone = bones[m_constraint.real_constraint_bone]
+ cons_obj = getConsObj(end_bone)
+ # It's a control empty: turn the ik back on
+ if not isinstance(cons_obj, bpy.types.PoseBone):
+ ik_con = hasIKConstraint(end_bone)
+ if ik_con:
+ ik_con.mute = False
+ m_constraint.active = True
diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py
index ef1bc7a1488..f8d424fbb5a 100644
--- a/release/scripts/modules/retarget.py
+++ b/release/scripts/modules/retarget.py
@@ -49,10 +49,15 @@ def createDictionary(perf_arm, end_arm):
root = end_arm.bones[0].name
feetBones = [bone.name for bone in perf_arm.bones if bone.foot]
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
-# these help with constraining, etc.
+
+
+def loadMapping(perf_arm, end_arm):
+
+ for end_bone in end_arm.bones:
+ #find its match and add perf_bone to the match's mapping
+ if end_bone.reverseMap:
+ for perf_bone in end_bone.reverseMap:
+ perf_arm.bones[perf_bone.name].map = end_bone.name
#creation of intermediate armature
# the intermediate armature has the hiearchy of the end user,
@@ -248,11 +253,13 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, root, s_frame, e_frame
stride_bone.name = "stride_bone"
if linearAvg:
+ #determine the average change in scale needed
avg = sum(linearAvg) / len(linearAvg)
scene.frame_set(s_frame)
initialPos = (tailLoc(perf_bones[perfRoot]) / avg)
for t in range(s_frame, e_frame):
scene.frame_set(t)
+ #calculate the new position, by dividing by the found ratio between performer and enduser
newTranslation = (tailLoc(perf_bones[perfRoot]) / avg)
stride_bone.location = (newTranslation - initialPos) * enduser_obj_mat
stride_bone.keyframe_insert("location")
@@ -281,6 +288,7 @@ def IKRetarget(performer_obj, enduser_obj, s_frame, e_frame, scene):
else:
target = ik_constraint.target
+ # bake the correct locations for the ik target bones
for t in range(s_frame, e_frame):
scene.frame_set(t)
if target_is_bone:
@@ -308,15 +316,17 @@ def turnOffIK(enduser_obj):
ik_constraint.mute = True
+#copy the object matrixes and clear them (to be reinserted later)
def cleanAndStoreObjMat(performer_obj, enduser_obj):
perf_obj_mat = performer_obj.matrix_world.copy()
enduser_obj_mat = enduser_obj.matrix_world.copy()
- zero_mat = Matrix() # Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0)))
+ zero_mat = Matrix()
performer_obj.matrix_world = zero_mat
enduser_obj.matrix_world = zero_mat
return perf_obj_mat, enduser_obj_mat
+#restore the object matrixes after parenting the auto generated IK empties
def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, stride_bone):
pose_bones = enduser_obj.pose.bones
for pose_bone in pose_bones:
@@ -328,6 +338,7 @@ def restoreObjMat(performer_obj, enduser_obj, perf_obj_mat, enduser_obj_mat, str
enduser_obj.parent = stride_bone
+#create (or return if exists) the related IK empty to the bone
def originalLocationTarget(end_bone):
if not end_bone.name + "Org" in bpy.data.objects:
bpy.ops.object.add()
@@ -339,6 +350,7 @@ def originalLocationTarget(end_bone):
return empty
+#create the specified NLA setup for base animation, constraints and tweak layer.
def NLASystemInitialize(enduser_obj, s_frame):
anim_data = enduser_obj.animation_data
mocapAction = anim_data.action
@@ -351,10 +363,13 @@ def NLASystemInitialize(enduser_obj, s_frame):
constraintTrack.name = "Mocap constraints"
constraintAction = bpy.data.actions.new("Mocap constraints")
constraintStrip = constraintTrack.strips.new("Mocap constraints", s_frame, constraintAction)
+ constraintStrip.extrapolation = "NOTHING"
anim_data.nla_tracks.active = constraintTrack
anim_data.action = constraintAction
+ anim_data.action_extrapolation = "NOTHING"
+#Main function that runs the retargeting sequence.
def totalRetarget(performer_obj, enduser_obj, scene, s_frame, e_frame):
perf_arm = performer_obj.data
end_arm = enduser_obj.data