~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to release/scripts/addons/mocap/mocap_constraints.py

  • Committer: Package Import Robot
  • Author(s): Matteo F. Vescovi
  • Date: 2012-07-23 08:54:18 UTC
  • mfrom: (14.2.16 sid)
  • mto: (14.2.19 sid)
  • mto: This revision was merged to the branch mainline in revision 42.
  • Revision ID: package-import@ubuntu.com-20120723085418-9foz30v6afaf5ffs
Tags: 2.63a-2
* debian/: Cycles support added (Closes: #658075)
  For now, this top feature has been enabled only
  on [any-amd64 any-i386] architectures because
  of OpenImageIO failing on all others
* debian/: scripts installation path changed
  from /usr/lib to /usr/share:
  + debian/patches/: patchset re-worked for path changing
  + debian/control: "Breaks" field added on yafaray-exporter

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# ##### BEGIN GPL LICENSE BLOCK #####
 
2
#
 
3
#  This program is free software; you can redistribute it and/or
 
4
#  modify it under the terms of the GNU General Public License
 
5
#  as published by the Free Software Foundation; either version 2
 
6
#  of the License, or (at your option) any later version.
 
7
#
 
8
#  This program is distributed in the hope that it will be useful,
 
9
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
#  GNU General Public License for more details.
 
12
#
 
13
#  You should have received a copy of the GNU General Public License
 
14
#  along with this program; if not, write to the Free Software Foundation,
 
15
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
16
#
 
17
# ##### END GPL LICENSE BLOCK #####
 
18
 
 
19
# <pep8 compliant>
 
20
 
 
21
import bpy
 
22
from mathutils import Vector
 
23
from bpy_extras import anim_utils
 
24
from .  import retarget
 
25
 
 
26
 
 
27
### Utility Functions
 
28
 
 
29
 
 
30
def getConsObj(bone):
 
31
    #utility function - returns related IK target if bone has IK
 
32
    ik = [constraint for constraint in bone.constraints if constraint.type == "IK"]
 
33
    if ik:
 
34
        ik = ik[0]
 
35
        cons_obj = ik.target
 
36
        if ik.subtarget:
 
37
            cons_obj = ik.target.pose.bones[ik.subtarget]
 
38
    else:
 
39
        cons_obj = bone
 
40
    return cons_obj
 
41
 
 
42
 
 
43
def consObjToBone(cons_obj):
 
44
    #Utility function - returns related bone from ik object
 
45
    if cons_obj.name[-3:] == "Org":
 
46
        return cons_obj.name[:-3]
 
47
    else:
 
48
        return cons_obj.name
 
49
 
 
50
### And and Remove Constraints (called from operators)
 
51
 
 
52
 
 
53
def addNewConstraint(m_constraint, cons_obj):
 
54
     #Decide the correct Blender constraint according to the Mocap constraint type
 
55
    if m_constraint.type == "point" or m_constraint.type == "freeze":
 
56
        c_type = "LIMIT_LOCATION"
 
57
    if m_constraint.type == "distance":
 
58
        c_type = "LIMIT_DISTANCE"
 
59
    if m_constraint.type == "floor":
 
60
        c_type = "LIMIT_LOCATION"
 
61
        #create and store the new constraint within m_constraint
 
62
    real_constraint = cons_obj.constraints.new(c_type)
 
63
    real_constraint.name = "Auto fixes " + str(len(cons_obj.constraints))
 
64
    m_constraint.real_constraint_bone = consObjToBone(cons_obj)
 
65
    m_constraint.real_constraint = real_constraint.name
 
66
    #set the rest of the constraint properties
 
67
    setConstraint(m_constraint, bpy.context)
 
68
 
 
69
 
 
70
def removeConstraint(m_constraint, cons_obj):
 
71
    #remove the influence fcurve and Blender constraint
 
72
    oldConstraint = cons_obj.constraints[m_constraint.real_constraint]
 
73
    removeFcurves(cons_obj, bpy.context.active_object, oldConstraint, m_constraint)
 
74
    cons_obj.constraints.remove(oldConstraint)
 
75
 
 
76
### Update functions. There are 3: UpdateType/Bone
 
77
### update framing (deals with changes in the desired frame range)
 
78
### And setConstraint which deals with the rest
 
79
 
 
80
 
 
81
def updateConstraintBoneType(m_constraint, context):
 
82
    #If the constraint exists, we need to remove it
 
83
    #from the old bone
 
84
    obj = context.active_object
 
85
    bones = obj.pose.bones
 
86
    if m_constraint.real_constraint:
 
87
        bone = bones[m_constraint.real_constraint_bone]
 
88
        cons_obj = getConsObj(bone)
 
89
        removeConstraint(m_constraint, cons_obj)
 
90
    #Regardless, after that we create a new constraint
 
91
    if m_constraint.constrained_bone:
 
92
        bone = bones[m_constraint.constrained_bone]
 
93
        cons_obj = getConsObj(bone)
 
94
        addNewConstraint(m_constraint, cons_obj)
 
95
 
 
96
 
 
97
def setConstraintFraming(m_constraint, context):
 
98
    obj = context.active_object
 
99
    bones = obj.pose.bones
 
100
    bone = bones[m_constraint.constrained_bone]
 
101
    cons_obj = getConsObj(bone)
 
102
    real_constraint = cons_obj.constraints[m_constraint.real_constraint]
 
103
    #remove the old keyframes
 
104
    removeFcurves(cons_obj, obj, real_constraint, m_constraint)
 
105
    #set the new ones according to the m_constraint properties
 
106
    s, e = m_constraint.s_frame, m_constraint.e_frame
 
107
    s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
 
108
    real_constraint.influence = 1
 
109
    real_constraint.keyframe_insert(data_path="influence", frame=s)
 
110
    real_constraint.keyframe_insert(data_path="influence", frame=e)
 
111
    real_constraint.influence = 0
 
112
    real_constraint.keyframe_insert(data_path="influence", frame=s - s_in)
 
113
    real_constraint.keyframe_insert(data_path="influence", frame=e + s_out)
 
114
 
 
115
 
 
116
def removeFcurves(cons_obj, obj, real_constraint, m_constraint):
 
117
    #Determine if the constrained object is a bone or an empty
 
118
    if isinstance(cons_obj, bpy.types.PoseBone):
 
119
        fcurves = obj.animation_data.action.fcurves
 
120
    else:
 
121
        fcurves = cons_obj.animation_data.action.fcurves
 
122
    #Find the RNA data path of the constraint's influence
 
123
    RNA_paths = []
 
124
    RNA_paths.append(real_constraint.path_from_id("influence"))
 
125
    if m_constraint.type == "floor" or m_constraint.type == "point":
 
126
        RNA_paths += [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")]
 
127
        RNA_paths += [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")]
 
128
        RNA_paths += [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")]
 
129
    #Retrieve the correct fcurve via the RNA data path and remove it
 
130
    fcurves_del = [fcurve for fcurve in fcurves if fcurve.data_path in RNA_paths]
 
131
    #clear the fcurve and set the frames.
 
132
    if fcurves_del:
 
133
        for fcurve in fcurves_del:
 
134
            fcurves.remove(fcurve)
 
135
    #remove armature fcurves (if user keyframed m_constraint properties)
 
136
    if obj.data.animation_data and m_constraint.type == "point":
 
137
        if obj.data.animation_data.action:
 
138
            path = m_constraint.path_from_id("targetPoint")
 
139
            m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path]
 
140
            for curve in m_fcurves:
 
141
                obj.data.animation_data.action.fcurves.remove(curve)
 
142
 
 
143
#Utility function for copying property fcurves over
 
144
 
 
145
 
 
146
def copyFCurve(newCurve, oldCurve):
 
147
    for point in oldCurve.keyframe_points:
 
148
        newCurve.keyframe_points.insert(frame=point.co.x, value=point.co.y)
 
149
 
 
150
#Creates new fcurves for the constraint properties (for floor and point)
 
151
 
 
152
 
 
153
def createConstraintFCurves(cons_obj, obj, real_constraint):
 
154
    if isinstance(cons_obj, bpy.types.PoseBone):
 
155
        c_fcurves = obj.animation_data.action.fcurves
 
156
    else:
 
157
        c_fcurves = cons_obj.animation_data.action.fcurves
 
158
    c_x_path = [real_constraint.path_from_id("max_x"), real_constraint.path_from_id("min_x")]
 
159
    c_y_path = [real_constraint.path_from_id("max_y"), real_constraint.path_from_id("min_y")]
 
160
    c_z_path = [real_constraint.path_from_id("max_z"), real_constraint.path_from_id("min_z")]
 
161
    c_constraints_path = c_x_path + c_y_path + c_z_path
 
162
    existing_curves = [fcurve for fcurve in c_fcurves if fcurve.data_path in c_constraints_path]
 
163
    if existing_curves:
 
164
        for curve in existing_curves:
 
165
            c_fcurves.remove(curve)
 
166
    xCurves, yCurves, zCurves = [], [], []
 
167
    for path in c_constraints_path:
 
168
        newCurve = c_fcurves.new(path)
 
169
        if path in c_x_path:
 
170
            xCurves.append(newCurve)
 
171
        elif path in c_y_path:
 
172
            yCurves.append(newCurve)
 
173
        else:
 
174
            zCurves.append(newCurve)
 
175
    return xCurves, yCurves, zCurves
 
176
 
 
177
 
 
178
# Function that copies all settings from m_constraint to the real Blender constraints
 
179
# Is only called when blender constraint already exists
 
180
 
 
181
 
 
182
def setConstraint(m_constraint, context):
 
183
    if not m_constraint.constrained_bone:
 
184
        return
 
185
    obj = context.active_object
 
186
    bones = obj.pose.bones
 
187
    bone = bones[m_constraint.constrained_bone]
 
188
    cons_obj = getConsObj(bone)
 
189
    real_constraint = cons_obj.constraints[m_constraint.real_constraint]
 
190
    NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap]
 
191
    obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track]
 
192
 
 
193
    #frame changing section
 
194
    setConstraintFraming(m_constraint, context)
 
195
    s, e = m_constraint.s_frame, m_constraint.e_frame
 
196
    s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
 
197
    s -= s_in
 
198
    e += s_out
 
199
    #Set the blender constraint parameters
 
200
    if m_constraint.type == "point":
 
201
        constraint_settings = False  # are fix settings keyframed?
 
202
        if not m_constraint.targetSpace == "constrained_boneB":
 
203
            real_constraint.owner_space = m_constraint.targetSpace
 
204
        else:
 
205
            real_constraint.owner_space = "LOCAL"
 
206
        if obj.data.animation_data:
 
207
            if obj.data.animation_data.action:
 
208
                path = m_constraint.path_from_id("targetPoint")
 
209
                m_fcurves = [fcurve for fcurve in obj.data.animation_data.action.fcurves if fcurve.data_path == path]
 
210
                if m_fcurves:
 
211
                    constraint_settings = True
 
212
                    xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint)
 
