#====================== 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 ======================== import bpy import imp import random import time from mathutils import Vector from math import ceil, floor from rna_prop_ui import rna_idprop_ui_prop_get RIG_DIR = "rigs" # Name of the directory where rig types are kept ORG_PREFIX = "ORG-" # Prefix of original bones. MCH_PREFIX = "MCH-" # Prefix of mechanism bones. DEF_PREFIX = "DEF-" # Prefix of deformation bones. WGT_PREFIX = "WGT-" # Prefix for widget objects ROOT_NAME = "root" # Name of the root bone. WGT_LAYERS = [x == 19 for x in range(0, 20)] # Widgets go on the last scene layer. MODULE_NAME = "rigify" # Windows/Mac blender is weird, so __package__ doesn't work #======================================================================= # Error handling #======================================================================= class MetarigError(Exception): """ Exception raised for errors. """ def __init__(self, message): self.message = message def __str__(self): return repr(self.message) #======================================================================= # Name manipulation #======================================================================= def org_name(name): """ Returns the name with ORG_PREFIX stripped from it. """ if name.startswith(ORG_PREFIX): return name[len(ORG_PREFIX):] else: return name def strip_org(name): """ Returns the name with ORG_PREFIX stripped from it. """ if name.startswith(ORG_PREFIX): return name[len(ORG_PREFIX):] else: return name org_name = strip_org def org(name): """ Prepends the ORG_PREFIX to a name if it doesn't already have it, and returns it. """ if name.startswith(ORG_PREFIX): return name else: return ORG_PREFIX + name make_original_name = org def mch(name): """ Prepends the MCH_PREFIX to a name if it doesn't already have it, and returns it. """ if name.startswith(MCH_PREFIX): return name else: return MCH_PREFIX + name make_mechanism_name = mch def deformer(name): """ Prepends the DEF_PREFIX to a name if it doesn't already have it, and returns it. """ if name.startswith(DEF_PREFIX): return name else: return DEF_PREFIX + name make_deformer_name = deformer def insert_before_lr(name, text): if name[-1] in ['l', 'L', 'r', 'R'] and name[-2] in ['.', '-', '_']: return name[:-2] + text + name[-2:] else: return name + text #======================= # Bone manipulation #======================= def new_bone(obj, bone_name): """ Adds a new bone to the given armature object. Returns the resulting bone's name. """ if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE': edit_bone = obj.data.edit_bones.new(bone_name) name = edit_bone.name edit_bone.head = (0, 0, 0) edit_bone.tail = (0, 1, 0) edit_bone.roll = 0 bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') return name else: raise MetarigError("Can't add new bone '%s' outside of edit mode." % bone_name) def copy_bone(obj, bone_name, assign_name=''): """ Makes a copy of the given bone in the given armature object. Returns the resulting bone's name. """ if bone_name not in obj.data.bones: raise MetarigError("copy_bone(): bone '%s' not found, cannot copy it." % bone_name) if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE': if assign_name == '': assign_name = bone_name # Copy the edit bone edit_bone_1 = obj.data.edit_bones[bone_name] edit_bone_2 = obj.data.edit_bones.new(assign_name) bone_name_1 = bone_name bone_name_2 = edit_bone_2.name edit_bone_2.parent = edit_bone_1.parent edit_bone_2.use_connect = edit_bone_1.use_connect # Copy edit bone attributes edit_bone_2.layers = list(edit_bone_1.layers) edit_bone_2.head = Vector(edit_bone_1.head) edit_bone_2.tail = Vector(edit_bone_1.tail) edit_bone_2.roll = edit_bone_1.roll edit_bone_2.use_inherit_rotation = edit_bone_1.use_inherit_rotation edit_bone_2.use_inherit_scale = edit_bone_1.use_inherit_scale edit_bone_2.use_local_location = edit_bone_1.use_local_location edit_bone_2.use_deform = edit_bone_1.use_deform edit_bone_2.bbone_segments = edit_bone_1.bbone_segments edit_bone_2.bbone_in = edit_bone_1.bbone_in edit_bone_2.bbone_out = edit_bone_1.bbone_out bpy.ops.object.mode_set(mode='OBJECT') # Get the pose bones pose_bone_1 = obj.pose.bones[bone_name_1] pose_bone_2 = obj.pose.bones[bone_name_2] # Copy pose bone attributes pose_bone_2.rotation_mode = pose_bone_1.rotation_mode pose_bone_2.rotation_axis_angle = tuple(pose_bone_1.rotation_axis_angle) pose_bone_2.rotation_euler = tuple(pose_bone_1.rotation_euler) pose_bone_2.rotation_quaternion = tuple(pose_bone_1.rotation_quaternion) pose_bone_2.lock_location = tuple(pose_bone_1.lock_location) pose_bone_2.lock_scale = tuple(pose_bone_1.lock_scale) pose_bone_2.lock_rotation = tuple(pose_bone_1.lock_rotation) pose_bone_2.lock_rotation_w = pose_bone_1.lock_rotation_w pose_bone_2.lock_rotations_4d = pose_bone_1.lock_rotations_4d bpy.ops.object.mode_set(mode='EDIT') return bone_name_2 else: raise MetarigError("Cannot copy bones outside of edit mode.") def flip_bone(obj, bone_name): """ Flips an edit bone. """ if bone_name not in obj.data.bones: raise MetarigError("flip_bone(): bone '%s' not found, cannot copy it." % bone_name) if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE': bone = obj.data.edit_bones[bone_name] head = Vector(bone.head) tail = Vector(bone.tail) bone.tail = head + tail bone.head = tail bone.tail = head else: raise MetarigError("Cannot flip bones outside of edit mode.") def put_bone(obj, bone_name, pos): """ Places a bone at the given position. """ if bone_name not in obj.data.bones: raise MetarigError("put_bone(): bone '%s' not found, cannot copy it." % bone_name) if obj == bpy.context.active_object and bpy.context.mode == 'EDIT_ARMATURE': bone = obj.data.edit_bones[bone_name] delta = pos - bone.head bone.translate(delta) else: raise MetarigError("Cannot 'put' bones outside of edit mode.") #============================================= # Widget creation #============================================= def obj_to_bone(obj, rig, bone_name): """ Places an object at the location/rotation/scale of the given bone. """ if bpy.context.mode == 'EDIT_ARMATURE': raise MetarigError("obj_to_bone(): does not work while in edit mode.") bone = rig.data.bones[bone_name] mat = rig.matrix_world * bone.matrix_local obj.location = mat.to_translation() obj.rotation_mode = 'XYZ' obj.rotation_euler = mat.to_euler() scl = mat.to_scale() scl_avg = (scl[0] + scl[1] + scl[2]) / 3 obj.scale = (bone.length * scl_avg), (bone.length * scl_avg), (bone.length * scl_avg) def create_widget(rig, bone_name): """ Creates an empty widget object for a bone, and returns the object. """ obj_name = WGT_PREFIX + bone_name scene = bpy.context.scene # Check if it already exists if obj_name in scene.objects: return None else: mesh = bpy.data.meshes.new(obj_name) obj = bpy.data.objects.new(obj_name, mesh) scene.objects.link(obj) obj_to_bone(obj, rig, bone_name) obj.layers = WGT_LAYERS return obj # Common Widgets def create_line_widget(rig, bone_name): """ Creates a basic line widget, a line that spans the length of the bone. """ obj = create_widget(rig, bone_name) if obj != None: mesh = obj.data mesh.from_pydata([(0, 0, 0), (0, 1, 0)], [(0, 1)], []) mesh.update() def create_circle_widget(rig, bone_name, radius=1.0, head_tail=0.0, with_line=False): """ Creates a basic circle widget, a circle around the y-axis. radius: the radius of the circle head_tail: where along the length of the bone the circle is (0.0=head, 1.0=tail) """ obj = create_widget(rig, bone_name) if obj != None: v = [(0.7071068286895752, 2.980232238769531e-07, -0.7071065306663513), (0.8314696550369263, 2.980232238769531e-07, -0.5555699467658997), (0.9238795042037964, 2.682209014892578e-07, -0.3826831877231598), (0.9807852506637573, 2.5331974029541016e-07, -0.19509011507034302), (1.0, 2.365559055306221e-07, 1.6105803979371558e-07), (0.9807853698730469, 2.2351741790771484e-07, 0.19509044289588928), (0.9238796234130859, 2.086162567138672e-07, 0.38268351554870605), (0.8314696550369263, 1.7881393432617188e-07, 0.5555704236030579), (0.7071068286895752, 1.7881393432617188e-07, 0.7071070075035095), (0.5555702447891235, 1.7881393432617188e-07, 0.8314698934555054), (0.38268327713012695, 1.7881393432617188e-07, 0.923879861831665), (0.19509008526802063, 1.7881393432617188e-07, 0.9807855486869812), (-3.2584136988589307e-07, 1.1920928955078125e-07, 1.000000238418579), (-0.19509072601795197, 1.7881393432617188e-07, 0.9807854294776917), (-0.3826838731765747, 1.7881393432617188e-07, 0.9238795638084412), (-0.5555707216262817, 1.7881393432617188e-07, 0.8314695358276367), (-0.7071071863174438, 1.7881393432617188e-07, 0.7071065902709961), (-0.8314700126647949, 1.7881393432617188e-07, 0.5555698871612549), (-0.923879861831665, 2.086162567138672e-07, 0.3826829195022583), (-0.9807853698730469, 2.2351741790771484e-07, 0.1950896978378296), (-1.0, 2.365559907957504e-07, -7.290432222362142e-07), (-0.9807850122451782, 2.5331974029541016e-07, -0.195091113448143), (-0.9238790273666382, 2.682209014892578e-07, -0.38268423080444336), (-0.831468939781189, 2.980232238769531e-07, -0.5555710196495056), (-0.7071058750152588, 2.980232238769531e-07, -0.707107424736023), (-0.555569052696228, 2.980232238769531e-07, -0.8314701318740845), (-0.38268208503723145, 2.980232238769531e-07, -0.923879861831665), (-0.19508881866931915, 2.980232238769531e-07, -0.9807853102684021), (1.6053570561780361e-06, 2.980232238769531e-07, -0.9999997615814209), (0.19509197771549225, 2.980232238769531e-07, -0.9807847142219543), (0.3826850652694702, 2.980232238769531e-07, -0.9238786101341248), (0.5555717945098877, 2.980232238769531e-07, -0.8314683437347412)] verts = [(a[0] * radius, head_tail, a[2] * radius) for a in v] if with_line: edges = [(28, 12), (0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (22, 23), (23, 24), (24, 25), (25, 26), (26, 27), (27, 28), (28, 29), (29, 30), (30, 31), (0, 31)] else: edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (22, 23), (23, 24), (24, 25), (25, 26), (26, 27), (27, 28), (28, 29), (29, 30), (30, 31), (0, 31)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() return obj else: return None def create_sphere_widget(rig, bone_name): """ Creates a basic sphere widget, three pependicular overlapping circles. """ obj = create_widget(rig, bone_name) if obj != None: verts = [(0.3535533845424652, 0.3535533845424652, 0.0), (0.4619397521018982, 0.19134171307086945, 0.0), (0.5, -2.1855694143368964e-08, 0.0), (0.4619397521018982, -0.19134175777435303, 0.0), (0.3535533845424652, -0.3535533845424652, 0.0), (0.19134174287319183, -0.4619397521018982, 0.0), (7.549790126404332e-08, -0.5, 0.0), (-0.1913416087627411, -0.46193981170654297, 0.0), (-0.35355329513549805, -0.35355350375175476, 0.0), (-0.4619397521018982, -0.19134178757667542, 0.0), (-0.5, 5.962440319251527e-09, 0.0), (-0.4619397222995758, 0.1913418024778366, 0.0), (-0.35355326533317566, 0.35355350375175476, 0.0), (-0.19134148955345154, 0.46193987131118774, 0.0), (3.2584136988589307e-07, 0.5, 0.0), (0.1913420855998993, 0.46193960309028625, 0.0), (7.450580596923828e-08, 0.46193960309028625, 0.19134199619293213), (5.9254205098113744e-08, 0.5, 2.323586443253589e-07), (4.470348358154297e-08, 0.46193987131118774, -0.1913415789604187), (2.9802322387695312e-08, 0.35355350375175476, -0.3535533547401428), (2.9802322387695312e-08, 0.19134178757667542, -0.46193981170654297), (5.960464477539063e-08, -1.1151834122813398e-08, -0.5000000596046448), (5.960464477539063e-08, -0.1913418024778366, -0.46193984150886536), (5.960464477539063e-08, -0.35355350375175476, -0.3535533845424652), (7.450580596923828e-08, -0.46193981170654297, -0.19134166836738586), (9.348272556053416e-08, -0.5, 1.624372103492533e-08), (1.043081283569336e-07, -0.4619397521018982, 0.19134168326854706), (1.1920928955078125e-07, -0.3535533845424652, 0.35355329513549805), (1.1920928955078125e-07, -0.19134174287319183, 0.46193966269493103), (1.1920928955078125e-07, -4.7414250303745575e-09, 0.49999991059303284), (1.1920928955078125e-07, 0.19134172797203064, 0.46193966269493103), (8.940696716308594e-08, 0.3535533845424652, 0.35355329513549805), (0.3535534739494324, 0.0, 0.35355329513549805), (0.1913418173789978, -2.9802322387695312e-08, 0.46193966269493103), (8.303572940349113e-08, -5.005858838558197e-08, 0.49999991059303284), (-0.19134165346622467, -5.960464477539063e-08, 0.46193966269493103), (-0.35355329513549805, -8.940696716308594e-08, 0.35355329513549805), (-0.46193963289260864, -5.960464477539063e-08, 0.19134168326854706), (-0.49999991059303284, -5.960464477539063e-08, 1.624372103492533e-08), (-0.4619397521018982, -2.9802322387695312e-08, -0.19134166836738586), (-0.3535534143447876, -2.9802322387695312e-08, -0.3535533845424652), (-0.19134171307086945, 0.0, -0.46193984150886536), (7.662531942287387e-08, 9.546055501630235e-09, -0.5000000596046448), (0.19134187698364258, 5.960464477539063e-08, -0.46193981170654297), (0.3535535931587219, 5.960464477539063e-08, -0.3535533547401428), (0.4619399905204773, 5.960464477539063e-08, -0.1913415789604187), (0.5000000596046448, 5.960464477539063e-08, 2.323586443253589e-07), (0.4619396924972534, 2.9802322387695312e-08, 0.19134199619293213)] edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (0, 15), (16, 31), (16, 17), (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (22, 23), (23, 24), (24, 25), (25, 26), (26, 27), (27, 28), (28, 29), (29, 30), (30, 31), (32, 33), (33, 34), (34, 35), (35, 36), (36, 37), (37, 38), (38, 39), (39, 40), (40, 41), (41, 42), (42, 43), (43, 44), (44, 45), (45, 46), (46, 47), (32, 47)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() def create_limb_widget(rig, bone_name): """ Creates a basic limb widget, a line that spans the length of the bone, with a circle around the center. """ obj = create_widget(rig, bone_name) if obj != None: verts = [(-1.1920928955078125e-07, 1.7881393432617188e-07, 0.0), (3.5762786865234375e-07, 1.0000004768371582, 0.0), (0.1767769455909729, 0.5000001192092896, 0.17677664756774902), (0.20786768198013306, 0.5000001192092896, 0.1388925313949585), (0.23097014427185059, 0.5000001192092896, 0.09567084908485413), (0.24519658088684082, 0.5000001192092896, 0.048772573471069336), (0.2500002384185791, 0.5000001192092896, -2.545945676502015e-09), (0.24519658088684082, 0.5000001192092896, -0.048772573471069336), (0.23097014427185059, 0.5000001192092896, -0.09567084908485413), (0.20786768198013306, 0.5000001192092896, -0.13889259099960327), (0.1767769455909729, 0.5000001192092896, -0.1767767071723938), (0.13889282941818237, 0.5000001192092896, -0.20786744356155396), (0.09567105770111084, 0.5000001192092896, -0.23096990585327148), (0.04877278208732605, 0.5000001192092896, -0.24519634246826172), (1.7279069197684294e-07, 0.5000000596046448, -0.25), (-0.0487724244594574, 0.5000001192092896, -0.24519634246826172), (-0.09567070007324219, 0.5000001192092896, -0.2309698462486267), (-0.13889241218566895, 0.5000001192092896, -0.20786738395690918), (-0.17677652835845947, 0.5000001192092896, -0.17677664756774902), (-0.20786726474761963, 0.5000001192092896, -0.13889244198799133), (-0.23096972703933716, 0.5000001192092896, -0.09567070007324219), (-0.24519610404968262, 0.5000001192092896, -0.04877239465713501), (-0.2499997615814209, 0.5000001192092896, 2.1997936983098043e-07), (-0.24519598484039307, 0.5000001192092896, 0.04877282679080963), (-0.23096948862075806, 0.5000001192092896, 0.09567108750343323), (-0.20786696672439575, 0.5000001192092896, 0.1388927698135376), (-0.1767762303352356, 0.5000001192092896, 0.17677688598632812), (-0.13889199495315552, 0.5000001192092896, 0.2078675627708435), (-0.09567028284072876, 0.5000001192092896, 0.23097002506256104), (-0.048771947622299194, 0.5000001192092896, 0.24519634246826172), (6.555903269145347e-07, 0.5000001192092896, 0.25), (0.04877324402332306, 0.5000001192092896, 0.24519622325897217), (0.09567153453826904, 0.5000001192092896, 0.23096966743469238), (0.13889318704605103, 0.5000001192092896, 0.20786714553833008)] edges = [(0, 1), (2, 3), (4, 3), (5, 4), (5, 6), (6, 7), (8, 7), (8, 9), (10, 9), (10, 11), (11, 12), (13, 12), (14, 13), (14, 15), (16, 15), (16, 17), (17, 18), (19, 18), (19, 20), (21, 20), (21, 22), (22, 23), (24, 23), (25, 24), (25, 26), (27, 26), (27, 28), (29, 28), (29, 30), (30, 31), (32, 31), (32, 33), (2, 33)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() def create_bone_widget(rig, bone_name): """ Creates a basic bone widget, a simple obolisk-esk shape. """ obj = create_widget(rig, bone_name) if obj != None: verts = [(0.04, 1.0, -0.04), (0.1, 0.0, -0.1), (-0.1, 0.0, -0.1), (-0.04, 1.0, -0.04), (0.04, 1.0, 0.04), (0.1, 0.0, 0.1), (-0.1, 0.0, 0.1), (-0.04, 1.0, 0.04)] edges = [(1, 2), (0, 1), (0, 3), (2, 3), (4, 5), (5, 6), (6, 7), (4, 7), (1, 5), (0, 4), (2, 6), (3, 7)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() def create_compass_widget(rig, bone_name): """ Creates a compass-shaped widget. """ obj = create_widget(rig, bone_name) if obj != None: verts = [(0.0, 1.2000000476837158, 0.0), (0.19509032368659973, 0.9807852506637573, 0.0), (0.3826834559440613, 0.9238795042037964, 0.0), (0.5555702447891235, 0.8314695954322815, 0.0), (0.7071067690849304, 0.7071067690849304, 0.0), (0.8314696550369263, 0.5555701851844788, 0.0), (0.9238795042037964, 0.3826834261417389, 0.0), (0.9807852506637573, 0.19509035348892212, 0.0), (1.2000000476837158, 7.549790126404332e-08, 0.0), (0.9807853102684021, -0.19509020447731018, 0.0), (0.9238795638084412, -0.38268327713012695, 0.0), (0.8314696550369263, -0.5555701851844788, 0.0), (0.7071067690849304, -0.7071067690849304, 0.0), (0.5555701851844788, -0.8314696550369263, 0.0), (0.38268327713012695, -0.9238796234130859, 0.0), (0.19509008526802063, -0.9807853102684021, 0.0), (-3.2584136988589307e-07, -1.2999999523162842, 0.0), (-0.19509072601795197, -0.9807851910591125, 0.0), (-0.3826838731765747, -0.9238793253898621, 0.0), (-0.5555707216262817, -0.8314692974090576, 0.0), (-0.7071072459220886, -0.707106351852417, 0.0), (-0.8314700126647949, -0.5555696487426758, 0.0), (-0.923879861831665, -0.3826826810836792, 0.0), (-0.9807854294776917, -0.1950894594192505, 0.0), (-1.2000000476837158, 9.655991561885457e-07, 0.0), (-0.980785071849823, 0.1950913518667221, 0.0), (-0.923879086971283, 0.38268446922302246, 0.0), (-0.831468939781189, 0.5555712580680847, 0.0), (-0.7071058750152588, 0.707107663154602, 0.0), (-0.5555691123008728, 0.8314703702926636, 0.0), (-0.38268208503723145, 0.9238801002502441, 0.0), (-0.19508881866931915, 0.9807855486869812, 0.0)] edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), (11, 12), (12, 13), (13, 14), (14, 15), (15, 16), (16, 17), (17, 18), (18, 19), (19, 20), (20, 21), (21, 22), (22, 23), (23, 24), (24, 25), (25, 26), (26, 27), (27, 28), (28, 29), (29, 30), (30, 31), (0, 31)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() def create_root_widget(rig, bone_name): """ Creates a widget for the root bone. """ obj = create_widget(rig, bone_name) if obj != None: verts = [(0.7071067690849304, 0.7071067690849304, 0.0), (0.7071067690849304, -0.7071067690849304, 0.0), (-0.7071067690849304, 0.7071067690849304, 0.0), (-0.7071067690849304, -0.7071067690849304, 0.0), (0.8314696550369263, 0.5555701851844788, 0.0), (0.8314696550369263, -0.5555701851844788, 0.0), (-0.8314696550369263, 0.5555701851844788, 0.0), (-0.8314696550369263, -0.5555701851844788, 0.0), (0.9238795042037964, 0.3826834261417389, 0.0), (0.9238795042037964, -0.3826834261417389, 0.0), (-0.9238795042037964, 0.3826834261417389, 0.0), (-0.9238795042037964, -0.3826834261417389, 0.0), (0.9807852506637573, 0.19509035348892212, 0.0), (0.9807852506637573, -0.19509035348892212, 0.0), (-0.9807852506637573, 0.19509035348892212, 0.0), (-0.9807852506637573, -0.19509035348892212, 0.0), (0.19509197771549225, 0.9807849526405334, 0.0), (0.19509197771549225, -0.9807849526405334, 0.0), (-0.19509197771549225, 0.9807849526405334, 0.0), (-0.19509197771549225, -0.9807849526405334, 0.0), (0.3826850652694702, 0.9238788485527039, 0.0), (0.3826850652694702, -0.9238788485527039, 0.0), (-0.3826850652694702, 0.9238788485527039, 0.0), (-0.3826850652694702, -0.9238788485527039, 0.0), (0.5555717945098877, 0.8314685821533203, 0.0), (0.5555717945098877, -0.8314685821533203, 0.0), (-0.5555717945098877, 0.8314685821533203, 0.0), (-0.5555717945098877, -0.8314685821533203, 0.0), (0.19509197771549225, 1.2807848453521729, 0.0), (0.19509197771549225, -1.2807848453521729, 0.0), (-0.19509197771549225, 1.2807848453521729, 0.0), (-0.19509197771549225, -1.2807848453521729, 0.0), (1.280785322189331, 0.19509035348892212, 0.0), (1.280785322189331, -0.19509035348892212, 0.0), (-1.280785322189331, 0.19509035348892212, 0.0), (-1.280785322189331, -0.19509035348892212, 0.0), (0.3950919806957245, 1.2807848453521729, 0.0), (0.3950919806957245, -1.2807848453521729, 0.0), (-0.3950919806957245, 1.2807848453521729, 0.0), (-0.3950919806957245, -1.2807848453521729, 0.0), (1.280785322189331, 0.39509034156799316, 0.0), (1.280785322189331, -0.39509034156799316, 0.0), (-1.280785322189331, 0.39509034156799316, 0.0), (-1.280785322189331, -0.39509034156799316, 0.0), (0.0, 1.5807849168777466, 0.0), (0.0, -1.5807849168777466, 0.0), (1.5807852745056152, 0.0, 0.0), (-1.5807852745056152, 0.0, 0.0)] edges = [(0, 4), (1, 5), (2, 6), (3, 7), (4, 8), (5, 9), (6, 10), (7, 11), (8, 12), (9, 13), (10, 14), (11, 15), (16, 20), (17, 21), (18, 22), (19, 23), (20, 24), (21, 25), (22, 26), (23, 27), (0, 24), (1, 25), (2, 26), (3, 27), (16, 28), (17, 29), (18, 30), (19, 31), (12, 32), (13, 33), (14, 34), (15, 35), (28, 36), (29, 37), (30, 38), (31, 39), (32, 40), (33, 41), (34, 42), (35, 43), (36, 44), (37, 45), (38, 44), (39, 45), (40, 46), (41, 46), (42, 47), (43, 47)] mesh = obj.data mesh.from_pydata(verts, edges, []) mesh.update() #============================================= # Misc #============================================= def get_rig_type(rig_type): """ Fetches a rig module by name, and returns it. """ #print("%s.%s.%s" % (__package__,RIG_DIR,rig_type)) submod = __import__(name="%s.%s.%s" % (MODULE_NAME, RIG_DIR, rig_type), fromlist=[rig_type]) imp.reload(submod) return submod def connected_children_names(obj, bone_name): """ Returns a list of bone names (in order) of the bones that form a single connected chain starting with the given bone as a parent. If there is a connected branch, the list stops there. """ bone = obj.data.bones[bone_name] names = [] while True: connects = 0 con_name = "" for child in bone.children: if child.use_connect: connects += 1 con_name = child.name if connects == 1: names += [con_name] bone = obj.data.bones[con_name] else: break return names def has_connected_children(bone): """ Returns true/false whether a bone has connected children or not. """ t = False for b in bone.children: t = t or b.use_connect return t def get_layers(layers): """ Does it's best to exctract a set of layers from any data thrown at it. """ if type(layers) == int: return [x == layers for x in range(0, 32)] elif type(layers) == str: s = layers.split(",") l = [] for i in s: try: l += [int(float(i))] except ValueError: pass return [x in l for x in range(0, 32)] elif type(layers) == tuple or type(layers) == list: return [x in layers for x in range(0, 32)] else: try: list(layers) except TypeError: pass else: return [x in layers for x in range(0, 32)] def write_metarig(obj, layers=False, func_name="create_sample"): ''' Write a metarig as a python script, this rig is to have all info needed for generating the real rig with rigify. ''' code = [] code.append("def %s(obj):" % func_name) code.append(" # generated by rigify.utils.write_metarig") bpy.ops.object.mode_set(mode='EDIT') code.append(" bpy.ops.object.mode_set(mode='EDIT')") code.append(" arm = obj.data") arm = obj.data # write parents first bones = [(len(bone.parent_recursive), bone.name) for bone in arm.edit_bones] bones.sort(key=lambda item: item[0]) bones = [item[1] for item in bones] code.append("\n bones = {}\n") for bone_name in bones: bone = arm.edit_bones[bone_name] code.append(" bone = arm.edit_bones.new('%s')" % bone.name) code.append(" bone.head[:] = %.4f, %.4f, %.4f" % bone.head.to_tuple(4)) code.append(" bone.tail[:] = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4)) code.append(" bone.roll = %.4f" % bone.roll) code.append(" bone.use_connect = %s" % str(bone.use_connect)) if bone.parent: code.append(" bone.parent = arm.edit_bones[bones['%s']]" % bone.parent.name) code.append(" bones['%s'] = bone.name" % bone.name) bpy.ops.object.mode_set(mode='OBJECT') code.append("") code.append(" bpy.ops.object.mode_set(mode='OBJECT')") # Rig type and other pose properties for bone_name in bones: pbone = obj.pose.bones[bone_name] pbone_written = False code.append(" pbone = obj.pose.bones[bones['%s']]" % bone_name) code.append(" pbone.rigify_type = '%s'" % pbone.rigify_type) code.append(" pbone.lock_location = %s" % str(tuple(pbone.lock_location))) code.append(" pbone.lock_rotation = %s" % str(tuple(pbone.lock_rotation))) code.append(" pbone.lock_rotation_w = %s" % str(pbone.lock_rotation_w)) code.append(" pbone.lock_scale = %s" % str(tuple(pbone.lock_scale))) code.append(" pbone.rotation_mode = '%s'" % str(pbone.rotation_mode)) if layers: code.append(" pbone.bone.layers = %s" % str(list(pbone.bone.layers))) # Rig type parameters if len(pbone.rigify_parameters) > 0: code.append(" pbone.rigify_parameters.add()") for param_name in pbone.rigify_parameters[0].keys(): param = getattr(pbone.rigify_parameters[0], param_name) if str(type(param)) == "": param = list(param) code.append(" try:") code.append(" pbone.rigify_parameters[0].%s = %s" % (param_name, str(param))) code.append(" except AttributeError:") code.append(" pass") code.append("\n bpy.ops.object.mode_set(mode='EDIT')") code.append(" for bone in arm.edit_bones:") code.append(" bone.select = False") code.append(" bone.select_head = False") code.append(" bone.select_tail = False") code.append(" for b in bones:") code.append(" bone = arm.edit_bones[bones[b]]") code.append(" bone.select = True") code.append(" bone.select_head = True") code.append(" bone.select_tail = True") code.append(" arm.edit_bones.active = bone") return "\n".join(code) def random_id(length = 8): """ Generates a random alphanumeric id string. """ tlength = int(length / 2) rlength = int(length / 2) + int(length % 2) chars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] text = "" for i in range(0, rlength): text += random.choice(chars) text += str(hex(int(time.time())))[2:][-tlength:].rjust(tlength, '0')[::-1] return text