~siretart/ubuntu/utopic/blender/libav10

« back to all changes in this revision

Viewing changes to release/scripts/addons/rigify/generate.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
import re
 
23
import time
 
24
import traceback
 
25
import sys
 
26
from rna_prop_ui import rna_idprop_ui_prop_get
 
27
from rigify.utils import MetarigError, new_bone, get_rig_type
 
28
from rigify.utils import ORG_PREFIX, MCH_PREFIX, DEF_PREFIX, WGT_PREFIX, ROOT_NAME, make_original_name
 
29
from rigify.utils import RIG_DIR
 
30
from rigify.utils import create_root_widget
 
31
from rigify.utils import random_id
 
32
from rigify.utils import copy_attributes
 
33
from rigify.rig_ui_template import UI_SLIDERS, layers_ui, UI_REGISTER
 
34
from rigify import rigs
 
35
 
 
36
RIG_MODULE = "rigs"
 
37
ORG_LAYER = [n == 31 for n in range(0, 32)]  # Armature layer that original bones should be moved to.
 
38
MCH_LAYER = [n == 30 for n in range(0, 32)]  # Armature layer that mechanism bones should be moved to.
 
39
DEF_LAYER = [n == 29 for n in range(0, 32)]  # Armature layer that deformation bones should be moved to.
 
40
ROOT_LAYER = [n == 28 for n in range(0, 32)]  # Armature layer that root bone should be moved to.
 
41
 
 
42
 
 
43
class Timer:
 
44
    def __init__(self):
 
45
        self.timez = time.time()
 
46
 
 
47
    def tick(self, string):
 
48
        t = time.time()
 
49
        print(string + "%.3f" % (t - self.timez))
 
50
        self.timez = t
 
51
 
 
52
 
 
53
# TODO: generalize to take a group as input instead of an armature.
 
54
def generate_rig(context, metarig):
 
55
    """ Generates a rig from a metarig.
 
56
 
 
57
    """
 
58
    t = Timer()
 
59
 
 
60
    # Random string with time appended so that
 
61
    # different rigs don't collide id's
 
62
    rig_id = random_id(16)
 
63
 
 
64
    # Initial configuration
 
65
    # mode_orig = context.mode  # UNUSED
 
66
    rest_backup = metarig.data.pose_position
 
67
    metarig.data.pose_position = 'REST'
 
68
 
 
69
    bpy.ops.object.mode_set(mode='OBJECT')
 
70
 
 
71
    scene = context.scene
 
72
 
 
73
    #------------------------------------------
 
74
    # Create/find the rig object and set it up
 
75
 
 
76
    # Check if the generated rig already exists, so we can
 
77
    # regenerate in the same object.  If not, create a new
 
78
    # object to generate the rig in.
 
79
    print("Fetch rig.")
 
80
    try:
 
81
        name = metarig["rig_object_name"]
 
82
    except KeyError:
 
83
        name = "rig"
 
84
 
 
85
    try:
 
86
        obj = scene.objects[name]
 
87
    except KeyError:
 
88
        obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
 
89
        obj.draw_type = 'WIRE'
 
90
        scene.objects.link(obj)
 
91
 
 
92
    obj.data.pose_position = 'POSE'
 
93
 
 
94
    # Get rid of anim data in case the rig already existed
 
95
    print("Clear rig animation data.")
 
96
    obj.animation_data_clear()
 
97
 
 
98
    # Select generated rig object
 
99
    metarig.select = False
 
100
    obj.select = True
 
101
    scene.objects.active = obj
 
102
 
 
103
    # Remove all bones from the generated rig armature.
 
104
    bpy.ops.object.mode_set(mode='EDIT')
 
105
    for bone in obj.data.edit_bones:
 
106
        obj.data.edit_bones.remove(bone)
 
107
    bpy.ops.object.mode_set(mode='OBJECT')
 
108
 
 
109
    # Create temporary duplicates for merging
 
110
    temp_rig_1 = metarig.copy()
 