213
                    for curve in xCurves:
 
214
                        copyFCurve(curve, m_fcurves[0])
 
215
                    for curve in yCurves:
 
216
                        copyFCurve(curve, m_fcurves[1])
 
217
                    for curve in zCurves:
 
218
                        copyFCurve(curve, m_fcurves[2])
 
219
        if m_constraint.targetSpace == "constrained_boneB" and m_constraint.constrained_boneB:
 
220
            c_frame = context.scene.frame_current
 
221
            bakedPos = {}
 
222
            src_bone = bones[m_constraint.constrained_boneB]
 
223
            if not constraint_settings:
 
224
                xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint)
 
225
            print("please wait a moment, calculating fix")
 
226
            for t in range(s, e):
 
227
                context.scene.frame_set(t)
 
228
                src_bone_pos = src_bone.matrix.to_translation()
 
229
                bakedPos[t] = src_bone_pos + m_constraint.targetPoint  # final position for constrained bone in object space
 
230
            context.scene.frame_set(c_frame)
 
231
            for frame in bakedPos.keys():
 
232
                pos = bakedPos[frame]
 
233
                for xCurve in xCurves:
 
234
                    xCurve.keyframe_points.insert(frame=frame, value=pos.x)
 
235
                for yCurve in yCurves:
 
