Changeset View
Changeset View
Standalone View
Standalone View
rigify/rigs/limbs/super_finger.py
| import bpy | import bpy | ||||
| from ...utils import copy_bone, flip_bone | import re | ||||
| from ...utils import strip_org, make_deformer_name, connected_children_names, make_mechanism_name | |||||
| from ...utils import create_circle_widget, create_widget | |||||
| from ...utils import MetarigError, align_bone_x_axis | |||||
| from ...utils.mechanism import make_property | |||||
| script = """ | |||||
| controls = [%s] | |||||
| master_name = '%s' | |||||
| if is_selected(controls): | |||||
| layout.prop(pose_bones[master_name], '["%s"]', text="Curvature", slider=True) | |||||
| """ | |||||
| from itertools import count, repeat | |||||
| class Rig: | from ...utils.errors import MetarigError | ||||
| from ...utils.rig import connected_children_names | |||||
| from ...utils.bones import flip_bone, align_chain_x_axis | |||||
| from ...utils.naming import strip_org, make_mechanism_name, make_deformer_name | |||||
| from ...utils.widgets import create_widget | |||||
| from ...utils.widgets_basic import create_circle_widget | |||||
| from ...utils.misc import map_list, map_apply | |||||
| def __init__(self, obj, bone_name, params): | from ...base_rig import * | ||||
| self.obj = obj | from ..chain_rigs import SimpleChainRig | ||||
| self.org_bones = [bone_name] + connected_children_names(obj, bone_name) | |||||
| self.params = params | |||||
| if len(self.org_bones) <= 1: | |||||
| raise MetarigError("RIGIFY ERROR: Bone '%s': listen bro, that finger rig jusaint put tugetha rite. A little hint, use more than one bone!!" % (strip_org(bone_name))) | |||||
| def orient_org_bones(self): | class Rig(SimpleChainRig): | ||||
| """A finger rig with master control.""" | |||||
| def initialize(self): | |||||
| super(Rig,self).initialize() | |||||
| bpy.ops.object.mode_set(mode='EDIT') | self.bbone_segments = 8 | ||||
| eb = self.obj.data.edit_bones | self.first_parent = self.get_bone_parent(self.bones.org[0]) | ||||
| def prepare_bones(self): | |||||
| if self.params.primary_rotation_axis == 'automatic': | if self.params.primary_rotation_axis == 'automatic': | ||||
| align_chain_x_axis(self.obj, self.bones.org) | |||||
| first_bone = eb[self.org_bones[0]] | ############################## | ||||
| last_bone = eb[self.org_bones[-1]] | # Master Control | ||||
| # Orient uarm farm bones | |||||
| chain_y_axis = last_bone.tail - first_bone.head | |||||
| chain_rot_axis = first_bone.y_axis.cross(chain_y_axis) # ik-plane normal axis (rotation) | |||||
| if chain_rot_axis.length < first_bone.length/100: | |||||
| chain_rot_axis = first_bone.x_axis.normalized() | |||||
| else: | |||||
| chain_rot_axis = chain_rot_axis.normalized() | |||||
| for bone in self.org_bones: | |||||
| align_bone_x_axis(self.obj, bone, chain_rot_axis) | |||||
| def generate(self): | @stage_generate_bones | ||||
| org_bones = self.org_bones | def make_master_control_bone(self): | ||||
| orgs = self.bones.org | |||||
| name = self.copy_bone(orgs[0], self.master_control_name(orgs[0]), parent=True) | |||||
| self.bones.ctrl.master = name | |||||
| first_bone = self.get_bone(orgs[0]) | |||||
| last_bone = self.get_bone(orgs[-1]) | |||||
| self.get_bone(name).tail += (last_bone.tail - first_bone.head) * 1.25 | |||||
| def master_control_name(self, org_name): | |||||
| # Compute master bone name: inherit .LR suffix, but strip trailing digits | |||||
| name_parts = re.match(r'^(.*?)(?:([._-])?\d+)?((?:[._-][LlRr])?)(?:\.\d+)?$', strip_org(org_name)) | |||||
| name_base, name_sep, name_suffix = name_parts.groups() | |||||
| name_base += name_sep if name_sep else '_' | |||||
| return name_base + 'master' + name_suffix | |||||
| @stage_configure_bones | |||||
| def configure_master_control_bone(self): | |||||
| master = self.bones.ctrl.master | |||||
| bone = self.get_bone(master) | |||||
| bone.lock_scale = True, False, True | |||||
| @stage_generate_widgets | |||||
| def make_master_control_widget(self): | |||||
| master_name = self.bones.ctrl.master | |||||
| bpy.ops.object.mode_set(mode='EDIT') | w = create_widget(self.obj, master_name) | ||||
| eb = self.obj.data.edit_bones | if w is not None: | ||||
| mesh = w.data | |||||
| verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)] | |||||
| if 'Z' in self.params.primary_rotation_axis: | |||||
| # Flip x/z coordinates | |||||
| temp = [] | |||||
| for v in verts: | |||||
| temp += [(v[2], v[1], v[0])] | |||||
| verts = temp | |||||
| edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)] | |||||
| mesh.from_pydata(verts, edges, []) | |||||
| mesh.update() | |||||
| self.orient_org_bones() | ############################## | ||||
| # Control chain | |||||
| # Bone name lists | @stage_generate_bones | ||||
| ctrl_chain = [] | def make_control_chain(self): | ||||
| def_chain = [] | orgs = self.bones.org | ||||
| mch_chain = [] | self.bones.ctrl.main = map_list(self.make_control_bone, orgs) | ||||
| mch_drv_chain = [] | self.bones.ctrl.main += [self.make_tip_control_bone(orgs[-1], orgs[0])] | ||||
| # Create ctrl master bone | def make_control_bone(self, org): | ||||
| org_name = self.org_bones[0] | return self.copy_bone(org, strip_org(org), parent=False) | ||||
| temp_name = strip_org(self.org_bones[0]) | |||||
| def make_tip_control_bone(self, org, name_org): | |||||
| if temp_name[-2:] == '.L' or temp_name[-2:] == '.R': | name = self.copy_bone(org, strip_org(name_org), parent=False) | ||||
| suffix = temp_name[-2:] | |||||
| master_name = temp_name[:-2] + "_master" + suffix | flip_bone(self.obj, name) | ||||
| self.get_bone(name).length /= 2 | |||||
| return name | |||||
| @stage_parent_bones | |||||
| def parent_control_chain(self): | |||||
| ctrls = self.bones.ctrl.main | |||||
| map_apply(self.set_bone_parent, ctrls, self.bones.mch.bend + ctrls[-2:]) | |||||
| @stage_configure_bones | |||||
| def configure_control_chain(self): | |||||
| map_apply(self.configure_control_bone, self.bones.org + [None], self.bones.ctrl.main) | |||||
| def configure_control_bone(self, org, ctrl): | |||||
| if org: | |||||
| self.copy_bone_properties(org, ctrl) | |||||
| else: | else: | ||||
| master_name = temp_name + "_master" | bone = self.get_bone(ctrl) | ||||
| master_name = copy_bone(self.obj, org_name, master_name) | bone.lock_rotation_w = True | ||||
| ctrl_bone_master = eb[master_name] | bone.lock_rotation = (True, True, True) | ||||
| bone.lock_scale = (True, True, True) | |||||
| # Parenting bug fix ?? | |||||
| ctrl_bone_master.use_connect = False | def make_control_widget(self, ctrl): | ||||
| ctrl_bone_master.parent = None | if ctrl == self.bones.ctrl.main[-1]: | ||||
| # Tip control | |||||
| ctrl_bone_master.tail += (eb[org_bones[-1]].tail - eb[org_name].head) * 1.25 | create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0) | ||||
| for bone in org_bones: | |||||
| eb[bone].use_connect = False | |||||
| if org_bones.index(bone) != 0: | |||||
| eb[bone].parent = None | |||||
| # Creating the bone chains | |||||
| for i in range(len(self.org_bones)): | |||||
| name = self.org_bones[i] | |||||
| ctrl_name = strip_org(name) | |||||
| # Create control bones | |||||
| ctrl_bone = copy_bone(self.obj, name, ctrl_name) | |||||
| ctrl_bone_e = eb[ctrl_name] | |||||
| # Create deformation bones | |||||
| def_name = make_deformer_name(ctrl_name) | |||||
| def_bone = copy_bone(self.obj, name, def_name) | |||||
| # Create mechanism bones | |||||
| mch_name = make_mechanism_name(ctrl_name) | |||||
| mch_bone = copy_bone(self.obj, name, mch_name) | |||||
| # Create mechanism driver bones | |||||
| drv_name = make_mechanism_name(ctrl_name) + "_drv" | |||||
| mch_bone_drv = copy_bone(self.obj, name, drv_name) | |||||
| # Adding to lists | |||||
| ctrl_chain += [ctrl_bone] | |||||
| def_chain += [def_bone] | |||||
| mch_chain += [mch_bone] | |||||
| mch_drv_chain += [mch_bone_drv] | |||||
| # Restoring org chain parenting | |||||
| for bone in org_bones[1:]: | |||||
| eb[bone].parent = eb[org_bones[org_bones.index(bone) - 1]] | |||||
| # Parenting the master bone to the first org | |||||
| ctrl_bone_master = eb[master_name] | |||||
| ctrl_bone_master.parent = eb[org_bones[0]] | |||||
| # Parenting chain bones | |||||
| for i in range(len(self.org_bones)): | |||||
| # Edit bone references | |||||
| def_bone_e = eb[def_chain[i]] | |||||
| ctrl_bone_e = eb[ctrl_chain[i]] | |||||
| mch_bone_e = eb[mch_chain[i]] | |||||
| mch_bone_drv_e = eb[mch_drv_chain[i]] | |||||
| if i == 0: | |||||
| # First ctl bone | |||||
| ctrl_bone_e.parent = mch_bone_drv_e | |||||
| ctrl_bone_e.use_connect = False | |||||
| # First def bone | |||||
| def_bone_e.parent = eb[self.org_bones[i]].parent | |||||
| def_bone_e.use_connect = False | |||||
| # First mch bone | |||||
| mch_bone_e.parent = eb[self.org_bones[i]].parent | |||||
| mch_bone_e.use_connect = False | |||||
| # First mch driver bone | |||||
| mch_bone_drv_e.parent = eb[self.org_bones[i]].parent | |||||
| mch_bone_drv_e.use_connect = False | |||||
| else: | else: | ||||
| # The rest | create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) | ||||
| ctrl_bone_e.parent = mch_bone_drv_e | |||||
| ctrl_bone_e.use_connect = False | |||||
| def_bone_e.parent = eb[def_chain[i-1]] | |||||
| def_bone_e.use_connect = True | |||||
| mch_bone_drv_e.parent = eb[ctrl_chain[i-1]] | |||||
| mch_bone_drv_e.use_connect = False | |||||
| # Parenting mch bone | |||||
| mch_bone_e.parent = ctrl_bone_e | |||||
| mch_bone_e.use_connect = False | |||||
| # Creating tip control bone | |||||
| tip_name = copy_bone(self.obj, org_bones[-1], temp_name) | |||||
| ctrl_bone_tip = eb[tip_name] | |||||
| flip_bone(self.obj, tip_name) | |||||
| ctrl_bone_tip.length /= 2 | |||||
| ctrl_bone_tip.parent = eb[ctrl_chain[-1]] | |||||
| bpy.ops.object.mode_set(mode='OBJECT') | |||||
| pb = self.obj.pose.bones | ############################## | ||||
| # MCH bend chain | |||||
| # Setting pose bones locks | @stage_generate_bones | ||||
| pb_master = pb[master_name] | def make_mch_bend_chain(self): | ||||
| pb_master.lock_scale = True, False, True | self.bones.mch.bend = map_list(self.make_mch_bend_bone, self.bones.org) | ||||
| pb[tip_name].lock_scale = True, True, True | def make_mch_bend_bone(self, org): | ||||
| pb[tip_name].lock_rotation = True, True, True | return self.copy_bone(org, make_mechanism_name(strip_org(org)) + "_drv", parent=False) | ||||
| pb[tip_name].lock_rotation_w = True | |||||
| @stage_parent_bones | |||||
| make_property(pb_master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") | def parent_mch_bend_chain(self): | ||||
| ctrls = self.bones.ctrl.main | |||||
| # Pose settings | map_apply(self.set_bone_parent, self.bones.mch.bend, [self.first_parent] + ctrls) | ||||
| for org, ctrl, deform, mch, mch_drv in zip(self.org_bones, ctrl_chain, def_chain, mch_chain, mch_drv_chain): | |||||
| # Constraining the deform bones | |||||
| con = pb[deform].constraints.new('COPY_TRANSFORMS') | |||||
| con.target = self.obj | |||||
| con.subtarget = mch | |||||
| # Constraining the mch bones | |||||
| if mch_chain.index(mch) == 0: | |||||
| con = pb[mch].constraints.new('COPY_LOCATION') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl | |||||
| con = pb[mch].constraints.new('COPY_SCALE') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl | |||||
| con = pb[mch].constraints.new('DAMPED_TRACK') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1] | |||||
| con = pb[mch].constraints.new('STRETCH_TO') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1] | |||||
| con.volume = 'NO_VOLUME' | |||||
| elif mch_chain.index(mch) == len(mch_chain) - 1: | |||||
| con = pb[mch].constraints.new('DAMPED_TRACK') | |||||
| con.target = self.obj | |||||
| con.subtarget = tip_name | |||||
| con = pb[mch].constraints.new('STRETCH_TO') | |||||
| con.target = self.obj | |||||
| con.subtarget = tip_name | |||||
| con.volume = 'NO_VOLUME' | |||||
| else: | |||||
| con = pb[mch].constraints.new('DAMPED_TRACK') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1] | |||||
| con = pb[mch].constraints.new('STRETCH_TO') | |||||
| con.target = self.obj | |||||
| con.subtarget = ctrl_chain[ctrl_chain.index(ctrl)+1] | |||||
| con.volume = 'NO_VOLUME' | |||||
| # Constraining and driving mch driver bones | |||||
| pb[mch_drv].rotation_mode = 'YZX' | |||||
| if mch_drv_chain.index(mch_drv) == 0: | |||||
| # Constraining to master bone | |||||
| con = pb[mch_drv].constraints.new('COPY_LOCATION') | |||||
| con.target = self.obj | |||||
| con.subtarget = master_name | |||||
| con = pb[mch_drv].constraints.new('COPY_ROTATION') | |||||
| con.target = self.obj | |||||
| con.subtarget = master_name | |||||
| con.target_space = 'LOCAL' | |||||
| con.owner_space = 'LOCAL' | |||||
| else: | |||||
| # Match axis to expression | # Match axis to expression | ||||
| options = { | axis_options = { | ||||
| "automatic": {"axis": 0, | "automatic": {"axis": 0, | ||||
| "expr": '(1-sy)*pi'}, | "expr": '(1-sy)*pi'}, | ||||
| "X": {"axis": 0, | "X": {"axis": 0, | ||||
| "expr": '(1-sy)*pi'}, | "expr": '(1-sy)*pi'}, | ||||
| "-X": {"axis": 0, | "-X": {"axis": 0, | ||||
| "expr": '-((1-sy)*pi)'}, | "expr": '-((1-sy)*pi)'}, | ||||
| "Y": {"axis": 1, | "Y": {"axis": 1, | ||||
| "expr": '(1-sy)*pi'}, | "expr": '(1-sy)*pi'}, | ||||
| "-Y": {"axis": 1, | "-Y": {"axis": 1, | ||||
| "expr": '-((1-sy)*pi)'}, | "expr": '-((1-sy)*pi)'}, | ||||
| "Z": {"axis": 2, | "Z": {"axis": 2, | ||||
| "expr": '(1-sy)*pi'}, | "expr": '(1-sy)*pi'}, | ||||
| "-Z": {"axis": 2, | "-Z": {"axis": 2, | ||||
| "expr": '-((1-sy)*pi)'} | "expr": '-((1-sy)*pi)'} | ||||
| } | } | ||||
| @stage_rig_bones | |||||
| def rig_mch_bend_chain(self): | |||||
| map_apply(self.rig_mch_bend_bone, count(0), self.bones.mch.bend) | |||||
| def rig_mch_bend_bone(self, i, mch): | |||||
| master = self.bones.ctrl.master | |||||
| if i == 0: | |||||
| self.make_constraint(mch, 'COPY_LOCATION', master) | |||||
| self.make_constraint(mch, 'COPY_ROTATION', master, space='LOCAL') | |||||
| else: | |||||
| axis = self.params.primary_rotation_axis | axis = self.params.primary_rotation_axis | ||||
| options = self.axis_options[axis] | |||||
| # Drivers | bone = self.get_bone(mch) | ||||
| drv = pb[mch_drv].driver_add("rotation_euler", options[axis]["axis"]).driver | bone.rotation_mode = 'YZX' | ||||
| drv.type = 'SCRIPTED' | |||||
| drv.expression = options[axis]["expr"] | |||||
| drv_var = drv.variables.new() | |||||
| drv_var.name = 'sy' | |||||
| drv_var.type = "SINGLE_PROP" | |||||
| drv_var.targets[0].id = self.obj | |||||
| drv_var.targets[0].data_path = pb[master_name].path_from_id() + '.scale.y' | |||||
| # Setting bone curvature setting, custom property, and drivers | |||||
| def_bone = self.obj.data.bones[deform] | |||||
| def_bone.bbone_segments = 8 | |||||
| drv = def_bone.driver_add("bbone_easein").driver # Ease in | |||||
| drv.type='SUM' | |||||
| drv_var = drv.variables.new() | |||||
| drv_var.name = "curvature" | |||||
| drv_var.type = "SINGLE_PROP" | |||||
| drv_var.targets[0].id = self.obj | |||||
| drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]' | |||||
| drv = def_bone.driver_add("bbone_easeout").driver # Ease out | |||||
| drv.type='SUM' | |||||
| drv_var = drv.variables.new() | |||||
| drv_var.name = "curvature" | |||||
| drv_var.type = "SINGLE_PROP" | |||||
| drv_var.targets[0].id = self.obj | |||||
| drv_var.targets[0].data_path = pb_master.path_from_id() + '["finger_curve"]' | |||||
| # Assigning shapes to control bones | self.make_driver( | ||||
| create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5) | bone, 'rotation_euler', index=options['axis'], | ||||
| expression=options['expr'], | |||||
| variables={'sy': (master, '.scale.y')} | |||||
| ) | |||||
| ############################## | |||||
| # MCH stretch chain | |||||
| @stage_generate_bones | |||||
| def make_mch_stretch_chain(self): | |||||
| self.bones.mch.stretch = map_list(self.make_mch_stretch_bone, self.bones.org) | |||||
| def make_mch_stretch_bone(self, org): | |||||
| return self.copy_bone(org, make_mechanism_name(strip_org(org)), parent=False) | |||||
| @stage_parent_bones | |||||
| def parent_mch_stretch_chain(self): | |||||
| ctrls = self.bones.ctrl.main | |||||
| map_apply(self.set_bone_parent, self.bones.mch.stretch, [self.first_parent] + ctrls[1:]) | |||||
| @stage_rig_bones | |||||
| def rig_mch_stretch_chain(self): | |||||
| ctrls = self.bones.ctrl.main | |||||
| map_apply(self.rig_mch_stretch_bone, count(0), self.bones.mch.stretch, ctrls, ctrls[1:]) | |||||
| # Create ctrl master widget | def rig_mch_stretch_bone(self, i, mch, ctrl, ctrl_next): | ||||
| w = create_widget(self.obj, master_name) | if i == 0: | ||||
| if w is not None: | self.make_constraint(mch, 'COPY_LOCATION', ctrl) | ||||
| mesh = w.data | self.make_constraint(mch, 'COPY_SCALE', ctrl) | ||||
| verts = [(0, 0, 0), (0, 1, 0), (0.05, 1, 0), (0.05, 1.1, 0), (-0.05, 1.1, 0), (-0.05, 1, 0)] | |||||
| if 'Z' in self.params.primary_rotation_axis: | |||||
| # Flip x/z coordinates | |||||
| temp = [] | |||||
| for v in verts: | |||||
| temp += [(v[2], v[1], v[0])] | |||||
| verts = temp | |||||
| edges = [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 1)] | |||||
| mesh.from_pydata(verts, edges, []) | |||||
| mesh.update() | |||||
| # Create tip control widget | self.make_constraint(mch, 'DAMPED_TRACK', ctrl_next) | ||||
| create_circle_widget(self.obj, tip_name, radius=0.3, head_tail=0.0) | self.make_constraint(mch, 'STRETCH_TO', ctrl_next, volume='NO_VOLUME') | ||||
| ############################## | |||||
| # ORG chain | |||||
| @stage_rig_bones | |||||
| def rig_org_chain(self): | |||||
| map_apply(self.rig_org_bone, self.bones.org, self.bones.mch.stretch) | |||||
| ############################## | |||||
| # Deform chain | |||||
| @stage_configure_bones | |||||
| def configure_master_properties(self): | |||||
| master = self.bones.ctrl.master | |||||
| self.make_property(master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect") | |||||
| # Create UI | # Create UI | ||||
| controls_string = ", ".join( | self.script.add_panel_selected_check(self.bones.ctrl.flatten()) | ||||
| ["'" + x + "'" for x in ctrl_chain] | self.script.add_panel_custom_prop(master, 'finger_curve', text="Curvature", slider=True) | ||||
| ) + ", " + "'" + master_name + "'" | |||||
| return [script % (controls_string, master_name, 'finger_curve')] | def rig_deform_bone(self, org, deform): | ||||
| master = self.bones.ctrl.master | |||||
| bone = self.get_bone(deform) | |||||
| self.make_constraint(deform, 'COPY_TRANSFORMS', org) | |||||
| self.make_driver(bone.bone, 'bbone_easein', variables=[(master, 'finger_curve')]) | |||||
| self.make_driver(bone.bone, 'bbone_easeout', variables=[(master, 'finger_curve')]) | |||||
| def add_parameters(params): | ############### | ||||
| # OPTIONS | |||||
| @classmethod | |||||
| def add_parameters(self, params): | |||||
| """ Add the parameters of this rig type to the | """ Add the parameters of this rig type to the | ||||
| RigifyParameters PropertyGroup | RigifyParameters PropertyGroup | ||||
| """ | """ | ||||
| items = [('automatic', 'Automatic', ''), ('X', 'X manual', ''), ('Y', 'Y manual', ''), ('Z', 'Z manual', ''), | items = [('automatic', 'Automatic', ''), ('X', 'X manual', ''), ('Y', 'Y manual', ''), ('Z', 'Z manual', ''), | ||||
| ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')] | ('-X', '-X manual', ''), ('-Y', '-Y manual', ''), ('-Z', '-Z manual', '')] | ||||
| params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic') | params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='automatic') | ||||
| @classmethod | |||||
| def parameters_ui(layout, params): | def parameters_ui(self, layout, params): | ||||
| """ Create the ui for the rig parameters. | """ Create the ui for the rig parameters. | ||||
| """ | """ | ||||
| r = layout.row() | r = layout.row() | ||||
| r.label(text="Bend rotation axis:") | r.label(text="Bend rotation axis:") | ||||
| r.prop(params, "primary_rotation_axis", text="") | r.prop(params, "primary_rotation_axis", text="") | ||||
| def create_sample(obj): | def create_sample(obj): | ||||
| # generated by rigify.utils.write_metarig | # generated by rigify.utils.write_metarig | ||||
| bpy.ops.object.mode_set(mode='EDIT') | bpy.ops.object.mode_set(mode='EDIT') | ||||
| arm = obj.data | arm = obj.data | ||||
| bones = {} | bones = {} | ||||
| ▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | for bone in arm.edit_bones: | ||||
| bone.select_head = False | bone.select_head = False | ||||
| bone.select_tail = False | bone.select_tail = False | ||||
| for b in bones: | for b in bones: | ||||
| bone = arm.edit_bones[bones[b]] | bone = arm.edit_bones[bones[b]] | ||||
| bone.select = True | bone.select = True | ||||
| bone.select_head = True | bone.select_head = True | ||||
| bone.select_tail = True | bone.select_tail = True | ||||
| arm.edit_bones.active = bone | arm.edit_bones.active = bone | ||||