111
    temp_rig_1.data = metarig.data.copy()
 
112
    scene.objects.link(temp_rig_1)
 
113
 
 
114
    temp_rig_2 = metarig.copy()
 
115
    temp_rig_2.data = obj.data
 
116
    scene.objects.link(temp_rig_2)
 
117
 
 
118
    # Select the temp rigs for merging
 
119
    for objt in scene.objects:
 
120
        objt.select = False  # deselect all objects
 
121
    temp_rig_1.select = True
 
122
    temp_rig_2.select = True
 
123
    scene.objects.active = temp_rig_2
 
124
 
 
125
    # Merge the temporary rigs
 
126
    bpy.ops.object.join()
 
127
 
 
128
    # Delete the second temp rig
 
129
    bpy.ops.object.delete()
 
130
 
 
131
    # Select the generated rig
 
132
    for objt in scene.objects:
 
133
        objt.select = False  # deselect all objects
 
134
    obj.select = True
 
135
    scene.objects.active = obj
 
136
 
 
137
    # Copy over bone properties
 
138
    for bone in metarig.data.bones:
 
139
        bone_gen = obj.data.bones[bone.name]
 
140
 
 
141
        # B-bone stuff
 
142
        bone_gen.bbone_segments = bone.bbone_segments
 
143
        bone_gen.bbone_in = bone.bbone_in
 
144
        bone_gen.bbone_out = bone.bbone_out
 
145
 
 
146
    # Copy over the pose_bone properties
 
147
    for bone in metarig.pose.bones:
 
148
        bone_gen = obj.pose.bones[bone.name]
 
149
 
 
150
        # Rotation mode and transform locks
 
151
        bone_gen.rotation_mode = bone.rotation_mode
 
152
        bone_gen.lock_rotation = tuple(bone.lock_rotation)
 
153
        bone_gen.lock_rotation_w = bone.lock_rotation_w
 
154
        bone_gen.lock_rotations_4d = bone.lock_rotations_4d
 
155
        bone_gen.lock_location = tuple(bone.lock_location)
 
156
        bone_gen.lock_scale = tuple(bone.lock_scale)
 
157
 
 
158
        # rigify_type and rigify_parameters
 
159
        bone_gen.rigify_type = bone.rigify_type
 
160
        if len(bone.rigify_parameters) > 0:
 
161
            bone_gen.rigify_parameters.add()
 
162
            for prop in dir(bone_gen.rigify_parameters[0]):
 
163
                if (not prop.startswith("_")) \
 
164
                and (not prop.startswith("bl_")) \
 
165
                and (prop != "rna_type"):
 
166
                    try:
 
167
                        setattr(bone_gen.rigify_parameters[0], prop, \
 
168
                                getattr(bone.rigify_parameters[0], prop))
 
169
                    except AttributeError:
 
170
                        print("FAILED TO COPY PARAMETER: " + str(prop))
 
171
 
 
172
        # Custom properties
 
173
        for prop in bone.keys():
 
174
            try:
 
175
                bone_gen[prop] = bone[prop]
 
176
            except KeyError:
 
177
                pass
 
178
 
 
179
        # Constraints
 
180
        for con1 in bone.constraints:
 
181
            con2 = bone_gen.constraints.new(type=con1.type)
 
182
            copy_attributes(con1, con2)
 
183
 
 
184
            # Set metarig target to rig target
 
185
            if "target" in dir(con2):
 
186
                if con2.target == metarig:
 
187
                    con2.target = obj
 
188
 
 
189
    # Copy drivers
 
190
    if metarig.animation_data:
 
191
        for d1 in metarig.animation_data.drivers:
 
192
            d2 = obj.driver_add(d1.data_path)
 
193
            copy_attributes(d1, d2)
 
194
            copy_attributes(d1.driver, d2.driver)
 
195
 
 
196
            # Remove default modifiers, variables, etc.
 
197
            for m in d2.modifiers:
 
198
                d2.modifiers.remove(m)
 
199
            for v in d2.driver.variables:
 