236
                    yCurve.keyframe_points.insert(frame=frame, value=pos.y)
 
237
                for zCurve in zCurves:
 
238
                    zCurve.keyframe_points.insert(frame=frame, value=pos.z)
 
239
 
 
240
        if not constraint_settings:
 
241
            x, y, z = m_constraint.targetPoint
 
242
            real_constraint.max_x = x
 
243
            real_constraint.max_y = y
 
244
            real_constraint.max_z = z
 
245
            real_constraint.min_x = x
 
246
            real_constraint.min_y = y
 
247
            real_constraint.min_z = z
 
248
            real_constraint.use_max_x = True
 
249
            real_constraint.use_max_y = True
 
250
            real_constraint.use_max_z = True
 
251
            real_constraint.use_min_x = True
 
252
            real_constraint.use_min_y = True
 
253
            real_constraint.use_min_z = True
 
254
 
 
255
    if m_constraint.type == "freeze":
 
256
        context.scene.frame_set(s)
 
257
        real_constraint.owner_space = m_constraint.targetSpace
 
258
        bpy.context.scene.frame_set(m_constraint.s_frame)
 
259
        if isinstance(cons_obj, bpy.types.PoseBone):
 
260
            vec = obj.matrix_world * (cons_obj.matrix.to_translation())
 
