def execute(self, context): if self.bones: bones = eval(self.bones) else: bones = Get.selected_pose_bones(context) if not bones: return {'CANCELLED'} wgts = readWidgets() if self.widget: widget = wgts[self.widget] else: widget = wgts[context.scene.widget_list] for bone in bones: if bone.id_data.proxy: continue slide = list(self.slide) rotate = list(self.rotate) if self.mirror: mirror = findMirrorObject(bone) if mirror and mirror in bones and bone.name.endswith( ('L', 'l')): slide[0] *= -1 rotate[1] *= -1 rotate[2] *= -1 createWidget( context, bone, widget, self.relative_size, self.global_size, [*self.scale], slide, rotate, get_collection(context), ) utils.update(context) pr = utils.prefs(__addon__).bone_widgets # pr = prefs.prefs().bone_widgets if pr.keep_settings: pr.slide = self.slide pr.rotate = self.rotate pr.relative_size = self.relative_size pr.global_size = self.global_size pr.scale = self.scale pr.mirror = self.mirror # Create new object then delete it. # When creating multiple widgets, if the last one tries to enter edit # mode before a particular update occurs, Blender will crash. # If the last object created (I.E. this empty) is not the widget, # Blender can enter edit mode without crash Get.objects(context, link=True).unlink(New.object(context)) return {'FINISHED'}
def object(context, name='Object', data=None, link=True): """ Create a new object using the specified data. If no data is provided, the object will be an empty. """ object = bpy.data.objects.new(name, data) if link: Get.objects(context, link=True).link(object) return object
def in_scene(context, object, value=True): # TODO: set this function to be able to remove an object from scene # currently it ONLY uses the value for set at True if value: if Is.collection(object): scn = context.scene if not Get.collection_from_scene(object, scn.collection): scn.collection.children.link(object) elif not (Is.in_scene(context, object) and Is.in_view(context, object)): Get.objects(context, link=True).link(object)
def poll_parse(self, context, rig): null = [None] * 3 if not Is.armature(rig): return null val = rig.get('daz_to_rigify') if val == 'metarig': meta = rig for rig in Get.objects(context): if rig.get('daz_to_rigify') == repr(meta): break else: rig = meta.data.rigify_target_rig if rig is None: return null elif val is None: if rig.data.rigify_layers: # Is a regular metarig meta = rig else: # Is a regular rig return null else: try: meta = eval(val) if meta is None: return null except: return null return (meta, rig)
def execute(self, context): active = Get.active(context) active_select = Is.selected(active) selected = Get.selected(context) is_pose = bool(context.mode == 'POSE') arg = dict(only_selected=bool(selected)) if is_pose: clear = bpy.ops.pose.paths_clear # Operator only runs on active rig, so repeat for all in pose mode if selected: obs = {b.id_data for b in selected} else: obs = {ob for ob in Get.objects(context) if ob.mode == 'POSE'} for ob in obs: Set.active(context, ob) clear(**arg) else: Set.active(context, active) Set.select(active, active_select) elif bpy.ops.object.paths_clear.poll(context.copy()): bpy.ops.object.paths_clear(**arg) return {'FINISHED'}
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 poll(cls, context): ob = context.object if Is.armature(ob) and ob.mode in ('POSE', 'EDIT'): return Get.selected(context, ob) if not bpy.ops.paint.weight_from_bones.poll(context.copy()): return if Is.mesh(ob) and (ob.mode == 'WEIGHT_PAINT'): for mod in ob.modifiers: if (mod.type == 'ARMATURE') and (mod.object in Get.objects(context)[:]): if mod.object.mode == 'POSE': return True
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 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 get_selected_keys_and_extents(): context = bpy.context pbones = context.selected_pose_bones if pbones is None: pbones = [] curve_datas = [] selected = [] objects = [] bones = [] fcurves = [] try: only_selected = context.space_data.dopesheet.show_only_selected show_hidden = context.space_data.dopesheet.show_hidden except: only_selected = True show_hidden = False def add_obj(obj): if show_hidden is False and not Is.visible(context, obj): return None if obj not in selected: selected.append(obj) def add_bone(b): if only_selected and not b.bone.select: return None add_obj(b.id_data) bones.append(b) for obj in Get.objects(context): if show_hidden is False and not Is.visible(context, obj): continue # Add object and bones if not (only_selected and not Is.selected(obj)): add_obj(obj) if obj.pose is not None: for (name, pbone) in obj.pose.bones.items(): if any((only_selected is False, Is.selected(obj), pbone in pbones,)): add_bone(pbone) # Add fcurves from objects for obj in selected: anim = obj.animation_data if anim and anim.action: fcurves.extend([(obj, fc) for fc in anim.action.fcurves]) # Scan fcurves for keyframes for obj, curve in fcurves: if curve.hide or curve.lock or not curve.select: continue first_co = None points = None last_co = None path = curve.data_path # Read path to get target's name if (path.startswith('pose.bones')): # btype = 'BONE' # bpath = path.split('"]', 1)[1] ## Transforms and custom prop # if (bpath.startswith('.')): ## constraints? # bpath = bpath.split('.', 1)[1] bname = (path.split('["', 1)[1].split('"]', 1)[0]) bone = obj.pose.bones.get(bname) elif (path.startswith('bones')): # data.bones # btype = 'BONE' # bpath = path.split('"].', 1)[1] bname = (path.split('["', 1)[1].split('"]', 1)[0]) bone = obj.bones.get(bname) else: # btype = 'OBJECT' # bpath = path bname = obj.name bone = obj if (bone is None and curve.is_valid is True) or (bone is not None and bone != obj and bone not in bones): # Bone not selected continue keyframes_referenced = [] keyframes_data = [] for keyframe in curve.keyframe_points: if keyframe.select_control_point: if first_co is None: first_co = keyframe.co else: last_co = keyframe.co keyframes_referenced.append(keyframe) keyframes_data.append({ 'co': deepcopy(keyframe.co), 'handle_left': deepcopy(keyframe.handle_left), 'handle_right': deepcopy(keyframe.handle_right) }) # needs to be all three data points! if last_co is not None: curve_datas.append([keyframes_referenced, first_co, last_co, keyframes_data, curve]) return curve_datas
def get_keys(self, context): scn_frame = context.scene.frame_current_final fcurves = dict() quats = dict() updates = dict() break_sync = False if hasattr(context.scene, 'sync'): break_sync = context.scene.sync.sync_3d and context.scene.sync.sync_between_3d if context.mode == 'POSE': # objects = [o for o in Get.objects(context) if o.mode == 'POSE'] objects = list() for ob in Get.objects(context): if ob.mode != 'POSE': continue bones = tuple([f"pose.bones[\"{b.name}\"]" for b in Get.selected_pose_bones(context, ob)]) if bones: objects.append((ob, bones)) if not objects: for ob in Get.objects(context): if ob.mode != 'POSE': continue bones = tuple([f"pose.bones[\"{b.name}\"]" for b in ob.pose.bones if Is.visible(context, b)]) if bones: objects.append((ob, bones)) else: objects = [(o, list()) for o in Get.selected_objects(context)] for (ob, bones) in objects: for anim in Get.animation_datas(ob): action = anim.action if not action: continue if anim.use_tweak_mode: frame = Get.frame_to_strip(context, anim, scn_frame) for s in Get.strips(anim.id_data): if s.action == action: strip = s if s.active: break blend = strip.blend_type else: frame = scn_frame blend = anim.action_blend_type offset = abs(frame - scn_frame) if (scn_frame < frame): offset *= -1 for fc in anim.action.fcurves: path = fc.data_path index = fc.array_index if len(fc.keyframe_points) < 2: continue if bones: src = None for bone in bones: if path.startswith(bone): try: eval(repr(ob) + '.' + path) # Validate path src = eval(repr(ob) + '.' + bone) attr = path.replace(bone, '', 1) if attr.startswith('.'): attr = attr.replace('.', '', 1) is_custom = False else: is_custom = True except: # curve points to a removed bone or something src = None break else: # Pose mode but bone not selected continue if src is None: # Missing bone continue else: attr = path src = ob if attr in transforms: is_custom = False elif attr.startswith('["'): is_custom = True else: # if attr.startswith(('pose.bones', 'bones')): continue # Find the property to be able to manipulate, and its current value if is_custom: prop = src split = attr.rsplit('"]["', 1) if len(split) == 2: prop = eval(repr(src) + split[0] + '"]') attr = '["' + split[1] prop_value = getattr(prop, attr) elif hasattr(src, attr): prop = getattr(src, attr) if Is.iterable(prop): # elif attr in transforms: # prop = src.path_resolve(attr) prop_value = prop[index] else: prop = src prop_value = getattr(prop, attr) else: # maybe a constraint: # pose.bones[bone.name].constraints[con.name].influence continue # Function to apply values to the bone/object, later if Is.iterable(prop): def apply(self, val): "Function to apply values to (array) in bone/object, later" self.prop[self.index] = val prop = src.path_resolve(attr) prop_value = prop[index] is_array = True else: def apply(self, val): setattr(self.prop, self.attr, val) is_array = False cache = dict( attr=attr, apply=apply, index=index, is_array=is_array, key=None, quat=None, prop=prop, src=src, value=fc.evaluate(frame), ) left = type('', (), cache) current = type('', (), cache) current.found = False right = type('', (), cache) pre_key = None # Find the current keyframe, and keys left and right if break_sync: # types = context.scene.keyframe_navigation_types types = ('KEYFRAME', 'MOVING_HOLD') for key in fc.keyframe_points: if key.co.x < frame: if (left.key is None) or (key.type in types): left.key = key left.value = key.co.y right.key = key right.value = key.co.y elif key.co.x == frame: if left.key is None: left.key = key left.value = key.co.y current.key = key current.found = True right.key = key right.value = key.co.y elif key.co.x > frame: if left.key is None: left.key = key left.value = key.co.y if (key.type in types) or key == fc.keyframe_points[-1]: right.key = key right.value = key.co.y break if not (left.key and right.key): for key in fc.keyframe_points: if key.co.x < frame: left.key = key left.value = key.co.y right.key = key right.value = key.co.y elif key.co.x == frame: if left.key is None: left.key = key left.value = key.co.y current.key = key current.found = True right.key = key right.value = key.co.y elif key.co.x > frame: if left.key is None: left.key = key left.value = key.co.y right.key = key right.value = key.co.y break if not (left.key and right.key): # Nothing to tween continue # Get info for current keyframe's defaults sVal = left.key.co.x + offset eVal = right.key.co.x + offset current.w1 = frame - sVal current.w2 = eVal - frame left.frame = left.key.co.x current.frame = frame right.frame = right.key.co.x current.in_range = False if frame < left.frame: left.value = prop_value elif right.frame < frame: right.value = prop_value else: current.in_range = True if blend == 'REPLACE': current.value = prop_value else: if not self.has_additive: self.has_additive = True if current.key: value = current.key.co.y else: value = fc.evaluate(frame) left.value = prop_value + (left.value - value) current.value = prop_value # + (value - value) right.value = prop_value + (right.value - value) if tween.update: if sVal not in updates: updates[sVal] = list() if eVal not in updates: updates[eVal] = list() updates[sVal].append(left) updates[eVal].append(right) # Add classes to memory fcurves[fc] = [left, current, right] if attr == 'rotation_quaternion': # Do math for quaternions if (action, path) not in quats: quats[(action, path)] = dict() if (src.lock_rotations_4d or not src.lock_rotation_w) \ and True not in src.lock_rotation[:]: quats[(action, path)][index] = (left, current, right) if updates: for frame in updates: context.scene.frame_set(frame) for (cls) in updates[frame]: if Is.iterable(prop): cls.value = cls.prop[cls.index] else: cls.value = getattr(cls.prop, cls.attr) context.scene.frame_set(scn_frame) for (action, path) in quats: if len(quats[action, path]) < 4: continue (w_left, w_current, w_right) = quats[action, path][0] (x_left, x_current, x_right) = quats[action, path][1] (y_left, y_current, y_right) = quats[action, path][2] (z_left, z_current, z_right) = quats[action, path][3] left_quat = [x.value for x in (w_left, x_left, y_left, z_left)] current_quat = [x.value for x in (w_current, x_current, y_current, z_current)] right_quat = [x.value for x in (w_right, x_right, y_right, z_right)] cpp.normalize_qt(left_quat) cpp.normalize_qt(current_quat) cpp.normalize_qt(right_quat) for x in (w_left, x_left, y_left, z_left): x.quat = left_quat for x in (w_current, x_current, y_current, z_current): x.quat = current_quat for x in (w_right, x_right, y_right, z_right): x.quat = right_quat return fcurves
def update_pose(self, context): # for region in context.area.regions: # if region.type == 'WINDOW': # break # else: # return self.cancel(context) region = context.region rv3d = context.space_data.region_3d gp = context.annotation_data stroke = gp.layers.active.frames[0].strokes[0] for chain in Get.sorted_chains(context.selected_pose_bones): bone_chain = list() for bone in reversed(chain): bone_chain.insert(0, bone) if bone == chain[0]: # Do location pass # continue # or break; should do the same else: pass while bone.parent not in chain: # Do unselected in betweens bone = bone.parent if not Is.visible(context, bone): # Don't rotate hidden bones continue bone_chain.insert(0, bone) bcount = len(bone_chain) - 1 gcount = len(stroke.points) - 1 # if bcount: # while gcount > bcount * 3: # # Split point count in half # index = 0 # while index < len(stroke.points) - 1: # stroke.points.pop(index=index + 1) # index += 1 # print(bcount, gcount, '\t', index, len(stroke.points)) # gcount = len(stroke.points) - 1 bone_mats = list() con_tmp = list() index = 0 for bone in bone_chain: if index > bcount: index = bcount point_index = utils.scale_range(index, 0, bcount, 0, gcount) point = stroke.points[int(point_index)] if index == 0: if not (bone.parent): bone = bone_chain[0] point = stroke.points[0] to_2d = location_3d_to_region_2d( region, rv3d, point.co) # get 2d space of stroke if to_2d: to_3d = region_2d_to_location_3d( region, rv3d, to_2d, bone.head) # keep depth of bone empty = New.object(context, bone.name) empty.empty_display_size = 0.25 empty.location = to_3d con = bone.constraints.new('COPY_LOCATION') con.target = empty con_tmp.append((bone, con, empty)) if bcount == 0: point = stroke.points[-1] else: # index += 1 point_index = utils.scale_range( 0.5, 0, bcount, 0, gcount) point = stroke.points[int(point_index)] to_2d = location_3d_to_region_2d( region, rv3d, point.co) # get 2d space of stroke if to_2d: to_3d = region_2d_to_location_3d( region, rv3d, to_2d, bone.tail) # keep depth of bone empty = New.object(context, bone.name) empty.empty_display_size = 0.1 empty.location = to_3d con = bone.constraints.new('DAMPED_TRACK') con.target = empty con_tmp.append((bone, con, empty)) index += 1 utils.update(context) for (bone, con, empty) in reversed(con_tmp): mat = Get.matrix_constraints(context, bone) # mat = Get.matrix(bone) bone_mats.append((bone, mat)) bone.constraints.remove(con) Get.objects(context, link=True).unlink(empty) for (bone, mat) in bone_mats: Set.matrix(bone, mat) keyframe.keyingset(context, selected=[bone], skip_bones=True) self.remove_annotation(context) return {'FINISHED'}