200
                d2.driver.variables.remove(v)
 
201
 
 
202
            # Copy modifiers
 
203
            for m1 in d1.modifiers:
 
204
                m2 = d2.modifiers.new(type=m1.type)
 
205
                copy_attributes(m1, m2)
 
206
 
 
207
            # Copy variables
 
208
            for v1 in d1.driver.variables:
 
209
                v2 = d2.driver.variables.new()
 
210
                copy_attributes(v1, v2)
 
211
                for i in range(len(v1.targets)):
 
212
                    copy_attributes(v1.targets[i], v2.targets[i])
 
213
                    # Switch metarig targets to rig targets
 
214
                    if v2.targets[i].id == metarig:
 
215
                        v2.targets[i].id = obj
 
216
 
 
217
                    # Mark targets that may need to be altered after rig generation
 
218
                    tar = v2.targets[i]
 
219
                    # If a custom property
 
220
                    if v2.type == 'SINGLE_PROP' \
 
221
                    and re.match('^pose.bones\["[^"\]]*"\]\["[^"\]]*"\]$', tar.data_path):
 
222
                        tar.data_path = "RIGIFY-" + tar.data_path
 
223
 
 
224
            # Copy key frames
 
225
            for i in range(len(d1.keyframe_points)):
 
226
                d2.keyframe_points.add()
 
227
                k1 = d1.keyframe_points[i]
 
228
                k2 = d2.keyframe_points[i]
 
229
                copy_attributes(k1, k2)
 
230
 
 
231
    t.tick("Duplicate rig: ")
 
232
    #----------------------------------
 
233
    # Make a list of the original bones so we can keep track of them.
 
234
    original_bones = [bone.name for bone in obj.data.bones]
 
235
 
 
236
    # Add the ORG_PREFIX to the original bones.
 
237
    bpy.ops.object.mode_set(mode='OBJECT')
 
238
    for i in range(0, len(original_bones)):
 
239
        obj.data.bones[original_bones[i]].name = make_original_name(original_bones[i])
 
240
        original_bones[i] = make_original_name(original_bones[i])
 
241
 
 
242
    # Create a sorted list of the original bones, sorted in the order we're
 
243
    # going to traverse them for rigging.
 
244
    # (root-most -> leaf-most, alphabetical)
 
245
    bones_sorted = []
 
246
    for name in original_bones:
 
247
        bones_sorted += [name]
 
248
    bones_sorted.sort()  # first sort by names
 
249
    bones_sorted.sort(key=lambda bone: len(obj.pose.bones[bone].parent_recursive))  # then parents before children
 
250
 
 
251
    t.tick("Make list of org bones: ")
 
252
    #----------------------------------
 
253
    # Create the root bone.
 
254
    bpy.ops.object.mode_set(mode='EDIT')
 
255
    root_bone = new_bone(obj, ROOT_NAME)
 
256
    obj.data.edit_bones[root_bone].head = (0, 0, 0)
 
257
    obj.data.edit_bones[root_bone].tail = (0, 1, 0)
 
258
    obj.data.edit_bones[root_bone].roll = 0
 
259
    bpy.ops.object.mode_set(mode='OBJECT')
 
260
    obj.data.bones[root_bone].layers = ROOT_LAYER
 
261
    # Put the rig_name in the armature custom properties
 
262
    rna_idprop_ui_prop_get(obj.data, "rig_id", create=True)
 
263
    obj.data["rig_id"] = rig_id
 
264
 
 
265
    t.tick("Create root bone: ")
 
266
    #----------------------------------
 
267
    try:
 
268
        # Collect/initialize all the rigs.
 
269
        rigs = []
 
270
        deformation_rigs = []
 
271
        for bone in bones_sorted:
 
272
            bpy.ops.object.mode_set(mode='EDIT')
 
273
            rigs += get_bone_rigs(obj, bone)
 
274
        t.tick("Initialize rigs: ")
 
275
 
 
276
        # Generate all the rigs.
 