261
            #~ if obj.parent:
 
262
                #~ vec = obj.parent.matrix_world * vec
 
263
            x, y, z = vec
 
264
        else:
 
265
            x, y, z = cons_obj.matrix_world.to_translation()
 
266
 
 
267
        real_constraint.max_x = x
 
268
        real_constraint.max_y = y
 
269
        real_constraint.max_z = z
 
270
        real_constraint.min_x = x
 
271
        real_constraint.min_y = y
 
272
        real_constraint.min_z = z
 
273
        real_constraint.use_max_x = True
 
274
        real_constraint.use_max_y = True
 
275
        real_constraint.use_max_z = True
 
276
        real_constraint.use_min_x = True
 
277
        real_constraint.use_min_y = True
 
278
        real_constraint.use_min_z = True
 
279
 
 
280
    if m_constraint.type == "distance" and m_constraint.constrained_boneB:
 
281
        real_constraint.owner_space = "WORLD"
 
282
        real_constraint.target = obj
 
283
        real_constraint.subtarget = getConsObj(bones[m_constraint.constrained_boneB]).name
 
284
        real_constraint.limit_mode = "LIMITDIST_ONSURFACE"
 
285
        if m_constraint.targetDist < 0.01:
 
286
            m_constraint.targetDist = 0.01
 
287
        real_constraint.distance = m_constraint.targetDist
 
288
 
 
289
    if m_constraint.type == "floor" and m_constraint.targetMesh:
 
290
        real_constraint.mute = True
 
291
        real_constraint.owner_space = "WORLD"
 
292
        #calculate the positions thoughout the range
 
293
        s, e = m_constraint.s_frame, m_constraint.e_frame
 
294
        s_in, s_out = m_constraint.smooth_in, m_constraint.smooth_out
 
295
        s -= s_in
 
296
        e += s_out
 
297
        bakedPos = {}
 
