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-02 22:24:05 +0400
committerBenjy Cook <benjycook@hotmail.com>2011-07-02 22:24:05 +0400
commit8c3f2923fdc0626d4c2e7f6307c1ec4fd0e8c7f3 (patch)
treef4cd3bf908ce9c1138aeb9b4b8a35a6e9425372d /release/scripts
parent87030e6a320b6bc770ab7055e73c9d3a7dacc4f3 (diff)
Early commit of mocap constraint work. Still very much a WIP, but Point constraints should work - but buggy.
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/modules/mocap_constraints.py141
-rw-r--r--release/scripts/modules/retarget.py37
-rw-r--r--release/scripts/startup/ui_mocap.py117
3 files changed, 227 insertions, 68 deletions
diff --git a/release/scripts/modules/mocap_constraints.py b/release/scripts/modules/mocap_constraints.py
new file mode 100644
index 00000000000..1251786d882
--- /dev/null
+++ b/release/scripts/modules/mocap_constraints.py
@@ -0,0 +1,141 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from mathutils import *
+
+### 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"]
+ if ik:
+ ik = ik[0]
+ cons_obj = ik.target
+ if ik.subtarget:
+ cons_obj = ik.target.pose.bones[ik.subtarget]
+ else:
+ cons_obj = bone
+ return cons_obj
+
+### And and Remove Constraints (called from operators)
+
+
+def addNewConstraint(m_constraint, cons_obj):
+ 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"
+ real_constraint = cons_obj.constraints.new(c_type)
+ real_constraint.name = "Mocap constraint " + str(len(cons_obj.constraints))
+ m_constraint.real_constraint_bone = cons_obj.name
+ m_constraint.real_constraint = real_constraint.name
+ setConstraint(m_constraint)
+
+
+def removeConstraint(m_constraint, cons_obj):
+ oldConstraint = cons_obj.constraints[m_constraint.real_constraint]
+ cons_obj.constraints.remove(oldConstraint)
+
+### Update functions. There are 3: UpdateType, UpdateBone
+### and update for the others.
+
+
+def updateConstraint(self, context):
+ setConstraint(self)
+
+
+def updateConstraintType(m_constraint, context):
+ pass
+ #If the constraint exists, we need to remove it
+ #Then create a new one.
+
+
+def updateConstraintTargetBone(m_constraint, context):
+ #If the constraint exists, we need to remove it
+ #from the old bone
+ obj = context.active_object
+ bones = obj.pose.bones
+ if m_constraint.real_constraint:
+ bone = bones[m_constraint.real_constraint_bone]
+ cons_obj = getConsObj(bone)
+ removeConstraint(m_constraint, cons_obj)
+ #Regardless, after that we create a new constraint
+ bone = bones[m_constraint.constrained_bone]
+ cons_obj = getConsObj(bone)
+ 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 setConstraint(m_constraint):
+ if not m_constraint.constrained_bone:
+ return
+ obj = bpy.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
+ fcurves = obj.animation_data.action.fcurves
+ influence_RNA = real_constraint.path_from_id("influence")
+ 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 = bpy.context.scene.frame_start, bpy.context.scene.frame_end
+ real_constraint.influence = 0
+ real_constraint.keyframe_insert(data_path="influence", frame=s)
+ real_constraint.keyframe_insert(data_path="influence", frame=e)
+ s, e = m_constraint.s_frame, m_constraint.e_frame
+ 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 - 10)
+ real_constraint.keyframe_insert(data_path="influence", frame=e + 10)
+
+ #Set the blender constraint parameters
+ if m_constraint.type == "point":
+ real_constraint.target_space = "WORLD" # temporary for now, just World is supported
+ x, y, z = m_constraint.targetPoint
+ real_constraint.max_x = x
+ real_constraint.max_y = y
+ real_constraint.max_z = z
+ real_constraint.min_x = x
+ real_constraint.min_y = y
+ real_constraint.min_z = z
+ real_constraint.use_max_x = True
+ real_constraint.use_max_y = True
+ real_constraint.use_max_z = True
+ real_constraint.use_min_x = True
+ real_constraint.use_min_y = True
+ real_constraint.use_min_z = True
diff --git a/release/scripts/modules/retarget.py b/release/scripts/modules/retarget.py
index 7688f9657a2..3ce90f64075 100644
--- a/release/scripts/modules/retarget.py
+++ b/release/scripts/modules/retarget.py
@@ -71,13 +71,13 @@ def createIntermediate(performer_obj, enduser_obj, bonemap, bonemapr, root, s_fr
#useful for storing the important data in the original motion
#i.e. using this empty to IK the chain to that pos / DEBUG
def locOfOriginal(inter_bone, perf_bone):
- if not perf_bone.name + "Org" in bpy.data.objects:
+ if not inter_bone.name + "Org" in bpy.data.objects:
bpy.ops.object.add()
empty = bpy.context.active_object
- empty.name = perf_bone.name + "Org"
+ empty.name = inter_bone.name + "Org"
empty.empty_draw_size = 0.1
#empty.parent = enduser_obj
- empty = bpy.data.objects[perf_bone.name + "Org"]
+ empty = bpy.data.objects[inter_bone.name + "Org"]
offset = perf_bone.vector
if inter_bone.length == 0 or perf_bone.length == 0:
scaling = 1
@@ -263,17 +263,17 @@ def copyTranslation(performer_obj, enduser_obj, perfFeet, bonemap, bonemapr, roo
#end bone's delta
if endV.length != 0:
linearAvg.append(hipV.length / endV.length)
-
+
bpy.ops.object.add()
stride_bone = bpy.context.active_object
stride_bone.name = "stride_bone"
-
+
if linearAvg:
avg = sum(linearAvg) / len(linearAvg)
for t in range(s_frame, e_frame):
scene.frame_set(t)
newTranslation = (tailLoc(perf_bones[perfRoot]) / avg)
- stride_bone.location = newTranslation
+ stride_bone.location = newTranslation * enduser_obj.matrix_world
stride_bone.keyframe_insert("location")
return stride_bone
@@ -287,7 +287,7 @@ def IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame,
perf_bone = bonemapr[pose_bone.name]
if isinstance(perf_bone, list):
perf_bone = bonemapr[pose_bone.name][-1]
- end_empty = bpy.data.objects[perf_bone + "Org"]
+ end_empty = bpy.data.objects[pose_bone.name + "Org"]
ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0]
if not ik_constraint.target:
ik_constraint.target = end_empty
@@ -326,23 +326,26 @@ def turnOffIK(enduser_obj):
ik_constraint = [constraint for constraint in pose_bone.constraints if constraint.type == "IK"][0]
ik_constraint.mute = True
-def cleanAndStoreObjMat(performer_obj,enduser_obj):
+
+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() # Matrix(((0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0)))
performer_obj.matrix_world = zero_mat
enduser_obj.matrix_world = zero_mat
return perf_obj_mat, enduser_obj_mat
-def restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat):
- perf_bones = performer_obj.pose.bones
- for perf_bone in perf_bones:
- if perf_bone.name + "Org" in bpy.data.objects:
- empty = bpy.data.objects[perf_bone.name + "Org"]
+
+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:
+ if pose_bone.name + "Org" in bpy.data.objects:
+ empty = bpy.data.objects[pose_bone.name + "Org"]
empty.parent = enduser_obj
performer_obj.matrix_world = perf_obj_mat
enduser_obj.matrix_world = enduser_obj_mat
+
def totalRetarget():
print("retargeting...")
enduser_obj = bpy.context.active_object
@@ -357,16 +360,16 @@ def totalRetarget():
s_frame = scene.frame_start
e_frame = scene.frame_end
bonemap, bonemapr, root = createDictionary(perf_arm)
- perf_obj_mat, enduser_obj_mat = cleanAndStoreObjMat(performer_obj,enduser_obj)
+ 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, ["RightFoot", "LeftFoot"], bonemap, bonemapr, root, s_frame, e_frame, scene)
IKRetarget(bonemap, bonemapr, performer_obj, enduser_obj, s_frame, e_frame, scene)
- restoreObjMat(performer_obj,enduser_obj,perf_obj_mat,enduser_obj_mat)
+ 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()
if __name__ == "__main__":
- totalRetarget() \ No newline at end of file
+ totalRetarget()
diff --git a/release/scripts/startup/ui_mocap.py b/release/scripts/startup/ui_mocap.py
index 4abc777f59e..4273eb74984 100644
--- a/release/scripts/startup/ui_mocap.py
+++ b/release/scripts/startup/ui_mocap.py
@@ -19,12 +19,10 @@
# <pep8 compliant>
import bpy
-import time
from bpy.props import *
from bpy import *
-from mathutils import Vector
-from math import isfinite
+from mocap_constraints import *
# MocapConstraint class
# Defines MocapConstraint datatype, used to add and configute mocap constraints
@@ -32,49 +30,62 @@ from math import isfinite
class MocapConstraint(bpy.types.PropertyGroup):
- name = bpy.props.StringProperty(name = "Name",
- default = "Mocap Constraint",
- description = "Name of Mocap Constraint")
- boneA = bpy.props.StringProperty(name = "Bone",
- default = "",
- description = "Constrained Bone")
- boneB = bpy.props.StringProperty(name = "Bone (2)",
- default = "",
- description = "Other Constrained Bone (optional, depends on type)")
- s_frame = bpy.props.IntProperty(name = "S",
- default = 1,
- description = "Start frame of constraint")
- e_frame = bpy.props.IntProperty(name = "E",
- default = 500,
- description = "End frame of constrain")
- targetMesh = bpy.props.StringProperty(name = "Mesh",
- default = "",
- description = "Target of Constraint - Mesh (optional, depends on type)")
- active = bpy.props.BoolProperty(name = "Active",
- default = True,
- description = "Constraint is active")
- baked = bpy.props.BoolProperty(name = "Baked / Applied",
- default = False,
- description = "Constraint has been baked to NLA layer")
- targetFrame = bpy.props.IntProperty(name = "Frame",
- default = 1,
- description = "Target of Constraint - Frame (optional, depends on type)")
- targetPoint = bpy.props.FloatVectorProperty(name = "Point", size = 3,
- subtype = "XYZ", default = (0.0, 0.0, 0.0),
- description = "Target of Constraint - Point")
+ name = bpy.props.StringProperty(name="Name",
+ default="Mocap Constraint",
+ description="Name of Mocap Constraint",
+ update=updateConstraint)
+ constrained_bone = bpy.props.StringProperty(name="Bone",
+ default="",
+ description="Constrained Bone",
+ update=updateConstraintTargetBone)
+ constrained_boneB = bpy.props.StringProperty(name="Bone (2)",
+ default="",
+ description="Other Constrained Bone (optional, depends on type)",
+ update=updateConstraint)
+ s_frame = bpy.props.IntProperty(name="S",
+ default=1,
+ description="Start frame of constraint",
+ update=updateConstraint)
+ e_frame = bpy.props.IntProperty(name="E",
+ default=500,
+ description="End frame of constrain",
+ update=updateConstraint)
+ targetMesh = bpy.props.StringProperty(name="Mesh",
+ default="",
+ description="Target of Constraint - Mesh (optional, depends on type)",
+ update=updateConstraint)
+ active = bpy.props.BoolProperty(name="Active",
+ default=True,
+ description="Constraint is active",
+ update=updateConstraint)
+ baked = bpy.props.BoolProperty(name="Baked / Applied",
+ default=False,
+ description="Constraint has been baked to NLA layer",
+ update=updateConstraint)
+ targetFrame = bpy.props.IntProperty(name="Frame",
+ default=1,
+ description="Target of Constraint - Frame (optional, depends on type)",
+ update=updateConstraint)
+ targetPoint = bpy.props.FloatVectorProperty(name="Point", size=3,
+ subtype="XYZ", default=(0.0, 0.0, 0.0),
+ description="Target of Constraint - Point",
+ update=updateConstraint)
targetSpace = bpy.props.EnumProperty(
- items = [("world", "World Space", "Evaluate target in global space"),
+ items=[("world", "World Space", "Evaluate target in global space"),
("object", "Object space", "Evaluate target in object space"),
- ("boneb", "Other Bone Space", "Evaluate target in specified other bone space")],
- name = "Space",
- description = "In which space should Point type target be evaluated")
+ ("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)
type = bpy.props.EnumProperty(name="Type of constraint",
- items = [("point", "Maintain Position", "Bone is at a specific point"),
+ 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"),
("floor", "Stay above", "Bone does not cross specified mesh object eg floor"),
("distance", "Maintain distance", "Target bones maintained specified distance")],
- description = "Type of constraint")
- realConstraint = bpy.props.StringProperty()
+ description="Type of constraint",
+ update=updateConstraint)
+ real_constraint = bpy.props.StringProperty()
+ real_constraint_bone = bpy.props.StringProperty()
bpy.utils.register_class(MocapConstraint)
@@ -112,9 +123,9 @@ def toggleIKBone(self, context):
bone.IKRetarget = False
bpy.types.Bone.map = bpy.props.StringProperty()
-bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name = "IK",
- description = "Toggles IK Retargeting method for given bone",
- update = toggleIKBone, default = False)
+bpy.types.PoseBone.IKRetarget = bpy.props.BoolProperty(name="IK",
+ description="Toggles IK Retargeting method for given bone",
+ update=toggleIKBone, default=False)
def hasIKConstraint(pose_bone):
@@ -207,15 +218,15 @@ class MocapConstraintsPanel(bpy.types.Panel):
if context.active_object.data.name in bpy.data.armatures:
enduser_obj = context.active_object
enduser_arm = enduser_obj.data
- layout.operator("mocap.addconstraint", text = 'Add constraint')
+ layout.operator("mocap.addconstraint")
layout.separator()
for i, m_constraint in enumerate(enduser_arm.mocap_constraints):
box = layout.box()
box.prop(m_constraint, 'name')
box.prop(m_constraint, 'type')
- box.prop_search(m_constraint, 'boneA', enduser_obj.pose, "bones")
+ box.prop_search(m_constraint, 'constrained_bone', enduser_obj.pose, "bones")
if m_constraint.type == "distance" or m_constraint.type == "point":
- box.prop_search(m_constraint, 'boneB', enduser_obj.pose, "bones")
+ box.prop_search(m_constraint, 'constrained_boneB', enduser_obj.pose, "bones")
frameRow = box.row()
frameRow.label("Frame Range:")
frameRow.prop(m_constraint, 's_frame')
@@ -234,7 +245,7 @@ class MocapConstraintsPanel(bpy.types.Panel):
checkRow = box.row()
checkRow.prop(m_constraint, 'active')
checkRow.prop(m_constraint, 'baked')
- layout.operator("mocap.removeconstraint", text = "Remove constraint").constraint = i
+ layout.operator("mocap.removeconstraint", text="Remove constraint").constraint = i
layout.separator()
@@ -288,7 +299,7 @@ class OBJECT_OT_AddMocapConstraint(bpy.types.Operator):
def execute(self, context):
enduser_obj = bpy.context.active_object
enduser_arm = enduser_obj.data
- newCon = enduser_arm.mocap_constraints.add()
+ new_mcon = enduser_arm.mocap_constraints.add()
return {"FINISHED"}
@@ -300,8 +311,13 @@ class OBJECT_OT_RemoveMocapConstraint(bpy.types.Operator):
def execute(self, context):
enduser_obj = bpy.context.active_object
enduser_arm = enduser_obj.data
- constraints = enduser_arm.mocap_constraints
- constraints.remove(self.constraint)
+ m_constraints = enduser_arm.mocap_constraints
+ m_constraint = m_constraints[self.constraint]
+ if m_constraint.real_constraint:
+ bone = enduser_obj.pose.bones[m_constraint.real_constraint_bone]
+ cons_obj = getConsObj(bone)
+ removeConstraint(m_constraint, cons_obj)
+ m_constraints.remove(self.constraint)
return {"FINISHED"}
@@ -312,6 +328,5 @@ def register():
def unregister():
bpy.utils.unregister_module(__name__)
-
if __name__ == "__main__":
register()