277
        ui_scripts = []
 
278
        for rig in rigs:
 
279
            # Go into editmode in the rig armature
 
280
            bpy.ops.object.mode_set(mode='OBJECT')
 
281
            context.scene.objects.active = obj
 
282
            obj.select = True
 
283
            bpy.ops.object.mode_set(mode='EDIT')
 
284
            scripts = rig.generate()
 
285
            if scripts != None:
 
286
                ui_scripts += [scripts[0]]
 
287
        t.tick("Generate rigs: ")
 
288
    except Exception as e:
 
289
        # Cleanup if something goes wrong
 
290
        print("Rigify: failed to generate rig.")
 
291
        metarig.data.pose_position = rest_backup
 
292
        obj.data.pose_position = 'POSE'
 
293
        bpy.ops.object.mode_set(mode='OBJECT')
 
294
 
 
295
        # Continue the exception
 
296
        raise e
 
297
 
 
298
    #----------------------------------
 
299
    bpy.ops.object.mode_set(mode='OBJECT')
 
300
 
 
301
    # Get a list of all the bones in the armature
 
302
    bones = [bone.name for bone in obj.data.bones]
 
303
 
 
304
    # Parent any free-floating bones to the root.
 
305
    bpy.ops.object.mode_set(mode='EDIT')
 
306
    for bone in bones:
 
307
        if obj.data.edit_bones[bone].parent is None:
 
308
            obj.data.edit_bones[bone].use_connect = False
 
309
            obj.data.edit_bones[bone].parent = obj.data.edit_bones[root_bone]
 
310
    bpy.ops.object.mode_set(mode='OBJECT')
 
311
 
 
312
    # Every bone that has a name starting with "DEF-" make deforming.  All the
 
313
    # others make non-deforming.
 
314
    for bone in bones:
 
315
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
 
316
            obj.data.bones[bone].use_deform = True
 
317
        else:
 
318
            obj.data.bones[bone].use_deform = False
 
319
 
 
320
    # Alter marked driver targets
 
321
    if obj.animation_data:
 
322
        for d in obj.animation_data.drivers:
 
323
            for v in d.driver.variables:
 
324
                for tar in v.targets:
 
325
                    if tar.data_path.startswith("RIGIFY-"):
 
326
                        temp, bone, prop = tuple([x.strip('"]') for x in tar.data_path.split('["')])
 
327
                        if bone in obj.data.bones \
 
328
                        and prop in obj.pose.bones[bone].keys():
 
329
                            tar.data_path = tar.data_path[7:]
 
330
                        else:
 
331
                            tar.data_path = 'pose.bones["%s"]["%s"]' % (make_original_name(bone), prop)
 
332
 
 
333
    # Move all the original bones to their layer.
 
334
    for bone in original_bones:
 
335
        obj.data.bones[bone].layers = ORG_LAYER
 
336
 
 
337
    # Move all the bones with names starting with "MCH-" to their layer.
 
338
    for bone in bones:
 
339
        if obj.data.bones[bone].name.startswith(MCH_PREFIX):
 
340
            obj.data.bones[bone].layers = MCH_LAYER
 
341
 
 
342
    # Move all the bones with names starting with "DEF-" to their layer.
 
343
    for bone in bones:
 
344
        if obj.data.bones[bone].name.startswith(DEF_PREFIX):
 
345
            obj.data.bones[bone].layers = DEF_LAYER
 
346
 
 
347
    # Create root bone widget
 
348
    create_root_widget(obj, "root")
 
349
 
 
350
    # Assign shapes to bones
 
351
    # Object's with name WGT-<bone_name> get used as that bone's shape.
 
352
    for bone in bones:
 
353
        wgt_name = (WGT_PREFIX + obj.data.bones[bone].name)[:21]  # Object names are limited to 21 characters... arg
 
354
        if wgt_name in context.scene.objects:
 
355
            # Weird temp thing because it won't let me index by object name
 
356
            for ob in context.scene.objects:
 
357
                if ob.name == wgt_name:
 