298
        floor = bpy.data.objects[m_constraint.targetMesh]
 
299
        c_frame = context.scene.frame_current
 
300
        print("please wait a moment, calculating fix")
 
301
        for t in range(s, e):
 
302
            context.scene.frame_set(t)
 
303
            axis = obj.matrix_world.to_3x3() * Vector((0, 0, 100))
 
304
            offset = obj.matrix_world.to_3x3() * Vector((0, 0, m_constraint.targetDist))
 
305
            ray_origin = (cons_obj.matrix * obj.matrix_world).to_translation() - offset  # world position of constrained bone
 
306
            ray_target = ray_origin + axis
 
307
            #convert ray points to floor's object space
 
308
            ray_origin = floor.matrix_world.inverted() * ray_origin
 
309
            ray_target = floor.matrix_world.inverted() * ray_target
 
310
            hit, nor, ind = floor.ray_cast(ray_origin, ray_target)
 
311
            if hit != Vector((0, 0, 0)):
 
312
                bakedPos[t] = (floor.matrix_world * hit)
 
313
                bakedPos[t] += Vector((0, 0, m_constraint.targetDist))
 
314
            else:
 
315
                bakedPos[t] = (cons_obj.matrix * obj.matrix_world).to_translation()
 
316
        context.scene.frame_set(c_frame)
 
317
        #create keyframes for real constraint
 
318
        xCurves, yCurves, zCurves = createConstraintFCurves(cons_obj, obj, real_constraint)
 
319
        for frame in bakedPos.keys():
 
320
            pos = bakedPos[frame]
 
321
            for xCurve in xCurves:
 
322
                xCurve.keyframe_points.insert(frame=frame, value=pos.x)
 
323
            for yCurve in yCurves:
 
324
                yCurve.keyframe_points.insert(frame=frame, value=pos.y)
 
325
            for zCurve in zCurves:
 
326
                zCurve.keyframe_points.insert(frame=frame, value=pos.z)
 
327
        real_constraint.use_max_x = True
 
328
        real_constraint.use_max_y = True
 
329
        real_constraint.use_max_z = True
 
330
        real_constraint.use_min_x = True
 
331
        real_constraint.use_min_y = True
 
332
        real_constraint.use_min_z = True
 
333
 
 
334
    # active/baked check
 
335
    real_constraint.mute = (not m_constraint.active)
 
336
 
 
337
 
 
338
def locBake(s_frame, e_frame, bones):
 
339
    scene = bpy.context.scene
 
340
    bakeDict = {}
 
341
    for bone in bones:
 
342
        bakeDict[bone.name] = {}
 
343
    for t in range(s_frame, e_frame):
 
344
        scene.frame_set(t)
 
345
        for bone in bones:
 
346
            bakeDict[bone.name][t] = bone.matrix.copy()
 
347
    for t in range(s_frame, e_frame):
 
348
        for bone in bones:
 
349
            print(bone.bone.matrix_local.to_translation())
 
350
            bone.matrix = bakeDict[bone.name][t]
 
351
            bone.keyframe_insert("location", frame=t)
 
352
 
 
353
 
 
354
# Baking function which bakes all bones effected by the constraint
 
355
def bakeAllConstraints(obj, s_frame, e_frame, bones):
 
356
    for bone in bones:
 
357
        bone.bone.select = False
 
358
    selectedBones = []  # Marks bones that need a full bake
 
359
    simpleBake = []  # Marks bones that need only a location bake
 
360
    for end_bone in bones:
 
361
        if end_bone.name in [m_constraint.real_constraint_bone for m_constraint in obj.data.mocap_constraints]:
 
362
            #For all bones that have a constraint:
 
363
            ik = retarget.hasIKConstraint(end_bone)
 
364
            cons_obj = getConsObj(end_bone)
 
365
            if ik:
 
366
                #If it's an auto generated IK:
 
367
                if ik.chain_count == 0:
 
