def selected(context, src=None, mirror=False, mirror_x_only=True): """ return selected objects or selected bones. If src is specified, return selected bones from it """ mode = context.mode if mode in ('POSE', 'PAINT_WEIGHT'): selected = Get.selected_pose_bones(context, src) if mirror: for bone in selected: rig = bone.id_data if (rig.pose.use_mirror_x or not mirror_x_only): flip = rig.pose.bones.get(utils.flip_name(bone.name)) if flip and (flip not in selected): selected.append(flip) elif mode == 'EDIT_ARMATURE': selected = Get.selected_edit_bones(context, src) if mirror: for bone in selected: arm = bone.id_data if (arm.use_mirror_x or not mirror_x_only): flip = arm.edit_bones.get(utils.flip_name(bone.name)) if flip and (flip not in selected): selected.append(flip) else: selected = Get.selected_objects(context, True) return selected
def get_name(bone, bbone): bn = bone.name (prefix, replace, suffix, number) = utils.flip_name(bn, only_split=True) if bn == bn.title(): bbone = bbone.title() elif bn == bn.upper(): bbone = bbone.upper() if prefix and replace: return f"{prefix}.{bbone}{replace}{suffix}{number}" elif (suffix or number) and (bn != utils.flip_name(bn)): return f"{prefix}{replace}{suffix}.{bbone}{number}" else: return f"{bn}.{bbone}"
def execute(self, context): obj = context.object in_edit = (obj.mode == 'EDIT') if in_edit: Set.mode(context, 'OBJECT') active = obj.active_shape_key vg = active.vertex_group index = obj.active_shape_key_index pin = obj.show_only_shape_key obj.show_only_shape_key = True active.vertex_group = '' bpy.ops.object.shape_key_add(from_mix=True) while obj.active_shape_key_index > (index + 1): bpy.ops.object.shape_key_move(type='UP') active.vertex_group = vg shape = obj.active_shape_key if self.mirror: shape.name = utils.flip_name(active.name) shape.vertex_group = utils.flip_name(vg) else: shape.vertex_group = vg shape.name = active.name for var in ('interpolation', 'mute', 'relative_key', 'slider_max', 'slider_min', 'value'): setattr(shape, var, getattr(active, var)) driver = Get.driver(active, var) if not driver: continue newdriver = utils.copy_driver(driver, shape, var) if self.mirror: for v in newdriver.driver.variables: for t in v.targets: t.bone_target = utils.flip_name(t.bone_target) # obj.active_shape_key_index = index obj.show_only_shape_key = pin if in_edit: Set.mode(context, 'EDIT') return {'FINISHED'}
def mirror_bone(bone): name = utils.flip_name(bone.name) if name == bone.name: return if Is.posebone(bone): return bone.id_data.pose.bones.get(name) elif Is.editbone(bone): return bone.id_data.edit_bones.get(name) elif Is.bone(bone): return bone.id_data.bones.get(name)
def description(cls, context, properties): txt = cls.bl_description if properties.mirror: obj = context.object if obj and obj.active_shape_key: active = obj.active_shape_key sk = utils.flip_name(active.name) vg = utils.flip_name(active.vertex_group) if (sk != active.name): txt += f", and name it {sk}" if (vg != active.vertex_group): txt += f" with the vertex group [{vg}]" elif (vg != active.vertex_group): txt += f", and switch its vertex group with [{vg}]" else: txt += ", and flip it's name and vertex group if it has a Left/Right mirroed name indicators" return txt
def add_bones_dupli(self, context, rig): # Add bones then set their defaults root = self.get_root(rig) prev_bones = self.get_prev_bones(rig) pose_bones = [] flip_bones = [] def add_bone(bone_name): prev = rig.data.edit_bones[bone_name] bone = rig.data.edit_bones.new(prev.name) pose_bones.append([bone.name, prev.name]) self.reset(bone, prev) bone.parent = prev.parent bone.use_deform = prev.use_deform for bone_name in prev_bones: add_bone(bone_name) if rig.pose.use_mirror_x: flip = utils.flip_name(bone_name) if (flip in rig.data.edit_bones) and (flip not in ( *prev_bones, *(p for (b, p) in pose_bones))): # Mirrored bone exists but not selected add_bone(flip) flip_bones.append(flip) # Switch back to Pose mode and setup pose bones Set.mode(context, 'POSE', rig) for (bone, prev) in pose_bones: bone = rig.pose.bones[bone] prev = rig.pose.bones[prev] if (prev.name not in flip_bones): rig.data.bones.active = bone.bone bone.custom_shape = prev.custom_shape bone.custom_shape_transform = prev.custom_shape_transform bone.bone.show_wire = prev.bone.show_wire bone.matrix = prev.matrix bone.bone_group = prev.bone_group for lock in [ 'location', 'rotations_4d', 'rotation_w', 'rotation', 'scale' ]: setattr(bone, 'lock_' + lock, getattr(prev, 'lock_' + lock))
def pose_func(self, context, bone): rig = bone.id_data bones = rig.pose.bones bbones = ('bbone', 'bbone_start', 'bbone_end', 'bbone_head', 'bbone_in', 'bbone_out') def parse(bbone): self.bones[bbone] = rig # Prep the widget for removal wgt = bbone.custom_shape if wgt: self.widgets.add(wgt) # Remove stretch constraints for con in list(bone.constraints): if (getattr(con, 'target', None) == rig) and (con.subtarget == bbone.name): bone.constraints.remove(con) # Remove Custom Handle if bone.bbone_custom_handle_start == bbone: bone.bone.bbone_custom_handle_start = None bone.bone.bbone_handle_type_start = 'AUTO' if bone.bbone_custom_handle_end == bbone: bone.bone.bbone_custom_handle_end = None bone.bone.bbone_handle_type_end = 'AUTO' for bbone_name in bbones: bbone = bones.get(get_name(bone, bbone_name)) if not bbone: continue parse(bbone) if bbone_name in ('bbone_start', 'bbone_end') and Get.mirror_bone(bbone): (prefix, replace, suffix, number) = utils.flip_name(bone.name, only_split=True) center_name = prefix + suffix + number center = bones.get(center_name) if center: parse(center) # Remove BBone drivers if bbone_name in ('bbone_in', 'bbone_out'): in_out = bbone_name.split('_')[1] in_outs = ( f'bbone_curve{in_out}x', f'bbone_curve{in_out}y', f'bbone_roll{in_out}', f'bbone_scale{in_out}x', f'bbone_scale{in_out}y', f'bbone_ease{in_out}', ) for bbone_in_out in in_outs: Driver = Get.driver(bone, bbone_in_out) try: target = Driver.driver.variables[0].targets[0] except: continue if (target.bone_target == bbone.name) and (target.id == rig): bone.driver_remove(bbone_in_out)
def edit_mirror_center(self, context): def get_bones(rig, bbone): ebones = rig.data.edit_bones ebone = ebones.get(get_name(bone, bbone)) mebone = Get.mirror_bone(ebone) return (ebone, mebone) found = [] for (bone, rig) in self.selected: if not (rig.pose.use_mirror_x or rig.data.use_mirror_x): continue mbone = Get.mirror_bone(bone) if mbone in found: continue else: found.append(bone) (ebone, mebone) = get_bones(rig, 'bbone_start') if not (ebone and mebone): continue if (ebone.parent == mebone.parent): # Connect heads if Is.connected(bone): # The parent will already handle the symmetry continue parent = ebone.parent else: (ebone, mebone) = get_bones(rig, 'bbone_end') if not (ebone and mebone): continue # Find a mutual parent between the two bones parent = [ *(x for x in ebone.parent_recursive if x in mebone.parent_recursive), None ][0] distance = abs(sum(ebone.head) - sum(mebone.head)) / 2 margin = utils.lerp(bone.bone.length, mbone.bone.length, 0.5) / bone.bone.bbone_segments if distance >= margin: # Bones too far apart continue (prefix, replace, suffix, number) = utils.flip_name(bone.name, only_split=True) center_name = prefix + suffix + number center = New.bone(context, rig, name=center_name, overwrite=True) attributes = [ 'head', 'head_radius', 'tail', 'tail_radius', 'roll', 'matrix', 'layers', 'bbone_x', 'bbone_z', ] for atr in attributes: if hasattr(center, atr): setattr( center, atr, utils.lerp(getattr(ebone, atr), getattr(mebone, atr), 0.5)) center.use_deform = False center.inherit_scale = 'NONE' center.parent = parent center.hide = True ebone.parent = mebone.parent = center self.hide_bones[rig].extend((ebone.name, mebone.name)) self.center_bones[rig].append(center.name)