358
                    obj.pose.bones[bone].custom_shape = ob
 
359
                    break
 
360
            # This is what it should do:
 
361
            # obj.pose.bones[bone].custom_shape = context.scene.objects[wgt_name]
 
362
    # Reveal all the layers with control bones on them
 
363
    vis_layers = [False for n in range(0, 32)]
 
364
    for bone in bones:
 
365
        for i in range(0, 32):
 
366
            vis_layers[i] = vis_layers[i] or obj.data.bones[bone].layers[i]
 
367
    for i in range(0, 32):
 
368
        vis_layers[i] = vis_layers[i] and not (ORG_LAYER[i] or MCH_LAYER[i] or DEF_LAYER[i])
 
369
    obj.data.layers = vis_layers
 
370
 
 
371
    # Ensure the collection of layer names exists
 
372
    for i in range(1 + len(metarig.data.rigify_layers), 29):
 
373
        metarig.data.rigify_layers.add()
 
374
 
 
375
    # Create list of layer name/row pairs
 
376
    layer_layout = []
 
377
    for l in metarig.data.rigify_layers:
 
378
        layer_layout += [(l.name, l.row)]
 
379
 
 
380
    # Generate the UI script
 
381
    if "rig_ui.py" in bpy.data.texts:
 
382
        script = bpy.data.texts["rig_ui.py"]
 
383
        script.clear()
 
384
    else:
 
385
        script = bpy.data.texts.new("rig_ui.py")
 
386
    script.write(UI_SLIDERS % rig_id)
 
387
    for s in ui_scripts:
 
388
        script.write("\n        " + s.replace("\n", "\n        ") + "\n")
 
389
    script.write(layers_ui(vis_layers, layer_layout))
 
390
    script.write(UI_REGISTER)
 
391
    script.use_module = True
 
392
 
 
393
    # Run UI script
 
394
    exec(script.as_string(), {})
 
395
 
 
396
    t.tick("The rest: ")
 
397
    #----------------------------------
 
398
    # Deconfigure
 
399
    bpy.ops.object.mode_set(mode='OBJECT')
 
400
    metarig.data.pose_position = rest_backup
 
401
    obj.data.pose_position = 'POSE'
 
402
 
 
403
 
 
404
def get_bone_rigs(obj, bone_name, halt_on_missing=False):
 
405
    """ Fetch all the rigs specified on a bone.
 
406
    """
 
407
    rigs = []
 
408
    rig_type = obj.pose.bones[bone_name].rigify_type
 
409
    rig_type = rig_type.replace(" ", "")
 
410
 
 
411
    if rig_type == "":
 
412
        pass
 
413
    else:
 
414
        # Gather parameters
 
415
        try:
 
416
            params = obj.pose.bones[bone_name].rigify_parameters[0]
 
417
        except (KeyError, IndexError):
 
418
            params = None
 
419
 
 
420
        # Get the rig
 
421
        try:
 
422
            rig = get_rig_type(rig_type).Rig(obj, bone_name, params)
 
423
        except ImportError:
 
424
            message = "Rig Type Missing: python module for type '%s' not found (bone: %s)" % (rig_type, bone_name)
 
425
            if halt_on_missing:
 
426
                raise MetarigError(message)
 
427
            else:
 
428
                print(message)
 
429
                print('print_exc():')
 
430
                traceback.print_exc(file=sys.stdout)
 
431
        else:
 
432
            rigs += [rig]
 
433
    return rigs
 
434
 
 
435
 
 
436
def param_matches_type(param_name, rig_type):
 
437
    """ Returns True if the parameter name is consistent with the rig type.
 
438
    """
 
439
    if param_name.rsplit(".", 1)[0] == rig_type:
 
440
        return True
 
441
    else:
 
442
        return False
 
443
 
 
444
 
 
445
def param_name(param_name, rig_type):
 
446
    """ Get the actual parameter name, sans-rig-type.
 
447
    """
 
448
    return param_name[len(rig_type) + 1:]