368
                    selectedBones += bones  # Chain len 0, bake everything
 
369
                else:
 
370
                    selectedBones += [end_bone] + end_bone.parent_recursive[:ik.chain_count - 1]  # Bake the chain
 
371
            else:
 
372
                #It's either an FK bone which we should just bake
 
373
                #OR a user created IK target bone
 
374
                simpleBake += [end_bone]
 
375
    for bone in selectedBones:
 
376
        bone.bone.select = True
 
377
    NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap]
 
378
    obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track]
 
379
    constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track]
 
380
    constraintStrip = constraintTrack.strips[0]
 
381
    constraintStrip.action_frame_start = s_frame
 
382
    constraintStrip.action_frame_end = e_frame
 
383
    constraintStrip.frame_start = s_frame
 
384
    constraintStrip.frame_end = e_frame
 
385
    if selectedBones:
 
386
        # Use bake function from NLA Bake Action operator
 
387
        anim_utils.bake_action(s_frame,
 
388
                               e_frame,
 
389
                               action=constraintStrip.action,
 
390
                               only_selected=True,
 
391
                               do_pose=True,
 
392
                               do_object=False,
 
393
                               )
 
394
    if simpleBake:
 
395
        #Do a "simple" bake, location only, world space only.
 
396
        locBake(s_frame, e_frame, simpleBake)
 
397
 
 
398
 
 
399
#Calls the baking function and decativates releveant constraints
 
400
def bakeConstraints(context):
 
401
    obj = context.active_object
 
402
    bones = obj.pose.bones
 
403
    s_frame, e_frame = context.scene.frame_start, context.scene.frame_end
 
404
    #Bake relevant bones
 
405
    bakeAllConstraints(obj, s_frame, e_frame, bones)
 
406
    for m_constraint in obj.data.mocap_constraints:
 
407
        end_bone = bones[m_constraint.real_constraint_bone]
 
408
        cons_obj = getConsObj(end_bone)
 
409
        # It's a control empty: turn the ik off
 
410
        if not isinstance(cons_obj, bpy.types.PoseBone):
 
411
            ik_con = retarget.hasIKConstraint(end_bone)
 
412
            if ik_con:
 
413
                ik_con.mute = True
 
414
        # Deactivate related Blender Constraint
 
415
        m_constraint.active = False
 
416
 
 
417
 
 
418
#Deletes the baked fcurves and reactivates relevant constraints
 
419
def unbakeConstraints(context):
 
420
    # to unbake constraints we delete the whole strip
 
421
    obj = context.active_object
 
422
    bones = obj.pose.bones
 
423
    scene = bpy.context.scene
 
424
    NLATracks = obj.data.mocapNLATracks[obj.data.active_mocap]
 
425
    obj.animation_data.action = bpy.data.actions[NLATracks.auto_fix_track]
 
426
    constraintTrack = obj.animation_data.nla_tracks[NLATracks.auto_fix_track]
 
427
    constraintStrip = constraintTrack.strips[0]
 
428
    action = constraintStrip.action
 
429
    # delete the fcurves on the strip
 
430
    for fcurve in action.fcurves:
 
431
        action.fcurves.remove(fcurve)
 
432
    # reactivate relevant constraints
 
433
    for m_constraint in obj.data.mocap_constraints:
 
434
        end_bone = bones[m_constraint.real_constraint_bone]
 
435
        cons_obj = getConsObj(end_bone)
 
436
        # It's a control empty: turn the ik back on
 
437
        if not isinstance(cons_obj, bpy.types.PoseBone):
 
438
            ik_con = retarget.hasIKConstraint(end_bone)
 
439
            if ik_con:
 
440
                ik_con.mute = False
 
441
        m_constraint.active = True
 
442
 
 
443
 
 
444
def updateConstraints(obj, context):
 
445
    fixes = obj.data.mocap_constraints
 
446
    for fix in fixes:
 
447
        fix.active = False
 
448
        fix.active = True