diff --git a/rigify/metarigs/human.py b/rigify/metarigs/human.py index a2524c3f412caf32ff7ca8eae26309a43bb00bab..e4eb9f2bf617019d731024d0cc2c3020ac04e68e 100644 --- a/rigify/metarigs/human.py +++ b/rigify/metarigs/human.py @@ -470,6 +470,8 @@ def create(obj): bpy.ops.object.mode_set(mode='OBJECT') pbone = obj.pose.bones[bones['hips']] pbone.rigify_type = 'spine' + pbone.rigify_parameters.add() + pbone.rigify_parameters[0].chain_bone_controls = "1, 2, 3" pbone.lock_location = (False, False, False) pbone.lock_rotation = (False, False, False) pbone.lock_rotation_w = False diff --git a/rigify/rigs/spine.py b/rigify/rigs/spine.py index 37dda1b1cd75c8b7800b07fc65d7a12f3c1b2438..2b4558f4f5c2b6c7cc919a6b14e170de689033a3 100644 --- a/rigify/rigs/spine.py +++ b/rigify/rigs/spine.py @@ -16,23 +16,31 @@ # #======================= END GPL LICENSE BLOCK ======================== +""" TODO: + - Add parameters for bone transform alphas. +""" + +from math import floor + import bpy from mathutils import Vector from rigify.utils import MetarigError -from rigify.utils import copy_bone, flip_bone, put_bone +from rigify.utils import copy_bone, new_bone, flip_bone, put_bone from rigify.utils import connected_children_names from rigify.utils import strip_org, make_mechanism_name, make_deformer_name -from rigify.utils import obj_to_bone, create_circle_widget +from rigify.utils import obj_to_bone, create_circle_widget, create_compass_widget from rna_prop_ui import rna_idprop_ui_prop_get script = """ -hips = "%s" -ribs = "%s" -if is_selected([hips, ribs]): - layout.prop(pose_bones[ribs], '["pivot_slide"]', text="Pivot Slide (" + ribs + ")", slider=True) -if is_selected(ribs): - layout.prop(pose_bones[ribs], '["isolate"]', text="Isolate Rotation (" + ribs + ")", slider=True) +main = "%s" +spine = [%s] +if is_selected([main]+ spine): + layout.prop(pose_bones[main], '["pivot_slide"]', text="Pivot Slide (" + main + ")", slider=True) + +for name in spine[1:-1]: + if is_selected(name): + layout.prop(pose_bones[name], '["auto_rotate"]', text="Auto Rotate (" + name + ")", slider=True) """ @@ -49,6 +57,23 @@ class Rig: self.org_bones = [bone_name] + connected_children_names(obj, bone_name) self.params = params + # Collect control bone indices + self.control_indices = [0, len(self.org_bones) - 1] + temp = self.params.chain_bone_controls.split(",") + for i in temp: + try: + j = int(i) - 1 + except ValueError: + pass + else: + if (j > 0) and (j < len(self.org_bones)) and (j not in self.control_indices): + self.control_indices += [j] + self.control_indices.sort() + + self.pivot_rest = self.params.rest_pivot_slide + self.pivot_rest = max(self.pivot_rest, 1.0/len(self.org_bones)) + self.pivot_rest = min(self.pivot_rest, 1.0-(1.0/len(self.org_bones))) + if len(self.org_bones) <= 1: raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 2 or more bones." % (strip_org(bone))) @@ -83,215 +108,200 @@ class Rig: """ Generate the control rig. """ - #--------------------------------- - # Create the hip and rib controls bpy.ops.object.mode_set(mode='EDIT') - - # Copy org bones - hip_control = copy_bone(self.obj, self.org_bones[0], strip_org(self.org_bones[0])) - rib_control = copy_bone(self.obj, self.org_bones[-1], strip_org(self.org_bones[-1])) - rib_mch = copy_bone(self.obj, self.org_bones[-1], make_mechanism_name(strip_org(self.org_bones[-1] + ".follow"))) - hinge = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[-1]) + ".hinge")) - eb = self.obj.data.edit_bones + #------------------------- + # Get rest slide position + a = self.pivot_rest * len(self.org_bones) + i = floor(a) + a -= i + if i == len(self.org_bones): + i -= 1 + a = 1.0 + + pivot_rest_pos = eb[self.org_bones[i]].head.copy() + pivot_rest_pos += eb[self.org_bones[i]].vector * a + + #---------------------- + # Create controls + + # Create control bones + controls = [] + for i in self.control_indices: + name = copy_bone(self.obj, self.org_bones[i], strip_org(self.org_bones[i])) + controls += [name] + + # Create control parents + control_parents = [] + for i in self.control_indices[1:-1]: + name = new_bone(self.obj, make_mechanism_name("par_" + strip_org(self.org_bones[i]))) + control_parents += [name] + + # Create sub-control bones + subcontrols = [] + for i in self.control_indices: + name = new_bone(self.obj, make_mechanism_name("sub_" + strip_org(self.org_bones[i]))) + subcontrols += [name] + + # Create main control bone + main_control = new_bone(self.obj, self.params.spine_main_control_name) + + # Create main control WGT bones + main_wgt1 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".01")) + main_wgt2 = new_bone(self.obj, make_mechanism_name(self.params.spine_main_control_name + ".02")) - hip_control_e = eb[hip_control] - rib_control_e = eb[rib_control] - rib_mch_e = eb[rib_mch] - hinge_e = eb[hinge] - - # Parenting - hip_control_e.use_connect = False - rib_control_e.use_connect = False - rib_mch_e.use_connect = False - hinge_e.use_connect = False - - hinge_e.parent = None - rib_control_e.parent = hinge_e - rib_mch_e.parent = rib_control_e - - # Position - flip_bone(self.obj, hip_control) - flip_bone(self.obj, hinge) - - hinge_e.length /= 2 - rib_mch_e.length /= 2 - - put_bone(self.obj, rib_control, hip_control_e.head) - put_bone(self.obj, rib_mch, hip_control_e.head) - - bpy.ops.object.mode_set(mode='POSE') - bpy.ops.object.mode_set(mode='EDIT') eb = self.obj.data.edit_bones - # Switch to object mode + # Parent the main control + eb[main_control].use_connect = False + eb[main_control].parent = eb[self.org_bones[0]].parent + + # Parent the main WGTs + eb[main_wgt1].use_connect = False + eb[main_wgt1].parent = eb[main_control] + eb[main_wgt2].use_connect = False + eb[main_wgt2].parent = eb[main_wgt1] + + # Parent the controls and sub-controls + for name, subname in zip(controls, subcontrols): + eb[name].use_connect = False + eb[name].parent = eb[main_control] + eb[subname].use_connect = False + eb[subname].parent = eb[name] + + # Parent the control parents + for name, par_name in zip(controls[1:-1], control_parents): + eb[par_name].use_connect = False + eb[par_name].parent = eb[main_control] + eb[name].parent = eb[par_name] + + # Position the main bone + put_bone(self.obj, main_control, pivot_rest_pos) + eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2 + + # Position the main WGTs + eb[main_wgt1].tail = (0.0, 0.0, sum([eb[b].length for b in self.org_bones]) / 4) + eb[main_wgt2].length = sum([eb[b].length for b in self.org_bones]) / 4 + put_bone(self.obj, main_wgt1, pivot_rest_pos) + put_bone(self.obj, main_wgt2, pivot_rest_pos) + + # Position the controls and sub-controls + pos = eb[controls[0]].head.copy() + for name, subname in zip(controls, subcontrols): + put_bone(self.obj, name, pivot_rest_pos) + put_bone(self.obj, subname, pivot_rest_pos) + eb[subname].length = eb[name].length / 3 + + # Position the control parents + for name, par_name in zip(controls[1:-1], control_parents): + put_bone(self.obj, par_name, pivot_rest_pos) + eb[par_name].length = eb[name].length / 2 + + #----------------------------------------- + # Control bone constraints and properties bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - hip_control_p = pb[hip_control] - rib_control_p = pb[rib_control] - hinge_p = pb[hinge] - # No translation on rib control - rib_control_p.lock_location = [True, True, True] - - # Hip does not use local location - hip_control_p.bone.use_local_location = False - - # Custom hinge property - prop = rna_idprop_ui_prop_get(rib_control_p, "isolate", create=True) - rib_control_p["isolate"] = 1.0 - prop["soft_min"] = prop["min"] = 0.0 - prop["soft_max"] = prop["max"] = 1.0 + # Lock control locations + for name in controls: + bone = pb[name] + bone.lock_location = True, True, True + + # Main control doesn't use local location + pb[main_control].bone.use_local_location = False + + + + # Intermediate controls follow hips and spine + for name, par_name, i in zip(controls[1:-1], control_parents, self.control_indices[1:-1]): + bone = pb[par_name] + + # Custom bend_alpha property + prop = rna_idprop_ui_prop_get(pb[name], "bend_alpha", create=True) + pb[name]["bend_alpha"] = i / (len(self.org_bones) - 1) # set bend alpha + prop["min"] = 0.0 + prop["max"] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + # Custom auto_rotate + prop = rna_idprop_ui_prop_get(pb[name], "auto_rotate", create=True) + pb[name]["auto_rotate"] = 1.0 + prop["min"] = 0.0 + prop["max"] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + # Constraints + con1 = bone.constraints.new('COPY_TRANSFORMS') + con1.name = "copy_transforms" + con1.target = self.obj + con1.subtarget = subcontrols[0] + + con2 = bone.constraints.new('COPY_TRANSFORMS') + con2.name = "copy_transforms" + con2.target = self.obj + con2.subtarget = subcontrols[-1] + + # Drivers + fcurve = con1.driver_add("influence") + driver = fcurve.driver + driver.type = 'AVERAGE' + var = driver.variables.new() + var.name = "auto" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' - # Constraints - con = hinge_p.constraints.new('COPY_LOCATION') - con.name = "copy_location" - con.target = self.obj - con.subtarget = hip_control - - con1 = hinge_p.constraints.new('COPY_ROTATION') - con1.name = "isolate_off.01" - con1.target = self.obj - con1.subtarget = hip_control - - con2 = rib_control_p.constraints.new('COPY_SCALE') - con2.name = "isolate_off.02" - con2.target = self.obj - con2.subtarget = hip_control - con2.use_offset = True - con2.target_space = 'LOCAL' - con2.owner_space = 'LOCAL' - - # Drivers for "isolate_off" - fcurve = con1.driver_add("influence") - driver = fcurve.driver - var = driver.variables.new() - driver.type = 'AVERAGE' - var.name = "var" - var.targets[0].id_type = 'OBJECT' - var.targets[0].id = self.obj - var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' - mod = fcurve.modifiers[0] - mod.poly_order = 1 - mod.coefficients[0] = 1.0 - mod.coefficients[1] = -1.0 - - fcurve = con2.driver_add("influence") - driver = fcurve.driver - var = driver.variables.new() - driver.type = 'AVERAGE' - var.name = "var" - var.targets[0].id_type = 'OBJECT' - var.targets[0].id = self.obj - var.targets[0].data_path = rib_control_p.path_from_id() + '["isolate"]' - mod = fcurve.modifiers[0] - mod.poly_order = 1 - mod.coefficients[0] = 1.0 - mod.coefficients[1] = -1.0 - - # Appearence - hip_control_p.custom_shape_transform = pb[self.org_bones[0]] - rib_control_p.custom_shape_transform = pb[self.org_bones[-1]] + fcurve = con2.driver_add("influence") + driver = fcurve.driver + driver.type = 'SCRIPTED' + driver.expression = "alpha * auto" + var = driver.variables.new() + var.name = "alpha" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = pb[name].path_from_id() + '["bend_alpha"]' + var = driver.variables.new() + var.name = "auto" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = pb[name].path_from_id() + '["auto_rotate"]' #------------------------- # Create flex spine chain - - # Create bones/parenting/positiong bpy.ops.object.mode_set(mode='EDIT') flex_bones = [] - flex_helpers = [] + flex_subs = [] prev_bone = None for b in self.org_bones: # Create bones bone = copy_bone(self.obj, b, make_mechanism_name(strip_org(b) + ".flex")) - helper = copy_bone(self.obj, rib_mch, make_mechanism_name(strip_org(b) + ".flex_h")) + sub = new_bone(self.obj, make_mechanism_name(strip_org(b) + ".flex_s")) flex_bones += [bone] - flex_helpers += [helper] + flex_subs += [sub] eb = self.obj.data.edit_bones bone_e = eb[bone] - helper_e = eb[helper] + sub_e = eb[sub] # Parenting bone_e.use_connect = False - helper_e.use_connect = False + sub_e.use_connect = False if prev_bone is None: - helper_e.parent = eb[hip_control] - bone_e.parent = helper_e + sub_e.parent = eb[controls[0]] + else: + sub_e.parent = eb[prev_bone] + bone_e.parent = sub_e # Position - put_bone(self.obj, helper, bone_e.head) - helper_e.length /= 4 + put_bone(self.obj, sub, bone_e.head) + sub_e.length /= 4 + if prev_bone is not None: + sub_e.use_connect = True prev_bone = bone - # Constraints - bpy.ops.object.mode_set(mode='OBJECT') - pb = self.obj.pose.bones - rib_control_p = pb[rib_control] - rib_mch_p = pb[rib_mch] - - inc = 1.0 / (len(flex_helpers) - 1) - inf = 1.0 / (len(flex_helpers) - 1) - for b in zip(flex_helpers[1:], flex_bones[:-1], self.org_bones[1:]): - bone_p = pb[b[0]] - - # Scale constraints - con = bone_p.constraints.new('COPY_SCALE') - con.name = "copy_scale1" - con.target = self.obj - con.subtarget = flex_helpers[0] - con.influence = 1.0 - - con = bone_p.constraints.new('COPY_SCALE') - con.name = "copy_scale2" - con.target = self.obj - con.subtarget = rib_mch - con.influence = inf - - # Bend constraints - con = bone_p.constraints.new('COPY_ROTATION') - con.name = "bend1" - con.target = self.obj - con.subtarget = flex_helpers[0] - con.influence = 1.0 - - con = bone_p.constraints.new('COPY_ROTATION') - con.name = "bend2" - con.target = self.obj - con.subtarget = rib_mch - con.influence = inf - - # If not the rib control - if b[0] != flex_helpers[-1]: - # Custom bend property - prop_name = "bend_" + strip_org(b[2]) - prop = rna_idprop_ui_prop_get(rib_control_p, prop_name, create=True) - rib_control_p[prop_name] = inf - prop["min"] = 0.0 - prop["max"] = 1.0 - prop["soft_min"] = 0.0 - prop["soft_max"] = 1.0 - - # Bend driver - fcurve = con.driver_add("influence") - driver = fcurve.driver - var = driver.variables.new() - driver.type = 'AVERAGE' - var.name = prop_name - var.targets[0].id_type = 'OBJECT' - var.targets[0].id = self.obj - var.targets[0].data_path = rib_control_p.path_from_id() + '["' + prop_name + '"]' - - # Location constraint - con = bone_p.constraints.new('COPY_LOCATION') - con.name = "copy_location" - con.target = self.obj - con.subtarget = b[1] - con.head_tail = 1.0 - - inf += inc - #---------------------------- # Create reverse spine chain @@ -315,7 +325,7 @@ class Rig: bone_e.tail = Vector(eb[b[0]].head) #bone_e.head = Vector(eb[b[0]].tail) if prev_bone is None: - pass # Position base bone wherever you want, for now do nothing (i.e. position at hips) + put_bone(self.obj, bone, pivot_rest_pos) else: put_bone(self.obj, bone, eb[prev_bone].tail) @@ -332,41 +342,48 @@ class Rig: con.name = "copy_location" con.target = self.obj if prev_bone is None: - con.subtarget = hip_control # Position base bone wherever you want, for now hips + con.subtarget = main_control else: con.subtarget = prev_bone con.head_tail = 1.0 prev_bone = bone - #--------------------------------------------- - # Constrain org bones to flex bone's rotation + #---------------------------------------- + # Constrain original bones to flex spine + bpy.ops.object.mode_set(mode='OBJECT') pb = self.obj.pose.bones - for b in zip(self.org_bones, flex_bones): - con = pb[b[0]].constraints.new('COPY_TRANSFORMS') - con.name = "copy_rotation" + + for obone, fbone in zip(self.org_bones, flex_bones): + con = pb[obone].constraints.new('COPY_TRANSFORMS') + con.name = "copy_transforms" con.target = self.obj - con.subtarget = b[1] + con.subtarget = fbone #--------------------------- # Create pivot slide system pb = self.obj.pose.bones bone_p = pb[self.org_bones[0]] - rib_control_p = pb[rib_control] + main_control_p = pb[main_control] # Custom pivot_slide property - prop = rna_idprop_ui_prop_get(rib_control_p, "pivot_slide", create=True) - rib_control_p["pivot_slide"] = 1.0 / len(self.org_bones) + prop = rna_idprop_ui_prop_get(main_control_p, "pivot_slide", create=True) + main_control_p["pivot_slide"] = self.pivot_rest prop["min"] = 0.0 prop["max"] = 1.0 prop["soft_min"] = 1.0 / len(self.org_bones) prop["soft_max"] = 1.0 - (1.0 / len(self.org_bones)) - # Anchor constraint + # Anchor constraints con = bone_p.constraints.new('COPY_LOCATION') con.name = "copy_location" con.target = self.obj con.subtarget = rev_bones[0] + con = pb[main_wgt1].constraints.new('COPY_ROTATION') + con.name = "copy_rotation" + con.target = self.obj + con.subtarget = rev_bones[0] + # Slide constraints i = 1 tot = len(rev_bones) @@ -385,25 +402,113 @@ class Rig: var.name = "slide" var.targets[0].id_type = 'OBJECT' var.targets[0].id = self.obj - var.targets[0].data_path = rib_control_p.path_from_id() + '["pivot_slide"]' + var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' mod = fcurve.modifiers[0] mod.poly_order = 1 mod.coefficients[0] = 1 - i mod.coefficients[1] = tot + # Main WGT + con = pb[main_wgt1].constraints.new('COPY_ROTATION') + con.name = "slide." + str(i) + con.target = self.obj + con.subtarget = rb + + # Driver + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'AVERAGE' + var.name = "slide" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = main_control_p.path_from_id() + '["pivot_slide"]' + mod = fcurve.modifiers[0] + mod.poly_order = 1 + mod.coefficients[0] = 1.5 - i + mod.coefficients[1] = tot + i += 1 + #---------------------------------- + # Constrain flex spine to controls + bpy.ops.object.mode_set(mode='OBJECT') + pb = self.obj.pose.bones + + # Constrain the bones that correspond exactly to the controls + for i, name in zip(self.control_indices, subcontrols): + con = pb[flex_subs[i]].constraints.new('COPY_TRANSFORMS') + con.name = "copy_transforms" + con.target = self.obj + con.subtarget = name + + # Constrain the bones in-between the controls + for i, j, name1, name2 in zip(self.control_indices, self.control_indices[1:], subcontrols, subcontrols[1:]): + if (i + 1) < j: + for n in range(i + 1, j): + bone = pb[flex_subs[n]] + # Custom bend_alpha property + prop = rna_idprop_ui_prop_get(bone, "bend_alpha", create=True) + bone["bend_alpha"] = (n - i) / (j - i) # set bend alpha + prop["min"] = 0.0 + prop["max"] = 1.0 + prop["soft_min"] = 0.0 + prop["soft_max"] = 1.0 + + con = bone.constraints.new('COPY_TRANSFORMS') + con.name = "copy_transforms" + con.target = self.obj + con.subtarget = name1 + + con = bone.constraints.new('COPY_TRANSFORMS') + con.name = "copy_transforms" + con.target = self.obj + con.subtarget = name2 + + # Driver + fcurve = con.driver_add("influence") + driver = fcurve.driver + var = driver.variables.new() + driver.type = 'AVERAGE' + var.name = "alpha" + var.targets[0].id_type = 'OBJECT' + var.targets[0].id = self.obj + var.targets[0].data_path = bone.path_from_id() + '["bend_alpha"]' + + #------------- + # Final stuff + bpy.ops.object.mode_set(mode='OBJECT') + pb = self.obj.pose.bones + + # Control appearance + # Main + pb[main_control].custom_shape_transform = pb[main_wgt2] + w = create_compass_widget(self.obj, main_control) + if w != None: + obj_to_bone(w, self.obj, main_wgt2) + + # Spines + for name, i in zip(controls[1:-1], self.control_indices[1:-1]): + pb[name].custom_shape_transform = pb[self.org_bones[i]] + # Create control widgets + w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True) + if w != None: + obj_to_bone(w, self.obj, self.org_bones[i]) + # Hips + pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]] # Create control widgets - w1 = create_circle_widget(self.obj, hip_control, radius=1.0, head_tail=1.0) - w2 = create_circle_widget(self.obj, rib_control, radius=1.0, head_tail=0.0) + w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True) + if w != None: + obj_to_bone(w, self.obj, self.org_bones[0]) - if w1 != None: - obj_to_bone(w1, self.obj, self.org_bones[0]) - if w2 != None: - obj_to_bone(w2, self.obj, self.org_bones[-1]) + # Ribs + pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]] + # Create control widgets + w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True) + if w != None: + obj_to_bone(w, self.obj, self.org_bones[-1]) - # Return control names - return hip_control, rib_control + return [main_control] + controls def generate(self): """ Generate the rig. @@ -412,9 +517,35 @@ class Rig: """ self.gen_deform() - hips, ribs = self.gen_control() + controls = self.gen_control() + + controls_string = ", ".join(["'" + x + "'" for x in controls[1:]]) + return [script % (controls[0], controls_string)] + + @classmethod + def add_parameters(self, group): + """ Add the parameters of this rig type to the + RigifyParameters PropertyGroup + """ + group.spine_main_control_name = bpy.props.StringProperty(name="Main control name", default="torso", description="Name that the main control bone should be given.") + group.rest_pivot_slide = bpy.props.FloatProperty(name="Rest Pivot Slide", default=0.0, min=0.0, max=1.0, soft_min=0.0, soft_max=1.0, description="The pivot slide value in the rest pose.") + group.chain_bone_controls = bpy.props.StringProperty(name="Control bone list", default="", description="Define which bones have controls.") + - return [script % (hips, ribs)] + @classmethod + def parameters_ui(self, layout, obj, bone): + """ Create the ui for the rig parameters. + """ + params = obj.pose.bones[bone].rigify_parameters[0] + + r = layout.row() + r.prop(params, "spine_main_control_name") + + r = layout.row() + r.prop(params, "rest_pivot_slide", slider=True) + + r = layout.row() + r.prop(params, "chain_bone_controls") @classmethod def create_sample(self, obj): @@ -469,6 +600,8 @@ class Rig: pbone.rotation_mode = 'QUATERNION' pbone = obj.pose.bones[bones['hips']] pbone['rigify_type'] = 'spine' + pbone.rigify_parameters.add() + pbone.rigify_parameters[0].chain_bone_controls = "1, 2, 3" bpy.ops.object.mode_set(mode='EDIT') for bone in arm.edit_bones: @@ -481,4 +614,3 @@ class Rig: bone.select_head = True bone.select_tail = True arm.edit_bones.active = bone - diff --git a/rigify/utils.py b/rigify/utils.py index 193a2779a36982d5e1dc8c15df837faae1bfd4b2..c97712228b03d0dc52c5eaed9c8f6a133bd6dadf 100644 --- a/rigify/utils.py +++ b/rigify/utils.py @@ -279,7 +279,7 @@ def create_line_widget(rig, bone_name): mesh.update() -def create_circle_widget(rig, bone_name, radius=1.0, head_tail=0.0): +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) @@ -288,7 +288,10 @@ def create_circle_widget(rig, bone_name, radius=1.0, head_tail=0.0): 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] - 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)] + 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() @@ -334,6 +337,17 @@ def create_bone_widget(rig, bone_name): 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. """