def poll(cls, context): if context.mode == 'OBJECT': for o in context.selected_objects: if o and o.type == 'MESH': return True elif context.mode == 'EDIT_MESH': for o in Get.in_view(context): if o and o.type == 'MESH' and o.mode == 'EDIT': return True
def execute(self, context): value = None for (ob, strips) in Get.strips_nla(context): for item in strips: if value is None: value = not item.strip.use_sync_length item.strip.use_sync_length = value return {'FINISHED'}
def active(context, target): """Set target as active scene object or bone""" objects = Get.objects(context) # Remember previous active previous = Get.active(context) selected = Is.selected(target) # Set the active if Is.object(target): obj = target elif Is.posebone(target): obj = target.id_data obj.data.bones.active = obj.data.bones.get(target.name) elif isinstance(target, bpy.types.Armature): obj = Get.rig(context, target) elif Is.bone(target): obj = Get.rig(context, target) bones = target.id_data.bones bones.active = bones.get(target.name) elif Is.editbone(target): obj = Get.rig(context, target) if obj: in_edit = (obj.mode == 'EDIT') else: in_edit = (context.mode == 'EDIT_ARMATURE') if in_edit: bones = target.id_data.edit_bones bones.active = bones.get(target.name) elif target is None: obj = None # debug("Set.active() has None as the target") else: assert None, ("Set.active() can't use the provided target", target) if (target and Is.selected(target) != selected): # When setting a bone as active in a rig, it gets selected as well. Set.select(target, selected) objects.active = obj return previous
def execute(self, context): # editWidget(context, context.active_pose_bone) bones = Get.selected_pose_bones(context) # bpy.ops.object.mode_set(mode='OBJECT') for bone in bones: if (bone.custom_shape) and (not bone.id_data.proxy): editWidget(context, bone) return {'FINISHED'}
def execute(self, context): rig = context.active_object active = None if context.mode == 'PAINT_WEIGHT': for obj in context.selected_objects: if obj.type == 'ARMATURE': active = rig rig = obj Set.active(context, rig) # if rig.type =='ARMATURE' and context.mode != 'EDIT_ARMATURE': meshes = self.get_meshes(context, rig) bone1 = context.active_pose_bone # bone2 = context.selected_pose_bones[1] for bone2 in context.selected_pose_bones: if bone2 == bone1: continue found = None for mesh in meshes: utils.merge_vertex_groups( mesh, bone1.name, bone2.name, # If remove is False, and the bone stayed, it would be equivalent to transferring only partial weights remove=(self.mode == 'remove')) found = True # if found: # if self.mode == 'hide': # bone2.hide = True # elif self.mode == 'show': # bone2.hide = False # elif self.mode == 'remove': if (found and self.mode == 'remove'): for ch in bone2.id_data.children: if (ch.parent_type == 'BONE') and (ch.parent_bone == bone2.name): mat = Get.matrix(ch) ch.parent_bone = bone1.name Set.matrix(ch, mat) name2 = bone2.name Set.mode(context, mode='EDIT') bone2 = rig.data.edit_bones[name2] rig.data.edit_bones.remove(bone2) Set.mode(context, mode='POSE') if active: Set.active(context, active) return {'FINISHED'}
def fcurve(action, path, index=-1, group=""): """Create a new fcurve in an action if it doesn't exist""" if group is None: group = "" fc = Get.fcurve(action, path, index) if fc is None: fc = action.fcurves.new(path, index=index, action_group=group) return fc
def execute(self, context): for src in Get.selected(context): if src.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'): src.rotation_quaternion *= -1 for (i, r) in enumerate(src.rotation_axis_angle): src.rotation_axis_angle[i] *= -1 if keyframe.use_auto(context): keyframe.rotation(context, src) return {'FINISHED'}
def update_constraint_matrix(mats): from zpy import utils # Set the matrix for con in constraints: if hasattr(con, 'use_offset') and con.use_offset: utils.update(context) # utils.update(context) for src in srcs: new_mat = Get.matrix_constraints(context, src, mats[src], constraints) mats[src] = new_mat
def rigify_to_meta(rigify, metarig): """Retarget Rigify meshes to Metarig""" pose = (metarig.data.pose_position, rigify.data.pose_position) (metarig.data.pose_position, rigify.data.pose_position) = ('REST', 'REST') utils.update(bpy.context) for obj in bpy.data.objects: if Is.curve(obj) and obj.name.startswith(rigify.name + '-MCH-'): # Splines from angavrilov's spline rig continue for mod in obj.modifiers: if hasattr(mod, 'object') and mod.object == rigify: mod.object = metarig metafy_vgroups(rigify, obj, metarig) if (obj.parent == rigify): rigify_bone = obj.parent_bone if rigify_bone: if rigify_bone.startswith('DEF-'): meta_bone = rigify_bone[4:] else: meta_bone = rigify_bone if meta_bone in metarig.data.bones: mat = Get.matrix(obj) # pmat = obj.matrix_parent_inverse.copy() obj.parent = metarig obj.parent_bone = meta_bone # obj.matrix_parent_inverse = pmat Set.matrix(obj, mat) else: obj.parent = metarig if Is.mesh(obj): meshes = {obj.data} if hasattr(obj, 'variants'): # The LoDs store the mesh datas and drivers without an object for layer in obj.variants.layers: if layer.mesh: meshes.add(layer.mesh) for lod in layer.lods: meshes.add(lod.mesh) for mesh in meshes: if mesh: rigify_drivers(rigify, metarig, mesh.shape_keys) for mat in bpy.data.materials: rigify_drivers(rigify, metarig, mat) rigify_drivers(rigify, metarig, mat.node_tree) (metarig.data.pose_position, rigify.data.pose_position) = pose
def get_rig_meshes(self, context): """ Find the selected rigs and meshes, attached together. If only a rig is selected, find all the meshes that use it. """ active = context.object if context.mode == 'PAINT_WEIGHT': meshes = {active} rig = None for mod in active.modifiers: if (mod.type == 'ARMATURE') and (mod.object in Get.objects(context)[:]): rig = mod.object if rig.mode == 'POSE': break if not rig: self.report({'ERROR'}, "Can't find rig using the active mesh") else: rig = active meshes = set() for ob in context.selected_objects: if Is.mesh(ob): for mod in ob.modifiers: if (mod.type == 'ARMATURE') and (mod.object == rig): meshes.add(ob) if not meshes: for ob in Get.objects(context): if not Is.visible(context, ob): continue for mod in ob.modifiers: if (mod.type == 'ARMATURE') and (mod.object == rig): meshes.add(ob) if not meshes: self.report({'ERROR'}, "Can't find mesh using the active rig") return (rig, meshes)
def set_influence(): def get_src(constraint): for src in srcs: for con in src.constraints: if con == constraint: return src for constraint in constraints: driver = Get.driver(constraint, 'influence') if driver: (constraint, prop) = Get.controls_from_driver(driver)[0] src = constraint else: prop = 'influence' src = get_src(constraint) if src is None: continue if influence is None: # mode = 'apply' pass elif influence is False: # mode = 'invert' setattr(constraint, prop, not getattr(constraint, prop)) else: # mode = 'set' setattr(constraint, prop, influence) # key_con = prefs.get("Keyframe Constraints Inf") # if key_con: if insert_key: keyframe.prop( context, constraint, prop, group=keyframe.group_name(src), options={'INSERTKEY_NEEDED'}, )
def execute(self, context): fac = (self.factor / 100) selected = Get.selected(context, mirror=True) for src in selected: base = pose.base[repr(src)] reset = pose.reset[repr(src)] if src.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'): euler = 'XYZ' else: euler = src.rotation_mode if Is.matrix(reset): matrix = utils.lerp(base, reset, fac) matrix = utils.matrix_to_transforms(matrix, euler=euler) else: location = base.to_translation() rotation_quaternion = base.to_quaternion() axis = base.to_quaternion().to_axis_angle() rotation_axis_angle = (*axis[0], axis[1]) rotation_euler = base.to_euler(euler) scale = base.to_scale() matrix = type( 'matrix and transforms', (), dict( location=utils.lerp(location, reset.location, fac), rotation_quaternion=utils.lerp( rotation_quaternion, reset.rotation_quaternion, fac), rotation_axis_angle=utils.lerp( rotation_axis_angle, reset.rotation_axis_angle, fac), rotation_euler=utils.lerp(rotation_euler, reset.rotation_euler, fac), scale=utils.lerp(scale, reset.scale, fac), )) if 'loc' in self.mode: src.location = matrix.location if 'rot' in self.mode: src.rotation_quaternion = matrix.rotation_quaternion src.rotation_axis_angle = matrix.rotation_axis_angle src.rotation_euler = matrix.rotation_euler if 'scale' in self.mode: src.scale = matrix.scale keyframe.keyingset(context, selected=selected) return {'FINISHED'}
def execute(self, context): global Auto_normalize, Locks ts = context.scene.tool_settings pbones = Get.selected_pose_bones(context, force=True) mode = self.mode obj = context.object # 2.8 doesn't do multi-object weight paint if Auto_normalize is None: # first run Auto_normalize = ts.use_auto_normalize # Without auto normalize, locks essentially do nothing if self.mode in ['None', 'DEFAULT']: # In case op called without invoke # Allow op to be called to only run in one mode regardless as to selection self.mode = 'None' mode = ('RESET', 'SET')[bool(pbones)] if mode == 'SET': bones = [b.name for b in pbones] toggled = 0 for vg in obj.vertex_groups: if (obj.name, vg.name) not in Locks: # store initial value Locks[obj.name, vg.name] = vg.lock_weight if vg.name in bones: vg.lock_weight = False toggled += 1 else: vg.lock_weight = True report = f"{toggled}/{len(obj.vertex_groups)} " \ "Bone Weight Groups Locked" ts.use_auto_normalize = True else: for vg in obj.vertex_groups: vg.lock_weight = Locks.get((obj.name, vg.name), vg.lock_weight) report = f"Reset {len(Locks)} Vertex Group Locks" # reset first run value ts.use_auto_normalize = Auto_normalize Auto_normalize = None Locks = {} self.report({'INFO'}, report) return {'FINISHED'}
def execute(self, context): # editWidget(context, context.active_pose_bone) bones = Get.selected_pose_bones(context) # bpy.ops.object.mode_set(mode='OBJECT') for bone in bones: wgt = bone.custom_shape if wgt and (not bone.id_data.proxy): bone.custom_shape = None if wgt.users < 2: # only used by widget collection now, so delete it bpy.data.objects.remove(wgt) return {'FINISHED'}
def execute(self, context): objs = self.get_objs(context) active_bone = context.active_pose_bone selected_bones = [ b for b in Get.selected_pose_bones(context) if b != active_bone ] for ob in objs: for b in selected_bones: if self.target == 'selected': utils.subtract_vertex_groups(ob, active_bone.name, b.name) elif self.target == 'active': utils.subtract_vertex_groups(ob, b.name, active_bone.name) return {'FINISHED'}
def active_select(context, target, isolate=True): # , isolate_mode=False): """ Set target as active scene object or bone, and select it\\ # isolate_mode would set all other selected objects to Object mode """ # def deselect(src): # if isolate_mode and src.id_data.mode != 'OBJECT': # Set.mode(context, 'OBJECT', src) # Set.select(src, False) if isolate: objects = Get.selected_objects(context) bones = Get.selected_pose_bones(context) for src in [*objects, *bones]: # deselect(src) Set.select(src, False) Set.visible(context, target, True) Set.active(context, target) Set.select(target, True) if Is.posebone(target): Set.mode(context, 'POSE', target)
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 hook(curve, target, index): mod = curve.modifiers.new("Modifier Name", 'HOOK') mod.object = target.id_data if Is.posebone(target): mod.subtarget = target.name # modifier sets indices (which are the points + their two handles) mod_points = (index * 3 + 0, index * 3 + 1, index * 3 + 2) mod.vertex_indices_set(mod_points) mod.matrix_inverse = Get.matrix(target).inverted_safe() # Set the matrix, to allow the hook to stay with the "posed" bones # Don't get target's matrix, because it hasn't been updated yet mod.show_expanded = False return mod
def meta_to_rigify(metarig, rigify): """Retarget Metarig meshes to Rigify rig""" pose = (metarig.data.pose_position, rigify.data.pose_position) (metarig.data.pose_position, rigify.data.pose_position) = ('REST', 'REST') utils.update(bpy.context) for obj in bpy.data.objects: for mod in obj.modifiers: if hasattr(mod, 'object') and mod.object == metarig: mod.object = rigify rigify_vgroups(metarig, rigify, obj) if obj.parent == metarig: if obj.parent_bone: rigify_bone = vg_names.get(obj.parent_bone, False) if rigify_bone is False: rigify_bone = 'DEF-' + obj.parent_bone if rigify_bone and rigify_bone in rigify.data.bones: mat = Get.matrix(obj) # pmat = obj.matrix_parent_inverse.copy() obj.parent = rigify obj.parent_bone = rigify_bone # obj.matrix_parent_inverse = pmat Set.matrix(obj, mat) else: obj.parent = rigify if Is.mesh(obj): meshes = {obj.data} if hasattr(obj, 'variants'): # The LoDs store the mesh datas and drivers without an object for layer in obj.variants.layers: if layer.mesh: meshes.add(layer.mesh) for lod in layer.lods: meshes.add(lod.mesh) for mesh in meshes: if mesh: rigify_drivers(metarig, rigify, mesh.shape_keys) for mat in bpy.data.materials: rigify_drivers(metarig, rigify, mat) rigify_drivers(metarig, rigify, mat.node_tree) (metarig.data.pose_position, rigify.data.pose_position) = pose
def poll_parse(self, context, rig): null = [None] * 2 if (not Is.armature(rig)): return null if (rig.data.get('rig_id') is None): meta = rig rig = meta.data.rigify_target_rig if rig is None: return null else: for meta in Get.objects(context): if Is.armature(meta) and meta.data.rigify_target_rig == rig: break else: return null return (rig, meta)
def restore_quats(skip): nonlocal quats for index in range(4): if index == skip: continue fc = Get.fcurve(action, keypath, index=index) if fc and len(fc.keyframe_points) > quats[index]: for key in fc.keyframe_points: if key.co.x == tweak_frame: fc.keyframe_points.remove(key) break else: # Shouldn't happen but backup in case fail to find key key_args = dict(index=index, frame=frame, group=group) if sub is None: src.keyframe_delete(path, **key_args) else: sub.keyframe_delete(path, **key_args)
def transfer_by_pos2(context, obj, selobj, ob_key, precision, scale): if (selobj.data.shape_keys is None): selobj.shape_key_add(from_mix=False).name = "Basis" selobj.active_shape_key_index = 0 selobj_keys = selobj.data.shape_keys.key_blocks index = 0 for (del_index, del_key) in enumerate(selobj_keys): if ob_key.name == del_key.name: index = del_index selobj.shape_key_remove(del_key) break selob_key = selobj.shape_key_add(name=ob_key.name, from_mix=False) if index: active = selobj.active_shape_key_index selobj.active_shape_key_index = len(selobj_keys) - 1 while selobj_keys[index] != selob_key: bpy.ops.object.shape_key_move((dict(object=selobj)), type='UP') selobj.active_shape_key_index = active # find matches using a rounding precision of 5 and a scale of 1 ddict = find_doubles_with_other(obj, selobj) nomatch = ddict[1] ddict = ddict[0] copydoublesco(ob_key, selob_key, ddict) # set precision and scale to use for the second pass # generates a dictionary which archives verts in active obj:matching vert in selected obj pass2 = generate_rounded_pos_dict(obj, precision, scale) round_pass(obj, selobj, ob_key, selob_key, nomatch, scale, precision, pass2) selob_key.vertex_group = ob_key.vertex_group selob_key.relative_key = ob_key.relative_key selob_key.slider_min = ob_key.slider_min selob_key.slider_max = ob_key.slider_max selob_key.value = ob_key.value driver = Get.driver(ob_key, 'value') if driver: utils.copy_driver(driver, selob_key, 'value')
def execute(self, context): obj = context.object in_edit = (obj.mode == 'EDIT') if in_edit: Set.mode(context, 'OBJECT') active = obj.active_shape_key index = obj.active_shape_key_index pin = obj.show_only_shape_key obj.show_only_shape_key = True 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') shape = obj.active_shape_key for var in ('interpolation', 'mute', 'relative_key', 'slider_max', 'slider_min', 'value'): setattr(shape, var, getattr(active, var)) # if self.keep_vertex_group: # shape.vertex_group = active.vertex_group # Redirect drivers, so that they auto update after operation for var in ('slider_max', 'slider_min', 'value'): driver = Get.driver(active, var) if driver: driver.data_path = f'key_blocks["{shape.name}"].{var}' # driver.data_path = driver.data_path.replace(active.name, shape.name, 1) name = active.name active.name += ".masked" shape.name = name obj.active_shape_key_index = index bpy.ops.object.shape_key_remove(all=False) obj.active_shape_key_index = index obj.show_only_shape_key = pin if in_edit: Set.mode(context, 'EDIT') return {'FINISHED'}
def draw_menu(self, context): w_menu = getattr(self, 'bl_idname', None) == 'VIEW3D_MT_pose_context_menu' # self.bl_label == 'Pose Context Menu' if w_menu and context.mode != 'PAINT_WEIGHT': return if not Locks: name = "Lock by Selected Bones" elif Get.selected_pose_bones(context, force=True): name = "Toggle Locks to Selected Bones" else: name = "Reset Weight Locks" layout = self.layout layout.operator('object.vertex_group_isolate_bones', text=name, icon='PINNED') if w_menu: layout.separator()
def get_rig_bones(context): rigs = dict() # rig object with a list of selected and mirrored bones selected = list() # remember selected and non-selected mirror bones for bone in context.selected_pose_bones: rig = bone.id_data if Is.linked(rig): continue if rig not in rigs: rigs[rig] = list() if (bone not in rigs[rig]): rigs[rig].append(bone) selected.append((bone, rig)) if (rig.pose.use_mirror_x or rig.data.use_mirror_x): mirror = Get.mirror_bone(bone) if mirror and (mirror not in rigs[rig]): rigs[rig].append(mirror) selected.append((mirror, rig)) return (rigs, selected)
def fix_toe_roll(): """ The Toe controller bone may have a bad automated roll, so recalculate it """ mode = Get.mode(rig) Set.mode(bpy.context, 'EDIT', rig) bones = rig.data.edit_bones ebones = bpy.context.selected_bones for ebone in ebones: ebone.select = False bone = tweak = None def get(name): nonlocal bone, tweak bone = bones.get(name) tweak = bones.get(name.replace('_master', '')) return (bone and tweak) def roll(name): if get(name): bone.select = True bones.active = tweak bpy.ops.armature.calculate_roll(type='ACTIVE') bone.select = False for lr in ('L', 'R'): for ind in range(1, 6): roll(f'toe{ind}.01_master.{lr}') roll(f'thumb.01_master.{lr}') roll(f'f_index.01_master.{lr}') roll(f'f_middle.01_master.{lr}') roll(f'f_ring.01_master.{lr}') roll(f'f_pinky.01_master.{lr}') for ebone in ebones: ebone.select = True Set.mode(bpy.context, mode, rig)
def get_pole(pole, line): from math import radians from mathutils import Matrix bone["pole_vector"] = 0 pole = get(pole) line = get(line) # lock rotation/scale, since bone only suppose to be moved pole.rotation_mode = 'XYZ' pole.lock_rotation_w = True pole.lock_rotation = (True, True, True) pole.lock_scale = (True, True, True) utils.update(bpy.context) mat = getmat(pole, line) @ Matrix.Rotation(radians(180), 4, 'X') rotcopy(pole, mat) utils.update(bpy.context) poles[pole.name] = Get.matrix(pole) rotcopy(pole, Matrix()) pole.location = (0, 0, 0)
def execute(self, context): active = Get.active(context) mode = context.mode pose = list() for rig in context.selected_objects: (rig, meta) = self.poll_parse(context, rig) if None in (rig, meta): continue rigify_to_meta(rig, meta) pose.append((meta, rig)) else: if mode == 'POSE': Set.mode(context, 'OBJECT') for (meta, rig) in pose: Set.select(rig, False) Set.select(meta, True) if rig == active: Set.active(context, meta) if mode == 'POSE': Set.mode(context, 'POSE') return {'FINISHED'}
def execute(self, context): # TODO: Redo / Cleanup code class props: keep_matrix = True connect = False connect_child = False stretch = False if self.type == 'BONE': pass elif self.type == 'BONE_CONNECT': connect = True elif self.type == 'STRETCH': stretch = True elif self.type == 'STRETCH_CONNECT': stretch = True connect = True elif self.type == 'CHILD_CONNECT': connect_child = True ap = context.active_pose_bone bones = dict() matrices = {b: b.matrix.copy() for b in context.selected_pose_bones} for rig in context.selected_objects: if rig.mode != 'POSE': continue Set.mode(context, 'EDIT', rig) mirror = rig.data.use_mirror_x rig.data.use_mirror_x = False ab = context.active_bone edit_bones = Get.selected_edit_bones(context, rig) if ab and ab.parent in edit_bones: for eb in [*ab.parent_recursive, None]: if eb in edit_bones: # bones.append((rig, eb.name)) continue ab.use_connect = False ab.parent = eb bones[ab.name] = rig break for eb in edit_bones: if props.connect_child: for bb in eb.children: if bb in edit_bones: eb.tail = bb.head bb.use_connect = True else: if eb == ab: # or it'll delete itself continue eb.use_connect = False if props.stretch: eb.head = ab.tail eb.parent = ab bones[eb.name] = rig if props.connect: head = ab.tail - eb.head tail = ab.tail - eb.tail connects = [] for ebc in [*eb.children_recursive, eb]: connects.append([ebc, ebc.use_connect]) ebc.use_connect = False for ebc, c in connects: ebc.translate(ab.tail - eb.head) for ebc, c in connects: ebc.use_connect = c eb.use_connect = True rig.data.use_mirror_x = mirror Set.mode(context, 'POSE', rig) if props.keep_matrix: # ap.matrix = matrices[ap] # update() for b in bones: rig = bones[b] bone = rig.pose.bones.get(b) if bone is None: print(f"{rig.name} can't find {b}", *rig.pose.bones, sep='\n\t') continue if bone == ap: # Skip changing the active bone continue if bone not in matrices: print("Skip matrix,", bone.name) continue Set.matrix(bone, matrices[bone]) utils.update(context) return {'FINISHED'}
def poll(self, context): if context.mode == 'PAINT_WEIGHT': return return Get.selected_pose_bones(context)