Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Gavrilov <angavrilov@gmail.com>2019-09-14 09:17:30 +0300
committerAlexander Gavrilov <angavrilov@gmail.com>2019-09-14 09:30:00 +0300
commit8b1df843703fdb51ffa5758625c117c4f10bc6dd (patch)
tree949e84f80116132eab3ad5f3bac46e745c3a9195 /rigify/rigs
parent9b693a6be0aa2b0b4825d30ac5034655dce9c0dd (diff)
Rigify: replace rigs with new implementations using the new base rig.
Spine is split into parts. Limbs and tentacles simply converted. Differential Revision: https://developer.blender.org/D4624
Diffstat (limited to 'rigify/rigs')
-rw-r--r--rigify/rigs/limbs/arm.py1223
-rw-r--r--rigify/rigs/limbs/leg.py1248
-rw-r--r--rigify/rigs/limbs/limb_rigs.py1047
-rw-r--r--rigify/rigs/limbs/paw.py1383
-rw-r--r--rigify/rigs/limbs/rear_paw.py9
-rw-r--r--rigify/rigs/limbs/simple_tentacle.py335
-rw-r--r--rigify/rigs/limbs/super_finger.py538
-rw-r--r--rigify/rigs/limbs/super_limb.py221
-rw-r--r--rigify/rigs/limbs/ui.py182
-rw-r--r--rigify/rigs/spines/basic_spine.py321
-rw-r--r--rigify/rigs/spines/basic_tail.py246
-rw-r--r--rigify/rigs/spines/spine_rigs.py208
-rw-r--r--rigify/rigs/spines/super_head.py406
-rw-r--r--rigify/rigs/spines/super_spine.py1205
-rw-r--r--rigify/rigs/utils.py154
15 files changed, 3247 insertions, 5479 deletions
diff --git a/rigify/rigs/limbs/arm.py b/rigify/rigs/limbs/arm.py
index aacc1e86..4e9cf299 100644
--- a/rigify/rigs/limbs/arm.py
+++ b/rigify/rigs/limbs/arm.py
@@ -1,1015 +1,116 @@
-import bpy, re
-from ..widgets import create_hand_widget, create_gear_widget
-from .ui import create_script
-from .limb_utils import *
-from mathutils import Vector
-from ...utils import copy_bone, put_bone
-from ...utils import strip_org, strip_mch
-from ...utils import create_circle_widget, create_sphere_widget, create_line_widget
-from ...utils import make_mechanism_name
-from ...utils import create_limb_widget, connected_children_names
-from ...utils import align_bone_x_axis, align_bone_z_axis
-from ...rig_ui_template import UTILITIES_RIG_ARM, REGISTER_RIG_ARM
-from ...utils import ControlLayersOption
-from ...utils.mechanism import make_property, make_driver
-from ..widgets import create_ikarrow_widget
-from math import trunc, pi
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
-from ...utils.switch_parent import SwitchParentBuilder
+# <pep8 compliant>
+import bpy
-IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class
- # add_parameters and parameters_ui are unused for implementation classes
+from itertools import count
+from ...utils.bones import BoneDict, compute_chain_x_axis, align_bone_x_axis, align_bone_z_axis
+from ...utils.naming import make_derived_name
+from ...utils.misc import map_list
-class Rig:
+from ..widgets import create_hand_widget
- def __init__(self, obj, bone_name, params):
- """ Initialize arm rig and key rig properties """
- self.obj = obj
- self.params = params
+from ...base_rig import stage
- self.org_bones = list(
- [bone_name] + connected_children_names(obj, bone_name)
- )[:3] # The basic limb is the first 3 bones
+from .limb_rigs import BaseLimbRig
- self.segments = params.segments
- self.bbones = params.bbones
- self.limb_type = params.limb_type
- self.rot_axis = params.rotation_axis
- self.auto_align_extremity = params.auto_align_extremity
+class Rig(BaseLimbRig):
+ """Human arm rig."""
- def orient_org_bones(self):
+ def initialize(self):
+ if len(self.bones.org.main) != 3:
+ self.raise_error("Input to rig type must be a chain of 3 bones.")
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ super().initialize()
- thigh = self.org_bones[0]
- org_bones = list(
- [thigh] + connected_children_names(self.obj, thigh)
- ) # All the provided orgs
+ def prepare_bones(self):
+ orgs = self.bones.org.main
- org_uarm = eb[org_bones[0]]
- org_farm = eb[org_bones[1]]
- org_hand = eb[org_bones[2]]
+ if self.params.rotation_axis == 'automatic':
+ axis = compute_chain_x_axis(self.obj, orgs[0:2])
- if self.rot_axis != 'automatic':
- if self.auto_align_extremity:
- z_ground_projection = Vector((org_hand.z_axis[0], org_hand.z_axis[1], 0))
- align_bone_z_axis(self.obj, org_hand.name, z_ground_projection.normalized())
- return
+ for bone in orgs:
+ align_bone_x_axis(self.obj, bone, axis)
- # Orient uarm farm bones
- chain_y_axis = org_uarm.y_axis + org_farm.y_axis
- chain_rot_axis = org_uarm.y_axis.cross(chain_y_axis).normalized() # ik-plane normal axis (rotation)
+ elif self.params.auto_align_extremity:
+ axis = self.vector_without_z(self.get_bone(orgs[2]).z_axis)
- align_bone_x_axis(self.obj, org_uarm.name, chain_rot_axis)
- align_bone_x_axis(self.obj, org_farm.name, chain_rot_axis)
+ align_bone_z_axis(self.obj, orgs[2], axis)
- # Orient hand
- align_bone_x_axis(self.obj, org_hand.name, chain_rot_axis)
+ ####################################################
+ # Overrides
- def create_parent(self):
+ def register_switch_parents(self, pbuilder):
+ super().register_switch_parents(pbuilder)
- org_bones = self.org_bones
+ pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True)
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- name = get_bone_name( strip_org( org_bones[0] ), 'mch', 'parent' )
-
- mch = copy_bone( self.obj, org_bones[0], name )
- orient_bone( self, eb[mch], 'y' )
- eb[ mch ].length = eb[ org_bones[0] ].length / 4
-
- eb[ mch ].parent = eb[ org_bones[0] ].parent
-
- eb[ mch ].roll = 0.0
-
- # Add non-MCH main limb control
- name = get_bone_name(strip_org(org_bones[0]), 'ctrl', 'parent')
- main_parent = copy_bone(self.obj, org_bones[0], name)
- eb[main_parent].length = eb[org_bones[0]].length / 4
- eb[main_parent].parent = None
- eb[main_parent].roll = 0.0
-
- # Constraints
- make_constraint( self, mch, {
- 'constraint' : 'COPY_ROTATION',
- 'subtarget' : 'root'
- })
-
- make_constraint( self, mch, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
-
- # Limb Follow Driver
- pb = self.obj.pose.bones
-
- name = 'FK_limb_follow'
-
- # pb[ mch ][ name ] = 0.0
- # prop = rna_idprop_ui_prop_get( pb[ mch ], name, create = True )
- make_property(pb[main_parent], name, 0.0)
-
- make_driver(pb[mch].constraints[0], "influence", variables=[(self.obj, main_parent, name)])
-
- size = pb[main_parent].bone.y_axis.length * 10
- create_gear_widget(self.obj, main_parent, size=size, bone_transform_name=None)
-
- return [mch, main_parent]
-
- def create_tweak(self):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- tweaks = {}
- tweaks['ctrl'] = []
- tweaks['mch' ] = []
-
- # Create and parent mch and ctrl tweaks
- for i,org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range( self.segments ):
- # MCH
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org, name )
-
- # CTRL
- name = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, name )
-
- eb[ mch ].length /= self.segments
- eb[ ctrl ].length /= self.segments
-
- # If we have more than one segments, place the head of the
- # 2nd and onwards at the correct position
- if j > 0:
- put_bone(self.obj, mch, eb[ tweaks['mch' ][-1] ].tail)
- put_bone(self.obj, ctrl, eb[ tweaks['ctrl'][-1] ].tail)
-
- tweaks['ctrl'] += [ ctrl ]
- tweaks['mch' ] += [ mch ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- else: # Last limb bone - is not subdivided
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org_bones[i-1], name )
- eb[ mch ].length = eb[org].length / 4
- put_bone(
- self.obj,
- mch,
- eb[org_bones[i-1]].tail
- )
-
- ctrl = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, ctrl )
- eb[ ctrl ].length = eb[org].length / 2
-
- tweaks['mch'] += [ mch ]
- tweaks['ctrl'] += [ ctrl ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- # Scale to reduce widget size and maintain conventions!
- for mch, ctrl in zip( tweaks['mch'], tweaks['ctrl'] ):
- eb[ mch ].length /= 4
- eb[ ctrl ].length /= 2
-
- # Constraints
-
- for i,b in enumerate( tweaks['mch'] ):
- first = 0
- middle = trunc( len( tweaks['mch'] ) / 2 )
- last = len( tweaks['mch'] ) - 1
-
- if i == first or i == middle:
- make_constraint( self, b, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
- elif i != last:
- targets = []
- dt_target_idx = middle
- factor = 0
- if i < middle:
- targets = [first,middle]
- else:
- targets = [middle,last]
- factor = self.segments
- dt_target_idx = last
-
- # Use copy transforms constraints to position each bone
- # exactly in the location respective to its index (between
- # the two edges)
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[0]]
- })
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[1]],
- 'influence' : (i - factor) / self.segments
- })
- make_constraint( self, b, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks['ctrl'][ dt_target_idx ],
- })
-
- # Ctrl bones Locks and Widgets
- pb = self.obj.pose.bones
- for t in tweaks['ctrl']:
- pb[t].lock_rotation = True, False, True
- pb[t].lock_scale = False, True, False
-
- create_sphere_widget(self.obj, t, bone_transform_name=None)
-
- ControlLayersOption.TWEAK.assign(self.params, pb, tweaks['ctrl'])
-
- return tweaks
-
- def create_def(self, tweaks):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- def_bones = []
- for i, org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range(self.segments):
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
-
- eb[def_name].length /= self.segments
-
- # If we have more than one segments, place the 2nd and
- # onwards on the tail of the previous bone
- if j > 0:
- put_bone(self.obj, def_name, eb[ def_bones[-1] ].tail)
-
- def_bones += [def_name]
- else:
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
- def_bones.append(def_name)
-
- # Parent deform bones
- for i,b in enumerate( def_bones ):
- if i > 0: # For all bones but the first (which has no parent)
- eb[b].parent = eb[ def_bones[i-1] ] # to previous
- eb[b].use_connect = True
-
- # Constraint def to tweaks
- for d,t in zip(def_bones, tweaks):
- tidx = tweaks.index(t)
-
- make_constraint( self, d, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : t
- })
-
- if tidx != len(tweaks) - 1:
- make_constraint( self, d, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- make_constraint( self, d, {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- # Create bbone segments
- for bone in def_bones[:-1]:
- self.obj.data.bones[bone].bbone_segments = self.bbones
-
- self.obj.data.bones[ def_bones[0] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-2] ].bbone_easeout = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easeout = 0.0
-
-
- # Rubber hose drivers
- pb = self.obj.pose.bones
- for i,t in enumerate( tweaks[1:-1] ):
- # Create custom property on tweak bone to control rubber hose
- name = 'rubber_tweak'
-
- if i == trunc( len( tweaks[1:-1] ) / 2 ):
- defval = 0.0
- else:
- defval = 1.0
-
- make_property(pb[t], name, defval, max=2.0, soft_max=1.0)
-
- for j,d in enumerate(def_bones[:-1]):
- if j != 0:
- make_driver(self.obj.data.bones[d], "bbone_easein", variables=[(self.obj, tweaks[j], 'rubber_tweak')])
-
- if j != len( def_bones[:-1] ) - 1:
- make_driver(self.obj.data.bones[d], "bbone_easeout", variables=[(self.obj, tweaks[j+1], 'rubber_tweak')])
-
- return def_bones
-
- def create_ik(self, parent):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- ctrl = get_bone_name(org_bones[0], 'ctrl', 'ik')
- mch_ik = get_bone_name(org_bones[0], 'mch', 'ik')
- mch_target = get_bone_name(org_bones[0], 'mch', 'ik_target')
-
- for o, ik in zip( org_bones, [ ctrl, mch_ik, mch_target ] ):
- bone = copy_bone( self.obj, o, ik )
-
- if org_bones.index(o) == len( org_bones ) - 1:
- eb[ bone ].length /= 4
-
- # Create MCH Stretch
- mch_str = copy_bone(
- self.obj,
- org_bones[0],
- get_bone_name( org_bones[0], 'mch', 'ik_stretch' )
- )
-
- eb[ mch_str ].tail = eb[ org_bones[-1] ].head
-
- # Parenting
- eb[ctrl].parent = eb[parent]
- eb[mch_str].parent = eb[parent]
- eb[mch_ik].parent = eb[ctrl]
-
- # Make standard pole target bone
- pole_name = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
- pole_target = copy_bone(self.obj, org_bones[0], pole_name)
-
- lo_vector = eb[org_bones[1]].tail - eb[org_bones[1]].head
- tot_vector = eb[org_bones[0]].head - eb[org_bones[1]].tail
- tot_vector.normalize()
- elbow_vector = lo_vector.dot(tot_vector)*tot_vector - lo_vector # elbow_vec as rejection of lo on tot
- elbow_vector.normalize()
- elbow_vector *= (eb[org_bones[1]].tail - eb[org_bones[0]].head).length
-
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- z_vector = eb[org_bones[0]].z_axis + eb[org_bones[1]].z_axis
- alfa = elbow_vector.angle(z_vector)
- elif self.rot_axis == 'z':
- x_vector = eb[org_bones[0]].x_axis + eb[org_bones[1]].x_axis
- alfa = elbow_vector.angle(x_vector)
-
- if alfa > pi/2:
- pole_angle = -pi/2
- else:
- pole_angle = pi/2
-
- if self.rot_axis == 'z':
- pole_angle = 0
-
- eb[pole_target].head = eb[org_bones[0]].tail + elbow_vector
- eb[pole_target].tail = eb[pole_target].head - elbow_vector/8
- eb[pole_target].roll = 0.0
-
- # Make visual pole
- vispole_name = 'VIS_' + get_bone_name(org_bones[0], 'ctrl', 'ik_pole')
- vispole = copy_bone(self.obj, org_bones[1], vispole_name)
- eb[vispole].tail = eb[vispole].head + Vector((0.0, 0.0, eb[org_bones[1]].length/10))
- eb[vispole].use_connect = False
- eb[vispole].hide_select = True
- eb[vispole].parent = None
-
- make_constraint(self, mch_ik, {
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- make_constraint(self, mch_ik, { # 2_nd IK for pole targeted chain
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- # VIS pole constraints
- make_constraint(self, vispole, {
- 'constraint': 'COPY_LOCATION',
- 'name': 'copy_loc',
- 'subtarget': org_bones[1],
- })
-
- pb = self.obj.pose.bones
-
- make_constraint(self, vispole, {
- 'constraint': 'STRETCH_TO',
- 'name': 'stretch_to',
- 'subtarget': pole_target,
- 'volume': 'NO_VOLUME',
- 'rest_length': pb[vispole].length
- })
-
- pb[mch_ik].constraints[-1].pole_target = self.obj
- pb[mch_ik].constraints[-1].pole_subtarget = pole_target
- pb[mch_ik].constraints[-1].pole_angle = pole_angle
-
- pb[ mch_ik ].ik_stretch = 0.1
- pb[ ctrl ].ik_stretch = 0.1
-
- # IK constraint Rotation locks
- if self.rot_axis == 'z':
- pb[mch_ik].lock_ik_x = True
- pb[mch_ik].lock_ik_y = True
- else:
- pb[mch_ik].lock_ik_y = True
- pb[mch_ik].lock_ik_z = True
-
- # Locks and Widget
- pb[ctrl].lock_rotation = True, False, True
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- roll = 0
- else:
- roll = pi/2
- create_ikarrow_widget(self.obj, ctrl, bone_transform_name=None, roll=roll)
- create_sphere_widget(self.obj, pole_target, bone_transform_name=None)
- create_line_widget(self.obj, vispole)
-
- return {'ctrl': {'limb': ctrl, 'ik_target': pole_target},
- 'mch_ik': mch_ik,
- 'mch_target': mch_target,
- 'mch_str': mch_str,
- 'visuals': {'vispole': vispole}
- }
-
- def create_fk(self, parent):
- org_bones = self.org_bones.copy()
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- ctrls = []
-
- for o in org_bones:
- bone = copy_bone(self.obj, o, get_bone_name( o, 'ctrl', 'fk'))
- ctrls.append(bone)
-
- # MCH
- mch = copy_bone(
- self.obj, org_bones[-1], get_bone_name(o, 'mch', 'fk')
- )
-
- eb[mch].length /= 4
-
- # Parenting
- eb[ctrls[0]].parent = eb[parent]
- eb[ctrls[1]].parent = eb[ctrls[0]]
- eb[ctrls[1]].use_connect = True
- eb[ctrls[2]].parent = eb[mch]
- eb[mch].parent = eb[ctrls[1]]
- eb[mch].use_connect = True
-
- # Constrain MCH's scale to root
- make_constraint(self, mch, {
- 'constraint': 'COPY_SCALE',
- 'subtarget': 'root'
- })
-
- # Locks and widgets
- pb = self.obj.pose.bones
- pb[ctrls[2]].lock_location = True, True, True
-
- create_limb_widget(self.obj, ctrls[0])
- create_limb_widget(self.obj, ctrls[1])
-
- create_circle_widget(self.obj, ctrls[2], radius=0.4, head_tail=0.0)
-
- ControlLayersOption.FK.assign(self.params, pb, ctrls)
-
- return {'ctrl': ctrls, 'mch': mch}
-
- def org_parenting_and_switch(self, org_bones, ik, fk, parent):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
- # re-parent ORGs in a connected chain
- for i, o in enumerate(org_bones):
- if i > 0:
- eb[o].parent = eb[org_bones[i-1]]
- if i <= len(org_bones)-1:
- eb[o].use_connect = True
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
- pb_parent = pb[parent]
-
- # Create ik/fk switch property
- prop = make_property(pb_parent, 'IK_FK', 0.0, description='IK/FK Switch')
-
- # Constrain org to IK and FK bones
- iks = [ik['ctrl']['limb']]
- iks += [ik[k] for k in ['mch_ik', 'mch_target']]
-
- for o, i, f in zip(org_bones, iks, fk):
- make_constraint( self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': i
- })
- make_constraint(self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': f
- })
-
- # Add driver to relevant constraint
- make_driver(pb[o].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)])
-
- def create_arm(self, bones):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- pole_target = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
-
- # Create IK arm control
- ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')
- ctrl = copy_bone(self.obj, org_bones[2], ctrl)
-
- # clear parent (so that rigify will parent to root)
- eb[ctrl].parent = None
- eb[ctrl].use_connect = False
-
- # Parent
- eb[ bones['ik']['mch_target'] ].parent = eb[ ctrl ]
- eb[ bones['ik']['mch_target'] ].use_connect = False
-
- mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket')
- mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name)
- eb[mch_main_parent].length = eb[org_bones[0]].length / 12
- eb[mch_main_parent].parent = eb[bones['parent']]
- eb[mch_main_parent].roll = 0.0
- eb[bones['main_parent']].parent = eb[mch_main_parent]
-
- # Switchable parent
- pbuilder = SwitchParentBuilder(self.rigify_generator)
-
- if eb[org_bones[0]].parent:
- pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name)
-
- pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True)
-
- pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], ctrl, pole_target ]
-
- pbuilder.build_child(
- self.rigify_wrapper, ctrl,
- prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols,
- )
-
- pbuilder.build_child(
- self.rigify_wrapper, pole_target, extra_parents=[ctrl],
- prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols,
- no_fix_rotation=True, no_fix_scale=True
- )
-
- # Set up constraints
-
- # Constrain mch target bone to the ik control and mch stretch
- make_constraint( self, bones['ik']['mch_target'], {
- 'constraint' : 'COPY_LOCATION',
- 'subtarget' : bones['ik']['mch_str'],
- 'head_tail' : 1.0
- })
-
- # Constrain mch ik stretch bone to the ik control
- make_constraint(self, bones['ik']['mch_str'], {
- 'constraint': 'DAMPED_TRACK',
- 'subtarget': ctrl,
- })
- make_constraint(self, bones['ik']['mch_str'], {
- 'constraint': 'STRETCH_TO',
- 'subtarget': ctrl,
- })
- make_constraint(self, bones['ik']['mch_str'], {
- 'constraint': 'LIMIT_SCALE',
- 'use_min_y': True,
- 'use_max_y': True,
- 'max_y': 1.05,
- 'owner_space': 'LOCAL'
- })
- make_constraint(self, mch_main_parent, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': org_bones[0]
- })
-
- pb = self.obj.pose.bones
-
- # Create ik/fk switch property
- pb_parent = pb[bones['main_parent']]
- pb_parent.lock_location = True, True, True
- pb_parent.lock_rotation = True, True, True
- pb_parent.lock_scale = True, True, True
-
- # Modify rotation mode for ik and tweak controls
- pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'
-
- for b in bones['tweak']['ctrl']:
- pb[b].rotation_mode = 'ZXY'
-
- prop = make_property(pb_parent, 'IK_Stretch', 1.0, description='IK Stretch')
-
- # Add driver to limit scale constraint influence
- b = bones['ik']['mch_str']
-
- make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])
-
- # Create hand widget
+ def make_ik_ctrl_widget(self, ctrl):
create_hand_widget(self.obj, ctrl, bone_transform_name=None)
- bones['ik']['ctrl']['terminal'] = [ctrl]
-
- return bones
-
- def create_drivers(self, bones):
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- #owner = pb[bones['ik']['ctrl']['limb']]
- owner = pb[bones['main_parent']]
-
- props = ["pole_vector"]
-
- for prop in props:
-
- if prop == 'pole_vector':
- make_property(owner, prop, False)
- mch_ik = pb[bones['ik']['mch_ik']]
-
- # ik target hide driver
- pole_target = pb[bones['ik']['ctrl']['ik_target']]
-
- make_driver(pole_target.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
+ ####################################################
+ # Settings
- # vis-pole hide driver
- vispole = pb[bones['ik']['visuals']['vispole']]
+ @classmethod
+ def parameters_ui(self, layout, params):
+ super().parameters_ui(layout, params, 'Hand')
- make_driver(vispole.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
- # arrow hide driver
- # limb = pb[bones['ik']['ctrl']['limb']]
- #
- # make_driver(limb.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
-
- for cns in mch_ik.constraints:
- if 'IK' in cns.type:
- if not cns.pole_subtarget:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
- else:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
-
- @staticmethod
- def get_future_names(bones):
-
- if len(bones) != 3:
- return
-
- names = dict()
-
- uarm = strip_mch(strip_org(bones[0].name))
- farm = strip_mch(strip_org(bones[1].name))
- hand = strip_mch(strip_org(bones[2].name))
-
- suffix=''
- if uarm[-2:] == '.L' or uarm[-2:] == '.R':
- suffix = uarm[-2:]
- uarm = uarm.rstrip(suffix)
- farm = farm.rstrip(suffix)
- hand = hand.rstrip(suffix)
-
- # the following is declared in rig_ui
- # controls = ['upper_arm_ik.L', 'upper_arm_fk.L', 'forearm_fk.L', 'hand_fk.L', 'hand_ik.L', 'MCH-hand_fk.L',
- # 'upper_arm_parent.L']
- # tweaks = ['upper_arm_tweak.L.001', 'forearm_tweak.L', 'forearm_tweak.L.001']
- # ik_ctrl = ['hand_ik.L', 'MCH-upper_arm_ik.L', 'MCH-upper_arm_ik_target.L']
- # fk_ctrl = 'upper_arm_fk.L'
- # parent = 'upper_arm_parent.L'
- # hand_fk = 'hand_fk.L'
- # pole = 'upper_arm_ik_target.L'
-
- names['controls'] = [uarm + '_ik', uarm + '_fk', farm + '_fk', hand + '_fk', hand + '_ik',
- make_mechanism_name(hand + '_fk'), uarm + '_parent']
- names['ik_ctrl'] = [hand + '_ik', make_mechanism_name(uarm) + '_ik', make_mechanism_name(uarm) + '_ik_target']
- names['fk_ctrl'] = uarm + '_fk' + suffix
- names['parent'] = uarm + '_parent' + suffix
- names['hand_fk'] = hand + '_fk' + suffix
- names['pole'] = uarm + '_ik_target' + suffix
- names['limb_type'] = 'arm'
-
- if suffix:
- for i, name in enumerate(names['controls']):
- names['controls'][i] = name + suffix
- for i, name in enumerate(names['ik_ctrl']):
- names['ik_ctrl'][i] = name + suffix
-
- return names
-
- def generate(self):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Adjust org-bones rotation
- self.orient_org_bones()
-
- # Clear parents for org bones
- for bone in self.org_bones[1:]:
- eb[bone].use_connect = False
- eb[bone].parent = None
-
- bones = {}
-
- # Create mch limb parent
- mch_parent, main_parent = self.create_parent()
- bones['parent'] = mch_parent
- bones['main_parent'] = main_parent
- bones['tweak'] = self.create_tweak()
- bones['def'] = self.create_def(bones['tweak']['ctrl'])
- bones['ik'] = self.create_ik(bones['parent'])
- bones['fk'] = self.create_fk(bones['parent'])
-
- self.org_parenting_and_switch(self.org_bones, bones['ik'], bones['fk']['ctrl'], bones['main_parent'])
-
- bones = self.create_arm(bones)
- self.create_drivers(bones)
-
- # Create UI
- script = create_script(bones, 'arm')
-
- return {
- 'script': [script],
- 'utilities': UTILITIES_RIG_ARM,
- 'register': REGISTER_RIG_ARM,
- }
-
-
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
-
- items = [
- ('x', 'X manual', ''),
- ('z', 'Z manual', ''),
- ('automatic', 'Automatic', '')
- ]
-
- params.rotation_axis = bpy.props.EnumProperty(
- items = items,
- name = "Rotation Axis",
- default = 'automatic'
- )
-
- params.auto_align_extremity = bpy.props.BoolProperty(
- name='auto_align_extremity',
- default=False,
- description="Auto Align Extremity Bone"
- )
-
- params.segments = bpy.props.IntProperty(
- name = 'limb segments',
- default = 2,
- min = 1,
- description = 'Number of segments'
- )
-
- params.bbones = bpy.props.IntProperty(
- name = 'bbone segments',
- default = 10,
- min = 1,
- description = 'Number of segments'
- )
-
- # Setting up extra layers for the FK and tweak
- ControlLayersOption.FK.add_parameters(params)
- ControlLayersOption.TWEAK.add_parameters(params)
-
-
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters."""
-
- r = layout.row()
- r.prop(params, "rotation_axis")
-
- if 'auto' not in params.rotation_axis.lower():
- r = layout.row()
- text = "Auto align Hand"
- r.prop(params, "auto_align_extremity", text=text)
-
- r = layout.row()
- r.prop(params, "segments")
-
- r = layout.row()
- r.prop(params, "bbones")
-
- ControlLayersOption.FK.parameters_ui(layout, params)
- ControlLayersOption.TWEAK.parameters_ui(layout, params)
-
-
-def create_sample(obj):
+def create_sample(obj, limb=False):
# generated by rigify.utils.write_metarig
bpy.ops.object.mode_set(mode='EDIT')
arm = obj.data
bones = {}
-
bone = arm.edit_bones.new('upper_arm.L')
- bone.head[:] = 0.1953, 0.0267, 1.5846
- bone.tail[:] = 0.4424, 0.0885, 1.4491
+ bone.head[:] = -0.0016, 0.0060, -0.0012
+ bone.tail[:] = 0.2455, 0.0678, -0.1367
bone.roll = 2.0724
bone.use_connect = False
bones['upper_arm.L'] = bone.name
bone = arm.edit_bones.new('forearm.L')
- bone.head[:] = 0.4424, 0.0885, 1.4491
- bone.tail[:] = 0.6594, 0.0492, 1.3061
+ bone.head[:] = 0.2455, 0.0678, -0.1367
+ bone.tail[:] = 0.4625, 0.0285, -0.2797
bone.roll = 2.1535
bone.use_connect = True
bone.parent = arm.edit_bones[bones['upper_arm.L']]
bones['forearm.L'] = bone.name
bone = arm.edit_bones.new('hand.L')
- bone.head[:] = 0.6594, 0.0492, 1.3061
- bone.tail[:] = 0.7234, 0.0412, 1.2585
+ bone.head[:] = 0.4625, 0.0285, -0.2797
+ bone.tail[:] = 0.5265, 0.0205, -0.3273
bone.roll = 2.2103
bone.use_connect = True
bone.parent = arm.edit_bones[bones['forearm.L']]
bones['hand.L'] = bone.name
- bone = arm.edit_bones.new('palm.01.L')
- bone.head[:] = 0.6921, 0.0224, 1.2882
- bone.tail[:] = 0.7464, 0.0051, 1.2482
- bone.roll = -2.4928
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['hand.L']]
- bones['palm.01.L'] = bone.name
- bone = arm.edit_bones.new('palm.02.L')
- bone.head[:] = 0.6970, 0.0389, 1.2877
- bone.tail[:] = 0.7518, 0.0277, 1.2487
- bone.roll = -2.5274
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['hand.L']]
- bones['palm.02.L'] = bone.name
- bone = arm.edit_bones.new('palm.03.L')
- bone.head[:] = 0.6963, 0.0545, 1.2874
- bone.tail[:] = 0.7540, 0.0521, 1.2482
- bone.roll = -2.5843
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['hand.L']]
- bones['palm.03.L'] = bone.name
- bone = arm.edit_bones.new('palm.04.L')
- bone.head[:] = 0.6929, 0.0696, 1.2871
- bone.tail[:] = 0.7528, 0.0763, 1.2428
- bone.roll = -2.5155
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['hand.L']]
- bones['palm.04.L'] = bone.name
- bone = arm.edit_bones.new('f_index.01.L')
- bone.head[:] = 0.7464, 0.0051, 1.2482
- bone.tail[:] = 0.7718, 0.0013, 1.2112
- bone.roll = -2.0315
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['palm.01.L']]
- bones['f_index.01.L'] = bone.name
- bone = arm.edit_bones.new('thumb.01.L')
- bone.head[:] = 0.6705, 0.0214, 1.2738
- bone.tail[:] = 0.6857, 0.0015, 1.2404
- bone.roll = -0.1587
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['palm.01.L']]
- bones['thumb.01.L'] = bone.name
- bone = arm.edit_bones.new('f_middle.01.L')
- bone.head[:] = 0.7518, 0.0277, 1.2487
- bone.tail[:] = 0.7762, 0.0234, 1.2058
- bone.roll = -2.0067
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['palm.02.L']]
- bones['f_middle.01.L'] = bone.name
- bone = arm.edit_bones.new('f_ring.01.L')
- bone.head[:] = 0.7540, 0.0521, 1.2482
- bone.tail[:] = 0.7715, 0.0499, 1.2070
- bone.roll = -2.0082
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['palm.03.L']]
- bones['f_ring.01.L'] = bone.name
- bone = arm.edit_bones.new('f_pinky.01.L')
- bone.head[:] = 0.7528, 0.0763, 1.2428
- bone.tail[:] = 0.7589, 0.0765, 1.2156
- bone.roll = -1.9749
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['palm.04.L']]
- bones['f_pinky.01.L'] = bone.name
- bone = arm.edit_bones.new('f_index.02.L')
- bone.head[:] = 0.7718, 0.0013, 1.2112
- bone.tail[:] = 0.7840, -0.0003, 1.1858
- bone.roll = -1.8799
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_index.01.L']]
- bones['f_index.02.L'] = bone.name
- bone = arm.edit_bones.new('thumb.02.L')
- bone.head[:] = 0.6857, 0.0015, 1.2404
- bone.tail[:] = 0.7056, -0.0057, 1.2145
- bone.roll = -0.4798
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['thumb.01.L']]
- bones['thumb.02.L'] = bone.name
- bone = arm.edit_bones.new('f_middle.02.L')
- bone.head[:] = 0.7762, 0.0234, 1.2058
- bone.tail[:] = 0.7851, 0.0218, 1.1749
- bone.roll = -1.8283
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_middle.01.L']]
- bones['f_middle.02.L'] = bone.name
- bone = arm.edit_bones.new('f_ring.02.L')
- bone.head[:] = 0.7715, 0.0499, 1.2070
- bone.tail[:] = 0.7794, 0.0494, 1.1762
- bone.roll = -1.8946
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_ring.01.L']]
- bones['f_ring.02.L'] = bone.name
- bone = arm.edit_bones.new('f_pinky.02.L')
- bone.head[:] = 0.7589, 0.0765, 1.2156
- bone.tail[:] = 0.7618, 0.0770, 1.1932
- bone.roll = -1.9059
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_pinky.01.L']]
- bones['f_pinky.02.L'] = bone.name
- bone = arm.edit_bones.new('f_index.03.L')
- bone.head[:] = 0.7840, -0.0003, 1.1858
- bone.tail[:] = 0.7892, 0.0006, 1.1636
- bone.roll = -1.6760
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_index.02.L']]
- bones['f_index.03.L'] = bone.name
- bone = arm.edit_bones.new('thumb.03.L')
- bone.head[:] = 0.7056, -0.0057, 1.2145
- bone.tail[:] = 0.7194, -0.0098, 1.1995
- bone.roll = -0.5826
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['thumb.02.L']]
- bones['thumb.03.L'] = bone.name
- bone = arm.edit_bones.new('f_middle.03.L')
- bone.head[:] = 0.7851, 0.0218, 1.1749
- bone.tail[:] = 0.7888, 0.0216, 1.1525
- bone.roll = -1.7483
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_middle.02.L']]
- bones['f_middle.03.L'] = bone.name
- bone = arm.edit_bones.new('f_ring.03.L')
- bone.head[:] = 0.7794, 0.0494, 1.1762
- bone.tail[:] = 0.7781, 0.0498, 1.1577
- bone.roll = -1.6582
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_ring.02.L']]
- bones['f_ring.03.L'] = bone.name
- bone = arm.edit_bones.new('f_pinky.03.L')
- bone.head[:] = 0.7618, 0.0770, 1.1932
- bone.tail[:] = 0.7611, 0.0772, 1.1782
- bone.roll = -1.7639
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_pinky.02.L']]
- bones['f_pinky.03.L'] = bone.name
bpy.ops.object.mode_set(mode='OBJECT')
pbone = obj.pose.bones[bones['upper_arm.L']]
- pbone.rigify_type = 'limbs.super_limb'
+ pbone.rigify_type = 'limbs.super_limb' if limb else 'limbs.arm'
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
try:
- pbone.rigify_parameters.separate_ik_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.ik_layers = [False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.separate_hose_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.hose_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
except AttributeError:
pass
@@ -1031,199 +132,6 @@ def create_sample(obj):
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['palm.01.L']]
- pbone.rigify_type = 'limbs.super_palm'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'YXZ'
- pbone = obj.pose.bones[bones['palm.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'YXZ'
- pbone = obj.pose.bones[bones['palm.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'YXZ'
- pbone = obj.pose.bones[bones['palm.04.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'YXZ'
- pbone = obj.pose.bones[bones['f_index.01.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_extra_layers = False
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['thumb.01.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_extra_layers = False
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_middle.01.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_extra_layers = False
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_ring.01.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_extra_layers = False
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_pinky.01.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.separate_extra_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.extra_layers = [False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_extra_layers = False
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_index.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['thumb.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_middle.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_ring.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_pinky.02.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_index.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['thumb.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_middle.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_ring.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_pinky.03.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
bpy.ops.object.mode_set(mode='EDIT')
for bone in arm.edit_bones:
@@ -1237,13 +145,4 @@ def create_sample(obj):
bone.select_tail = True
arm.edit_bones.active = bone
- for eb in arm.edit_bones:
- if ('arm' in eb.name) or ('hand' in eb.name):
- eb.layers = (False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
- else:
- eb.layers = (False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
- arm.layers = (False, False, False, False, False, True, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
-
-
-if __name__ == "__main__":
- create_sample(bpy.context.active_object)
+ return bones
diff --git a/rigify/rigs/limbs/leg.py b/rigify/rigs/limbs/leg.py
index 59e6f799..098d303a 100644
--- a/rigify/rigs/limbs/leg.py
+++ b/rigify/rigs/limbs/leg.py
@@ -1,1134 +1,280 @@
-
-import bpy, math
-from ..widgets import create_foot_widget, create_ballsocket_widget, create_gear_widget
-from .ui import create_script
-from .limb_utils import *
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+import math
+
+from itertools import count
from mathutils import Vector
-from ...utils import copy_bone, flip_bone, put_bone
-from ...utils import strip_org, strip_mch
-from ...utils import create_circle_widget, create_sphere_widget, create_line_widget
-from ...utils import MetarigError, make_mechanism_name
-from ...utils import create_limb_widget, connected_children_names
-from ...utils import align_bone_y_axis, align_bone_x_axis, align_bone_z_axis
-from ...rig_ui_template import UTILITIES_RIG_LEG, REGISTER_RIG_LEG
-from ...utils import ControlLayersOption
-from rna_prop_ui import rna_idprop_ui_prop_get
-from ...utils.mechanism import make_property, make_driver
-from ..widgets import create_ikarrow_widget
-from math import trunc, pi
-from ...utils.switch_parent import SwitchParentBuilder
+from ...utils.rig import is_rig_base_bone
+from ...utils.bones import align_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
+from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation
+from ...utils.naming import make_derived_name
+from ...utils.misc import map_list
+from ..widgets import create_foot_widget, create_ballsocket_widget
-IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class
- # add_parameters and parameters_ui are unused for implementation classes
+from ...base_rig import stage
+from .limb_rigs import BaseLimbRig
-class Rig:
- def __init__(self, obj, bone_name, params):
- """ Initialize leg rig and key rig properties """
- self.obj = obj
- self.params = params
+DEG_360 = math.pi * 2
+ALL_TRUE = (True, True, True)
- self.org_bones = list(
- [bone_name] + connected_children_names(obj, bone_name)
- )[:3] # The basic limb is the first 3 bones
- self.segments = params.segments
- self.bbones = params.bbones
- self.limb_type = params.limb_type
- self.rot_axis = params.rotation_axis
- self.auto_align_extremity = params.auto_align_extremity
+class Rig(BaseLimbRig):
+ """Human leg rig."""
+ def find_org_bones(self, bone):
+ bones = super().find_org_bones(bone)
- def orient_org_bones(self):
+ for b in self.get_bone(bones.main[2]).bone.children:
+ if not b.use_connect and not b.children and not is_rig_base_bone(self.obj, b.name):
+ bones.heel = b.name
+ break
+ else:
+ self.raise_error("Heel bone not found.")
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ return bones
- thigh = self.org_bones[0]
- org_bones = list(
- [thigh] + connected_children_names(self.obj, thigh)
- ) # All the provided orgs
+ def initialize(self):
+ if len(self.bones.org.main) != 4:
+ self.raise_error("Input to rig type must be a chain of 4 bones.")
- # Get heel bone
- heel = ''
- for b in self.obj.data.bones[org_bones[2]].children:
- if not b.use_connect and not b.children:
- heel = b.name
- if heel:
- org_bones.append(heel)
+ super().initialize()
- org_thigh = eb[org_bones[0]]
- org_shin = eb[org_bones[1]]
- org_foot = eb[org_bones[2]]
- org_toe = eb[org_bones[3]]
- org_heel = eb[org_bones[4]]
+ def prepare_bones(self):
+ orgs = self.bones.org.main
- foot_projection_on_xy = Vector((org_foot.y_axis[0], org_foot.y_axis[1], 0))
- foot_x = foot_projection_on_xy.cross(Vector((0, 0, -1))).normalized()
+ foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, -1))
- if self.rot_axis != 'automatic':
+ if self.params.rotation_axis == 'automatic':
+ align_chain_x_axis(self.obj, orgs[0:2])
# Orient foot and toe
- if self.auto_align_extremity:
- if self.rot_axis == 'x':
- align_bone_x_axis(self.obj, org_foot.name, foot_x)
- align_bone_x_axis(self.obj, org_toe.name, -foot_x)
- elif self.rot_axis == 'z':
- align_bone_z_axis(self.obj, org_foot.name, foot_x)
- align_bone_z_axis(self.obj, org_toe.name, -foot_x)
- else:
- raise MetarigError(message='IK on %s has forbidden rotation axis (Y)' % self.org_bones[0])
-
- return
-
- # Orient thigh and shin bones
- chain_y_axis = org_thigh.y_axis + org_shin.y_axis
- chain_rot_axis = org_thigh.y_axis.cross(chain_y_axis).normalized() # ik-plane normal axis (rotation)
-
- align_bone_x_axis(self.obj, org_thigh.name, chain_rot_axis)
- align_bone_x_axis(self.obj, org_shin.name, chain_rot_axis)
-
- # Orient foot and toe
- align_bone_x_axis(self.obj, org_foot.name, foot_x)
- align_bone_x_axis(self.obj, org_toe.name, -foot_x)
-
- # Orient heel
- align_bone_z_axis(self.obj, org_heel.name, Vector((0, 0, 1)))
-
- def create_parent(self):
-
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ align_bone_x_axis(self.obj, orgs[2], foot_x)
+ align_bone_x_axis(self.obj, orgs[3], -foot_x)
- name = get_bone_name( strip_org( org_bones[0] ), 'mch', 'parent' )
+ align_bone_x_axis(self.obj, self.bones.org.heel, Vector((0, 0, 1)))
- mch = copy_bone( self.obj, org_bones[0], name )
- orient_bone( self, eb[mch], 'y' )
- eb[ mch ].length = eb[ org_bones[0] ].length / 4
-
- eb[ mch ].parent = eb[ org_bones[0] ].parent
-
- eb[ mch ].roll = 0.0
-
- # Add non-MCH main limb control
- name = get_bone_name(strip_org(org_bones[0]), 'ctrl', 'parent')
- main_parent = copy_bone(self.obj, org_bones[0], name)
- eb[main_parent].length = eb[org_bones[0]].length / 4
- eb[main_parent].parent = eb[org_bones[0]]
- eb[main_parent].roll = 0.0
-
- # Constraints
- make_constraint( self, mch, {
- 'constraint' : 'COPY_ROTATION',
- 'subtarget' : 'root'
- })
-
- make_constraint( self, mch, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
-
- # Limb Follow Driver
- pb = self.obj.pose.bones
-
- name = 'FK_limb_follow'
-
- # pb[ mch ][ name ] = 0.0
- # prop = rna_idprop_ui_prop_get( pb[ mch ], name, create = True )
- make_property(pb[main_parent], name, 0.0)
-
- make_driver(pb[mch].constraints[0], "influence", variables=[(self.obj, main_parent, name)])
-
- size = pb[main_parent].bone.y_axis.length * 10
- create_gear_widget(self.obj, main_parent, size=size, bone_transform_name=None)
-
- return [mch, main_parent]
-
- def create_tweak(self):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- tweaks = {}
- tweaks['ctrl'] = []
- tweaks['mch' ] = []
-
- # Create and parent mch and ctrl tweaks
- for i,org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range( self.segments ):
- # MCH
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org, name )
-
- # CTRL
- name = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, name )
-
- eb[ mch ].length /= self.segments
- eb[ ctrl ].length /= self.segments
-
- # If we have more than one segments, place the head of the
- # 2nd and onwards at the correct position
- if j > 0:
- put_bone(self.obj, mch, eb[ tweaks['mch' ][-1] ].tail)
- put_bone(self.obj, ctrl, eb[ tweaks['ctrl'][-1] ].tail)
-
- tweaks['ctrl'] += [ ctrl ]
- tweaks['mch' ] += [ mch ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- else: # Last limb bone - is not subdivided
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org_bones[i-1], name )
- eb[ mch ].length = eb[org].length / 4
- put_bone(
- self.obj,
- mch,
- eb[org_bones[i-1]].tail
- )
-
- ctrl = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, ctrl )
- eb[ ctrl ].length = eb[org].length / 2
-
- tweaks['mch'] += [ mch ]
- tweaks['ctrl'] += [ ctrl ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- # Scale to reduce widget size and maintain conventions!
- for mch, ctrl in zip( tweaks['mch'], tweaks['ctrl'] ):
- eb[ mch ].length /= 4
- eb[ ctrl ].length /= 2
-
- # Constraints
-
- for i,b in enumerate( tweaks['mch'] ):
- first = 0
- middle = trunc( len( tweaks['mch'] ) / 2 )
- last = len( tweaks['mch'] ) - 1
-
- if i == first or i == middle:
- make_constraint( self, b, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
- elif i != last:
- targets = []
- dt_target_idx = middle
- factor = 0
- if i < middle:
- targets = [first,middle]
- else:
- targets = [middle,last]
- factor = self.segments
- dt_target_idx = last
-
- # Use copy transforms constraints to position each bone
- # exactly in the location respective to its index (between
- # the two edges)
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[0]]
- })
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[1]],
- 'influence' : (i - factor) / self.segments
- })
- make_constraint( self, b, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks['ctrl'][ dt_target_idx ],
- })
-
- # Ctrl bones Locks and Widgets
- pb = self.obj.pose.bones
- for t in tweaks['ctrl']:
- pb[t].lock_rotation = True, False, True
- pb[t].lock_scale = False, True, False
-
- create_sphere_widget(self.obj, t, bone_transform_name=None)
-
- ControlLayersOption.TWEAK.assign(self.params, pb, tweaks['ctrl'])
-
- return tweaks
-
- def create_def(self, tweaks):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- def_bones = []
- for i, org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range(self.segments):
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
-
- eb[def_name].length /= self.segments
-
- # If we have more than one segments, place the 2nd and
- # onwards on the tail of the previous bone
- if j > 0:
- put_bone(self.obj, def_name, eb[ def_bones[-1] ].tail)
-
- def_bones += [def_name]
- else:
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
- def_bones.append(def_name)
-
- # Parent deform bones
- for i,b in enumerate( def_bones ):
- if i > 0: # For all bones but the first (which has no parent)
- eb[b].parent = eb[ def_bones[i-1] ] # to previous
- eb[b].use_connect = True
-
- # Constraint def to tweaks
- for d,t in zip(def_bones, tweaks):
- tidx = tweaks.index(t)
-
- make_constraint( self, d, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : t
- })
-
- if tidx != len(tweaks) - 1:
- make_constraint( self, d, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- make_constraint( self, d, {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- # Create bbone segments
- for bone in def_bones[:-1]:
- self.obj.data.bones[bone].bbone_segments = self.bbones
-
- self.obj.data.bones[ def_bones[0] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-2] ].bbone_easeout = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easeout = 0.0
-
-
- # Rubber hose drivers
- pb = self.obj.pose.bones
- for i, t in enumerate(tweaks[1:-1]):
- # Create custom property on tweak bone to control rubber hose
- name = 'rubber_tweak'
-
- if i == trunc( len( tweaks[1:-1] ) / 2 ):
- defval = 0.0
+ elif self.params.auto_align_extremity:
+ if self.main_axis == 'x':
+ align_bone_x_axis(self.obj, orgs[2], foot_x)
+ align_bone_x_axis(self.obj, orgs[3], -foot_x)
else:
- defval = 1.0
-
- make_property(pb[t], name, defval, max=2.0, soft_max=1.0)
-
- for j,d in enumerate(def_bones[:-1]):
- if j != 0:
- make_driver(self.obj.data.bones[d], "bbone_easein", variables=[(self.obj, tweaks[j], 'rubber_tweak')])
-
- if j != len( def_bones[:-1] ) - 1:
- make_driver(self.obj.data.bones[d], "bbone_easeout", variables=[(self.obj, tweaks[j+1], 'rubber_tweak')])
-
- return def_bones
-
- def create_ik(self, parent):
- org_bones = self.org_bones
+ align_bone_z_axis(self.obj, orgs[2], foot_x)
+ align_bone_z_axis(self.obj, orgs[3], -foot_x)
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
- ctrl = get_bone_name(org_bones[0], 'ctrl', 'ik')
- mch_ik = get_bone_name(org_bones[0], 'mch', 'ik')
- mch_target = get_bone_name(org_bones[0], 'mch', 'ik_target')
+ ####################################################
+ # EXTRA BONES
+ #
+ # org:
+ # heel:
+ # Heel location marker bone
+ # ctrl:
+ # heel:
+ # Foot roll control
+ # mch:
+ # heel[]:
+ # Chain of bones implementing foot roll.
+ #
+ ####################################################
- for o, ik in zip(org_bones, [ctrl, mch_ik, mch_target]):
- bone = copy_bone(self.obj, o, ik)
+ ####################################################
+ # IK controls
- if org_bones.index(o) == len(org_bones) - 1:
- eb[bone].length /= 4
+ def get_extra_ik_controls(self):
+ return [self.bones.ctrl.heel]
- # Create MCH Stretch
- mch_str = copy_bone(
- self.obj,
- org_bones[0],
- get_bone_name( org_bones[0], 'mch', 'ik_stretch' )
- )
+ def make_ik_control_bone(self, orgs):
+ name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
- eb[ mch_str ].tail = eb[ org_bones[-1] ].head
+ if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
+ align_bone_to_axis(self.obj, name, 'y', flip=True)
- # Parenting
- eb[ctrl].parent = eb[parent]
- eb[mch_str].parent = eb[parent]
- eb[mch_ik].parent = eb[ctrl]
-
- # Make standard pole target bone
- pole_name = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
- pole_target = copy_bone(self.obj, org_bones[0], pole_name)
-
- lo_vector = eb[org_bones[1]].tail - eb[org_bones[1]].head
- tot_vector = eb[org_bones[0]].head - eb[org_bones[1]].tail
- tot_vector.normalize()
- elbow_vector = lo_vector.dot(tot_vector)*tot_vector - lo_vector # elbow_vec as rejection of lo on tot
- elbow_vector.normalize()
- elbow_vector *= (eb[org_bones[1]].tail - eb[org_bones[0]].head).length
-
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- z_vector = eb[org_bones[0]].z_axis + eb[org_bones[1]].z_axis
- alfa = elbow_vector.angle(z_vector)
- elif self.rot_axis == 'z':
- x_vector = eb[org_bones[0]].x_axis + eb[org_bones[1]].x_axis
- alfa = elbow_vector.angle(x_vector)
-
- if alfa > pi/2:
- pole_angle = -pi/2
- else:
- pole_angle = pi/2
-
- if self.rot_axis == 'z':
- pole_angle = 0
-
- eb[pole_target].head = eb[org_bones[0]].tail + elbow_vector
- eb[pole_target].tail = eb[pole_target].head - elbow_vector/8
- eb[pole_target].roll = 0.0
-
- # Make visual pole
- vispole_name = 'VIS_' + get_bone_name(org_bones[0], 'ctrl', 'ik_pole')
- vispole = copy_bone(self.obj, org_bones[1], vispole_name)
- eb[vispole].tail = eb[vispole].head + Vector((0.0, 0.0, eb[org_bones[1]].length/10))
- eb[vispole].use_connect = False
- eb[vispole].hide_select = True
- eb[vispole].parent = None
-
- make_constraint(self, mch_ik, {
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- make_constraint(self, mch_ik, { # 2_nd IK for pole targeted chain
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- # VIS pole constraints
- make_constraint(self, vispole, {
- 'constraint': 'COPY_LOCATION',
- 'name': 'copy_loc',
- 'subtarget': org_bones[1],
- })
-
- pb = self.obj.pose.bones
-
- make_constraint(self, vispole, {
- 'constraint': 'STRETCH_TO',
- 'name': 'stretch_to',
- 'subtarget': pole_target,
- 'volume': 'NO_VOLUME',
- 'rest_length': pb[vispole].length
- })
-
- pb[mch_ik].constraints[-1].pole_target = self.obj
- pb[mch_ik].constraints[-1].pole_subtarget = pole_target
- pb[mch_ik].constraints[-1].pole_angle = pole_angle
-
- pb[ mch_ik ].ik_stretch = 0.1
- pb[ ctrl ].ik_stretch = 0.1
-
- # IK constraint Rotation locks
- if self.rot_axis == 'z':
- pb[mch_ik].lock_ik_x = True
- pb[mch_ik].lock_ik_y = True
- else:
- pb[mch_ik].lock_ik_y = True
- pb[mch_ik].lock_ik_z = True
-
- # Locks and Widget
- pb[ctrl].lock_rotation = True, False, True
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- roll = 0
- else:
- roll = pi/2
- create_ikarrow_widget(self.obj, ctrl, bone_transform_name=None, roll=roll)
- create_sphere_widget(self.obj, pole_target, bone_transform_name=None)
- create_line_widget(self.obj, vispole)
-
- return {'ctrl': {'limb': ctrl, 'ik_target': pole_target},
- 'mch_ik': mch_ik,
- 'mch_target': mch_target,
- 'mch_str': mch_str,
- 'visuals': {'vispole': vispole}
- }
-
- def create_fk(self, parent):
- org_bones = self.org_bones.copy()
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- ctrls = []
-
- for o in org_bones:
- bone = copy_bone(self.obj, o, get_bone_name( o, 'ctrl', 'fk'))
- ctrls.append(bone)
-
- # MCH
- mch = copy_bone(
- self.obj, org_bones[-1], get_bone_name(o, 'mch', 'fk')
- )
-
- eb[mch].length /= 4
-
- # Parenting
- eb[ctrls[0]].parent = eb[parent]
- eb[ctrls[1]].parent = eb[ctrls[0]]
- eb[ctrls[1]].use_connect = True
- eb[ctrls[2]].parent = eb[mch]
- eb[mch].parent = eb[ctrls[1]]
- eb[mch].use_connect = True
-
- # Constrain MCH's scale to root
- make_constraint(self, mch, {
- 'constraint': 'COPY_SCALE',
- 'subtarget': 'root'
- })
-
- # Locks and widgets
- pb = self.obj.pose.bones
- pb[ctrls[2]].lock_location = True, True, True
-
- create_limb_widget(self.obj, ctrls[0])
- create_limb_widget(self.obj, ctrls[1])
-
- create_circle_widget(self.obj, ctrls[2], radius=0.4, head_tail=0.0)
-
- ControlLayersOption.FK.assign(self.params, pb, ctrls)
-
- return {'ctrl': ctrls, 'mch': mch}
-
- def org_parenting_and_switch(self, org_bones, ik, fk, parent):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
- # re-parent ORGs in a connected chain
- for i, o in enumerate(org_bones):
- if i > 0:
- eb[o].parent = eb[org_bones[i-1]]
- if i <= len(org_bones)-1:
- eb[o].use_connect = True
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
- pb_parent = pb[parent]
-
- # Create ik/fk switch property
- prop = make_property(pb_parent, 'IK_FK', 0.0, description='IK/FK Switch')
-
- # Constrain org to IK and FK bones
- iks = [ik['ctrl']['limb']]
- iks += [ik[k] for k in ['mch_ik', 'mch_target']]
-
- for o, i, f in zip(org_bones, iks, fk):
- make_constraint( self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': i
- })
- make_constraint(self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': f
- })
-
- # Add driver to relevant constraint
- make_driver(pb[o].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)])
-
- def create_leg(self, bones):
- org_bones = list(
- [self.org_bones[0]] + connected_children_names(self.obj, self.org_bones[0])
- )
-
- bones['ik']['ctrl']['terminal'] = []
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Create toes def bone
- toes_def = get_bone_name(org_bones[-1], 'def')
- toes_def = copy_bone( self.obj, org_bones[-1], toes_def )
-
- eb[ toes_def ].use_connect = False
- eb[ toes_def ].parent = eb[ bones['def'][-1] ]
- eb[ toes_def ].use_connect = True
-
- bones['def'] += [ toes_def ]
-
- pole_target = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
-
- # Create IK leg control
- ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')
- ctrl = copy_bone(self.obj, org_bones[2], ctrl)
-
- # clear parent (so that rigify will parent to root)
- eb[ctrl].parent = None
- eb[ctrl].use_connect = False
-
- mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket')
- mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name)
- eb[mch_main_parent].length = eb[org_bones[0]].length / 12
- eb[mch_main_parent].parent = eb[bones['parent']]
- eb[mch_main_parent].roll = 0.0
- eb[bones['main_parent']].parent = eb[mch_main_parent]
-
- # Create heel ctrl bone
- heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik')
- heel = copy_bone(self.obj, org_bones[2], heel)
-
- ax = eb[org_bones[2]].head - eb[org_bones[2]].tail
- ax[2] = 0
- align_bone_y_axis(self.obj, heel, ax)
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- align_bone_x_axis(self.obj, heel, eb[org_bones[2]].x_axis)
- elif self.rot_axis == 'z':
- align_bone_z_axis(self.obj, heel, eb[org_bones[2]].z_axis)
- eb[heel].length = eb[org_bones[2]].length / 2
-
- # Reset control position and orientation
- if self.rot_axis == 'automatic' or self.auto_align_extremity:
- l = eb[ctrl].length
- orient_bone(self, eb[ctrl], 'y', reverse=True)
- eb[ctrl].length = l
else:
- flip_bone(self.obj, ctrl)
- eb[ctrl].tail[2] = eb[ctrl].head[2]
- eb[ctrl].roll = 0
-
- # Switchable parent
- pbuilder = SwitchParentBuilder(self.rigify_generator)
+ flip_bone(self.obj, name)
- if eb[org_bones[0]].parent:
- pbuilder.register_parent(self.rigify_wrapper, eb[org_bones[0]].parent.name)
-
- pbuilder.register_parent(self.rigify_wrapper, org_bones[2], exclude_self=True)
-
- pcontrols = [ bones['main_parent'], bones['ik']['ctrl']['limb'], heel, ctrl, pole_target ]
-
- pbuilder.build_child(
- self.rigify_wrapper, ctrl,
- prop_bone=bones['main_parent'], prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols,
- )
-
- pbuilder.build_child(
- self.rigify_wrapper, pole_target, extra_parents=[(bones['ik']['mch_target'], ctrl)],
- prop_bone=bones['main_parent'], prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols,
- no_fix_rotation=True, no_fix_scale=True
- )
-
- # Parent
- eb[ heel ].use_connect = False
- eb[ heel ].parent = eb[ ctrl ]
-
- eb[ bones['ik']['mch_target'] ].parent = eb[ heel ]
- eb[ bones['ik']['mch_target'] ].use_connect = False
-
- # Create foot mch rock and roll bones
-
- # Get the tmp heel (floating unconnected without children)
- tmp_heel = ""
- for b in self.obj.data.bones[org_bones[2]].children:
- if not b.use_connect and not b.children:
- tmp_heel = b.name
-
- # roll1 MCH bone
- roll1_mch = get_bone_name(tmp_heel, 'mch', 'roll')
- roll1_mch = copy_bone(self.obj, org_bones[2], roll1_mch)
-
- # clear parent
- eb[roll1_mch].use_connect = False
- eb[roll1_mch].parent = None
-
- flip_bone(self.obj, roll1_mch)
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- align_bone_x_axis(self.obj, roll1_mch, eb[org_bones[2]].x_axis)
- elif self.rot_axis == 'z':
- align_bone_z_axis(self.obj, roll1_mch, eb[org_bones[2]].z_axis)
-
- # Create 2nd roll mch, and two rock mch bones
- roll2_mch = get_bone_name(tmp_heel, 'mch', 'roll')
- roll2_mch = copy_bone(self.obj, org_bones[3], roll2_mch)
-
- eb[roll2_mch].use_connect = False
- eb[roll2_mch].parent = None
-
- put_bone(
- self.obj,
- roll2_mch,
- (eb[tmp_heel].head + eb[tmp_heel].tail) / 2
- )
-
- eb[ roll2_mch ].length /= 4
-
- # Rock MCH bones
- rock1_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
- rock1_mch = copy_bone( self.obj, tmp_heel, rock1_mch )
-
- eb[ rock1_mch ].use_connect = False
- eb[ rock1_mch ].parent = None
-
- orient_bone( self, eb[ rock1_mch ], 'y', 1.0, reverse = True )
- align_bone_y_axis(self.obj, rock1_mch, ax)
- eb[ rock1_mch ].length = eb[ tmp_heel ].length / 2
-
- rock2_mch = get_bone_name( tmp_heel, 'mch', 'rock' )
- rock2_mch = copy_bone( self.obj, tmp_heel, rock2_mch )
-
- eb[ rock2_mch ].use_connect = False
- eb[ rock2_mch ].parent = None
-
- #orient_bone( self, eb[ rock2_mch ], 'y', 1.0 )
- align_bone_y_axis(self.obj, rock2_mch, ax)
- eb[ rock2_mch ].length = eb[ tmp_heel ].length / 2
-
- # Parent rock and roll MCH bones
- eb[ roll1_mch ].parent = eb[ roll2_mch ]
- eb[ roll2_mch ].parent = eb[ rock1_mch ]
- eb[ rock1_mch ].parent = eb[ rock2_mch ]
- eb[ rock2_mch ].parent = eb[ ctrl ]
-
- # make mch toe bone
- toe = ''
- foot = eb[self.org_bones[-1]]
- for c in foot.children:
- if 'org' in c.name.lower() and c.head == foot.tail:
- toe = c.name
- if not toe:
- raise MetarigError.message("Wrong metarig: can't find ORG-<toe>")
-
- toe_mch = get_bone_name(toe, 'mch')
- toe_mch = copy_bone(self.obj, toe, toe_mch)
- eb[toe_mch].length /= 3
- eb[toe_mch].parent = eb[self.org_bones[2]]
- eb[toe].use_connect = False
- eb[toe].parent = eb[toe_mch]
-
- # Constrain rock and roll MCH bones
- make_constraint( self, roll1_mch, {
- 'constraint' : 'COPY_ROTATION',
- 'subtarget' : heel,
- 'owner_space' : 'LOCAL',
- 'target_space' : 'LOCAL'
- })
-
- if self.rot_axis == 'x'or self.rot_axis == 'automatic':
- make_constraint(self, roll1_mch, {
- 'constraint': 'LIMIT_ROTATION',
- 'use_limit_x': True,
- 'max_x': math.radians(360),
- 'owner_space': 'LOCAL'
- })
- make_constraint(self, roll2_mch, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': heel,
- 'use_y': False,
- 'use_z': False,
- 'invert_x': True,
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
- make_constraint(self, roll2_mch, {
- 'constraint': 'LIMIT_ROTATION',
- 'use_limit_x': True,
- 'max_x': math.radians(360),
- 'owner_space': 'LOCAL'
- })
-
- elif self.rot_axis == 'z':
- make_constraint(self, roll1_mch, {
- 'constraint': 'LIMIT_ROTATION',
- 'use_limit_z': True,
- 'max_z': math.radians(360),
- 'owner_space': 'LOCAL'
- })
- make_constraint(self, roll2_mch, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': heel,
- 'use_y': False,
- 'use_x': False,
- 'invert_z': True,
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
- make_constraint(self, roll2_mch, {
- 'constraint': 'LIMIT_ROTATION',
- 'use_limit_z': True,
- 'max_z': math.radians(360),
- 'owner_space': 'LOCAL'
- })
-
- pb = self.obj.pose.bones
- if self.rot_axis == 'x'or self.rot_axis == 'automatic':
- ik_rot_axis = pb[org_bones[0]].x_axis
- elif self.rot_axis == 'z':
- ik_rot_axis = pb[org_bones[0]].z_axis
- heel_x_orientation = pb[tmp_heel].y_axis.dot(ik_rot_axis)
- for i, b in enumerate([rock1_mch, rock2_mch]):
- if heel_x_orientation > 0:
- if not i:
- min_y = 0
- max_y = math.radians(360)
- else:
- min_y = math.radians(-360)
- max_y = 0
- else:
- if not i:
- min_y = math.radians(-360)
- max_y = 0
- else:
- min_y = 0
- max_y = math.radians(360)
-
-
- make_constraint( self, b, {
- 'constraint' : 'COPY_ROTATION',
- 'subtarget' : heel,
- 'use_x' : False,
- 'use_z' : False,
- 'owner_space' : 'LOCAL',
- 'target_space' : 'LOCAL'
- })
- make_constraint( self, b, {
- 'constraint' : 'LIMIT_ROTATION',
- 'use_limit_y' : True,
- 'min_y' : min_y,
- 'max_y' : max_y,
- 'owner_space' : 'LOCAL'
- })
-
- # Cns toe_mch to MCH roll2
- make_constraint( self, toe_mch, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : roll2_mch
- })
-
- # Set up constraints
-
- # Constrain mch target bone to the ik control and mch stretch
- make_constraint( self, bones['ik']['mch_target'], {
- 'constraint' : 'COPY_LOCATION',
- 'subtarget' : bones['ik']['mch_str'],
- 'head_tail' : 1.0
- })
-
- # Constrain mch ik stretch bone to the ik control
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : roll1_mch,
- 'head_tail' : 1.0
- })
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : roll1_mch,
- 'head_tail' : 1.0
- })
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'LIMIT_SCALE',
- 'use_min_y' : True,
- 'use_max_y' : True,
- 'max_y' : 1.05,
- 'owner_space' : 'LOCAL'
- })
- make_constraint(self, mch_main_parent, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': org_bones[0]
- })
-
- # Create ik/fk switch property
- pb_parent = pb[bones['main_parent']]
- pb_parent.lock_location = True, True, True
- pb_parent.lock_rotation = True, True, True
- pb_parent.lock_scale = True, True, True
-
- prop = make_property(pb_parent, 'IK_Stretch', 1.0, description='IK Stretch')
-
- # Add driver to limit scale constraint influence
- b = bones['ik']['mch_str']
-
- make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])
-
- # Create leg widget
- create_foot_widget(self.obj, ctrl, bone_transform_name=None)
-
- # Create heel ctrl locks
- pb[heel].lock_location = True, True, True
- if self.rot_axis == 'x'or self.rot_axis == 'automatic':
- pb[heel].lock_rotation = False, False, True
- elif self.rot_axis == 'z':
- pb[heel].lock_rotation = True, False, False
- pb[heel].lock_scale = True, True, True
+ bone = self.get_bone(name)
+ bone.tail[2] = bone.head[2]
+ bone.roll = 0
- # Add ballsocket widget to heel
- create_ballsocket_widget(self.obj, heel, bone_transform_name=None)
+ return name
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ def register_switch_parents(self, pbuilder):
+ super().register_switch_parents(pbuilder)
- if len(org_bones) >= 4:
- # Create toes control bone
- toes = get_bone_name(org_bones[3], 'ctrl')
- toes = copy_bone(self.obj, org_bones[3], toes)
+ pbuilder.register_parent(self, self.bones.org.main[2], exclude_self=True)
- eb[toes].use_connect = False
- eb[toes].parent = eb[toe_mch]
+ def make_ik_ctrl_widget(self, ctrl):
+ create_foot_widget(self.obj, ctrl, bone_transform_name=None)
- # Constrain 4th ORG to toes
- make_constraint(self, org_bones[3], {
- 'constraint': 'COPY_TRANSFORMS',
- # 'subtarget' : roll2_mch
- 'subtarget': toes
- })
- # Constrain toes def bones
- make_constraint(self, bones['def'][-2], {
- 'constraint': 'DAMPED_TRACK',
- 'subtarget': toes
- })
- make_constraint(self, bones['def'][-2], {
- 'constraint': 'STRETCH_TO',
- 'subtarget': toes
- })
- make_constraint(self, bones['def'][-1], {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': toes
- })
+ ####################################################
+ # Heel control
- # Find IK/FK switch property
- pb = self.obj.pose.bones
- prop = rna_idprop_ui_prop_get( pb[bones['fk']['ctrl'][-1]], 'IK_FK' )
+ @stage.generate_bones
+ def make_heel_control_bone(self):
+ org = self.bones.org.main[2]
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'), scale=1/2)
+ self.bones.ctrl.heel = name
- # Modify rotation mode for ik and tweak controls
- pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'
+ self.align_roll_bone(org, name, -self.vector_without_z(self.get_bone(org).vector))
- for b in bones['tweak']['ctrl']:
- pb[b].rotation_mode = 'ZXY'
+ @stage.parent_bones
+ def parent_heel_control_bone(self):
+ self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik)
- # Add driver to limit scale constraint influence
- b = toe_mch
+ @stage.configure_bones
+ def configure_heel_control_bone(self):
+ bone = self.get_bone(self.bones.ctrl.heel)
+ bone.lock_location = True, True, True
- make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])
+ if self.main_axis == 'x':
+ bone.lock_rotation = False, False, True
+ else:
+ bone.lock_rotation = True, False, False
- # Create toe circle widget
- create_circle_widget(self.obj, toes, radius=0.4, head_tail=0.5)
+ bone.lock_scale = True, True, True
- bones['ik']['ctrl']['terminal'] += [toes]
+ @stage.generate_widgets
+ def generate_heel_control_widget(self):
+ create_ballsocket_widget(self.obj, self.bones.ctrl.heel, bone_transform_name=None)
- bones['ik']['ctrl']['terminal'] += [ heel, ctrl ]
- return bones
+ ####################################################
+ # Heel roll MCH
- def create_drivers(self, bones):
+ @stage.generate_bones
+ def make_roll_mch_chain(self):
+ orgs = self.bones.org.main
+ self.bones.mch.heel = self.make_roll_mch_bones(orgs[2], orgs[3], self.bones.org.heel)
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
+ def make_roll_mch_bones(self, foot, toe, heel):
+ foot_bone = self.get_bone(foot)
+ heel_bone = self.get_bone(heel)
+ axis = -self.vector_without_z(foot_bone.vector)
- #owner = pb[bones['ik']['ctrl']['limb']]
- owner = pb[bones['main_parent']]
+ roll1 = self.copy_bone(foot, make_derived_name(heel, 'mch', '_roll1'))
- props = ["pole_vector"]
+ flip_bone(self.obj, roll1)
+ self.align_roll_bone(foot, roll1, -foot_bone.vector)
- for prop in props:
+ roll2 = self.copy_bone(toe, make_derived_name(heel, 'mch', '_roll2'), scale=1/4)
- if prop == 'pole_vector':
- make_property(owner, prop, False)
- mch_ik = pb[bones['ik']['mch_ik']]
+ put_bone(self.obj, roll2, (heel_bone.head + heel_bone.tail) / 2)
+ self.align_roll_bone(foot, roll2, -axis)
- # ik target hide driver
- pole_target = pb[bones['ik']['ctrl']['ik_target']]
+ rock1 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock1'))
- make_driver(pole_target.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
+ align_bone_to_axis(self.obj, rock1, 'y', roll=0, length=heel_bone.length/2, flip=True)
+ align_bone_y_axis(self.obj, rock1, axis)
- # vis-pole hide driver
- vispole = pb[bones['ik']['visuals']['vispole']]
+ rock2 = self.copy_bone(heel, make_derived_name(heel, 'mch', '_rock2'))
- make_driver(vispole.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
+ align_bone_to_axis(self.obj, rock2, 'y', roll=0, length=heel_bone.length/2)
+ align_bone_y_axis(self.obj, rock2, axis)
- # arrow hide driver
- # limb = pb[bones['ik']['ctrl']['limb']]
- #
- # make_driver(limb.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
+ return [ rock2, rock1, roll2, roll1 ]
- for cns in mch_ik.constraints:
- if 'IK' in cns.type:
- if not cns.pole_subtarget:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
- else:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
+ @stage.parent_bones
+ def parent_roll_mch_chain(self):
+ chain = self.bones.mch.heel
+ self.set_bone_parent(chain[0], self.bones.ctrl.ik)
+ self.parent_bone_chain(chain)
+ @stage.rig_bones
+ def rig_roll_mch_chain(self):
+ self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel)
- @staticmethod
- def get_future_names(bones):
+ def rig_roll_mch_bones(self, chain, heel, org_heel):
+ rock2, rock1, roll2, roll1 = chain
- if len(bones) != 4:
- return
+ self.make_constraint(roll1, 'COPY_ROTATION', heel, space='LOCAL')
+ self.make_constraint(roll2, 'COPY_ROTATION', heel, space='LOCAL')
- names = dict()
+ if self.main_axis == 'x':
+ self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_x=True, max_x=DEG_360, space='LOCAL')
+ self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_x=-DEG_360, space='LOCAL')
+ else:
+ self.make_constraint(roll1, 'LIMIT_ROTATION', use_limit_z=True, max_z=DEG_360, space='LOCAL')
+ self.make_constraint(roll2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_z=-DEG_360, space='LOCAL')
- thigh = strip_mch(strip_org(bones[0].name))
- shin = strip_mch(strip_org(bones[1].name))
- foot = strip_mch(strip_org(bones[2].name))
- toe = strip_mch(strip_org(bones[3].name))
+ direction = self.get_main_axis(self.get_bone(heel)).dot(self.get_bone(org_heel).vector)
- suffix = ''
- if thigh[-2:] == '.L' or thigh[-2:] == '.R':
- suffix = thigh[-2:]
- thigh = thigh.rstrip(suffix)
- shin = shin.rstrip(suffix)
- foot = foot.rstrip(suffix)
- toe = toe.rstrip(suffix)
-
- # the following is declared in rig_ui
- # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R',
- # 'MCH-foot_fk.R', 'thigh_parent.R']
- # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001']
- # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R']
- # fk_ctrl = 'thigh_fk.R'
- # parent = 'thigh_parent.R'
- # foot_fk = 'foot_fk.R'
- # pole = 'thigh_ik_target.R'
+ if direction < 0:
+ rock2, rock1 = rock1, rock2
- names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik',
- foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent']
- names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target']
- names['fk_ctrl'] = thigh + '_fk' + suffix
- names['parent'] = thigh + '_parent' + suffix
- names['foot_fk'] = foot + '_fk' + suffix
- names['pole'] = thigh + '_ik_target' + suffix
+ self.make_constraint(rock1, 'COPY_ROTATION', heel, space='LOCAL')
+ self.make_constraint(rock2, 'COPY_ROTATION', heel, space='LOCAL')
- names['limb_type'] = 'leg'
+ self.make_constraint(rock1, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, max_y=DEG_360, space='LOCAL')
+ self.make_constraint(rock2, 'LIMIT_ROTATION', use_limit_xyz=ALL_TRUE, min_y=-DEG_360, space='LOCAL')
- if suffix:
- for i, name in enumerate(names['controls']):
- names['controls'][i] = name + suffix
- for i, name in enumerate(names['ik_ctrl']):
- names['ik_ctrl'][i] = name + suffix
- return names
+ ####################################################
+ # FK parents MCH chain
- def generate(self):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
+ if i == 3:
+ align_bone_orientation(self.obj, parent_mch, self.bones.mch.heel[-2])
- # Adjust org-bones rotation
- self.orient_org_bones()
+ self.set_bone_parent(parent_mch, prev_org, use_connect=True)
- # Clear parents for org bones
- for bone in self.org_bones[1:]:
- eb[bone].use_connect = False
- eb[bone].parent = None
+ else:
+ super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
- bones = {}
+ def rig_fk_parent_bone(self, i, parent_mch, org):
+ if i == 3:
+ con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.heel[-2])
- # Create mch limb parent
- mch_parent, main_parent = self.create_parent()
- bones['parent'] = mch_parent
- bones['main_parent'] = main_parent
- bones['tweak'] = self.create_tweak()
- bones['def'] = self.create_def(bones['tweak']['ctrl'])
- bones['ik'] = self.create_ik(bones['parent'])
- bones['fk'] = self.create_fk(bones['parent'])
+ self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
- self.org_parenting_and_switch(self.org_bones, bones['ik'], bones['fk']['ctrl'], bones['main_parent'])
-
- bones = self.create_leg(bones)
- self.create_drivers(bones)
+ else:
+ super().rig_fk_parent_bone(i, parent_mch, org)
- # Create UI
- script = create_script(bones, 'leg')
- return {
- 'script': [script],
- 'utilities': UTILITIES_RIG_LEG,
- 'register': REGISTER_RIG_LEG,
- }
-
-
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
-
- items = [
- ('x', 'X manual', ''),
- ('z', 'Z manual', ''),
- ('automatic', 'Automatic', '')
- ]
-
- params.rotation_axis = bpy.props.EnumProperty(
- items = items,
- name = "Rotation Axis",
- default = 'automatic'
- )
-
- params.auto_align_extremity = bpy.props.BoolProperty(
- name='auto_align_extremity',
- default=False,
- description="Auto Align Extremity Bone"
- )
-
- params.segments = bpy.props.IntProperty(
- name = 'limb segments',
- default = 2,
- min = 1,
- description = 'Number of segments'
- )
-
- params.bbones = bpy.props.IntProperty(
- name = 'bbone segments',
- default = 10,
- min = 1,
- description = 'Number of segments'
- )
-
- # Setting up extra layers for the FK and tweak
- ControlLayersOption.FK.add_parameters(params)
- ControlLayersOption.TWEAK.add_parameters(params)
+ ####################################################
+ # IK system MCH
+ ik_input_head_tail = 1.0
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters."""
+ def get_ik_input_bone(self):
+ return self.bones.mch.heel[-1]
- r = layout.row()
- r.prop(params, "rotation_axis")
+ @stage.parent_bones
+ def parent_ik_mch_chain(self):
+ super().parent_ik_mch_chain()
- if 'auto' not in params.rotation_axis.lower():
- r = layout.row()
- text = "Auto align Foot"
- r.prop(params, "auto_align_extremity", text=text)
+ self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
- r = layout.row()
- r.prop(params, "segments")
- r = layout.row()
- r.prop(params, "bbones")
+ ####################################################
+ # Settings
- ControlLayersOption.FK.parameters_ui(layout, params)
- ControlLayersOption.TWEAK.parameters_ui(layout, params)
+ @classmethod
+ def parameters_ui(self, layout, params):
+ super().parameters_ui(layout, params, 'Foot')
def create_sample(obj):
@@ -1176,7 +322,7 @@ def create_sample(obj):
bpy.ops.object.mode_set(mode='OBJECT')
pbone = obj.pose.bones[bones['thigh.L']]
- pbone.rigify_type = 'limbs.super_limb'
+ pbone.rigify_type = 'limbs.leg'
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
@@ -1256,6 +402,4 @@ def create_sample(obj):
arm.layers = (False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
-
-if __name__ == "__main__":
- create_sample(bpy.context.active_object)
+ return bones
diff --git a/rigify/rigs/limbs/limb_rigs.py b/rigify/rigs/limbs/limb_rigs.py
new file mode 100644
index 00000000..0b6c0425
--- /dev/null
+++ b/rigify/rigs/limbs/limb_rigs.py
@@ -0,0 +1,1047 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+import json
+
+from ...utils.animation import add_generic_snap_fk_to_ik, add_fk_ik_snap_buttons
+from ...utils.rig import connected_children_names
+from ...utils.bones import BoneDict, put_bone, compute_chain_x_axis, align_bone_orientation
+from ...utils.bones import align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
+from ...utils.naming import strip_org, make_derived_name
+from ...utils.layers import ControlLayersOption
+from ...utils.misc import pairwise_nozip, padnone, map_list
+from ...utils.switch_parent import SwitchParentBuilder
+
+from ...base_rig import stage, BaseRig
+
+from ...utils.widgets_basic import create_circle_widget, create_sphere_widget, create_line_widget, create_limb_widget
+from ..widgets import create_gear_widget, create_ikarrow_widget
+
+from ...rig_ui_template import UTILITIES_FUNC_COMMON_IKFK
+
+from math import pi
+from itertools import count, repeat, chain
+from mathutils import Vector
+from collections import namedtuple
+
+
+SegmentEntry = namedtuple('SegmentEntry', ['org', 'org_idx', 'seg_idx', 'pos'])
+
+
+class BaseLimbRig(BaseRig):
+ """Common base for limb rigs."""
+
+ segmented_orgs = 2 # Number of org bones to segment
+
+ def find_org_bones(self, bone):
+ return BoneDict(
+ main=[bone.name] + connected_children_names(self.obj, bone.name),
+ )
+
+ def initialize(self):
+ orgs = self.bones.org.main
+
+ if len(orgs) < self.segmented_orgs + 1:
+ self.raise_error("Input to rig type must be a chain of at least 3 bones.")
+
+ self.segments = self.params.segments
+ self.bbone_segments = self.params.bbones
+
+ rot_axis = self.params.rotation_axis
+
+ if rot_axis in {'x', 'automatic'}:
+ self.main_axis, self.aux_axis = 'x', 'z'
+ elif rot_axis == 'z':
+ self.main_axis, self.aux_axis = 'z', 'x'
+ else:
+ self.raise_error('Unexpected axis value: {}', rot_axis)
+
+ self.segment_table = [
+ SegmentEntry(org, i, j, self.get_segment_pos(org, j))
+ for i, org in enumerate(orgs[:self.segmented_orgs])
+ for j in range(self.segments)
+ ]
+ self.segment_table_end = [
+ SegmentEntry(org, i + self.segmented_orgs, None, self.get_bone(org).head)
+ for i, org in enumerate(orgs[self.segmented_orgs:])
+ ]
+
+ self.segment_table_full = self.segment_table + self.segment_table_end
+ self.segment_table_tweak = self.segment_table + self.segment_table_end[0:1]
+
+ def generate_bones(self):
+ bones = map_list(self.get_bone, self.bones.org.main[0:2])
+
+ self.elbow_vector = self.compute_elbow_vector(bones)
+ self.pole_angle = self.compute_pole_angle(bones, self.elbow_vector)
+ self.rig_parent_bone = self.get_bone_parent(self.bones.org.main[0])
+
+
+ ####################################################
+ # Utilities
+
+ def compute_elbow_vector(self, bones):
+ lo_vector = bones[1].vector
+ tot_vector = bones[1].tail - bones[0].head
+ return (lo_vector.project(tot_vector) - lo_vector).normalized() * tot_vector.length
+
+ def get_main_axis(self, bone):
+ return getattr(bone, self.main_axis + '_axis')
+
+ def get_aux_axis(self, bone):
+ return getattr(bone, self.aux_axis + '_axis')
+
+ def compute_pole_angle(self, bones, elbow_vector):
+ if self.params.rotation_axis == 'z':
+ return 0
+
+ vector = self.get_aux_axis(bones[0]) + self.get_aux_axis(bones[1])
+
+ if elbow_vector.angle(vector) > pi/2:
+ return -pi/2
+ else:
+ return pi/2
+
+ def get_segment_pos(self, org, seg):
+ bone = self.get_bone(org)
+ return bone.head + bone.vector * (seg / self.segments)
+
+ def align_roll_bone(self, org, name, y_axis):
+ if y_axis:
+ align_bone_y_axis(self.obj, name, y_axis)
+
+ if self.main_axis == 'x':
+ align_bone_x_axis(self.obj, name, self.get_bone(org).x_axis)
+ else:
+ align_bone_z_axis(self.obj, name, self.get_bone(org).z_axis)
+
+ @staticmethod
+ def vector_without_z(vector):
+ return Vector((vector[0], vector[1], 0))
+
+ ####################################################
+ # BONES
+ #
+ # org:
+ # main[]:
+ # Main ORG bone chain
+ # ctrl:
+ # master:
+ # Main property control.
+ # fk[]:
+ # FK control chain.
+ # tweak[]:
+ # Tweak control chain.
+ # ik_base, ik_pole, ik
+ # IK controls
+ # ik_vispole
+ # IK pole visualization.
+ # mch:
+ # master:
+ # Parent of the master control.
+ # follow:
+ # FK follow behavior.
+ # fk[]:
+ # FK chain parents (or None)
+ # ik_stretch
+ # IK stretch switch implementation.
+ # ik_target
+ # Corrected target position.
+ # ik_end
+ # End of the IK chain: [ik_base, ik_end]
+ # deform[]:
+ # DEF bones
+ #
+ ####################################################
+
+ ####################################################
+ # Master control
+
+ @stage.generate_bones
+ def make_master_control(self):
+ org = self.bones.org.main[0]
+ self.bones.mch.master = name = self.copy_bone(org, make_derived_name(org, 'mch', '_parent_socket'), scale=1/12)
+ self.get_bone(name).roll = 0
+ self.bones.ctrl.master = name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_parent'), scale=1/4)
+ self.get_bone(name).roll = 0
+ self.prop_bone = self.bones.ctrl.master
+
+ @stage.parent_bones
+ def parent_master_control(self):
+ self.set_bone_parent(self.bones.ctrl.master, self.bones.mch.master)
+ self.set_bone_parent(self.bones.mch.master, self.bones.mch.follow)
+
+ @stage.configure_bones
+ def configure_master_control(self):
+ bone = self.get_bone(self.bones.ctrl.master)
+ bone.lock_location = (True, True, True)
+ bone.lock_rotation = (True, True, True)
+ bone.lock_scale = (True, True, True)
+ bone.lock_rotation_w = True
+
+ @stage.rig_bones
+ def rig_master_control(self):
+ self.make_constraint(self.bones.mch.master, 'COPY_ROTATION', self.bones.org.main[0])
+
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ create_gear_widget(self.obj, self.bones.ctrl.master, size=10)
+
+
+ ####################################################
+ # FK follow MCH
+
+ @stage.generate_bones
+ def make_mch_follow_bone(self):
+ org = self.bones.org.main[0]
+ self.bones.mch.follow = self.copy_bone(org, make_derived_name(org, 'mch', '_parent'), scale=1/4)
+
+ @stage.parent_bones
+ def parent_mch_follow_bone(self):
+ mch = self.bones.mch.follow
+ align_bone_orientation(self.obj, mch, 'root')
+ self.set_bone_parent(mch, self.rig_parent_bone)
+
+ @stage.configure_bones
+ def configure_mch_follow_bone(self):
+ ctrl = self.bones.ctrl
+ panel = self.script.panel_with_selected_check(self, [ctrl.master, *ctrl.fk])
+
+ self.make_property(self.prop_bone, 'FK_limb_follow', default=0.0)
+ panel.custom_prop(self.prop_bone, 'FK_limb_follow', text='FK Limb Follow', slider=True)
+
+ @stage.rig_bones
+ def rig_mch_follow_bone(self):
+ mch = self.bones.mch.follow
+
+ con = self.make_constraint(mch, 'COPY_ROTATION', 'root')
+ self.make_constraint(mch, 'COPY_SCALE', 'root')
+
+ self.make_driver(con, 'influence', variables=[(self.prop_bone, 'FK_limb_follow')])
+
+
+ ####################################################
+ # FK control chain
+
+ @stage.generate_bones
+ def make_fk_control_chain(self):
+ self.bones.ctrl.fk = map_list(self.make_fk_control_bone, count(0), self.bones.org.main)
+
+ def get_fk_name(self, i, org, kind):
+ return make_derived_name(org, kind, '_fk' if i <= 2 else '')
+
+ def make_fk_control_bone(self, i, org):
+ return self.copy_bone(org, self.get_fk_name(i, org, 'ctrl'))
+
+ @stage.parent_bones
+ def parent_fk_control_chain(self):
+ fk = self.bones.ctrl.fk
+ for args in zip(count(0), fk, [self.bones.mch.follow]+fk, self.bones.org.main, self.bones.mch.fk):
+ self.parent_fk_control_bone(*args)
+
+ def parent_fk_control_bone(self, i, ctrl, prev, org, parent_mch):
+ if parent_mch:
+ self.set_bone_parent(ctrl, parent_mch)
+ else:
+ self.set_bone_parent(ctrl, prev, use_connect=(i > 0))
+
+ @stage.configure_bones
+ def configure_fk_control_chain(self):
+ for args in zip(count(0), self.bones.ctrl.fk, self.bones.org.main):
+ self.configure_fk_control_bone(*args)
+
+ ControlLayersOption.FK.assign(self.params, self.obj, self.bones.ctrl.fk[0:3])
+
+ def configure_fk_control_bone(self, i, ctrl, org):
+ self.copy_bone_properties(org, ctrl)
+
+ if i == 2:
+ self.get_bone(ctrl).lock_location = True, True, True
+
+ @stage.generate_widgets
+ def make_fk_control_widgets(self):
+ for args in zip(count(0), self.bones.ctrl.fk):
+ self.make_fk_control_widget(*args)
+
+ def make_fk_control_widget(self, i, ctrl):
+ if i < 2:
+ create_limb_widget(self.obj, ctrl)
+ elif i == 2:
+ create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.0)
+ else:
+ create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.5)
+
+
+ ####################################################
+ # FK parents MCH chain
+
+ @stage.generate_bones
+ def make_fk_parent_chain(self):
+ self.bones.mch.fk = map_list(self.make_fk_parent_bone, count(0), self.bones.org.main)
+
+ def make_fk_parent_bone(self, i, org):
+ if 2 <= i <= 3:
+ return self.copy_bone(org, self.get_fk_name(i, org, 'mch'), parent=True, scale=1/4)
+
+ @stage.parent_bones
+ def parent_fk_parent_chain(self):
+ mch = self.bones.mch
+ orgs = self.bones.org.main
+ for args in zip(count(0), mch.fk, [mch.follow]+self.bones.ctrl.fk, orgs, [None]+orgs):
+ self.parent_fk_parent_bone(*args)
+
+ def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
+ if i == 2:
+ self.set_bone_parent(parent_mch, prev_ctrl, use_connect=True)
+
+ @stage.rig_bones
+ def rig_fk_parent_chain(self):
+ for args in zip(count(0), self.bones.mch.fk, self.bones.org.main):
+ self.rig_fk_parent_bone(*args)
+
+ def rig_fk_parent_bone(self, i, parent_mch, org):
+ if i == 2:
+ self.make_constraint(parent_mch, 'COPY_SCALE', 'root')
+
+
+ ####################################################
+ # IK controls
+
+ def get_extra_ik_controls(self):
+ return []
+
+ def get_all_ik_controls(self):
+ ctrl = self.bones.ctrl
+ return [ctrl.ik_base, ctrl.ik_pole, ctrl.ik] + self.get_extra_ik_controls()
+
+ @stage.generate_bones
+ def make_ik_controls(self):
+ orgs = self.bones.org.main
+
+ self.bones.ctrl.ik_base = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik'))
+ self.bones.ctrl.ik_pole = self.make_ik_pole_bone(orgs)
+ self.bones.ctrl.ik = self.make_ik_control_bone(orgs)
+
+ self.build_ik_parent_switch(SwitchParentBuilder(self.generator))
+
+ def make_ik_pole_bone(self, orgs):
+ name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik_target'))
+
+ pole = self.get_bone(name)
+ pole.head = self.get_bone(orgs[0]).tail + self.elbow_vector
+ pole.tail = pole.head - self.elbow_vector/8
+ pole.roll = 0
+
+ return name
+
+ def make_ik_control_bone(self, orgs):
+ return self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
+
+ def register_switch_parents(self, pbuilder):
+ if self.rig_parent_bone:
+ pbuilder.register_parent(self, self.rig_parent_bone)
+
+ def build_ik_parent_switch(self, pbuilder):
+ ctrl = self.bones.ctrl
+
+ master = lambda: self.bones.ctrl.master
+ pcontrols = lambda: [ ctrl.master ] + self.get_all_ik_controls()
+ pole_parents = lambda: [(self.bones.mch.ik_target, ctrl.ik)]
+
+ self.register_switch_parents(pbuilder)
+
+ pbuilder.build_child(
+ self, ctrl.ik, prop_bone=master, select_parent='root',
+ prop_id='IK_parent', prop_name='IK Parent', controls=pcontrols,
+ )
+
+ pbuilder.build_child(
+ self, ctrl.ik_pole, prop_bone=master, extra_parents=pole_parents,
+ prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols,
+ no_fix_rotation=True, no_fix_scale=True,
+ )
+
+ @stage.parent_bones
+ def parent_ik_controls(self):
+ self.set_bone_parent(self.bones.ctrl.ik_base, self.bones.mch.follow)
+
+ @stage.configure_bones
+ def configure_ik_controls(self):
+ base = self.get_bone(self.bones.ctrl.ik_base)
+ base.rotation_mode = 'ZXY'
+ base.lock_rotation = True, False, True
+ base.ik_stretch = 0.1
+
+ @stage.rig_bones
+ def rig_ik_controls(self):
+ self.rig_hide_pole_control(self.bones.ctrl.ik_pole)
+
+ @stage.generate_widgets
+ def make_ik_control_widgets(self):
+ self.make_ik_base_widget(self.bones.ctrl.ik_base)
+ self.make_ik_pole_widget(self.bones.ctrl.ik_pole)
+ self.make_ik_ctrl_widget(self.bones.ctrl.ik)
+
+ def make_ik_base_widget(self, ctrl):
+ if self.main_axis == 'x':
+ roll = 0
+ else:
+ roll = pi/2
+
+ create_ikarrow_widget(self.obj, ctrl, bone_transform_name=None, roll=roll)
+
+ def make_ik_pole_widget(self, ctrl):
+ create_sphere_widget(self.obj, ctrl, bone_transform_name=None)
+
+ def make_ik_ctrl_widget(self, ctrl):
+ raise NotImplementedError()
+
+
+ ####################################################
+ # IK pole visualization
+
+ @stage.generate_bones
+ def make_ik_vispole_bone(self):
+ orgs = self.bones.org.main
+ name = self.copy_bone(orgs[1], 'VIS_'+make_derived_name(orgs[0], 'ctrl', '_ik_pole'))
+ self.bones.ctrl.ik_vispole = name
+
+ bone = self.get_bone(name)
+ bone.tail = bone.head + Vector((0, 0, bone.length / 10))
+ bone.hide_select = True
+
+ @stage.rig_bones
+ def rig_ik_vispole_bone(self):
+ name = self.bones.ctrl.ik_vispole
+
+ self.make_constraint(name, 'COPY_LOCATION', self.bones.org.main[1])
+ self.make_constraint(
+ name, 'STRETCH_TO', self.bones.ctrl.ik_pole,
+ volume='NO_VOLUME', rest_length=self.get_bone(name).length
+ )
+
+ self.rig_hide_pole_control(name)
+
+ @stage.generate_widgets
+ def make_ik_vispole_widget(self):
+ create_line_widget(self.obj, self.bones.ctrl.ik_vispole)
+
+
+ ####################################################
+ # IK system MCH
+
+ ik_input_head_tail = 0.0
+
+ def get_ik_input_bone(self):
+ return self.bones.ctrl.ik
+
+ def get_ik_output_chain(self):
+ return [self.bones.ctrl.ik_base, self.bones.mch.ik_end, self.bones.mch.ik_target]
+
+ @stage.generate_bones
+ def make_ik_mch_chain(self):
+ orgs = self.bones.org.main
+ self.bones.mch.ik_stretch = self.make_ik_mch_stretch_bone(orgs)
+ self.bones.mch.ik_target = self.make_ik_mch_target_bone(orgs)
+ self.bones.mch.ik_end = self.copy_bone(orgs[1], make_derived_name(orgs[1], 'mch', '_ik'))
+
+ def make_ik_mch_stretch_bone(self, orgs):
+ name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'mch', '_ik_stretch'))
+ self.get_bone(name).tail = self.get_bone(orgs[2]).head
+ return name
+
+ def make_ik_mch_target_bone(self, orgs):
+ return self.copy_bone(orgs[2], make_derived_name(orgs[0], 'mch', '_ik_target'))
+
+ @stage.parent_bones
+ def parent_ik_mch_chain(self):
+ self.set_bone_parent(self.bones.mch.ik_stretch, self.bones.mch.follow)
+ self.set_bone_parent(self.bones.mch.ik_target, self.get_ik_input_bone())
+ self.set_bone_parent(self.bones.mch.ik_end, self.bones.ctrl.ik_base)
+
+ @stage.configure_bones
+ def configure_ik_mch_chain(self):
+ ctrl = self.bones.ctrl
+ panel = self.script.panel_with_selected_check(self, ctrl.flatten())
+
+ rig_name = strip_org(self.bones.org.main[2])
+
+ self.make_property(self.prop_bone, 'IK_FK', default=0.0, description='IK/FK Switch')
+ panel.custom_prop(self.prop_bone, 'IK_FK', text='IK-FK ({})'.format(rig_name), slider=True)
+
+ self.add_global_buttons(panel, rig_name)
+
+ panel = self.script.panel_with_selected_check(self, [ctrl.master, *self.get_all_ik_controls()])
+
+ self.make_property(self.prop_bone, 'IK_Stretch', default=1.0, description='IK Stretch')
+ panel.custom_prop(self.prop_bone, 'IK_Stretch', text='IK Stretch', slider=True)
+
+ self.make_property(self.prop_bone, 'pole_vector', default=False, description='Use a pole target control')
+
+ self.add_ik_only_buttons(panel, rig_name)
+
+ def add_global_buttons(self, panel, rig_name):
+ ctrl = self.bones.ctrl
+ ik_chain = self.get_ik_output_chain()
+
+ add_generic_snap_fk_to_ik(
+ panel,
+ fk_bones=self.bones.ctrl.fk[0:len(ik_chain)],
+ ik_bones=ik_chain,
+ ik_ctrl_bones=self.get_all_ik_controls(),
+ rig_name=rig_name
+ )
+
+ add_limb_snap_ik_to_fk(
+ panel,
+ master=ctrl.master,
+ fk_bones=self.bones.ctrl.fk, ik_bones=ik_chain,
+ ik_ctrl_bones=[ctrl.ik_base, ctrl.ik, ctrl.ik_pole],
+ ik_extra_ctrls=self.get_extra_ik_controls(),
+ rig_name=rig_name
+ )
+
+ def add_ik_only_buttons(self, panel, rig_name):
+ ctrl = self.bones.ctrl
+ ik_chain = self.get_ik_output_chain()
+
+ add_limb_toggle_pole(
+ panel, master=ctrl.master,
+ ik_bones=ik_chain,
+ ik_ctrl_bones=[ctrl.ik_base, ctrl.ik, ctrl.ik_pole],
+ ik_extra_ctrls=self.get_extra_ik_controls(),
+ )
+
+ @stage.rig_bones
+ def rig_ik_mch_chain(self):
+ mch = self.bones.mch
+ input_bone = self.get_ik_input_bone()
+
+ self.rig_ik_mch_stretch_bone(mch.ik_stretch, input_bone)
+ self.rig_ik_mch_target_bone(mch.ik_target, mch.ik_stretch, input_bone)
+ self.rig_ik_mch_end_bone(mch.ik_end, mch.ik_target, self.bones.ctrl.ik_pole)
+
+ def rig_ik_mch_stretch_bone(self, mch_stretch, input_bone):
+ self.make_constraint(mch_stretch, 'DAMPED_TRACK', input_bone, head_tail=self.ik_input_head_tail)
+ self.make_constraint(mch_stretch, 'STRETCH_TO', input_bone, head_tail=self.ik_input_head_tail)
+
+ con = self.make_constraint(mch_stretch, 'LIMIT_SCALE', min_y=0.0, max_y=1.05, owner_space='LOCAL')
+
+ self.make_driver(con, "influence", variables=[(self.prop_bone, 'IK_Stretch')], polynomial=[1.0, -1.0])
+
+ def rig_ik_mch_target_bone(self, mch_target, mch_stretch, input_bone):
+ self.make_constraint(mch_target, 'COPY_LOCATION', mch_stretch, head_tail=1.0)
+
+ def rig_ik_mch_end_bone(self, mch_ik, mch_target, ctrl_pole):
+ bone = self.get_bone(mch_ik)
+ bone.ik_stretch = 0.1
+
+ bone.lock_ik_x = bone.lock_ik_y = bone.lock_ik_z = True
+ setattr(bone, 'lock_ik_' + self.main_axis, False)
+
+ con = self.make_constraint(
+ mch_ik, 'IK', mch_target, chain_count=2,
+ )
+
+ self.make_driver(con, "mute", variables=[(self.prop_bone, 'pole_vector')], polynomial=[0.0, 1.0])
+
+ con_pole = self.make_constraint(
+ mch_ik, 'IK', mch_target, chain_count=2,
+ pole_target=self.obj, pole_subtarget=ctrl_pole, pole_angle=self.pole_angle,
+ )
+
+ self.make_driver(con_pole, "mute", variables=[(self.prop_bone, 'pole_vector')], polynomial=[1.0, -1.0])
+
+ def rig_hide_pole_control(self, name):
+ self.make_driver(
+ self.get_bone(name).bone, "hide",
+ variables=[(self.prop_bone, 'pole_vector')], polynomial=[1.0, -1.0],
+ )
+
+
+ ####################################################
+ # ORG chain
+
+ @stage.parent_bones
+ def parent_org_chain(self):
+ orgs = self.bones.org.main
+ if len(orgs) > 3:
+ self.get_bone(orgs[3]).use_connect = False
+
+ @stage.rig_bones
+ def rig_org_chain(self):
+ ik = self.get_ik_output_chain()
+ for args in zip(count(0), self.bones.org.main, self.bones.ctrl.fk, padnone(ik)):
+ self.rig_org_bone(*args)
+
+ def rig_org_bone(self, i, org, fk, ik):
+ self.make_constraint(org, 'COPY_TRANSFORMS', fk)
+
+ if ik:
+ con = self.make_constraint(org, 'COPY_TRANSFORMS', ik)
+
+ self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
+
+
+ ####################################################
+ # Tweak control chain
+
+ @stage.generate_bones
+ def make_tweak_chain(self):
+ self.bones.ctrl.tweak = map_list(self.make_tweak_bone, count(0), self.segment_table_tweak)
+
+ def make_tweak_bone(self, i, entry):
+ name = make_derived_name(entry.org, 'ctrl', '_tweak')
+ name = self.copy_bone(entry.org, name, scale=1/(2 * self.segments))
+ put_bone(self.obj, name, entry.pos)
+ return name
+
+ @stage.parent_bones
+ def parent_tweak_chain(self):
+ for ctrl, mch in zip(self.bones.ctrl.tweak, self.bones.mch.tweak):
+ self.set_bone_parent(ctrl, mch)
+
+ @stage.configure_bones
+ def configure_tweak_chain(self):
+ for args in zip(count(0), self.bones.ctrl.tweak, self.segment_table_tweak):
+ self.configure_tweak_bone(*args)
+
+ ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.tweak)
+
+ def configure_tweak_bone(self, i, tweak, entry):
+ tweak_pb = self.get_bone(tweak)
+ tweak_pb.lock_rotation = (True, False, True)
+ tweak_pb.lock_scale = (False, True, False)
+ tweak_pb.rotation_mode = 'ZXY'
+
+ if i > 0 and entry.seg_idx is not None:
+ self.make_rubber_tweak_property(i, tweak, entry)
+
+ def make_rubber_tweak_property(self, i, tweak, entry):
+ defval = 1.0 if entry.seg_idx else 0.0
+ text = 'Rubber Tweak ({})'.format(strip_org(entry.org))
+
+ self.make_property(tweak, 'rubber_tweak', defval, max=2.0, soft_max=1.0)
+
+ panel = self.script.panel_with_selected_check(self, [tweak])
+ panel.custom_prop(tweak, 'rubber_tweak', text=text, slider=True)
+
+ @stage.generate_widgets
+ def make_tweak_widgets(self):
+ for tweak in self.bones.ctrl.tweak:
+ self.make_tweak_widget(tweak)
+
+ def make_tweak_widget(self, tweak):
+ create_sphere_widget(self.obj, tweak)
+
+
+ ####################################################
+ # Tweak MCH chain
+
+ @stage.generate_bones
+ def make_tweak_mch_chain(self):
+ self.bones.mch.tweak = map_list(self.make_tweak_mch_bone, count(0), self.segment_table_tweak)
+
+ def make_tweak_mch_bone(self, i, entry):
+ name = make_derived_name(entry.org, 'mch', '_tweak')
+ name = self.copy_bone(entry.org, name, scale=1/(4 * self.segments))
+ put_bone(self.obj, name, entry.pos)
+ return name
+
+ @stage.parent_bones
+ def parent_tweak_mch_chain(self):
+ for mch, entry in zip(self.bones.mch.tweak, self.segment_table_tweak):
+ self.set_bone_parent(mch, entry.org)
+
+ @stage.rig_bones
+ def rig_tweak_mch_chain(self):
+ for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak):
+ self.rig_tweak_mch_bone(*args)
+
+ def rig_tweak_mch_bone(self, i, tweak, entry):
+ if entry.seg_idx:
+ tweaks = self.bones.ctrl.tweak
+ prev_tweak = tweaks[i - entry.seg_idx]
+ next_tweak = tweaks[i + self.segments - entry.seg_idx]
+
+ self.make_constraint(tweak, 'COPY_TRANSFORMS', prev_tweak)
+ self.make_constraint(
+ tweak, 'COPY_TRANSFORMS', next_tweak,
+ influence = entry.seg_idx / self.segments
+ )
+ self.make_constraint(tweak, 'DAMPED_TRACK', next_tweak)
+
+ elif entry.seg_idx is not None:
+ self.make_constraint(tweak, 'COPY_SCALE', 'root')
+
+
+ ####################################################
+ # Deform chain
+
+ @stage.generate_bones
+ def make_deform_chain(self):
+ self.bones.deform = map_list(self.make_deform_bone, count(0), self.segment_table_full)
+
+ def make_deform_bone(self, i, entry):
+ name = make_derived_name(entry.org, 'def')
+
+ if entry.seg_idx is None:
+ name = self.copy_bone(entry.org, name)
+ else:
+ name = self.copy_bone(entry.org, name, bbone=True, scale=1/self.segments)
+ put_bone(self.obj, name, entry.pos)
+ self.get_bone(name).bbone_segments = self.bbone_segments
+
+ return name
+
+ @stage.parent_bones
+ def parent_deform_chain(self):
+ self.set_bone_parent(self.bones.deform[0], self.rig_parent_bone)
+ self.parent_bone_chain(self.bones.deform, use_connect=True)
+
+ @stage.rig_bones
+ def rig_deform_chain(self):
+ tweaks = pairwise_nozip(padnone(self.bones.ctrl.tweak))
+ entries = pairwise_nozip(padnone(self.segment_table_full))
+
+ for args in zip(count(0), self.bones.deform, *entries, *tweaks):
+ self.rig_deform_bone(*args)
+
+ def rig_deform_bone(self, i, deform, entry, next_entry, tweak, next_tweak):
+ if tweak:
+ self.make_constraint(deform, 'COPY_TRANSFORMS', tweak)
+
+ if next_tweak:
+ self.make_constraint(deform, 'DAMPED_TRACK', next_tweak)
+ self.make_constraint(deform, 'STRETCH_TO', next_tweak)
+
+ self.rig_deform_easing(i, deform, tweak, next_tweak)
+
+ elif next_entry:
+ self.make_constraint(deform, 'DAMPED_TRACK', next_entry.org)
+ self.make_constraint(deform, 'STRETCH_TO', next_entry.org)
+
+ else:
+ self.make_constraint(deform, 'COPY_TRANSFORMS', entry.org)
+
+ def rig_deform_easing(self, i, deform, tweak, next_tweak):
+ pbone = self.get_bone(deform)
+
+ if 'rubber_tweak' in self.get_bone(tweak):
+ self.make_driver(pbone.bone, 'bbone_easein', variables=[(tweak, 'rubber_tweak')])
+ else:
+ pbone.bone.bbone_easein = 0.0
+
+ if 'rubber_tweak' in self.get_bone(next_tweak):
+ self.make_driver(pbone.bone, 'bbone_easeout', variables=[(next_tweak, 'rubber_tweak')])
+ else:
+ pbone.bone.bbone_easeout = 0.0
+
+
+ ####################################################
+ # Settings
+
+ @classmethod
+ def add_parameters(self, params):
+ """ Add the parameters of this rig type to the
+ RigifyParameters PropertyGroup
+ """
+
+ items = [
+ ('x', 'X manual', ''),
+ ('z', 'Z manual', ''),
+ ('automatic', 'Automatic', '')
+ ]
+
+ params.rotation_axis = bpy.props.EnumProperty(
+ items = items,
+ name = "Rotation Axis",
+ default = 'automatic'
+ )
+
+ params.auto_align_extremity = bpy.props.BoolProperty(
+ name='auto_align_extremity',
+ default=False,
+ description="Auto Align Extremity Bone"
+ )
+
+ params.segments = bpy.props.IntProperty(
+ name = 'limb segments',
+ default = 2,
+ min = 1,
+ description = 'Number of segments'
+ )
+
+ params.bbones = bpy.props.IntProperty(
+ name = 'bbone segments',
+ default = 10,
+ min = 1,
+ description = 'Number of segments'
+ )
+
+ # Setting up extra layers for the FK and tweak
+ ControlLayersOption.FK.add_parameters(params)
+ ControlLayersOption.TWEAK.add_parameters(params)
+
+ @classmethod
+ def parameters_ui(self, layout, params, end='End'):
+ """ Create the ui for the rig parameters."""
+
+ r = layout.row()
+ r.prop(params, "rotation_axis")
+
+ if 'auto' not in params.rotation_axis.lower():
+ r = layout.row()
+ r.prop(params, "auto_align_extremity", text="Auto Align "+end)
+
+ r = layout.row()
+ r.prop(params, "segments")
+
+ r = layout.row()
+ r.prop(params, "bbones")
+
+ ControlLayersOption.FK.parameters_ui(layout, params)
+ ControlLayersOption.TWEAK.parameters_ui(layout, params)
+
+
+###########################
+# Limb IK to FK operator ##
+###########################
+
+SCRIPT_REGISTER_OP_SNAP_IK_FK = ['POSE_OT_rigify_limb_ik2fk', 'POSE_OT_rigify_limb_ik2fk_bake']
+
+SCRIPT_UTILITIES_OP_SNAP_IK_FK = UTILITIES_FUNC_COMMON_IKFK + ['''
+########################
+## Limb Snap IK to FK ##
+########################
+
+class RigifyLimbIk2FkBase:
+ prop_bone: StringProperty(name="Settings Bone")
+ pole_prop: StringProperty(name="Pole target switch", default="pole_vector")
+ fk_bones: StringProperty(name="FK Bone Chain")
+ ik_bones: StringProperty(name="IK Result Bone Chain")
+ ctrl_bones: StringProperty(name="IK Controls")
+ extra_ctrls: StringProperty(name="Extra IK Controls")
+
+ keyflags = None
+
+ def init_execute(self, context):
+ if self.fk_bones:
+ self.fk_bone_list = json.loads(self.fk_bones)
+ self.ik_bone_list = json.loads(self.ik_bones)
+ self.ctrl_bone_list = json.loads(self.ctrl_bones)
+ self.extra_ctrl_list = json.loads(self.extra_ctrls)
+
+ def get_use_pole(self, obj):
+ bone = obj.pose.bones[self.prop_bone]
+ return self.pole_prop in bone and bone[self.pole_prop]
+
+ def save_frame_state(self, context, obj):
+ return get_chain_transform_matrices(obj, self.fk_bone_list)
+
+ def compute_base_rotation(self, context, ik_bones, ctrl_bones, matrices, use_pole):
+ context.view_layer.update()
+
+ if use_pole:
+ match_pole_target(
+ context.view_layer,
+ ik_bones[0], ik_bones[1], ctrl_bones[2], matrices[0],
+ (ik_bones[0].length + ik_bones[1].length)
+ )
+
+ else:
+ correct_rotation(context.view_layer, ctrl_bones[0], matrices[0])
+
+ def apply_frame_state(self, context, obj, matrices):
+ ik_bones = [ obj.pose.bones[k] for k in self.ik_bone_list ]
+ ctrl_bones = [ obj.pose.bones[k] for k in self.ctrl_bone_list ]
+
+ use_pole = len(ctrl_bones) > 2 and self.get_use_pole(obj)
+
+ # Set the end control position
+ tgt_matrix = ik_bones[2].bone.matrix_local
+ ctrl_matrix = ctrl_bones[1].bone.matrix_local
+ endmat = matrices[2] @ tgt_matrix.inverted() @ ctrl_matrix
+
+ set_transform_from_matrix(
+ obj, self.ctrl_bone_list[1], endmat, keyflags=self.keyflags
+ )
+
+ # Remove foot heel transform, if present
+ for extra in self.extra_ctrl_list:
+ set_transform_from_matrix(
+ obj, extra, Matrix.Identity(4), space='LOCAL', keyflags=self.keyflags
+ )
+
+ # Set the base bone position
+ ctrl_bones[0].matrix_basis = Matrix.Identity(4)
+
+ set_transform_from_matrix(
+ obj, self.ctrl_bone_list[0], matrices[0],
+ no_scale=True, no_rot=use_pole,
+ )
+
+ self.compute_base_rotation(context, ik_bones, ctrl_bones, matrices, use_pole)
+
+ correct_scale(context.view_layer, ctrl_bones[0], matrices[0])
+
+ # Keyframe controls
+ if self.keyflags is not None:
+ if use_pole:
+ keyframe_transform_properties(
+ obj, self.ctrl_bone_list[2], self.keyflags,
+ no_rot=True, no_scale=True,
+ )
+
+ keyframe_transform_properties(
+ obj, self.ctrl_bone_list[0], self.keyflags,
+ no_rot=use_pole,
+ )
+
+class POSE_OT_rigify_limb_ik2fk(RigifyLimbIk2FkBase, RigifySingleUpdateMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_limb_ik2fk_" + rig_id
+ bl_label = "Snap IK->FK"
+ bl_options = {'UNDO', 'INTERNAL'}
+ bl_description = "Snap the IK chain to FK result"
+
+class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_limb_ik2fk_bake_" + rig_id
+ bl_label = "Apply Snap IK->FK To Keyframes"
+ bl_options = {'UNDO', 'INTERNAL'}
+ bl_description = "Snap the IK chain keyframes to FK result"
+
+ def execute_scan_curves(self, context, obj):
+ self.bake_add_bone_frames(self.fk_bone_list, TRANSFORM_PROPS_ALL)
+ return self.bake_get_all_bone_curves(self.ctrl_bone_list + self.extra_ctrl_list, TRANSFORM_PROPS_ALL)
+''']
+
+def add_limb_snap_ik_to_fk(panel, *, master=None, fk_bones=[], ik_bones=[], ik_ctrl_bones=[], ik_extra_ctrls=[], rig_name=''):
+ panel.use_bake_settings()
+ panel.script.add_utilities(SCRIPT_UTILITIES_OP_SNAP_IK_FK)
+ panel.script.register_classes(SCRIPT_REGISTER_OP_SNAP_IK_FK)
+
+ op_props = {
+ 'prop_bone': master,
+ 'fk_bones': json.dumps(fk_bones),
+ 'ik_bones': json.dumps(ik_bones),
+ 'ctrl_bones': json.dumps(ik_ctrl_bones),
+ 'extra_ctrls': json.dumps(ik_extra_ctrls),
+ }
+
+ add_fk_ik_snap_buttons(
+ panel, 'pose.rigify_limb_ik2fk_{rig_id}', 'pose.rigify_limb_ik2fk_bake_{rig_id}',
+ label='IK->FK', rig_name=rig_name, properties=op_props,
+ clear_bones=ik_ctrl_bones + ik_extra_ctrls,
+ )
+
+#########################
+# Toggle Pole operator ##
+#########################
+
+SCRIPT_REGISTER_OP_TOGGLE_POLE = ['POSE_OT_rigify_limb_toggle_pole', 'POSE_OT_rigify_limb_toggle_pole_bake']
+
+SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + ['''
+####################
+## Toggle IK Pole ##
+####################
+
+class RigifyLimbTogglePoleBase(RigifyLimbIk2FkBase):
+ use_pole: bpy.props.BoolProperty(name="Use Pole Vector")
+
+ keyflags_switch = None
+
+ def save_frame_state(self, context, obj):
+ return get_chain_transform_matrices(obj, self.ik_bone_list)
+
+ def apply_frame_state(self, context, obj, matrices):
+ ik_bones = [ obj.pose.bones[k] for k in self.ik_bone_list ]
+ ctrl_bones = [ obj.pose.bones[k] for k in self.ctrl_bone_list ]
+
+ # Set the pole property
+ set_custom_property_value(
+ obj, self.prop_bone, self.pole_prop, int(self.use_pole),
+ keyflags=self.keyflags_switch
+ )
+
+ # Reset the base bone rotation
+ set_pose_rotation(ctrl_bones[0], Matrix.Identity(4))
+
+ self.compute_base_rotation(context, ik_bones, ctrl_bones, matrices, self.use_pole)
+
+ # Keyframe controls
+ if self.keyflags is not None:
+ if self.use_pole:
+ keyframe_transform_properties(
+ obj, self.ctrl_bone_list[2], self.keyflags,
+ no_rot=True, no_scale=True,
+ )
+ else:
+ keyframe_transform_properties(
+ obj, self.ctrl_bone_list[0], self.keyflags,
+ no_loc=True, no_scale=True,
+ )
+
+ def init_invoke(self, context):
+ self.use_pole = not bool(context.active_object.pose.bones[self.prop_bone][self.pole_prop])
+
+class POSE_OT_rigify_limb_toggle_pole(RigifyLimbTogglePoleBase, RigifySingleUpdateMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_limb_toggle_pole_" + rig_id
+ bl_label = "Toggle Pole"
+ bl_options = {'UNDO', 'INTERNAL'}
+ bl_description = "Switch the IK chain between pole and rotation"
+
+class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeKeyframesMixin, bpy.types.Operator):
+ bl_idname = "pose.rigify_limb_toggle_pole_bake_" + rig_id
+ bl_label = "Apply Toggle Pole To Keyframes"
+ bl_options = {'UNDO', 'INTERNAL'}
+ bl_description = "Switch the IK chain between pole and rotation over a frame range"
+
+ def execute_scan_curves(self, context, obj):
+ self.bake_add_bone_frames(self.ctrl_bone_list, TRANSFORM_PROPS_ALL)
+
+ rot_curves = self.bake_get_all_bone_curves(self.ctrl_bone_list[0], TRANSFORM_PROPS_ROTATION)
+ pole_curves = self.bake_get_all_bone_curves(self.ctrl_bone_list[2], TRANSFORM_PROPS_LOCATION)
+ return rot_curves + pole_curves
+
+ def execute_before_apply(self, context, obj, range, range_raw):
+ self.bake_replace_custom_prop_keys_constant(self.prop_bone, self.pole_prop, int(self.use_pole))
+
+ def draw(self, context):
+ self.layout.prop(self, 'use_pole')
+''']
+
+def add_limb_toggle_pole(panel, *, master=None, ik_bones=[], ik_ctrl_bones=[], ik_extra_ctrls=[]):
+ panel.use_bake_settings()
+ panel.script.add_utilities(SCRIPT_UTILITIES_OP_TOGGLE_POLE)
+ panel.script.register_classes(SCRIPT_REGISTER_OP_TOGGLE_POLE)
+
+ op_props = {
+ 'prop_bone': master,
+ 'ik_bones': json.dumps(ik_bones),
+ 'ctrl_bones': json.dumps(ik_ctrl_bones),
+ 'extra_ctrls': json.dumps(ik_extra_ctrls),
+ }
+
+ row = panel.row(align=True)
+ lsplit = row.split(factor=0.75, align=True)
+ lsplit.operator('pose.rigify_limb_toggle_pole_{rig_id}', icon='FORCE_MAGNETIC', properties=op_props)
+ lsplit.custom_prop(master, 'pole_vector', text='')
+ row.operator('pose.rigify_limb_toggle_pole_bake_{rig_id}', text='', icon='ACTION_TWEAK', properties=op_props)
diff --git a/rigify/rigs/limbs/paw.py b/rigify/rigs/limbs/paw.py
index b57f07dd..fa590b66 100644
--- a/rigify/rigs/limbs/paw.py
+++ b/rigify/rigs/limbs/paw.py
@@ -1,1044 +1,202 @@
-import bpy
-from .ui import create_script
-from .limb_utils import *
-from mathutils import Vector
-from ...utils import copy_bone, flip_bone, put_bone
-from ...utils import strip_org, strip_mch
-from ...utils import create_circle_widget, create_sphere_widget, create_line_widget
-from ...utils import MetarigError, make_mechanism_name
-from ...utils import create_limb_widget, connected_children_names
-from ...utils import align_bone_x_axis, align_bone_z_axis
-from ...rig_ui_template import UTILITIES_RIG_LEG, REGISTER_RIG_LEG
-from ...utils import ControlLayersOption
-from rna_prop_ui import rna_idprop_ui_prop_get
-from ...utils.mechanism import make_property, make_driver
-from ..widgets import create_ikarrow_widget, create_gear_widget
-from ..widgets import create_foot_widget, create_ballsocket_widget
-from math import trunc, pi
-
-extra_script = """
-controls = [%s]
-ctrl = '%s'
-
-if is_selected( controls ):
- layout.prop( pose_bones[ ctrl ], '["%s"]')
- if '%s' in pose_bones[ctrl].keys():
- layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True )
- if '%s' in pose_bones[ctrl].keys():
- layout.prop( pose_bones[ ctrl ], '["%s"]', slider = True )
-"""
-
-IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class
- # add_parameters and parameters_ui are unused for implementation classes
-
-
-class Rig:
-
- def __init__(self, obj, bone_name, params):
- """ Initialize paw rig and key rig properties """
- self.obj = obj
- self.params = params
-
- self.org_bones = list(
- [bone_name] + connected_children_names(obj, bone_name)
- )[:4] # The basic limb is the first 4 bones for a paw
-
- self.segments = params.segments
- self.bbones = params.bbones
- self.limb_type = params.limb_type
- self.rot_axis = params.rotation_axis
- self.auto_align_extremity = params.auto_align_extremity
-
- def orient_org_bones(self):
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
- thigh = self.org_bones[0]
- org_bones = list(
- [thigh] + connected_children_names(self.obj, thigh)
- ) # All the provided orgs
-
- org_thigh = eb[org_bones[0]]
- org_shin = eb[org_bones[1]]
- org_foot = eb[org_bones[2]]
- org_toe = eb[org_bones[3]]
-
- foot_projection_on_xy = Vector((org_foot.y_axis[0], org_foot.y_axis[1], 0))
- foot_x = foot_projection_on_xy.cross(Vector((0, 0, 1))).normalized()
-
- if self.rot_axis != 'automatic':
-
- # Orient foot and toe
- if self.auto_align_extremity:
- if self.rot_axis == 'x':
- align_bone_x_axis(self.obj, org_foot.name, foot_x)
- align_bone_x_axis(self.obj, org_toe.name, foot_x)
- elif self.rot_axis == 'z':
- align_bone_z_axis(self.obj, org_foot.name, -foot_x)
- align_bone_z_axis(self.obj, org_toe.name, -foot_x)
- else:
- raise MetarigError(message='IK on %s has forbidden rotation axis (Y)' % self.org_bones[0])
+import bpy
+import math
- return
+from itertools import count
+from mathutils import Vector
- # Orient thigh and shin bones
- chain_y_axis = org_thigh.y_axis + org_shin.y_axis
- chain_rot_axis = org_thigh.y_axis.cross(chain_y_axis).normalized() # ik-plane normal axis (rotation)
+from ...utils.bones import compute_chain_x_axis, align_bone_x_axis, align_bone_y_axis, align_bone_z_axis
+from ...utils.bones import align_bone_to_axis, flip_bone, put_bone, align_bone_orientation
+from ...utils.naming import make_derived_name
+from ...utils.misc import map_list
- align_bone_x_axis(self.obj, org_thigh.name, chain_rot_axis)
- align_bone_x_axis(self.obj, org_shin.name, chain_rot_axis)
+from ...utils.widgets_basic import create_circle_widget
+from ..widgets import create_foot_widget, create_ballsocket_widget
- # # Orient foot and toe
- align_bone_x_axis(self.obj, org_foot.name, chain_rot_axis)
- align_bone_x_axis(self.obj, org_toe.name, chain_rot_axis)
+from ...base_rig import stage
- def create_parent(self):
+from .limb_rigs import BaseLimbRig
- org_bones = self.org_bones
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+class Rig(BaseLimbRig):
+ """Paw rig."""
- name = get_bone_name( strip_org( org_bones[0] ), 'mch', 'parent' )
+ segmented_orgs = 3
- mch = copy_bone( self.obj, org_bones[0], name )
- orient_bone( self, eb[mch], 'y' )
- eb[ mch ].length = eb[ org_bones[0] ].length / 4
+ def initialize(self):
+ if len(self.bones.org.main) != 4:
+ self.raise_error("Input to rig type must be a chain of 4 bones.")
- eb[ mch ].parent = eb[ org_bones[0] ].parent
+ super().initialize()
- eb[ mch ].roll = 0.0
+ def prepare_bones(self):
+ orgs = self.bones.org.main
- # Add non-MCH main limb control
- name = get_bone_name(strip_org(org_bones[0]), 'ctrl', 'parent')
- main_parent = copy_bone(self.obj, org_bones[0], name)
- eb[main_parent].length = eb[org_bones[0]].length / 4
- eb[main_parent].parent = eb[org_bones[0]]
- eb[main_parent].roll = 0.0
+ foot_x = self.vector_without_z(self.get_bone(orgs[2]).y_axis).cross((0, 0, 1))
- # Constraints
- make_constraint( self, mch, {
- 'constraint' : 'COPY_ROTATION',
- 'subtarget' : 'root'
- })
+ if self.params.rotation_axis == 'automatic':
+ axis = compute_chain_x_axis(self.obj, orgs[0:2])
- make_constraint( self, mch, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
+ for bone in orgs:
+ align_bone_x_axis(self.obj, bone, axis)
- # Limb Follow Driver
- pb = self.obj.pose.bones
-
- name = 'FK_limb_follow'
-
- # pb[ mch ][ name ] = 0.0
- # prop = rna_idprop_ui_prop_get( pb[ mch ], name, create = True )
- make_property(pb[main_parent], name, 0.0)
-
- make_driver(pb[mch].constraints[0], "influence", variables=[(self.obj, main_parent, name)])
-
- size = pb[main_parent].bone.y_axis.length * 10
- create_gear_widget(self.obj, main_parent, size=size, bone_transform_name=None)
-
- return [mch, main_parent]
-
- def create_tweak(self):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- tweaks = {}
- tweaks['ctrl'] = []
- tweaks['mch' ] = []
-
- # Create and parent mch and ctrl tweaks
- for i,org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range( self.segments ):
- # MCH
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org, name )
-
- # CTRL
- name = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, name )
-
- eb[ mch ].length /= self.segments
- eb[ ctrl ].length /= self.segments
-
- # If we have more than one segments, place the head of the
- # 2nd and onwards at the correct position
- if j > 0:
- put_bone(self.obj, mch, eb[ tweaks['mch' ][-1] ].tail)
- put_bone(self.obj, ctrl, eb[ tweaks['ctrl'][-1] ].tail)
-
- tweaks['ctrl'] += [ ctrl ]
- tweaks['mch' ] += [ mch ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- else: # Last limb bone - is not subdivided
- name = get_bone_name( strip_org(org), 'mch', 'tweak' )
- mch = copy_bone( self.obj, org_bones[i-1], name )
- eb[ mch ].length = eb[org].length / 4
- put_bone(
- self.obj,
- mch,
- eb[org_bones[i-1]].tail
- )
-
- ctrl = get_bone_name( strip_org(org), 'ctrl', 'tweak' )
- ctrl = copy_bone( self.obj, org, ctrl )
- eb[ ctrl ].length = eb[org].length / 2
-
- tweaks['mch'] += [ mch ]
- tweaks['ctrl'] += [ ctrl ]
-
- # Parenting the tweak ctrls to mchs
- eb[ mch ].parent = eb[ org ]
- eb[ ctrl ].parent = eb[ mch ]
-
- # Scale to reduce widget size and maintain conventions!
- for mch, ctrl in zip( tweaks['mch'], tweaks['ctrl'] ):
- eb[ mch ].length /= 4
- eb[ ctrl ].length /= 2
-
- # Constraints
-
- for i,b in enumerate( tweaks['mch'] ):
- first = 0
- middle = trunc( len( tweaks['mch'] ) / 3 )
- middle1 = middle + self.segments
- last = len( tweaks['mch'] ) - 1
-
- if i == first or i == middle or i == middle1:
- make_constraint( self, b, {
- 'constraint' : 'COPY_SCALE',
- 'subtarget' : 'root'
- })
- elif i != last:
- targets = []
- factor = 0
- if i < middle:
- dt_target_idx = middle
- targets = [first,middle]
- elif i > middle and i < middle1:
- targets = [middle,middle1]
- factor = self.segments
- dt_target_idx = middle1
- else:
- targets = [middle1,last]
- factor = self.segments * 2
- dt_target_idx = last
-
- # Use copy transforms constraints to position each bone
- # exactly in the location respective to its index (between
- # the two edges)
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[0]]
- })
- make_constraint( self, b, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : tweaks['ctrl'][targets[1]],
- 'influence' : (i - factor) / self.segments
- })
- make_constraint( self, b, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks['ctrl'][ dt_target_idx ],
- })
-
- # Ctrl bones Locks and Widgets
- pb = self.obj.pose.bones
- for t in tweaks['ctrl']:
- pb[t].lock_rotation = True, False, True
- pb[t].lock_scale = False, True, False
-
- create_sphere_widget(self.obj, t, bone_transform_name=None)
-
- ControlLayersOption.TWEAK.assign(self.params, pb, tweaks['ctrl'])
-
- return tweaks
-
- def create_def(self, tweaks):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
-
- def_bones = []
- for i, org in enumerate(org_bones):
- if i < len(org_bones) - 1:
- # Create segments if specified
- for j in range(self.segments):
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
-
- eb[def_name].length /= self.segments
-
- # If we have more than one segments, place the 2nd and
- # onwards on the tail of the previous bone
- if j > 0:
- put_bone(self.obj, def_name, eb[ def_bones[-1] ].tail)
-
- def_bones += [def_name]
- else:
- name = get_bone_name(strip_org(org), 'def')
- def_name = copy_bone(self.obj, org, name)
- def_bones.append(def_name)
-
- # Parent deform bones
- for i,b in enumerate( def_bones ):
- if i > 0: # For all bones but the first (which has no parent)
- eb[b].parent = eb[ def_bones[i-1] ] # to previous
- eb[b].use_connect = True
-
- # Constraint def to tweaks
- for d,t in zip(def_bones, tweaks):
- tidx = tweaks.index(t)
-
- make_constraint( self, d, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : t
- })
-
- if tidx != len(tweaks) - 1:
- make_constraint( self, d, {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- make_constraint( self, d, {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : tweaks[ tidx + 1 ],
- })
-
- # Create bbone segments
- for bone in def_bones[:-1]:
- self.obj.data.bones[bone].bbone_segments = self.bbones
-
- self.obj.data.bones[ def_bones[0] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-2] ].bbone_easeout = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easein = 0.0
- self.obj.data.bones[ def_bones[-1] ].bbone_easeout = 0.0
-
-
- # Rubber hose drivers
- pb = self.obj.pose.bones
- for i, t in enumerate(tweaks[1:-1]):
- # Create custom property on tweak bone to control rubber hose
- name = 'rubber_tweak'
-
- if not (i+1) % self.segments:
- defvalue = 0.0
+ elif self.params.auto_align_extremity:
+ if self.main_axis == 'x':
+ align_bone_x_axis(self.obj, orgs[2], foot_x)
+ align_bone_x_axis(self.obj, orgs[3], -foot_x)
else:
- defvalue = 1.0
-
- make_property(pb[t], name, defvalue, max=2.0, soft_max=1.0)
-
- for j,d in enumerate(def_bones[:-1]):
- if j != 0:
- make_driver(self.obj.data.bones[d], "bbone_easein", variables=[(self.obj, tweaks[j], 'rubber_tweak')])
-
- if j != len( def_bones[:-1] ) - 1:
- make_driver(self.obj.data.bones[d], "bbone_easeout", variables=[(self.obj, tweaks[j+1], 'rubber_tweak')])
-
- return def_bones
+ align_bone_z_axis(self.obj, orgs[2], foot_x)
+ align_bone_z_axis(self.obj, orgs[3], -foot_x)
- def create_ik(self, parent):
- org_bones = self.org_bones
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ ####################################################
+ # EXTRA BONES
+ #
+ # ctrl:
+ # heel:
+ # Foot heel control
+ # mch:
+ # toe_socket:
+ # IK toe orientation bone.
+ #
+ ####################################################
- ctrl = get_bone_name(org_bones[0], 'ctrl', 'ik')
- mch_ik = get_bone_name(org_bones[0], 'mch', 'ik')
- mch_target = get_bone_name(org_bones[0], 'mch', 'ik_target')
+ ####################################################
+ # IK controls
- for o, ik in zip(org_bones, [ctrl, mch_ik, mch_target]):
- bone = copy_bone(self.obj, o, ik)
+ def get_extra_ik_controls(self):
+ return [self.bones.ctrl.heel]
- if org_bones.index(o) == len(org_bones) - 1:
- eb[bone].length /= 4
+ def make_ik_control_bone(self, orgs):
+ name = self.copy_bone(orgs[3], make_derived_name(orgs[2], 'ctrl', '_ik'))
- # Create MCH Stretch
- mch_str = copy_bone(
- self.obj,
- org_bones[0],
- get_bone_name( org_bones[0], 'mch', 'ik_stretch' )
- )
+ if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
+ align_bone_to_axis(self.obj, name, 'y', flip=True)
- eb[ mch_str ].tail = eb[ org_bones[-2] ].head
-
- # Parenting
- eb[ctrl].parent = eb[parent]
- eb[mch_str].parent = eb[parent]
- eb[mch_ik].parent = eb[ctrl]
-
- # Make standard pole target bone
- pole_name = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
- pole_target = copy_bone(self.obj, org_bones[0], pole_name)
-
- lo_vector = eb[org_bones[1]].tail - eb[org_bones[1]].head
- tot_vector = eb[org_bones[0]].head - eb[org_bones[1]].tail
- tot_vector.normalize()
- elbow_vector = lo_vector.dot(tot_vector)*tot_vector - lo_vector # elbow_vec as rejection of lo on tot
- elbow_vector.normalize()
- elbow_vector *= (eb[org_bones[1]].tail - eb[org_bones[0]].head).length
-
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- z_vector = eb[org_bones[0]].z_axis + eb[org_bones[1]].z_axis
- alfa = elbow_vector.angle(z_vector)
- elif self.rot_axis == 'z':
- x_vector = eb[org_bones[0]].x_axis + eb[org_bones[1]].x_axis
- alfa = elbow_vector.angle(x_vector)
-
- if alfa > pi/2:
- pole_angle = -pi/2
- else:
- pole_angle = pi/2
-
- if self.rot_axis == 'z':
- pole_angle = 0
-
- eb[pole_target].head = eb[org_bones[0]].tail + elbow_vector
- eb[pole_target].tail = eb[pole_target].head - elbow_vector/8
- eb[pole_target].roll = 0.0
-
- # Make visual pole
- vispole_name = 'VIS_' + get_bone_name(org_bones[0], 'ctrl', 'ik_pole')
- vispole = copy_bone(self.obj, org_bones[1], vispole_name)
- eb[vispole].tail = eb[vispole].head + Vector((0.0, 0.0, eb[org_bones[1]].length/10))
- eb[vispole].use_connect = False
- eb[vispole].hide_select = True
- eb[vispole].parent = None
-
- make_constraint(self, mch_ik, {
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- make_constraint(self, mch_ik, { # 2_nd IK for pole targeted chain
- 'constraint': 'IK',
- 'subtarget': mch_target,
- 'chain_count': 2,
- })
-
- # VIS pole constraints
- make_constraint(self, vispole, {
- 'constraint': 'COPY_LOCATION',
- 'name': 'copy_loc',
- 'subtarget': org_bones[1],
- })
-
- pb = self.obj.pose.bones
-
- make_constraint(self, vispole, {
- 'constraint': 'STRETCH_TO',
- 'name': 'stretch_to',
- 'subtarget': pole_target,
- 'volume': 'NO_VOLUME',
- 'rest_length': pb[vispole].length
- })
-
- pb[mch_ik].constraints[-1].pole_target = self.obj
- pb[mch_ik].constraints[-1].pole_subtarget = pole_target
- pb[mch_ik].constraints[-1].pole_angle = pole_angle
-
- pb[ mch_ik ].ik_stretch = 0.1
- pb[ ctrl ].ik_stretch = 0.1
-
- # IK constraint Rotation locks
- if self.rot_axis == 'z':
- pb[mch_ik].lock_ik_x = True
- pb[mch_ik].lock_ik_y = True
else:
- pb[mch_ik].lock_ik_y = True
- pb[mch_ik].lock_ik_z = True
+ flip_bone(self.obj, name)
- # Locks and Widget
- pb[ctrl].lock_rotation = True, False, True
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- roll = 0
- else:
- roll = pi/2
- create_ikarrow_widget(self.obj, ctrl, bone_transform_name=None, roll=roll)
- create_sphere_widget(self.obj, pole_target, bone_transform_name=None)
- create_line_widget(self.obj, vispole)
+ bone = self.get_bone(name)
+ bone.tail[2] = bone.head[2]
+ bone.roll = 0
- return {'ctrl': {'limb': ctrl, 'ik_target': pole_target},
- 'mch_ik': mch_ik,
- 'mch_target': mch_target,
- 'mch_str': mch_str,
- 'visuals': {'vispole': vispole}
- }
+ vec = self.get_bone(orgs[3]).tail - self.get_bone(orgs[2]).head
+ self.get_bone(name).length = self.vector_without_z(vec).length
- def create_fk(self, parent):
- org_bones = self.org_bones.copy()
+ return name
+ def register_switch_parents(self, pbuilder):
+ super().register_switch_parents(pbuilder)
- org_bones.pop()
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- ctrls = []
-
- for o in org_bones:
- bone = copy_bone(self.obj, o, get_bone_name( o, 'ctrl', 'fk'))
- ctrls.append(bone)
-
- # MCH
- mch = copy_bone(
- self.obj, org_bones[-1], get_bone_name(o, 'mch', 'fk')
- )
-
- eb[mch].length /= 4
-
- # Parenting
- eb[ctrls[0]].parent = eb[parent]
- eb[ctrls[1]].parent = eb[ctrls[0]]
- eb[ctrls[1]].use_connect = True
- eb[ctrls[2]].parent = eb[mch]
- eb[mch].parent = eb[ctrls[1]]
- eb[mch].use_connect = True
-
- # Constrain MCH's scale to root
- make_constraint(self, mch, {
- 'constraint': 'COPY_SCALE',
- 'subtarget': 'root'
- })
-
- # Locks and widgets
- pb = self.obj.pose.bones
- pb[ctrls[2]].lock_location = True, True, True
-
- create_limb_widget(self.obj, ctrls[0])
- create_limb_widget(self.obj, ctrls[1])
-
- create_circle_widget(self.obj, ctrls[2], radius=0.4, head_tail=0.0)
-
- ControlLayersOption.FK.assign(self.params, pb, ctrls)
-
- return {'ctrl': ctrls, 'mch': mch}
-
- def org_parenting_and_switch(self, org_bones, ik, fk, parent):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
- # re-parent ORGs in a connected chain
- for i, o in enumerate(org_bones):
- if i > 0:
- eb[o].parent = eb[org_bones[i-1]]
- if i <= len(org_bones)-1:
- eb[o].use_connect = True
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
- pb_parent = pb[parent]
-
- # Create ik/fk switch property
- prop = make_property(pb_parent, 'IK_FK', 0.0, description='IK/FK Switch')
-
- # Constrain org to IK and FK bones
- iks = [ik['ctrl']['limb']]
- iks += [ik[k] for k in ['mch_ik', 'mch_target']]
-
- for o, i, f in zip(org_bones, iks, fk):
- make_constraint( self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': i
- })
- make_constraint(self, o, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': f
- })
-
- # Add driver to relevant constraint
- make_driver(pb[o].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)])
-
- def create_paw(self, bones):
- org_bones = list(
- [self.org_bones[0]] + connected_children_names(self.obj, self.org_bones[0])
- )
-
- bones['ik']['ctrl']['terminal'] = []
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- pole_target = get_bone_name(org_bones[0], 'ctrl', 'ik_target')
-
- # Create IK paw control
- ctrl = get_bone_name(org_bones[2], 'ctrl', 'ik')
- ctrl = copy_bone(self.obj, org_bones[3], ctrl)
-
- # clear parent (so that rigify will parent to root)
- eb[ctrl].parent = None
- eb[ctrl].use_connect = False
-
- # MCH for ik control
- ctrl_socket = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_socket'))
- eb[ctrl_socket].tail = eb[ctrl_socket].head + 0.8*(eb[ctrl_socket].tail-eb[ctrl_socket].head)
- eb[ctrl_socket].parent = None
- eb[ctrl].parent = eb[ctrl_socket]
-
- # MCH for pole ik control
- ctrl_pole_socket = copy_bone(self.obj, org_bones[2], get_bone_name(org_bones[2], 'mch', 'pole_ik_socket'))
- eb[ctrl_pole_socket].tail = eb[ctrl_pole_socket].head + 0.8 * (eb[ctrl_pole_socket].tail - eb[ctrl_pole_socket].head)
- eb[ctrl_pole_socket].parent = None
- eb[pole_target].parent = eb[ctrl_pole_socket]
-
- ctrl_root = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_root'))
- eb[ctrl_root].tail = eb[ctrl_root].head + 0.7*(eb[ctrl_root].tail-eb[ctrl_root].head)
- eb[ctrl_root].use_connect = False
- eb[ctrl_root].parent = eb['root']
-
- if eb[org_bones[0]].parent:
- paw_parent = eb[org_bones[0]].parent
- ctrl_parent = copy_bone(self.obj, org_bones[2], get_bone_name( org_bones[2], 'mch', 'ik_parent'))
- eb[ctrl_parent].tail = eb[ctrl_parent].head + 0.6*(eb[ctrl_parent].tail-eb[ctrl_parent].head)
- eb[ctrl_parent].use_connect = False
- if eb[org_bones[0]].parent_recursive:
- eb[ctrl_parent].parent = eb[org_bones[0]].parent_recursive[-1]
- else:
- eb[ctrl_parent].parent = eb[org_bones[0]].parent
- else:
- paw_parent = None
+ pbuilder.register_parent(self, self.bones.org.main[3], exclude_self=True)
- mch_name = get_bone_name(strip_org(org_bones[0]), 'mch', 'parent_socket')
- mch_main_parent = copy_bone(self.obj, org_bones[0], mch_name)
- eb[mch_main_parent].length = eb[org_bones[0]].length / 12
- eb[mch_main_parent].parent = eb[bones['parent']]
- eb[mch_main_parent].roll = 0.0
- eb[bones['main_parent']].parent = eb[mch_main_parent]
-
- # Create heel ctrl bone
- heel = get_bone_name(org_bones[2], 'ctrl', 'heel_ik')
- heel = copy_bone(self.obj, org_bones[2], heel)
-
- if self.rot_axis == 'x' or self.rot_axis == 'automatic':
- align_bone_x_axis(self.obj, heel, eb[org_bones[2]].x_axis)
- elif self.rot_axis == 'z':
- align_bone_z_axis(self.obj, heel, eb[org_bones[2]].z_axis)
-
- # clear parent
- eb[ heel ].parent = None
- eb[ heel ].use_connect = False
-
- # Parent
- eb[ heel ].parent = eb[ ctrl ]
- eb[ heel ].use_connect = False
-
- flip_bone( self.obj, heel )
-
- eb[ bones['ik']['mch_target'] ].parent = eb[ heel ]
- eb[ bones['ik']['mch_target'] ].use_connect = False
-
- # Reset control position and orientation
- if self.rot_axis == 'automatic' or self.auto_align_extremity:
- orient_bone(self, eb[ctrl], 'y', reverse=True)
- else:
- flip_bone(self.obj, ctrl)
- eb[ctrl].tail[2] = eb[ctrl].head[2]
- eb[ctrl].roll = 0
- v = eb[org_bones[-1]].tail - eb[org_bones[-2]].head
- eb[ctrl].length = Vector((v[0], v[1], 0)).length
-
- # make mch toe bone
- toes_mch = get_bone_name(org_bones[3], 'mch')
- toes_mch = copy_bone(self.obj, org_bones[3], toes_mch)
-
- eb[toes_mch].use_connect = False
- eb[toes_mch].parent = eb[ctrl]
-
- eb[toes_mch].length /= 4
-
- # make mch toe parent bone
- toes_mch_parent = get_bone_name(org_bones[3], 'mch', 'parent')
- toes_mch_parent = copy_bone(self.obj, org_bones[3], toes_mch_parent)
-
- eb[toes_mch_parent].use_connect = True
- eb[toes_mch_parent].parent = eb[org_bones[2]]
-
- eb[toes_mch_parent].length /= 2
-
- eb[org_bones[3]].use_connect = False
- eb[org_bones[3]].parent = eb[toes_mch_parent]
-
- # Set up constraints
-
- # Constrain ik ctrl to root / parent
-
- make_constraint( self, ctrl_socket, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : ctrl_root,
- })
-
- make_constraint(self, ctrl_pole_socket, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': ctrl_root,
- })
-
- if paw_parent:
- make_constraint( self, ctrl_socket, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : ctrl_parent,
- 'influence' : 0.0,
- })
-
- make_constraint(self, ctrl_pole_socket, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': bones['ik']['mch_target'],
- })
-
- # Constrain mch target bone to the ik control and mch stretch
- make_constraint( self, bones['ik']['mch_target'], {
- 'constraint' : 'COPY_LOCATION',
- 'subtarget' : bones['ik']['mch_str'],
- 'head_tail' : 1.0
- })
-
- # Constrain mch ik stretch bone to the ik control
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : heel,
- 'head_tail' : 1.0
- })
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : heel,
- 'head_tail' : 1.0
- })
- make_constraint( self, bones['ik']['mch_str'], {
- 'constraint' : 'LIMIT_SCALE',
- 'use_min_y' : True,
- 'use_max_y' : True,
- 'max_y' : 1.05,
- 'owner_space' : 'LOCAL'
- })
- make_constraint(self, mch_main_parent, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': org_bones[0]
- })
-
- pb = self.obj.pose.bones
-
- # Create ik/fk switch property
- pb_parent = pb[bones['main_parent']]
- pb_parent.lock_location = True, True, True
- pb_parent.lock_rotation = True, True, True
- pb_parent.lock_scale = True, True, True
-
- prop = make_property(pb_parent, 'IK_Stretch', 1.0, description='IK Stretch')
-
- # Add driver to limit scale constraint influence
- b = bones['ik']['mch_str']
-
- make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])
-
- # Create paw widget
+ def make_ik_ctrl_widget(self, ctrl):
create_foot_widget(self.obj, ctrl, bone_transform_name=None)
- # Create heel ctrl locks
- pb[heel].lock_location = True, True, True
- pb[heel].lock_scale = True, True, True
-
- # Add ballsocket widget to heel
- create_ballsocket_widget(self.obj, heel, bone_transform_name=None)
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- if len( org_bones ) >= 4:
- # Create toes control bone
- toes = get_bone_name( org_bones[3], 'ctrl' )
- toes = copy_bone( self.obj, org_bones[3], toes )
-
- eb[toes].use_connect = False
- eb[toes].parent = eb[toes_mch_parent]
- # Constrain 4th ORG to toes MCH bone
- make_constraint( self, toes_mch_parent, {
- 'constraint' : 'COPY_TRANSFORMS',
- 'subtarget' : toes_mch
- })
+ ####################################################
+ # Heel control
- # Constrain 4th ORG to toes MCH bone
- make_constraint(self, org_bones[3], {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': toes
- })
+ @stage.generate_bones
+ def make_heel_control_bone(self):
+ org = self.bones.org.main[2]
+ name = self.copy_bone(org, make_derived_name(org, 'ctrl', '_heel_ik'))
+ self.bones.ctrl.heel = name
- make_constraint( self, bones['def'][-1], {
- 'constraint' : 'DAMPED_TRACK',
- 'subtarget' : toes,
- 'head_tail' : 1
- })
- make_constraint( self, bones['def'][-1], {
- 'constraint' : 'STRETCH_TO',
- 'subtarget' : toes,
- 'head_tail' : 1
- })
+ flip_bone(self.obj, name)
- # Find IK/FK switch property
- pb = self.obj.pose.bones
- prop = rna_idprop_ui_prop_get( pb[bones['fk']['ctrl'][-1]], 'IK_FK' )
+ @stage.parent_bones
+ def parent_heel_control_bone(self):
+ self.set_bone_parent(self.bones.ctrl.heel, self.bones.ctrl.ik)
- # Modify rotation mode for ik and tweak controls
- pb[bones['ik']['ctrl']['limb']].rotation_mode = 'ZXY'
+ @stage.configure_bones
+ def configure_heel_control_bone(self):
+ bone = self.get_bone(self.bones.ctrl.heel)
+ bone.lock_location = True, True, True
+ bone.lock_scale = True, True, True
- for b in bones['tweak']['ctrl']:
- pb[b].rotation_mode = 'ZXY'
+ @stage.generate_widgets
+ def generate_heel_control_widget(self):
+ create_ballsocket_widget(self.obj, self.bones.ctrl.heel, bone_transform_name=None)
- # Add driver to limit scale constraint influence
- b = toes_mch_parent
- make_driver(pb[b].constraints[-1], "influence", variables=[(self.obj, pb_parent, prop.name)], polynomial=[1.0, -1.0])
+ ####################################################
+ # FK parents MCH chain
- # Create toe circle widget
- create_circle_widget(self.obj, toes, radius=0.4, head_tail=0.5)
+ @stage.generate_bones
+ def make_toe_socket_bone(self):
+ org = self.bones.org.main[3]
+ self.bones.mch.toe_socket = self.copy_bone(org, make_derived_name(org, 'mch', '_ik_socket'))
- bones['ik']['ctrl']['terminal'] += [toes]
+ def parent_fk_parent_bone(self, i, parent_mch, prev_ctrl, org, prev_org):
+ if i == 3:
+ self.set_bone_parent(parent_mch, prev_org, use_connect=True)
+ self.set_bone_parent(self.bones.mch.toe_socket, self.bones.ctrl.ik)
- bones['ik']['ctrl']['terminal'] += [ heel, ctrl ]
-
- if paw_parent:
- bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root, ctrl_parent]
else:
- bones['ik']['mch_foot'] = [ctrl_socket, ctrl_pole_socket, ctrl_root]
-
- return bones
-
- def create_drivers(self, bones):
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- ctrl = pb[bones['ik']['mch_foot'][0]]
- ctrl_pole = pb[bones['ik']['mch_foot'][1]]
-
- #owner = pb[bones['ik']['ctrl']['limb']]
- owner = pb[bones['main_parent']]
-
- props = ["IK_follow", "root/parent", "pole_vector", "pole_follow"]
-
- for prop in props:
-
- if prop == 'pole_vector':
- make_property(owner, prop, False)
- mch_ik = pb[bones['ik']['mch_ik']]
-
- # ik target hide driver
- pole_target = pb[bones['ik']['ctrl']['ik_target']]
-
- make_driver(pole_target.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- # vis-pole hide driver
- vispole = pb[bones['ik']['visuals']['vispole']]
-
- make_driver(vispole.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- # arrow hide driver
- # limb = pb[bones['ik']['ctrl']['limb']]
- #
- # make_driver(limb.bone, "hide", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
-
- for cns in mch_ik.constraints:
- if 'IK' in cns.type:
- if not cns.pole_subtarget:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[0.0, 1.0])
- else:
- make_driver(cns, "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- elif prop == 'IK_follow':
- make_property(owner, prop, True)
-
- make_driver(ctrl.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- if len(ctrl.constraints) > 1:
- make_driver(ctrl.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- make_driver(ctrl_pole.constraints[0], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- if len(ctrl_pole.constraints) > 1:
- make_driver(ctrl_pole.constraints[1], "mute", variables=[(self.obj, owner, prop)], polynomial=[1.0, -1.0])
-
- elif prop == 'root/parent':
- if len(ctrl.constraints) > 1:
- make_property(owner, prop, 0.0)
-
- make_driver(ctrl.constraints[1], "influence", variables=[(self.obj, owner, prop)])
-
- elif prop == 'pole_follow':
- if len(ctrl_pole.constraints) > 1:
- make_property(owner, prop, 0.0)
-
- make_driver(ctrl_pole.constraints[1], "influence", variables=[(self.obj, owner, prop)])
-
- @staticmethod
- def get_future_names(bones):
+ super().parent_fk_parent_bone(i, parent_mch, prev_ctrl, org, prev_org)
- if len(bones) != 4:
- return
+ def rig_fk_parent_bone(self, i, parent_mch, org):
+ if i == 3:
+ con = self.make_constraint(parent_mch, 'COPY_TRANSFORMS', self.bones.mch.toe_socket)
- names = dict()
+ self.make_driver(con, 'influence', variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
- thigh = strip_mch(strip_org(bones[0].name))
- shin = strip_mch(strip_org(bones[1].name))
- foot = strip_mch(strip_org(bones[2].name))
- toe = strip_mch(strip_org(bones[3].name))
-
- suffix = ''
- if thigh[-2:] == '.L' or thigh[-2:] == '.R':
- suffix = thigh[-2:]
- thigh = thigh.rstrip(suffix)
- shin = shin.rstrip(suffix)
- foot = foot.rstrip(suffix)
- toe = toe.rstrip(suffix)
-
- # the following is declared in rig_ui
- # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R',
- # 'MCH-foot_fk.R', 'thigh_parent.R']
- # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001']
- # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R']
- # fk_ctrl = 'thigh_fk.R'
- # parent = 'thigh_parent.R'
- # foot_fk = 'foot_fk.R'
- # pole = 'thigh_ik_target.R'
-
- names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik',
- foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent']
- names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target']
- names['fk_ctrl'] = thigh + '_fk' + suffix
- names['parent'] = thigh + '_parent' + suffix
- names['foot_fk'] = foot + '_fk' + suffix
- names['pole'] = thigh + '_ik_target' + suffix
-
- names['limb_type'] = 'paw'
-
- if suffix:
- for i, name in enumerate(names['controls']):
- names['controls'][i] = name + suffix
- for i, name in enumerate(names['ik_ctrl']):
- names['ik_ctrl'][i] = name + suffix
-
- return names
-
- def generate(self):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Adjust org-bones rotation
- self.orient_org_bones()
-
- # Clear parents for org bones
- for bone in self.org_bones[1:]:
- eb[bone].use_connect = False
- eb[bone].parent = None
-
- bones = {}
-
- # Create mch limb parent
- mch_parent, main_parent = self.create_parent()
- bones['parent'] = mch_parent
- bones['main_parent'] = main_parent
- bones['tweak'] = self.create_tweak()
- bones['def'] = self.create_def(bones['tweak']['ctrl'])
- bones['ik'] = self.create_ik(bones['parent'])
- bones['fk'] = self.create_fk(bones['parent'])
-
- self.org_parenting_and_switch(self.org_bones, bones['ik'], bones['fk']['ctrl'], bones['main_parent'])
-
- bones = self.create_paw(bones)
- self.create_drivers(bones)
-
- controls = [bones['ik']['ctrl']['limb'], bones['ik']['ctrl']['terminal'][-1], bones['ik']['ctrl']['terminal'][-2]]
+ else:
+ super().rig_fk_parent_bone(i, parent_mch, org)
- controls.append(bones['main_parent'])
- # Create UI
- controls_string = ", ".join(["'" + x + "'" for x in controls])
+ ####################################################
+ # IK system MCH
- script = create_script(bones, 'paw')
- script += extra_script % (controls_string, bones['main_parent'], 'IK_follow',
- 'pole_follow', 'pole_follow', 'root/parent', 'root/parent')
+ ik_input_head_tail = 1.0
- return {
- 'script': [script],
- 'utilities': UTILITIES_RIG_LEG,
- 'register': REGISTER_RIG_LEG,
- 'noparent_bones': [bones['ik']['mch_foot'][i] for i in [0,1]],
- }
-
-
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
-
- items = [
- ('x', 'X manual', ''),
- ('z', 'Z manual', ''),
- ('automatic', 'Automatic', '')
- ]
-
- params.rotation_axis = bpy.props.EnumProperty(
- items = items,
- name = "Rotation Axis",
- default = 'automatic'
- )
-
- params.auto_align_extremity = bpy.props.BoolProperty(
- name='auto_align_extremity',
- default=False,
- description="Auto Align Extremity Bone"
- )
-
- params.segments = bpy.props.IntProperty(
- name = 'limb segments',
- default = 2,
- min = 1,
- description = 'Number of segments'
- )
+ def get_ik_input_bone(self):
+ return self.bones.ctrl.heel
- params.bbones = bpy.props.IntProperty(
- name = 'bbone segments',
- default = 10,
- min = 1,
- description = 'Number of segments'
- )
+ @stage.parent_bones
+ def parent_ik_mch_chain(self):
+ super().parent_ik_mch_chain()
- # Setting up extra layers for the FK and tweak
- ControlLayersOption.FK.add_parameters(params)
- ControlLayersOption.TWEAK.add_parameters(params)
+ self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters."""
+ ####################################################
+ # Deform chain
- r = layout.row()
- r.prop(params, "rotation_axis")
+ def rig_deform_bone(self, i, deform, entry, next_entry, tweak, next_tweak):
+ super().rig_deform_bone(i, deform, entry, next_entry, tweak, next_tweak)
- if 'auto' not in params.rotation_axis.lower():
- r = layout.row()
- text = "Auto align Claw"
- r.prop(params, "auto_align_extremity", text=text)
+ if tweak and not (next_tweak or next_entry):
+ self.make_constraint(deform, 'DAMPED_TRACK', entry.org, head_tail=1.0)
+ self.make_constraint(deform, 'STRETCH_TO', entry.org, head_tail=1.0)
- r = layout.row()
- r.prop(params, "segments")
- r = layout.row()
- r.prop(params, "bbones")
+ ####################################################
+ # Settings
- ControlLayersOption.FK.parameters_ui(layout, params)
- ControlLayersOption.TWEAK.parameters_ui(layout, params)
+ @classmethod
+ def parameters_ui(self, layout, params):
+ super().parameters_ui(layout, params, 'Claw')
def create_sample(obj):
@@ -1048,275 +206,79 @@ def create_sample(obj):
bones = {}
- bone = arm.edit_bones.new('upper_arm.L')
- bone.head[:] = 0.0313, -0.1149, 0.2257
- bone.tail[:] = 0.0313, -0.0878, 0.1235
- bone.roll = 3.1416
- bone.use_connect = False
- bones['upper_arm.L'] = bone.name
- bone = arm.edit_bones.new('forearm.L')
- bone.head[:] = 0.0313, -0.0878, 0.1235
- bone.tail[:] = 0.0313, -0.1117, 0.0254
- bone.roll = 3.1416
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['upper_arm.L']]
- bones['forearm.L'] = bone.name
- bone = arm.edit_bones.new('hand.L')
- bone.head[:] = 0.0313, -0.1117, 0.0254
- bone.tail[:] = 0.0313, -0.1297, 0.0094
- bone.roll = 3.1416
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['forearm.L']]
- bones['hand.L'] = bone.name
- bone = arm.edit_bones.new('f_toe.L')
- bone.head[:] = 0.0313, -0.1297, 0.0094
- bone.tail[:] = 0.0313, -0.1463, 0.0094
+ bone = arm.edit_bones.new('thigh.L')
+ bone.head[:] = 0.0000, 0.0017, 0.7379
+ bone.tail[:] = 0.0000, -0.0690, 0.4731
bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['hand.L']]
- bones['f_toe.L'] = bone.name
- bone = arm.edit_bones.new('f_palm.004.L')
- bone.head[:] = 0.0393, -0.1278, 0.0100
- bone.tail[:] = 0.0406, -0.1304, 0.0100
- bone.roll = -0.0006
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_toe.L']]
- bones['f_palm.004.L'] = bone.name
- bone = arm.edit_bones.new('f_palm.001.L')
- bone.head[:] = 0.0216, -0.1278, 0.0100
- bone.tail[:] = 0.0199, -0.1331, 0.0100
- bone.roll = 0.0004
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_toe.L']]
- bones['f_palm.001.L'] = bone.name
- bone = arm.edit_bones.new('f_palm.002.L')
- bone.head[:] = 0.0273, -0.1278, 0.0100
- bone.tail[:] = 0.0273, -0.1345, 0.0100
- bone.roll = 3.1416
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_toe.L']]
- bones['f_palm.002.L'] = bone.name
- bone = arm.edit_bones.new('f_palm.003.L')
- bone.head[:] = 0.0341, -0.1278, 0.0100
- bone.tail[:] = 0.0340, -0.1345, 0.0100
- bone.roll = 0.0101
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_toe.L']]
- bones['f_palm.003.L'] = bone.name
- bone = arm.edit_bones.new('f_pinky.001.L')
- bone.head[:] = 0.0406, -0.1304, 0.0074
- bone.tail[:] = 0.0408, -0.1337, 0.0065
- bone.roll = -0.6234
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_palm.004.L']]
- bones['f_pinky.001.L'] = bone.name
- bone = arm.edit_bones.new('f_index.001.L')
- bone.head[:] = 0.0199, -0.1331, 0.0077
- bone.tail[:] = 0.0193, -0.1372, 0.0060
- bone.roll = 0.7154
bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_palm.001.L']]
- bones['f_index.001.L'] = bone.name
- bone = arm.edit_bones.new('f_middle.001.L')
- bone.head[:] = 0.0273, -0.1345, 0.0107
- bone.tail[:] = 0.0273, -0.1407, 0.0082
+ bones['thigh.L'] = bone.name
+ bone = arm.edit_bones.new('shin.L')
+ bone.head[:] = 0.0000, -0.0690, 0.4731
+ bone.tail[:] = 0.0000, 0.1364, 0.2473
bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_palm.002.L']]
- bones['f_middle.001.L'] = bone.name
- bone = arm.edit_bones.new('f_ring.001.L')
- bone.head[:] = 0.0340, -0.1345, 0.0107
- bone.tail[:] = 0.0340, -0.1407, 0.0082
- bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones[bones['f_palm.003.L']]
- bones['f_ring.001.L'] = bone.name
- bone = arm.edit_bones.new('f_pinky.002.L')
- bone.head[:] = 0.0408, -0.1337, 0.0065
- bone.tail[:] = 0.0413, -0.1400, 0.0023
- bone.roll = -0.2560
bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_pinky.001.L']]
- bones['f_pinky.002.L'] = bone.name
- bone = arm.edit_bones.new('f_index.002.L')
- bone.head[:] = 0.0193, -0.1372, 0.0060
- bone.tail[:] = 0.0186, -0.1427, 0.0028
- bone.roll = 0.5229
+ bone.parent = arm.edit_bones[bones['thigh.L']]
+ bones['shin.L'] = bone.name
+ bone = arm.edit_bones.new('foot.L')
+ bone.head[:] = 0.0000, 0.1364, 0.2473
+ bone.tail[:] = 0.0000, 0.0736, 0.0411
+ bone.roll = -0.0002
bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_index.001.L']]
- bones['f_index.002.L'] = bone.name
- bone = arm.edit_bones.new('f_middle.002.L')
- bone.head[:] = 0.0273, -0.1407, 0.0082
- bone.tail[:] = 0.0273, -0.1496, 0.0030
- bone.roll = 0.0000
+ bone.parent = arm.edit_bones[bones['shin.L']]
+ bones['foot.L'] = bone.name
+ bone = arm.edit_bones.new('toe.L')
+ bone.head[:] = 0.0000, 0.0736, 0.0411
+ bone.tail[:] = 0.0000, -0.0594, 0.0000
+ bone.roll = -3.1416
bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_middle.001.L']]
- bones['f_middle.002.L'] = bone.name
- bone = arm.edit_bones.new('f_ring.002.L')
- bone.head[:] = 0.0340, -0.1407, 0.0082
- bone.tail[:] = 0.0340, -0.1491, 0.0033
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['f_ring.001.L']]
- bones['f_ring.002.L'] = bone.name
+ bone.parent = arm.edit_bones[bones['foot.L']]
+ bones['toe.L'] = bone.name
bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones[bones['upper_arm.L']]
- pbone.rigify_type = 'limbs.super_limb'
+ pbone = obj.pose.bones[bones['thigh.L']]
+ pbone.rigify_type = 'limbs.paw'
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
try:
- pbone.rigify_parameters.separate_ik_layers = True
+ pbone.rigify_parameters.fk_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
except AttributeError:
pass
try:
- pbone.rigify_parameters.ik_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.separate_hose_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.hose_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
+ pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False]
except AttributeError:
pass
try:
pbone.rigify_parameters.limb_type = "paw"
except AttributeError:
pass
- try:
- pbone.rigify_parameters.fk_layers = [False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['forearm.L']]
+ pbone = obj.pose.bones[bones['shin.L']]
pbone.rigify_type = ''
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['hand.L']]
+ pbone = obj.pose.bones[bones['foot.L']]
pbone.rigify_type = ''
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_toe.L']]
+ pbone = obj.pose.bones[bones['toe.L']]
pbone.rigify_type = ''
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
pbone.lock_scale = (False, False, False)
pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_palm.004.L']]
- pbone.rigify_type = 'limbs.super_palm'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_palm.001.L']]
- pbone.rigify_type = 'limbs.super_palm'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_palm.002.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_palm.003.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_pinky.001.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_index.001.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_middle.001.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['f_ring.001.L']]
- pbone.rigify_type = 'limbs.simple_tentacle'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
+ pbone.rigify_parameters.limb_type = "paw"
except AttributeError:
pass
- pbone = obj.pose.bones[bones['f_pinky.002.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_index.002.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_middle.002.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['f_ring.002.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
bpy.ops.object.mode_set(mode='EDIT')
for bone in arm.edit_bones:
@@ -1329,14 +291,3 @@ def create_sample(obj):
bone.select_head = True
bone.select_tail = True
arm.edit_bones.active = bone
-
- for eb in arm.edit_bones:
- if ('arm' in eb.name) or ('hand' in eb.name):
- eb.layers = (False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
- else:
- eb.layers = (False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
- arm.layers = (False, False, False, False, False, True, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False)
-
-
-if __name__ == "__main__":
- create_sample(bpy.context.active_object)
diff --git a/rigify/rigs/limbs/rear_paw.py b/rigify/rigs/limbs/rear_paw.py
index 74974bb6..2d6894e1 100644
--- a/rigify/rigs/limbs/rear_paw.py
+++ b/rigify/rigs/limbs/rear_paw.py
@@ -1,17 +1,14 @@
import bpy
from .paw import Rig as pawRig
-from .paw import parameters_ui
-from .paw import add_parameters
+
IMPLEMENTATION = True # Include and set True if Rig is just an implementation for a wrapper class
# add_parameters and parameters_ui are unused for implementation classes
class Rig(pawRig):
-
- def __init__(self, obj, bone_name, params):
- super(Rig, self).__init__(obj, bone_name, params)
+ pass
def create_sample(obj):
@@ -135,7 +132,7 @@ def create_sample(obj):
bpy.ops.object.mode_set(mode='OBJECT')
pbone = obj.pose.bones[bones['thigh.L']]
- pbone.rigify_type = 'limbs.super_limb'
+ pbone.rigify_type = 'limbs.paw'
pbone.lock_location = (False, False, False)
pbone.lock_rotation = (False, False, False)
pbone.lock_rotation_w = False
diff --git a/rigify/rigs/limbs/simple_tentacle.py b/rigify/rigs/limbs/simple_tentacle.py
index 82fcafe8..ea5a2224 100644
--- a/rigify/rigs/limbs/simple_tentacle.py
+++ b/rigify/rigs/limbs/simple_tentacle.py
@@ -1,267 +1,118 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
import bpy
-from ...utils import copy_bone
-from ...utils import strip_org, make_deformer_name, connected_children_names
-from ...utils import put_bone, create_sphere_widget
-from ...utils import create_circle_widget, align_bone_x_axis
-from ...utils import MetarigError
-from ...utils import ControlLayersOption
+from itertools import count
-class Rig:
+from ...utils.bones import align_chain_x_axis
+from ...utils.widgets_basic import create_circle_widget
+from ...utils.layers import ControlLayersOption
+from ...utils.misc import map_list
- def __init__(self, obj, bone_name, params):
- self.obj = obj
- self.org_bones = [bone_name] + connected_children_names(obj, bone_name)
- self.params = params
+from ...base_rig import stage
- self.copy_rotation_axes = params.copy_rotation_axes
+from ..chain_rigs import TweakChainRig
- if len(self.org_bones) <= 1:
- raise MetarigError(
- "RIGIFY ERROR: invalid rig structure on bone: %s" % (strip_org(bone_name))
- )
- def orient_org_bones(self):
+class Rig(TweakChainRig):
+ def initialize(self):
+ super().initialize()
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ self.copy_rotation_axes = self.params.copy_rotation_axes
+ # Prepare
+ def prepare_bones(self):
if self.params.roll_alignment == "automatic":
-
- first_bone = eb[self.org_bones[0]]
- last_bone = eb[self.org_bones[-1]]
-
- # 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 make_controls(self):
-
- bpy.ops.object.mode_set(mode='EDIT')
- org_bones = self.org_bones
-
- ctrl_chain = []
- for i in range(len(org_bones)):
- name = org_bones[i]
-
- ctrl_bone = copy_bone(
- self.obj,
- name,
- strip_org(name)
- )
-
- ctrl_chain.append(ctrl_bone)
-
- # Make widgets
- bpy.ops.object.mode_set(mode='OBJECT')
-
- for ctrl in ctrl_chain:
- create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
-
- return ctrl_chain
-
- def make_tweaks(self):
-
- bpy.ops.object.mode_set(mode ='EDIT')
- eb = self.obj.data.edit_bones
- org_bones = self.org_bones
-
- tweak_chain = []
- for i in range(len(org_bones) + 1):
- if i == len(org_bones):
- # Make final tweak at the tip of the tentacle
- name = org_bones[i-1]
- else:
- name = org_bones[i]
-
- tweak_bone = copy_bone(
- self.obj,
- name,
- "tweak_" + strip_org(name)
+ align_chain_x_axis(self.obj, self.bones.org)
+
+ # Parent
+ @stage.parent_bones
+ def parent_control_chain(self):
+ # use_connect=False for backward compatibility
+ self.parent_bone_chain(self.bones.ctrl.fk, use_connect=False)
+
+ # Configure
+ @stage.configure_bones
+ def configure_tweak_chain(self):
+ super().configure_tweak_chain()
+
+ ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.tweak)
+
+ def configure_tweak_bone(self, i, tweak):
+ super().configure_tweak_bone(i, tweak)
+
+ # Backward compatibility
+ self.get_bone(tweak).rotation_mode = 'QUATERNION'
+
+ # Rig
+ @stage.rig_bones
+ def rig_control_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(count(0), ctrls, [None] + ctrls):
+ self.rig_control_bone(*args)
+
+ def rig_control_bone(self, i, ctrl, prev_ctrl):
+ if prev_ctrl:
+ self.make_constraint(
+ ctrl, 'COPY_ROTATION', prev_ctrl,
+ use_xyz=self.copy_rotation_axes,
+ space='LOCAL', use_offset=True
)
- tweak_e = eb[tweak_bone]
-
- tweak_e.length /= 2 # Set size to half
-
- if i == len( org_bones ):
- # Position final tweak at the tip
- put_bone(self.obj, tweak_bone, eb[org_bones[-1]].tail)
-
- tweak_chain.append(tweak_bone)
-
- # Make widgets
- bpy.ops.object.mode_set(mode='OBJECT')
+ # Widgets
+ def make_control_widget(self, ctrl):
+ create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
- for tweak in tweak_chain:
- create_sphere_widget(self.obj, tweak)
- tweak_pb = self.obj.pose.bones[tweak]
-
- # Set locks
- if tweak_chain.index(tweak) != len(tweak_chain) - 1:
- tweak_pb.lock_rotation = (True, False, True)
- tweak_pb.lock_scale = (False, True, False)
- else:
- tweak_pb.lock_rotation_w = True
- tweak_pb.lock_rotation = (True, True, True)
- tweak_pb.lock_scale = (True, True, True)
-
- ControlLayersOption.TWEAK.assign(self.params, self.obj.pose.bones, tweak_chain)
-
- return tweak_chain
-
- def make_deform(self):
-
- bpy.ops.object.mode_set(mode='EDIT')
- org_bones = self.org_bones
-
- def_chain = []
- for i in range(len(org_bones)):
- name = org_bones[i]
-
- def_bone = copy_bone(
- self.obj,
- name,
- make_deformer_name(strip_org(name))
+ @classmethod
+ def add_parameters(self, params):
+ """ Add the parameters of this rig type to the
+ RigifyParameters PropertyGroup
+ """
+ params.copy_rotation_axes = bpy.props.BoolVectorProperty(
+ size=3,
+ description="Automation axes",
+ default=tuple([i == 0 for i in range(0, 3)])
)
- def_chain.append(def_bone)
-
- return def_chain
-
- def parent_bones(self, all_bones):
-
- bpy.ops.object.mode_set(mode='EDIT')
- org_bones = self.org_bones
- eb = self.obj.data.edit_bones
-
- # Parent control bones
- for bone in all_bones['control'][1:]:
- previous_index = all_bones['control'].index(bone) - 1
- eb[bone].parent = eb[all_bones['control'][previous_index]]
-
- # Parent tweak bones
- tweaks = all_bones['tweak']
- for tweak in all_bones['tweak']:
- parent = ''
- if tweaks.index(tweak) == len(tweaks) - 1:
- parent = all_bones['control'][-1]
- else:
- parent = all_bones['control'][tweaks.index(tweak)]
-
- eb[tweak].parent = eb[parent]
-
- # Parent deform bones
- for bone in all_bones['deform'][1:]:
- previous_index = all_bones['deform'].index(bone) - 1
-
- eb[bone].parent = eb[all_bones['deform'][previous_index]]
- eb[bone].use_connect = True
-
- # Parent org bones ( to tweaks by default, or to the controls )
- for org, tweak in zip(org_bones, all_bones['tweak']):
- eb[org].parent = eb[tweak]
-
- def make_constraints(self, all_bones):
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- # Deform bones' constraints
- ctrls = all_bones['control']
- tweaks = all_bones['tweak']
- deforms = all_bones['deform']
-
- for deform, tweak, ctrl in zip( deforms, tweaks, ctrls ):
- con = pb[deform].constraints.new('COPY_TRANSFORMS')
- con.target = self.obj
- con.subtarget = tweak
-
- con = pb[deform].constraints.new('DAMPED_TRACK')
- con.target = self.obj
- con.subtarget = tweaks[tweaks.index(tweak) + 1]
-
- con = pb[deform].constraints.new('STRETCH_TO')
- con.target = self.obj
- con.subtarget = tweaks[tweaks.index(tweak) + 1]
-
- # Control bones' constraints
- if ctrl != ctrls[0]:
- con = pb[ctrl].constraints.new('COPY_ROTATION')
- con.target = self.obj
- con.subtarget = ctrls[ctrls.index(ctrl) - 1]
- for i, prop in enumerate(['use_x', 'use_y', 'use_z']):
- if self.copy_rotation_axes[i]:
- setattr(con, prop, True)
- else:
- setattr(con, prop, False)
- con.use_offset = True
- con.target_space = 'LOCAL'
- con.owner_space = 'LOCAL'
-
- def generate(self):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- self.orient_org_bones()
-
- # Clear all initial parenting
- for bone in self.org_bones:
- # eb[ bone ].parent = None
- eb[bone].use_connect = False
+ # Setting up extra tweak layers
+ ControlLayersOption.TWEAK.add_parameters(params)
- # Creating all bones
- ctrl_chain = self.make_controls()
- tweak_chain = self.make_tweaks()
- def_chain = self.make_deform()
+ items = [('automatic', 'Automatic', ''), ('manual', 'Manual', '')]
+ params.roll_alignment = bpy.props.EnumProperty(items=items, name="Bone roll alignment", default='automatic')
- all_bones = {
- 'control': ctrl_chain,
- 'tweak': tweak_chain,
- 'deform': def_chain
- }
- self.make_constraints(all_bones)
- self.parent_bones(all_bones)
+ @classmethod
+ def parameters_ui(self, layout, params):
+ """ Create the ui for the rig parameters.
+ """
+ r = layout.row()
+ r.prop(params, "roll_alignment")
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
- params.copy_rotation_axes = bpy.props.BoolVectorProperty(
- size=3,
- description="Automation axes",
- default=tuple([i == 0 for i in range(0, 3)])
- )
-
- # Setting up extra tweak layers
- ControlLayersOption.TWEAK.add_parameters(params)
-
- items = [('automatic', 'Automatic', ''), ('manual', 'Manual', '')]
- params.roll_alignment = bpy.props.EnumProperty(items=items, name="Bone roll alignment", default='automatic')
-
-
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters.
- """
-
- r = layout.row()
- r.prop(params, "roll_alignment")
+ row = layout.row(align=True)
+ for i, axis in enumerate(['x', 'y', 'z']):
+ row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis)
- row = layout.row(align=True)
- for i, axis in enumerate(['x', 'y', 'z']):
- row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis)
-
- ControlLayersOption.TWEAK.parameters_ui(layout, params)
+ ControlLayersOption.TWEAK.parameters_ui(layout, params)
def create_sample(obj):
diff --git a/rigify/rigs/limbs/super_finger.py b/rigify/rigs/limbs/super_finger.py
index 081dca7a..1a9171a7 100644
--- a/rigify/rigs/limbs/super_finger.py
+++ b/rigify/rigs/limbs/super_finger.py
@@ -1,298 +1,76 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
import bpy
-from ...utils import copy_bone, flip_bone
-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
+import re
-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
+from ...utils.errors import MetarigError
+from ...utils.bones import flip_bone, align_chain_x_axis
+from ...utils.naming import make_derived_name
+from ...utils.widgets import create_widget
+from ...utils.widgets_basic import create_circle_widget
+from ...utils.misc import map_list
-class Rig:
+from ...base_rig import stage
- def __init__(self, obj, bone_name, params):
- self.obj = obj
- self.org_bones = [bone_name] + connected_children_names(obj, bone_name)
- self.params = params
+from ..chain_rigs import SimpleChainRig
- 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().initialize()
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ self.bbone_segments = 8
+ self.first_parent = self.get_bone_parent(self.bones.org[0])
+ def prepare_bones(self):
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]]
-
- # 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)
+ ##############################
+ # Master Control
- def generate(self):
- org_bones = self.org_bones
+ @stage.generate_bones
+ def make_master_control(self):
+ orgs = self.bones.org
+ name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_master'), parent=True)
+ self.bones.ctrl.master = name
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ 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
- self.orient_org_bones()
+ @stage.configure_bones
+ def configure_master_control(self):
+ master = self.bones.ctrl.master
- # Bone name lists
- ctrl_chain = []
- def_chain = []
- mch_chain = []
- mch_drv_chain = []
+ bone = self.get_bone(master)
+ bone.lock_scale = True, False, True
- # Create ctrl master bone
- org_name = self.org_bones[0]
- temp_name = strip_org(self.org_bones[0])
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ master_name = self.bones.ctrl.master
- if temp_name[-2:] == '.L' or temp_name[-2:] == '.R':
- suffix = temp_name[-2:]
- master_name = temp_name[:-2] + "_master" + suffix
- else:
- master_name = temp_name + "_master"
- master_name = copy_bone(self.obj, org_name, master_name)
- ctrl_bone_master = eb[master_name]
-
- # Parenting bug fix ??
- ctrl_bone_master.use_connect = False
- ctrl_bone_master.parent = None
-
- ctrl_bone_master.tail += (eb[org_bones[-1]].tail - eb[org_name].head) * 1.25
-
- 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:
- # The rest
- 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
-
- # Setting pose bones locks
- pb_master = pb[master_name]
- pb_master.lock_scale = True, False, True
-
- pb[tip_name].lock_scale = True, True, True
- pb[tip_name].lock_rotation = True, True, True
- pb[tip_name].lock_rotation_w = True
-
- make_property(pb_master, 'finger_curve', 0.0, description="Rubber hose finger cartoon effect")
-
- # Pose settings
- 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
- options = {
- "automatic": {"axis": 0,
- "expr": '(1-sy)*pi'},
- "X": {"axis": 0,
- "expr": '(1-sy)*pi'},
- "-X": {"axis": 0,
- "expr": '-((1-sy)*pi)'},
- "Y": {"axis": 1,
- "expr": '(1-sy)*pi'},
- "-Y": {"axis": 1,
- "expr": '-((1-sy)*pi)'},
- "Z": {"axis": 2,
- "expr": '(1-sy)*pi'},
- "-Z": {"axis": 2,
- "expr": '-((1-sy)*pi)'}
- }
-
- axis = self.params.primary_rotation_axis
-
- # Drivers
- drv = pb[mch_drv].driver_add("rotation_euler", options[axis]["axis"]).driver
- 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
- create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
-
- # Create ctrl master widget
w = create_widget(self.obj, master_name)
if w is not None:
mesh = w.data
@@ -307,31 +85,189 @@ class Rig:
mesh.from_pydata(verts, edges, [])
mesh.update()
- # Create tip control widget
- create_circle_widget(self.obj, tip_name, radius=0.3, head_tail=0.0)
+ ##############################
+ # Control chain
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ orgs = self.bones.org
+ self.bones.ctrl.fk = map_list(self.make_control_bone, count(0), orgs)
+ self.bones.ctrl.fk += [self.make_tip_control_bone(orgs[-1], orgs[0])]
+
+ def make_control_bone(self, i, org):
+ return self.copy_bone(org, make_derived_name(org, 'ctrl'), parent=False)
+
+ def make_tip_control_bone(self, org, name_org):
+ name = self.copy_bone(org, make_derived_name(name_org, 'ctrl'), parent=False)
+
+ 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.fk
+ for args in zip(ctrls, self.bones.mch.bend + ctrls[-2:]):
+ self.set_bone_parent(*args)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ for args in zip(count(0), self.bones.ctrl.fk, self.bones.org + [None]):
+ self.configure_control_bone(*args)
+
+ def configure_control_bone(self, i, ctrl, org):
+ if org:
+ self.copy_bone_properties(org, ctrl)
+ else:
+ bone = self.get_bone(ctrl)
+ bone.lock_rotation_w = True
+ bone.lock_rotation = (True, True, True)
+ bone.lock_scale = (True, True, True)
+
+ def make_control_widget(self, ctrl):
+ if ctrl == self.bones.ctrl.fk[-1]:
+ # Tip control
+ create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.0)
+ else:
+ create_circle_widget(self.obj, ctrl, radius=0.3, head_tail=0.5)
+
+ ##############################
+ # MCH bend chain
+
+ @stage.generate_bones
+ def make_mch_bend_chain(self):
+ self.bones.mch.bend = map_list(self.make_mch_bend_bone, self.bones.org)
+
+ def make_mch_bend_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_drv'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_bend_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(self.bones.mch.bend, [self.first_parent] + ctrls):
+ self.set_bone_parent(*args)
+
+ # Match axis to expression
+ axis_options = {
+ "automatic": {"axis": 0,
+ "expr": '(1-sy)*pi'},
+ "X": {"axis": 0,
+ "expr": '(1-sy)*pi'},
+ "-X": {"axis": 0,
+ "expr": '-((1-sy)*pi)'},
+ "Y": {"axis": 1,
+ "expr": '(1-sy)*pi'},
+ "-Y": {"axis": 1,
+ "expr": '-((1-sy)*pi)'},
+ "Z": {"axis": 2,
+ "expr": '(1-sy)*pi'},
+ "-Z": {"axis": 2,
+ "expr": '-((1-sy)*pi)'}
+ }
+
+ @stage.rig_bones
+ def rig_mch_bend_chain(self):
+ for args in zip(count(0), self.bones.mch.bend):
+ self.rig_mch_bend_bone(*args)
+
+ 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
+ options = self.axis_options[axis]
+
+ bone = self.get_bone(mch)
+ bone.rotation_mode = 'YZX'
+
+ self.make_driver(
+ 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_derived_name(org, 'mch'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_stretch_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(self.bones.mch.stretch, [self.first_parent] + ctrls[1:]):
+ self.set_bone_parent(*args)
+
+ @stage.rig_bones
+ def rig_mch_stretch_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(count(0), self.bones.mch.stretch, ctrls, ctrls[1:]):
+ self.rig_mch_stretch_bone(*args)
+
+ def rig_mch_stretch_bone(self, i, mch, ctrl, ctrl_next):
+ if i == 0:
+ self.make_constraint(mch, 'COPY_LOCATION', ctrl)
+ self.make_constraint(mch, 'COPY_SCALE', ctrl)
+
+ self.make_constraint(mch, 'DAMPED_TRACK', ctrl_next)
+ self.make_constraint(mch, 'STRETCH_TO', ctrl_next, volume='NO_VOLUME')
+
+ ##############################
+ # ORG chain
+
+ @stage.rig_bones
+ def rig_org_chain(self):
+ for args in zip(count(0), self.bones.org, self.bones.mch.stretch):
+ self.rig_org_bone(*args)
+
+ ##############################
+ # 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
- controls_string = ", ".join(
- ["'" + x + "'" for x in ctrl_chain]
- ) + ", " + "'" + master_name + "'"
- return [script % (controls_string, master_name, 'finger_curve')]
-
-
-def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
- items = [('automatic', 'Automatic', ''), ('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')
-
-
-def parameters_ui(layout, params):
- """ Create the ui for the rig parameters.
- """
- r = layout.row()
- r.label(text="Bend rotation axis:")
- r.prop(params, "primary_rotation_axis", text="")
+ panel = self.script.panel_with_selected_check(self, self.bones.ctrl.flatten())
+ panel.custom_prop(master, 'finger_curve', text="Curvature", slider=True)
+
+ def rig_deform_bone(self, i, deform, org):
+ 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')])
+
+ ###############
+ # OPTIONS
+
+ @classmethod
+ def add_parameters(self, params):
+ """ Add the parameters of this rig type to the
+ RigifyParameters PropertyGroup
+ """
+ items = [('automatic', 'Automatic', ''), ('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')
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ """ Create the ui for the rig parameters.
+ """
+ r = layout.row()
+ r.label(text="Bend rotation axis:")
+ r.prop(params, "primary_rotation_axis", text="")
def create_sample(obj):
diff --git a/rigify/rigs/limbs/super_limb.py b/rigify/rigs/limbs/super_limb.py
index 0d557bb7..5020f091 100644
--- a/rigify/rigs/limbs/super_limb.py
+++ b/rigify/rigs/limbs/super_limb.py
@@ -1,46 +1,41 @@
-import bpy
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
-from .arm import Rig as armRig
-from .leg import Rig as legRig
-from .paw import Rig as pawRig
+import bpy
-from ...utils import ControlLayersOption
+from ...base_generate import SubstitutionRig
-class Rig:
+from .limb_rigs import BaseLimbRig
- def __init__(self, obj, bone_name, params):
- """ Initialize super_limb rig wrapper class """
- self.obj = obj
- self.params = params
+from . import arm, leg, paw
- if params.limb_type == 'arm':
- self.limb = armRig(obj, bone_name, params)
- elif params.limb_type == 'leg':
- self.limb = legRig(obj, bone_name, params)
- elif params.limb_type == 'paw':
- self.limb = pawRig(obj, bone_name, params)
- def generate(self):
- self.limb.rigify_generator = self.rigify_generator
- self.limb.rigify_wrapper = self.rigify_wrapper
+RIGS = { 'arm': arm.Rig, 'leg': leg.Rig, 'paw': paw.Rig }
- return self.limb.generate()
- @staticmethod
- def get_future_names(bones):
- if bones[0].rigify_parameters.limb_type == 'arm':
- return armRig.get_future_names(bones)
- elif bones[0].rigify_parameters.limb_type == 'leg':
- return legRig.get_future_names(bones)
- elif bones[0].rigify_parameters.limb_type == 'paw':
- return pawRig.get_future_names(bones)
+class Rig(SubstitutionRig):
+ def substitute(self):
+ return [ self.instantiate_rig(RIGS[self.params.limb_type], self.base_bone) ]
def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
-
items = [
('arm', 'Arm', ''),
('leg', 'Leg', ''),
@@ -53,171 +48,15 @@ def add_parameters(params):
default = 'arm'
)
- items = [
- ('x', 'X manual', ''),
- ('z', 'Z manual', ''),
- ('automatic', 'Automatic', '')
- ]
-
- params.rotation_axis = bpy.props.EnumProperty(
- items = items,
- name = "Rotation Axis",
- default = 'automatic'
- )
-
- params.auto_align_extremity = bpy.props.BoolProperty(
- name='auto_align_extremity',
- default=False,
- description="Auto Align Extremity Bone"
- )
-
- params.segments = bpy.props.IntProperty(
- name = 'limb segments',
- default = 2,
- min = 1,
- description = 'Number of segments'
- )
-
- params.bbones = bpy.props.IntProperty(
- name = 'bbone segments',
- default = 10,
- min = 1,
- description = 'Number of segments'
- )
-
- # Setting up extra layers for the FK and tweak
- ControlLayersOption.FK.add_parameters(params)
- ControlLayersOption.TWEAK.add_parameters(params)
+ BaseLimbRig.add_parameters(params)
def parameters_ui(layout, params):
- """ Create the ui for the rig parameters."""
-
r = layout.row()
r.prop(params, "limb_type")
- r = layout.row()
- r.prop(params, "rotation_axis")
-
- if 'auto' not in params.rotation_axis.lower():
- r = layout.row()
- etremities = {'arm': 'Hand', 'leg': 'Foot', 'paw': 'Claw'}
- text = "Auto align " + etremities[params.limb_type]
- r.prop(params, "auto_align_extremity", text=text)
-
- r = layout.row()
- r.prop(params, "segments")
-
- r = layout.row()
- r.prop(params, "bbones")
-
- ControlLayersOption.FK.parameters_ui(layout, params)
- ControlLayersOption.TWEAK.parameters_ui(layout, params)
+ RIGS[params.limb_type].parameters_ui(layout, params)
def create_sample(obj):
- # generated by rigify.utils.write_metarig
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- bones = {}
-
- bone = arm.edit_bones.new('upper_arm.L')
- bone.head[:] = -0.0016, 0.0060, -0.0012
- bone.tail[:] = 0.2455, 0.0678, -0.1367
- bone.roll = 2.0724
- bone.use_connect = False
- bones['upper_arm.L'] = bone.name
- bone = arm.edit_bones.new('forearm.L')
- bone.head[:] = 0.2455, 0.0678, -0.1367
- bone.tail[:] = 0.4625, 0.0285, -0.2797
- bone.roll = 2.1535
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['upper_arm.L']]
- bones['forearm.L'] = bone.name
- bone = arm.edit_bones.new('hand.L')
- bone.head[:] = 0.4625, 0.0285, -0.2797
- bone.tail[:] = 0.5265, 0.0205, -0.3273
- bone.roll = 2.2103
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['forearm.L']]
- bones['hand.L'] = bone.name
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones[bones['upper_arm.L']]
- pbone.rigify_type = 'limbs.super_limb'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- try:
- pbone.rigify_parameters.separate_ik_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.ik_layers = [
- False, False, False, False, False, False, False, False, True, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False
- ]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.separate_hose_layers = True
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.hose_layers = [
- False, False, False, False, False, False, False, False, False, True,
- False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False
- ]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_layers = [
- False, False, False, False, False, False, False, False, False, True,
- False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False
- ]
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.fk_layers = [
- False, False, False, False, False, False, False, False, True, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False, False, False, False, False, False, False, False, False,
- False, False
- ]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['forearm.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['hand.L']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
-
- bpy.ops.object.mode_set(mode='EDIT')
- for bone in arm.edit_bones:
- bone.select = False
- bone.select_head = False
- bone.select_tail = False
- for b in bones:
- bone = arm.edit_bones[bones[b]]
- bone.select = True
- bone.select_head = True
- bone.select_tail = True
- arm.edit_bones.active = bone
+ arm.create_sample(obj, limb=True)
diff --git a/rigify/rigs/limbs/ui.py b/rigify/rigs/limbs/ui.py
deleted file mode 100644
index 952fbca4..00000000
--- a/rigify/rigs/limbs/ui.py
+++ /dev/null
@@ -1,182 +0,0 @@
-script_arm = """
-controls = [%s]
-tweaks = [%s]
-ik_ctrl = [%s]
-fk_ctrl = '%s'
-parent = '%s'
-hand_fk = '%s'
-pole = '%s'
-
-# IK/FK Switch on all Control Bones
-if is_selected( controls ):
- layout.prop( pose_bones[parent], '["%s"]', slider = True )
- props = layout.operator("pose.rigify_arm_fk2ik_" + rig_id, text="Snap FK->IK (" + fk_ctrl + ")")
- props.uarm_fk = controls[1]
- props.farm_fk = controls[2]
- props.hand_fk = controls[3]
- props.uarm_ik = controls[0]
- props.farm_ik = ik_ctrl[1]
- props.hand_ik = controls[4]
- props = layout.operator("pose.rigify_arm_ik2fk_" + rig_id, text="Snap IK->FK (" + fk_ctrl + ")")
- props.uarm_fk = controls[1]
- props.farm_fk = controls[2]
- props.hand_fk = controls[3]
- props.uarm_ik = controls[0]
- props.farm_ik = ik_ctrl[1]
- props.hand_ik = controls[4]
- props.pole = pole
- props.main_parent = parent
- props = layout.operator("pose.rigify_rot2pole_" + rig_id, text="Switch Rotation-Pole")
- props.bone_name = controls[1]
- props.limb_type = "arm"
- props.controls = str(controls)
- props.ik_ctrl = str(ik_ctrl)
- props.fk_ctrl = str(fk_ctrl)
- props.parent = str(parent)
- props.pole = str(pole)
-
-
-# BBone rubber hose on each Respective Tweak
-for t in tweaks:
- if is_selected( t ):
- layout.prop( pose_bones[ t ], '["%s"]', slider = True )
-
-# IK Stretch and pole_vector on IK Control bone
-if is_selected( ik_ctrl ) or is_selected(parent):
- layout.prop( pose_bones[ parent ], '["%s"]', slider = True )
- layout.prop( pose_bones[ parent ], '["%s"]')
-
-# FK limb follow
-if is_selected( fk_ctrl ) or is_selected(parent):
- layout.prop( pose_bones[ parent ], '["%s"]', slider = True )
-"""
-
-script_leg = """
-controls = [%s]
-tweaks = [%s]
-ik_ctrl = [%s]
-fk_ctrl = '%s'
-parent = '%s'
-foot_fk = '%s'
-pole = '%s'
-
-# IK/FK Switch on all Control Bones
-if is_selected( controls ):
- layout.prop( pose_bones[parent], '["%s"]', slider = True )
- props = layout.operator("pose.rigify_leg_fk2ik_" + rig_id, text="Snap FK->IK (" + fk_ctrl + ")")
- props.thigh_fk = controls[1]
- props.shin_fk = controls[2]
- props.foot_fk = controls[3]
- props.mfoot_fk = controls[7]
- props.thigh_ik = controls[0]
- props.shin_ik = ik_ctrl[1]
- props.foot_ik = ik_ctrl[2]
- props.mfoot_ik = ik_ctrl[2]
- props = layout.operator("pose.rigify_leg_ik2fk_" + rig_id, text="Snap IK->FK (" + fk_ctrl + ")")
- props.thigh_fk = controls[1]
- props.shin_fk = controls[2]
- props.foot_fk = controls[3]
- props.mfoot_fk = controls[7]
- props.thigh_ik = controls[0]
- props.shin_ik = ik_ctrl[1]
- props.foot_ik = controls[6]
- props.pole = pole
- props.footroll = controls[5]
- props.mfoot_ik = ik_ctrl[2]
- props.main_parent = parent
- props = layout.operator("pose.rigify_rot2pole_" + rig_id, text="Toggle Rotation and Pole")
- props.bone_name = controls[1]
- props.limb_type = "leg"
- props.controls = str(controls)
- props.ik_ctrl = str(ik_ctrl)
- props.fk_ctrl = str(fk_ctrl)
- props.parent = str(parent)
- props.pole = str(pole)
-
-# BBone rubber hose on each Respective Tweak
-for t in tweaks:
- if is_selected( t ):
- layout.prop( pose_bones[ t ], '["%s"]', slider = True )
-
-# IK Stretch and pole_vector on IK Control bone
-if is_selected( ik_ctrl ) or is_selected(parent):
- layout.prop( pose_bones[ parent ], '["%s"]', slider = True )
- layout.prop( pose_bones[ parent ], '["%s"]')
-
-# FK limb follow
-if is_selected( fk_ctrl ) or is_selected(parent):
- layout.prop( pose_bones[ parent ], '["%s"]', slider = True )
-"""
-
-def create_script( bones, limb_type=None):
- # All ctrls have IK/FK switch
- controls = [bones['ik']['ctrl']['limb']] + bones['fk']['ctrl']
- controls += bones['ik']['ctrl']['terminal']
- controls += [bones['fk']['mch']]
- controls += [bones['main_parent']]
-
- controls_string = ", ".join(["'" + x + "'" for x in controls])
-
- # All tweaks have their own bbone prop
- tweaks = bones['tweak']['ctrl'][1:-1]
- tweaks_string = ", ".join(["'" + x + "'" for x in tweaks])
-
- # IK ctrl has IK stretch
- ik_ctrl = [ bones['ik']['ctrl']['terminal'][-1] ]
- ik_ctrl += [ bones['ik']['mch_ik'] ]
- ik_ctrl += [ bones['ik']['mch_target'] ]
-
- ik_ctrl_string = ", ".join(["'" + x + "'" for x in ik_ctrl])
-
- if 'ik_target' in bones['ik']['ctrl'].keys():
- pole = bones['ik']['ctrl']['ik_target']
- else:
- pole = ''
-
- if limb_type == 'arm':
- return script_arm % (
- controls_string,
- tweaks_string,
- ik_ctrl_string,
- bones['fk']['ctrl'][0],
- bones['main_parent'],
- bones['fk']['ctrl'][-1],
- pole,
- 'IK_FK',
- 'rubber_tweak',
- 'IK_Stretch',
- 'pole_vector',
- 'FK_limb_follow'
- )
-
- elif limb_type == 'leg':
- return script_leg % (
- controls_string,
- tweaks_string,
- ik_ctrl_string,
- bones['fk']['ctrl'][0],
- bones['main_parent'],
- bones['fk']['ctrl'][-1],
- pole,
- 'IK_FK',
- 'rubber_tweak',
- 'IK_Stretch',
- 'pole_vector',
- 'FK_limb_follow'
- )
-
- elif limb_type == 'paw':
- return script_leg % (
- controls_string,
- tweaks_string,
- ik_ctrl_string,
- bones['fk']['ctrl'][0],
- bones['main_parent'],
- bones['fk']['ctrl'][-1],
- pole,
- 'IK_FK',
- 'rubber_tweak',
- 'IK_Stretch',
- 'pole_vector',
- 'FK_limb_follow'
- )
diff --git a/rigify/rigs/spines/basic_spine.py b/rigify/rigs/spines/basic_spine.py
new file mode 100644
index 00000000..d90e4c8d
--- /dev/null
+++ b/rigify/rigs/spines/basic_spine.py
@@ -0,0 +1,321 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+
+from itertools import count, repeat
+
+from ...utils.errors import MetarigError
+from ...utils.layers import ControlLayersOption
+from ...utils.naming import strip_org, make_deformer_name, make_mechanism_name
+from ...utils.bones import BoneDict, put_bone, align_bone_to_axis
+from ...utils.widgets_basic import create_circle_widget
+from ...utils.misc import map_list
+
+from ...base_rig import stage
+from .spine_rigs import BaseSpineRig
+
+
+class Rig(BaseSpineRig):
+ """
+ Spine rig with fixed pivot, hip/chest controls and tweaks.
+ """
+
+ def initialize(self):
+ super().initialize()
+
+ # Check if user provided the pivot position
+ self.pivot_pos = self.params.pivot_pos
+
+ if not (0 < self.pivot_pos < len(self.bones.org)):
+ self.raise_error("Please specify a valid pivot bone position.")
+
+ ####################################################
+ # BONES
+ #
+ # org[]:
+ # ORG bones
+ # ctrl:
+ # master, hips, chest:
+ # Main controls.
+ # tweak[]:
+ # Tweak control chain.
+ # mch:
+ # pivot:
+ # Pivot tweak parent.
+ # chain:
+ # chest[], hips[]:
+ # Tweak parents, distributing master deform.
+ # wgt_hips, wgt_chest:
+ # Widget position bones.
+ # deform[]:
+ # DEF bones
+ #
+ ####################################################
+
+ ####################################################
+ # Master control bone
+
+ @stage.generate_bones
+ def make_master_control(self):
+ super().make_master_control()
+
+ # Put the main control in the middle of the hip bone
+ base_bone = self.get_bone(self.bones.org[0])
+ put_bone(self.obj, self.bones.ctrl.master, (base_bone.head + base_bone.tail) / 2)
+
+ ####################################################
+ # Main control bones
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ orgs = self.bones.org
+ pivot = self.pivot_pos
+
+ self.bones.ctrl.hips = self.make_hips_control_bone(orgs[pivot-1], 'hips')
+ self.bones.ctrl.chest = self.make_chest_control_bone(orgs[pivot], 'chest')
+
+ def make_hips_control_bone(self, org, name):
+ name = self.copy_bone(org, name, parent=False)
+ align_bone_to_axis(self.obj, name, 'y', length=self.length / 4, flip=True)
+ return name
+
+ def make_chest_control_bone(self, org, name):
+ name = self.copy_bone(org, name, parent=False)
+ align_bone_to_axis(self.obj, name, 'y', length=self.length / 3)
+ return name
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ ctrl = self.bones.ctrl
+ self.set_bone_parent(ctrl.hips, ctrl.master)
+ self.set_bone_parent(ctrl.chest, ctrl.master)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ pass
+
+ @stage.generate_widgets
+ def make_control_widgets(self):
+ ctrl = self.bones.ctrl
+ mch = self.bones.mch
+ self.make_control_widget(ctrl.hips, mch.wgt_hips)
+ self.make_control_widget(ctrl.chest, mch.wgt_chest)
+
+ def make_control_widget(self, ctrl, wgt_mch):
+ self.get_bone(ctrl).custom_shape_transform = self.get_bone(wgt_mch)
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius=1.0,
+ head_tail=0.75,
+ with_line=False,
+ bone_transform_name=wgt_mch
+ )
+
+ ####################################################
+ # MCH bones associated with main controls
+
+ @stage.generate_bones
+ def make_mch_control_bones(self):
+ orgs = self.bones.org
+ mch = self.bones.mch
+
+ mch.pivot = self.make_mch_pivot_bone(orgs[self.pivot_pos], 'pivot')
+ mch.wgt_hips = self.make_mch_widget_bone(orgs[0], 'WGT-hips')
+ mch.wgt_chest = self.make_mch_widget_bone(orgs[-1], 'WGT-chest')
+
+ def make_mch_pivot_bone(self, org, name):
+ name = self.copy_bone(org, make_mechanism_name(name), parent=False)
+ align_bone_to_axis(self.obj, name, 'y', length=self.length * 0.6 / 4)
+ return name
+
+ def make_mch_widget_bone(self, org, name):
+ return self.copy_bone(org, make_mechanism_name(name), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_control_bones(self):
+ mch = self.bones.mch
+ self.set_bone_parent(mch.pivot, mch.chain.chest[0])
+ self.set_bone_parent(mch.wgt_hips, mch.chain.hips[0])
+ self.set_bone_parent(mch.wgt_chest, mch.chain.chest[-1])
+
+ @stage.rig_bones
+ def rig_mch_control_bones(self):
+ mch = self.bones.mch
+ # Is it actually intending to compute average of these, or is this really intentional?
+ # This effectively adds rotations of the hip and chest controls.
+ self.make_constraint(mch.pivot, 'COPY_TRANSFORMS', mch.chain.hips[-1], space='LOCAL')
+
+ ####################################################
+ # MCH chain for distributing hip & chest transform
+
+ @stage.generate_bones
+ def make_mch_chain(self):
+ orgs = self.bones.org
+ self.bones.mch.chain = BoneDict(
+ hips = map_list(self.make_mch_bone, orgs[0:self.pivot_pos], repeat(True)),
+ chest = map_list(self.make_mch_bone, orgs[self.pivot_pos:], repeat(False)),
+ )
+
+ def make_mch_bone(self, org, is_hip):
+ name = self.copy_bone(org, make_mechanism_name(strip_org(org)), parent=False)
+ align_bone_to_axis(self.obj, name, 'y', length=self.length / 10, flip=is_hip)
+ return name
+
+ @stage.parent_bones
+ def parent_mch_chain(self):
+ master = self.bones.ctrl.master
+ chain = self.bones.mch.chain
+ self.parent_bone_chain([master, *reversed(chain.hips)])
+ self.parent_bone_chain([master, *chain.chest])
+
+ @stage.rig_bones
+ def rig_mch_chain(self):
+ ctrl = self.bones.ctrl
+ chain = self.bones.mch.chain
+ for mch in chain.hips:
+ self.rig_mch_bone(mch, ctrl.hips, len(chain.hips))
+ for mch in chain.chest:
+ self.rig_mch_bone(mch, ctrl.chest, len(chain.chest))
+
+ def rig_mch_bone(self, mch, control, count):
+ self.make_constraint(mch, 'COPY_TRANSFORMS', control, space='LOCAL', influence=1/count)
+
+ ####################################################
+ # Tweak bones
+
+ @stage.parent_bones
+ def parent_tweak_chain(self):
+ mch = self.bones.mch
+ chain = mch.chain
+ parents = [chain.hips[0], *chain.hips[0:-1], mch.pivot, *chain.chest[1:], chain.chest[-1]]
+ for args in zip(self.bones.ctrl.tweak, parents):
+ self.set_bone_parent(*args)
+
+ ####################################################
+ # SETTINGS
+
+ @classmethod
+ def add_parameters(self, params):
+ params.pivot_pos = bpy.props.IntProperty(
+ name='pivot_position',
+ default=2,
+ min=0,
+ description='Position of the torso control and pivot point'
+ )
+
+ super().add_parameters(params)
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ r = layout.row()
+ r.prop(params, "pivot_pos")
+
+ super().parameters_ui(layout, params)
+
+
+def create_sample(obj):
+ # generated by rigify.utils.write_metarig
+ bpy.ops.object.mode_set(mode='EDIT')
+ arm = obj.data
+
+ bones = {}
+
+ bone = arm.edit_bones.new('spine')
+ bone.head[:] = 0.0000, 0.0552, 1.0099
+ bone.tail[:] = 0.0000, 0.0172, 1.1573
+ bone.roll = 0.0000
+ bone.use_connect = False
+ bones['spine'] = bone.name
+
+ bone = arm.edit_bones.new('spine.001')
+ bone.head[:] = 0.0000, 0.0172, 1.1573
+ bone.tail[:] = 0.0000, 0.0004, 1.2929
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['spine']]
+ bones['spine.001'] = bone.name
+
+ bone = arm.edit_bones.new('spine.002')
+ bone.head[:] = 0.0000, 0.0004, 1.2929
+ bone.tail[:] = 0.0000, 0.0059, 1.4657
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['spine.001']]
+ bones['spine.002'] = bone.name
+
+ bone = arm.edit_bones.new('spine.003')
+ bone.head[:] = 0.0000, 0.0059, 1.4657
+ bone.tail[:] = 0.0000, 0.0114, 1.6582
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['spine.002']]
+ bones['spine.003'] = bone.name
+
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['spine']]
+ pbone.rigify_type = 'spines.basic_spine'
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+
+ try:
+ pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['spine.001']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ pbone = obj.pose.bones[bones['spine.002']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ pbone = obj.pose.bones[bones['spine.003']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ for bone in arm.edit_bones:
+ bone.select = False
+ bone.select_head = False
+ bone.select_tail = False
+ for b in bones:
+ bone = arm.edit_bones[bones[b]]
+ bone.select = True
+ bone.select_head = True
+ bone.select_tail = True
+ arm.edit_bones.active = bone
+
+ return bones
diff --git a/rigify/rigs/spines/basic_tail.py b/rigify/rigs/spines/basic_tail.py
new file mode 100644
index 00000000..6697858c
--- /dev/null
+++ b/rigify/rigs/spines/basic_tail.py
@@ -0,0 +1,246 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+
+from itertools import count
+
+from ...utils.naming import strip_org, make_derived_name
+from ...utils.bones import put_bone, flip_bone, is_same_position, connect_bbone_chain_handles, align_bone_orientation
+from ...utils.widgets_basic import create_circle_widget
+from ...utils.layers import ControlLayersOption
+from ...utils.misc import map_list
+
+from ...base_rig import stage
+
+from ..chain_rigs import TweakChainRig, SimpleChainRig
+from ..widgets import create_ballsocket_widget
+
+from .spine_rigs import BaseHeadTailRig
+
+
+class Rig(BaseHeadTailRig):
+ def initialize(self):
+ super().initialize()
+
+ self.copy_rotation_axes = self.params.copy_rotation_axes
+
+ def parent_bones(self):
+ super().parent_bones()
+
+ if self.connected_tweak and self.use_connect_reverse:
+ self.rig_parent_bone = self.connected_tweak
+
+ ####################################################
+ # Master control
+
+ @stage.generate_bones
+ def make_master_control(self):
+ org = self.bones.org[0]
+ self.bones.ctrl.master = self.copy_bone(org, make_derived_name(org, 'ctrl', '_master'))
+ self.default_prop_bone = self.bones.ctrl.master
+
+ @stage.parent_bones
+ def parent_master_control(self):
+ self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone)
+
+ @stage.configure_bones
+ def configure_master_control(self):
+ bone = self.get_bone(self.bones.ctrl.master)
+ bone.lock_location = True, True, True
+
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ bone = self.bones.ctrl.master
+ self.get_bone(bone).custom_shape_transform = self.get_bone(self.bones.ctrl.tweak[-1])
+ create_ballsocket_widget(self.obj, bone, size=0.7)
+
+ ####################################################
+ # Control bones
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ self.set_bone_parent(self.bones.ctrl.fk[0], self.bones.mch.rot_tail)
+ self.parent_bone_chain(self.bones.ctrl.fk, use_connect=False)
+
+ @stage.rig_bones
+ def rig_control_chain(self):
+ ctrls = self.bones.ctrl.fk
+ for args in zip(count(0), ctrls, [self.bones.ctrl.master] + ctrls):
+ self.rig_control_bone(*args)
+
+ def rig_control_bone(self, i, ctrl, prev_ctrl):
+ self.make_constraint(
+ ctrl, 'COPY_ROTATION', prev_ctrl,
+ use_xyz=self.copy_rotation_axes,
+ space='LOCAL', use_offset=True
+ )
+
+ # Widgets
+ def make_control_widget(self, ctrl):
+ create_circle_widget(self.obj, ctrl, radius=0.5, head_tail=0.75)
+
+ ####################################################
+ # MCH bones associated with main controls
+
+ @stage.generate_bones
+ def make_mch_control_bones(self):
+ self.bones.mch.rot_tail = self.make_mch_follow_bone(self.bones.org[0], 'tail', 0.0)
+
+ @stage.parent_bones
+ def parent_mch_control_bones(self):
+ self.set_bone_parent(self.bones.mch.rot_tail, self.rig_parent_bone)
+
+ ####################################################
+ # Tweak bones
+
+ @stage.generate_bones
+ def make_tweak_chain(self):
+ orgs = self.bones.org
+ self.bones.ctrl.tweak = map_list(self.make_tweak_bone, count(0), orgs[0:1] + orgs)
+
+ def make_tweak_bone(self, i, org):
+ if i == 0:
+ if self.check_connect_tweak(org):
+ return self.connected_tweak
+
+ else:
+ name = self.copy_bone(org, 'tweak_base_' + strip_org(org), parent=False, scale=0.5)
+
+ else:
+ name = self.copy_bone(org, 'tweak_' + strip_org(org), parent=False, scale=0.5)
+ put_bone(self.obj, name, self.get_bone(org).tail)
+
+ return name
+
+ ####################################################
+ # Deform chain
+
+ @stage.configure_bones
+ def configure_deform_chain(self):
+ if self.use_connect_chain and self.use_connect_reverse:
+ self.get_bone(self.bones.deform[-1]).bone.bbone_easein = 0.0
+ self.get_bone(self.rigify_parent.bones.deform[0]).bone.bbone_easein = 1.0
+ else:
+ self.get_bone(self.bones.deform[-1]).bone.bbone_easeout = 0.0
+
+
+ ####################################################
+ # SETTINGS
+
+ @classmethod
+ def add_parameters(self, params):
+ """ Add the parameters of this rig type to the
+ RigifyParameters PropertyGroup
+ """
+
+ super().add_parameters(params)
+
+ params.copy_rotation_axes = bpy.props.BoolVectorProperty(
+ size=3,
+ description="Automation axes",
+ default=tuple([i == 0 for i in range(0, 3)])
+ )
+
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ """ Create the ui for the rig parameters.
+ """
+
+ row = layout.row(align=True)
+ for i, axis in enumerate(['x', 'y', 'z']):
+ row.prop(params, "copy_rotation_axes", index=i, toggle=True, text=axis)
+
+ super().parameters_ui(layout, params)
+
+
+def create_sample(obj, *, parent=None):
+ # generated by rigify.utils.write_metarig
+ bpy.ops.object.mode_set(mode='EDIT')
+ arm = obj.data
+
+ bones = {}
+
+ bone = arm.edit_bones.new('tail')
+ bone.head[:] = 0.0000, 0.0552, 1.0099
+ bone.tail[:] = -0.0000, 0.0582, 0.8669
+ bone.roll = 0.0000
+ bone.use_connect = False
+ if parent:
+ bone.parent = arm.edit_bones[parent]
+ bones['tail'] = bone.name
+ bone = arm.edit_bones.new('tail.001')
+ bone.head[:] = -0.0000, 0.0582, 0.8669
+ bone.tail[:] = -0.0000, 0.0365, 0.7674
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['tail']]
+ bones['tail.001'] = bone.name
+ bone = arm.edit_bones.new('tail.002')
+ bone.head[:] = -0.0000, 0.0365, 0.7674
+ bone.tail[:] = -0.0000, 0.0010, 0.6984
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['tail.001']]
+ bones['tail.002'] = bone.name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['tail']]
+ pbone.rigify_type = 'spines.basic_tail'
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ try:
+ pbone.rigify_parameters.connect_chain = bool(parent)
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['tail.001']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ pbone = obj.pose.bones[bones['tail.002']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ for bone in arm.edit_bones:
+ bone.select = False
+ bone.select_head = False
+ bone.select_tail = False
+ for b in bones:
+ bone = arm.edit_bones[bones[b]]
+ bone.select = True
+ bone.select_head = True
+ bone.select_tail = True
+ arm.edit_bones.active = bone
diff --git a/rigify/rigs/spines/spine_rigs.py b/rigify/rigs/spines/spine_rigs.py
new file mode 100644
index 00000000..47a72287
--- /dev/null
+++ b/rigify/rigs/spines/spine_rigs.py
@@ -0,0 +1,208 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+
+from itertools import count
+
+from ...utils.layers import ControlLayersOption
+from ...utils.naming import make_derived_name
+from ...utils.bones import align_bone_orientation, align_bone_to_axis
+from ...utils.widgets_basic import create_cube_widget
+from ...utils.switch_parent import SwitchParentBuilder
+
+from ...base_rig import stage
+
+from ..chain_rigs import TweakChainRig, ConnectingChainRig
+
+
+class BaseSpineRig(TweakChainRig):
+ """
+ Spine rig with tweaks.
+ """
+
+ bbone_segments = 8
+
+ def initialize(self):
+ if len(self.bones.org) < 3:
+ self.raise_error("Input to rig type must be a chain of 3 or more bones.")
+
+ self.length = sum([self.get_bone(b).length for b in self.bones.org])
+
+ ####################################################
+ # BONES
+ #
+ # ctrl:
+ # master
+ # Main control.
+ #
+ ####################################################
+
+ ####################################################
+ # Master control bone
+
+ @stage.generate_bones
+ def make_master_control(self):
+ self.bones.ctrl.master = name = self.copy_bone(self.bones.org[0], 'torso')
+
+ align_bone_to_axis(self.obj, name, 'y', length=self.length * 0.6)
+
+ SwitchParentBuilder(self.generator).register_parent(self, name)
+
+ @stage.parent_bones
+ def parent_master_control(self):
+ self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone)
+
+ @stage.configure_bones
+ def configure_master_control(self):
+ pass
+
+ @stage.generate_widgets
+ def make_master_control_widget(self):
+ create_cube_widget(
+ self.obj, self.bones.ctrl.master,
+ radius=0.5,
+ bone_transform_name=None
+ )
+
+ ####################################################
+ # Tweak bones
+
+ @stage.configure_bones
+ def configure_tweak_chain(self):
+ super().configure_tweak_chain()
+
+ ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.tweak)
+
+ ####################################################
+ # Deform bones
+
+ @stage.configure_bones
+ def configure_bbone_chain(self):
+ self.get_bone(self.bones.deform[0]).bone.bbone_easein = 0.0
+
+ ####################################################
+ # SETTINGS
+
+ @classmethod
+ def add_parameters(self, params):
+ # Setting up extra layers for the FK and tweak
+ ControlLayersOption.TWEAK.add_parameters(params)
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ ControlLayersOption.TWEAK.parameters_ui(layout, params)
+
+
+class BaseHeadTailRig(ConnectingChainRig):
+ """ Base for head and tail rigs. """
+
+ def initialize(self):
+ super().initialize()
+
+ self.rotation_bones = []
+
+ ####################################################
+ # Utilities
+
+ def get_parent_master(self, default_bone):
+ """ Return the parent's master control bone if connecting and found. """
+
+ if self.use_connect_chain and 'master' in self.rigify_parent.bones.ctrl:
+ return self.rigify_parent.bones.ctrl.master
+ else:
+ return default_bone
+
+ def get_parent_master_panel(self, default_bone):
+ """ Return the parent's master control bone if connecting and found, and script panel. """
+
+ controls = self.bones.ctrl.flatten()
+ prop_bone = self.get_parent_master(default_bone)
+
+ if prop_bone != default_bone:
+ owner = self.rigify_parent
+ controls += self.rigify_parent.bones.ctrl.flatten()
+ else:
+ owner = self
+
+ return prop_bone, self.script.panel_with_selected_check(owner, controls)
+
+ ####################################################
+ # Rotation follow
+
+ def make_mch_follow_bone(self, org, name, defval, *, copy_scale=False):
+ bone = self.copy_bone(org, make_derived_name('ROT-'+name, 'mch'), parent=True)
+ self.rotation_bones.append((org, name, bone, defval, copy_scale))
+ return bone
+
+ @stage.parent_bones
+ def align_mch_follow_bones(self):
+ self.follow_bone = self.get_parent_master('root')
+
+ for org, name, bone, defval, copy_scale in self.rotation_bones:
+ align_bone_orientation(self.obj, bone, self.follow_bone)
+
+ @stage.configure_bones
+ def configure_mch_follow_bones(self):
+ self.prop_bone, panel = self.get_parent_master_panel(self.default_prop_bone)
+
+ for org, name, bone, defval, copy_scale in self.rotation_bones:
+ textname = name.replace('_',' ').title() + ' Follow'
+
+ self.make_property(self.prop_bone, name+'_follow', default=float(defval))
+ panel.custom_prop(self.prop_bone, name+'_follow', text=textname, slider=True)
+
+ @stage.rig_bones
+ def rig_mch_follow_bones(self):
+ for org, name, bone, defval, copy_scale in self.rotation_bones:
+ self.rig_mch_rotation_bone(bone, name+'_follow', copy_scale)
+
+ def rig_mch_rotation_bone(self, mch, prop_name, copy_scale):
+ con = self.make_constraint(mch, 'COPY_ROTATION', self.follow_bone)
+
+ self.make_driver(con, 'influence', variables=[(self.prop_bone, prop_name)], polynomial=[1,-1])
+
+ if copy_scale:
+ self.make_constraint(mch, 'COPY_SCALE', self.follow_bone)
+
+ ####################################################
+ # Tweak chain
+
+ @stage.configure_bones
+ def configure_tweak_chain(self):
+ super().configure_tweak_chain()
+
+ ControlLayersOption.TWEAK.assign(self.params, self.obj, self.bones.ctrl.tweak)
+
+ ####################################################
+ # Settings
+
+ @classmethod
+ def add_parameters(self, params):
+ super().add_parameters(params)
+
+ # Setting up extra layers for the FK and tweak
+ ControlLayersOption.TWEAK.add_parameters(params)
+
+ @classmethod
+ def parameters_ui(self, layout, params):
+ super().parameters_ui(layout, params)
+
+ ControlLayersOption.TWEAK.parameters_ui(layout, params)
diff --git a/rigify/rigs/spines/super_head.py b/rigify/rigs/spines/super_head.py
new file mode 100644
index 00000000..79ec2396
--- /dev/null
+++ b/rigify/rigs/spines/super_head.py
@@ -0,0 +1,406 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
+
+import bpy
+
+from itertools import count
+
+from ...utils.naming import make_derived_name
+from ...utils.bones import align_bone_orientation
+from ...utils.widgets_basic import create_circle_widget, create_cube_widget
+from ...utils.widgets_special import create_neck_bend_widget, create_neck_tweak_widget
+from ...utils.misc import map_list
+
+from ...base_rig import stage
+
+from .spine_rigs import BaseHeadTailRig
+
+
+class Rig(BaseHeadTailRig):
+ """
+ Head rig with long neck support and connect option.
+ """
+
+ use_connect_reverse = False
+
+ def initialize(self):
+ super().initialize()
+
+ self.long_neck = len(self.bones.org) > 3
+
+ ####################################################
+ # BONES
+ #
+ # org[]:
+ # ORG bones
+ # ctrl:
+ # neck, head, neck_bend:
+ # Main controls.
+ # tweak[]:
+ # Tweak control chain.
+ # mch:
+ # rot_neck, rot_head:
+ # Main control parents, implement FK follow.
+ # stretch
+ # Long neck stretch behavior.
+ # ik[]
+ # Long neck IK behavior.
+ # chain[]
+ # Tweak parents.
+ # deform[]:
+ # DEF bones
+ #
+ ####################################################
+
+ ####################################################
+ # Main control bones
+
+ @stage.generate_bones
+ def make_control_chain(self):
+ orgs = self.bones.org
+ ctrl = self.bones.ctrl
+
+ ctrl.neck = self.make_neck_control_bone(orgs[0], 'neck', orgs[-1])
+ ctrl.head = self.make_head_control_bone(orgs[-1], 'head')
+ if self.long_neck:
+ ctrl.neck_bend = self.make_neck_bend_control_bone(orgs[0], 'neck_bend', ctrl.neck)
+
+ self.default_prop_bone = ctrl.head
+
+ def make_neck_control_bone(self, org, name, org_head):
+ name = self.copy_bone(org, name, parent=False)
+
+ # Neck spans all neck bones (except head)
+ self.get_bone(name).tail = self.get_bone(org_head).head
+
+ return name
+
+ def make_neck_bend_control_bone(self, org, name, neck):
+ name = self.copy_bone(org, name, parent=False)
+ neck_bend_eb = self.get_bone(name)
+
+ # Neck pivot position
+ neck_bones = self.bones.org
+ if (len(neck_bones)-1) % 2: # odd num of neck bones (head excluded)
+ center_bone = self.get_bone(neck_bones[int((len(neck_bones))/2) - 1])
+ neck_bend_eb.head = (center_bone.head + center_bone.tail)/2
+ else:
+ center_bone = self.get_bone(neck_bones[int((len(neck_bones)-1)/2) - 1])
+ neck_bend_eb.head = center_bone.tail
+
+ align_bone_orientation(self.obj, name, neck)
+ neck_bend_eb.length = self.get_bone(neck).length / 2
+
+ return name
+
+ def make_head_control_bone(self, org, name):
+ return self.copy_bone(org, name, parent=False)
+
+ @stage.parent_bones
+ def parent_control_chain(self):
+ ctrl = self.bones.ctrl
+ mch = self.bones.mch
+ self.set_bone_parent(ctrl.neck, mch.rot_neck)
+ self.set_bone_parent(ctrl.head, mch.rot_head)
+ if self.long_neck:
+ self.set_bone_parent(ctrl.neck_bend, mch.stretch)
+
+ @stage.configure_bones
+ def configure_control_chain(self):
+ self.configure_control_bone(0, self.bones.ctrl.neck, self.bones.org[0])
+ self.configure_control_bone(2, self.bones.ctrl.head, self.bones.org[-1])
+ if self.long_neck:
+ self.configure_control_bone(1, self.bones.ctrl.neck_bend, self.bones.org[0])
+
+ @stage.generate_widgets
+ def make_control_widgets(self):
+ ctrl = self.bones.ctrl
+ self.make_neck_widget(ctrl.neck)
+ self.make_head_widget(ctrl.head)
+ if self.long_neck:
+ self.make_neck_bend_widget(ctrl.neck_bend)
+
+ def make_neck_widget(self, ctrl):
+ radius = 1/max(1, len(self.bones.mch.chain))
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius=radius,
+ head_tail=0.5,
+ bone_transform_name=None
+ )
+
+ def make_neck_bend_widget(self, ctrl):
+ radius = 1/max(1, len(self.bones.mch.chain))
+
+ create_neck_bend_widget(
+ self.obj, ctrl,
+ radius=radius/2,
+ head_tail=0.0,
+ bone_transform_name=None
+ )
+
+ def make_head_widget(self, ctrl):
+ # place wgt @ middle of head bone for long necks
+ if self.long_neck:
+ head_tail = 0.5
+ else:
+ head_tail = 1.0
+
+ create_circle_widget(
+ self.obj, ctrl,
+ radius = 0.5,
+ head_tail = head_tail,
+ with_line = False,
+ bone_transform_name = None
+ )
+
+ ####################################################
+ # MCH bones associated with main controls
+
+ @stage.generate_bones
+ def make_mch_control_bones(self):
+ orgs = self.bones.org
+ mch = self.bones.mch
+
+ mch.rot_neck = self.make_mch_follow_bone(orgs[0], 'neck', 0.5, copy_scale=True)
+ mch.rot_head = self.make_mch_follow_bone(orgs[-1], 'head', 0.0, copy_scale=True)
+ mch.stretch = self.make_mch_stretch_bone(orgs[0], 'STR-neck', orgs[-1])
+
+ def make_mch_stretch_bone(self, org, name, org_head):
+ name = self.copy_bone(org, make_derived_name(name, 'mch'), parent=False)
+ self.get_bone(name).tail = self.get_bone(org_head).head
+ return name
+
+ @stage.parent_bones
+ def parent_mch_control_bones(self):
+ self.set_bone_parent(self.bones.mch.rot_neck, self.rig_parent_bone)
+ self.set_bone_parent(self.bones.mch.rot_head, self.bones.ctrl.neck)
+ self.set_bone_parent(self.bones.mch.stretch, self.bones.ctrl.neck)
+
+ @stage.rig_bones
+ def rig_mch_control_bones(self):
+ self.rig_mch_stretch_bone(self.bones.mch.stretch, self.bones.ctrl.head)
+
+ def rig_mch_stretch_bone(self, mch, head):
+ self.make_constraint(mch, 'DAMPED_TRACK', head)
+ self.make_constraint(mch, 'STRETCH_TO', head)
+
+ ####################################################
+ # MCH IK chain for the long neck
+
+ @stage.generate_bones
+ def make_mch_ik_chain(self):
+ orgs = self.bones.org
+ if self.long_neck:
+ self.bones.mch.ik = map_list(self.make_mch_ik_bone, orgs[0:-1])
+
+ def make_mch_ik_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch', '_ik'), parent=False)
+
+ @stage.parent_bones
+ def parent_mch_ik_chain(self):
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ self.set_bone_parent(ik[0], self.bones.ctrl.tweak[0])
+ self.parent_bone_chain(ik, use_connect=True)
+
+ @stage.rig_bones
+ def rig_mch_ik_chain(self):
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ head = self.bones.ctrl.head
+ for args in zip(count(0), ik):
+ self.rig_mch_ik_bone(*args, len(ik), head)
+
+ def rig_mch_ik_bone(self, i, mch, ik_len, head):
+ if i == ik_len - 1:
+ self.make_constraint(mch, 'IK', head, chain_count=ik_len)
+
+ self.get_bone(mch).ik_stretch = 0.1
+
+ ####################################################
+ # MCH chain for the middle of the neck
+
+ @stage.generate_bones
+ def make_mch_chain(self):
+ orgs = self.bones.org
+ self.bones.mch.chain = map_list(self.make_mch_bone, orgs[1:-1])
+
+ def make_mch_bone(self, org):
+ return self.copy_bone(org, make_derived_name(org, 'mch'), parent=False, scale=1/4)
+
+ @stage.parent_bones
+ def align_mch_chain(self):
+ for mch in self.bones.mch.chain:
+ align_bone_orientation(self.obj, mch, self.bones.ctrl.neck)
+
+ @stage.parent_bones
+ def parent_mch_chain(self):
+ mch = self.bones.mch
+ for bone in mch.chain:
+ self.set_bone_parent(bone, mch.stretch)
+ self.get_bone(bone).use_inherit_scale = False
+
+ @stage.rig_bones
+ def rig_mch_chain(self):
+ chain = self.bones.mch.chain
+ if self.long_neck:
+ ik = self.bones.mch.ik
+ for args in zip(count(0), chain, ik[1:]):
+ self.rig_mch_bone_long(*args, len(chain))
+ else:
+ for args in zip(count(0), chain):
+ self.rig_mch_bone(*args, len(chain))
+
+ def rig_mch_bone_long(self, i, mch, ik, len_mch):
+ ctrl = self.bones.ctrl
+
+ self.make_constraint(mch, 'COPY_LOCATION', ik)
+
+ step = 2/(len_mch+1)
+ xval = (i+1)*step
+ influence = 2*xval - xval**2 #parabolic influence of pivot
+
+ self.make_constraint(
+ mch, 'COPY_LOCATION', ctrl.neck_bend,
+ influence=influence, use_offset=True, space='LOCAL'
+ )
+
+ self.make_constraint(mch, 'COPY_SCALE', ctrl.neck)
+
+ def rig_mch_bone(self, i, mch, len_mch):
+ ctrl = self.bones.ctrl
+
+ nfactor = float((i + 1) / (len_mch + 1))
+ self.make_constraint(
+ mch, 'COPY_ROTATION', ctrl.head,
+ influence=nfactor, space='LOCAL'
+ )
+
+ ####################################################
+ # Tweak bones
+
+ @stage.generate_bones
+ def make_tweak_chain(self):
+ orgs = self.bones.org
+ self.bones.ctrl.tweak = map_list(self.make_tweak_bone, count(0), orgs[0:-1])
+
+ @stage.parent_bones
+ def parent_tweak_chain(self):
+ ctrl = self.bones.ctrl
+ mch = self.bones.mch
+
+ for args in zip(ctrl.tweak, [ctrl.neck, *mch.chain]):
+ self.set_bone_parent(*args)
+
+ @stage.rig_bones
+ def generate_neck_tweak_widget(self):
+ # Generate the widget early to override connected parent
+ if self.long_neck:
+ bone = self.bones.ctrl.tweak[0]
+ create_neck_tweak_widget(self.obj, bone, size=1.0)
+
+ ####################################################
+ # ORG and DEF bones
+
+ @stage.configure_bones
+ def configure_bbone_chain(self):
+ self.get_bone(self.bones.deform[-1]).bone.bbone_segments = 1
+
+ @stage.rig_bones
+ def rig_org_chain(self):
+ tweaks = self.bones.ctrl.tweak + [self.bones.ctrl.head]
+ for args in zip(count(0), self.bones.org, tweaks, tweaks[1:] + [None]):
+ self.rig_org_bone(*args)
+
+
+def create_sample(obj, *, parent=None):
+ # generated by rigify.utils.write_metarig
+ bpy.ops.object.mode_set(mode='EDIT')
+ arm = obj.data
+
+ bones = {}
+
+ bone = arm.edit_bones.new('neck')
+ bone.head[:] = 0.0000, 0.0114, 1.6582
+ bone.tail[:] = 0.0000, -0.0130, 1.7197
+ bone.roll = 0.0000
+ bone.use_connect = False
+ if parent:
+ bone.parent = arm.edit_bones[parent]
+ bones['neck'] = bone.name
+ bone = arm.edit_bones.new('neck.001')
+ bone.head[:] = 0.0000, -0.0130, 1.7197
+ bone.tail[:] = 0.0000, -0.0247, 1.7813
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['neck']]
+ bones['neck.001'] = bone.name
+ bone = arm.edit_bones.new('head')
+ bone.head[:] = 0.0000, -0.0247, 1.7813
+ bone.tail[:] = 0.0000, -0.0247, 1.9796
+ bone.roll = 0.0000
+ bone.use_connect = True
+ bone.parent = arm.edit_bones[bones['neck.001']]
+ bones['head'] = bone.name
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pbone = obj.pose.bones[bones['neck']]
+ pbone.rigify_type = 'spines.super_head'
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ try:
+ pbone.rigify_parameters.connect_chain = bool(parent)
+ except AttributeError:
+ pass
+ try:
+ pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
+ except AttributeError:
+ pass
+ pbone = obj.pose.bones[bones['neck.001']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+ pbone = obj.pose.bones[bones['head']]
+ pbone.rigify_type = ''
+ pbone.lock_location = (False, False, False)
+ pbone.lock_rotation = (False, False, False)
+ pbone.lock_rotation_w = False
+ pbone.lock_scale = (False, False, False)
+ pbone.rotation_mode = 'QUATERNION'
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ for bone in arm.edit_bones:
+ bone.select = False
+ bone.select_head = False
+ bone.select_tail = False
+ for b in bones:
+ bone = arm.edit_bones[bones[b]]
+ bone.select = True
+ bone.select_head = True
+ bone.select_tail = True
+ arm.edit_bones.active = bone
diff --git a/rigify/rigs/spines/super_spine.py b/rigify/rigs/spines/super_spine.py
index ebc76fcb..3f7e41e1 100644
--- a/rigify/rigs/spines/super_spine.py
+++ b/rigify/rigs/spines/super_spine.py
@@ -1,1007 +1,108 @@
-import bpy
-from mathutils import Vector
-from ...utils import copy_bone, flip_bone, put_bone, org, align_bone_y_axis, align_bone_x_axis
-from ...utils import strip_org, make_deformer_name, connected_children_names
-from ...utils import create_circle_widget, create_sphere_widget, create_neck_bend_widget, create_neck_tweak_widget
-from ..widgets import create_ballsocket_widget
-from ...utils import MetarigError, make_mechanism_name, create_cube_widget
-from ...utils import ControlLayersOption
-from ...utils.mechanism import make_property, make_driver
-
-from ...utils.switch_parent import SwitchParentBuilder
-
-script = """
-controls = [%s]
-torso = '%s'
-
-if is_selected( controls ):
- if hasattr(pose_bones[torso],'["%s"]'):
- layout.prop( pose_bones[ torso ], '["%s"]', slider = True )
- if hasattr(pose_bones[torso],'["%s"]'):
- layout.prop( pose_bones[ torso ], '["%s"]', slider = True )
- if hasattr(pose_bones[torso],'["%s"]'):
- layout.prop( pose_bones[ torso ], '["%s"]', slider = True )
-"""
-
-
-class Rig:
-
- def __init__(self, obj, bone_name, params):
- """ Initialize torso rig and key rig properties """
-
- eb = obj.data.edit_bones
-
- self.obj = obj
- self.org_bones = [bone_name] + connected_children_names(obj, bone_name)
- self.params = params
- # self.spine_length = sum([eb[b].length for b in self.org_bones])
- self.copy_rotation_axes = params.copy_rotation_axes
- self.use_head = params.use_head
- self.use_tail = params.use_tail
-
- # Check if user provided the pivot position
- if params.pivot_pos:
- self.pivot_pos = params.pivot_pos + 1
- else:
- raise MetarigError(
- "RIGIFY ERROR: please specify pivot bone position"
- )
-
- # Check if neck is lower than pivot
- if self.use_head and params.neck_pos <= params.pivot_pos and params.neck_pos != 0:
- raise MetarigError(
- "RIGIFY ERROR: Neck cannot be below or the same as pivot. (use 0 for no neck)"
- )
- else:
- self.neck_pos = params.neck_pos
-
- if not self.use_head:
- self.neck_pos = len(self.org_bones)
-
- if self.use_tail and self.pivot_pos - 2 > 0:
- self.tail_pos = params.tail_pos
-
- # Report error of user created less than the minimum of bones for rig
- min_bone_number = 3
- if self.use_head:
- min_bone_number += 1
- if self.use_tail:
- min_bone_number += 2
-
- if len(self.org_bones) < min_bone_number:
- raise MetarigError(
- "RIGIFY ERROR: invalid rig structure on %s" % (strip_org(bone_name))
- )
-
- def build_bone_structure(self):
- """ Divide meta-rig into lists of bones according to torso rig anatomy:
- Neck --> Upper torso --> Lower torso --> Tail (optional) """
-
- if self.pivot_pos and (self.neck_pos == 0 or self.neck_pos > self.pivot_pos):
-
- neck_index = self.neck_pos - 1
- pivot_index = self.pivot_pos - 1
-
- tail_index = 0
- if self.use_tail and self.tail_pos > 1: # 2 bones for the tail at least
- tail_index = self.tail_pos - 1
-
- if self.use_head:
- neck_bones = self.org_bones[neck_index::]
- upper_torso_bones = self.org_bones[pivot_index :neck_index]
- else:
- neck_bones = []
- upper_torso_bones = self.org_bones[pivot_index ::]
-
- tail_bones = []
- if tail_index:
- lower_torso_bones = self.org_bones[tail_index + 1:pivot_index ]
- tail_bones = self.org_bones[:tail_index+1]
- else:
- lower_torso_bones = self.org_bones[:pivot_index ]
-
- torso_bones = upper_torso_bones + lower_torso_bones
- eb = self.obj.data.edit_bones
- self.spine_length = sum([eb[b].length for b in torso_bones])
-
- return {
- 'neck': neck_bones,
- 'upper': upper_torso_bones,
- 'lower': lower_torso_bones,
- 'tail': tail_bones
- }
-
- else:
- return 'ERROR'
-
- def orient_bone(self, eb, axis, scale, reverse=False):
- v = Vector((0,0,0))
-
- setattr(v, axis, scale)
-
- if reverse:
- tail_vec = v @ self.obj.matrix_world
- eb.head[:] = eb.tail
- eb.tail[:] = eb.head + tail_vec
- else:
- tail_vec = v @ self.obj.matrix_world
- eb.tail[:] = eb.head + tail_vec
-
- def create_pivot(self, pivot):
- """ Create the pivot control and mechanism bones """
- org_bones = self.org_bones
- pivot_name = org_bones[pivot-1]
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Create torso control bone
- torso_name = 'torso'
- ctrl_name = copy_bone(self.obj, pivot_name, torso_name)
- ctrl_eb = eb[ctrl_name]
-
- self.orient_bone(ctrl_eb, 'y', self.spine_length * 0.6)
-
- # Create mch_pivot
- mch_name = make_mechanism_name('pivot')
- mch_name = copy_bone(self.obj, ctrl_name, mch_name)
- mch_eb = eb[mch_name]
-
- mch_eb.length /= 4
-
- # Positioning pivot in a more usable location for animators
- # if self.use_tail and self.tail_pos > 0:
- # pivot_loc = eb[org_bones[pivot-1]].head
- if self.use_tail and self.tail_pos > 0:
- first_torso_bone = self.tail_pos
- pivot_loc = (eb[org_bones[first_torso_bone]].head + eb[org_bones[first_torso_bone]].tail)/2
- else:
- pivot_loc = (eb[org_bones[0]].head + eb[org_bones[0]].tail) / 2
-
- put_bone(self.obj, ctrl_name, pivot_loc)
-
- return {
- 'ctrl': ctrl_name,
- 'mch': mch_name
- }
-
- def create_deform(self):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- def_bones = []
- for org_b in org_bones:
- def_name = make_deformer_name(strip_org(org_b))
- def_name = copy_bone(self.obj, org_b, def_name)
- def_bones.append(def_name)
-
- return def_bones
-
- def create_neck(self, neck_bones):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- if not self.use_head:
- return {
- 'ctrl_neck': '',
- 'ctrl': '',
- 'mch_str': '',
- 'mch_neck': '',
- 'mch_head': '',
- 'mch': [],
- 'tweak': [],
- 'neck_bend': '',
- 'original_names': neck_bones
- }
-
- neck, neck_bend = '', ''
- if len(neck_bones) >= 2:
- # Create neck control
- neck = copy_bone(self.obj, org(neck_bones[0]), 'neck')
- neck_eb = eb[neck]
-
- # Neck spans all neck bones (except head)
- neck_eb.tail[:] = eb[org(neck_bones[-1])].head
-
- if len(neck_bones) > 3:
-
- # Create neck bend control
- neck_bend = copy_bone(self.obj, org(neck_bones[0]), 'neck_bend')
- neck_bend_eb = eb[neck_bend]
-
- # Neck pivot position
- if (len(neck_bones)-1) % 2: # odd num of neck bones (head excluded)
- center_bone = org(neck_bones[int((len(neck_bones))/2) - 1])
- neck_bend_eb.head = (eb[center_bone].head + eb[center_bone].tail)/2
- else:
- center_bone = org(neck_bones[int((len(neck_bones)-1)/2) - 1])
- neck_bend_eb.head = eb[center_bone].tail
-
- align_bone_y_axis(self.obj, neck_bend, eb[neck].y_axis)
- align_bone_x_axis(self.obj, neck_bend, eb[neck].x_axis)
- eb[neck_bend].length = eb[neck].length / 2
-
- # Create head control
- head = copy_bone(self.obj, org(neck_bones[-1]), 'head')
-
- # MCH bones
- mch_str, mch_neck = '', ''
- if len(neck_bones) >= 2:
- # Neck MCH stretch
- mch_str = copy_bone(self.obj, neck, make_mechanism_name('STR-neck'))
-
- # Neck MCH rotation
- mch_neck = copy_bone(
- self.obj, neck, make_mechanism_name('ROT-neck')
- )
-
- self.orient_bone(eb[mch_neck], 'y', self.spine_length / 10)
-
- # Head MCH rotation
- mch_head = copy_bone(self.obj, head, make_mechanism_name('ROT-head'))
- self.orient_bone(eb[mch_head], 'y', self.spine_length / 10)
-
- twk, mch = [], []
-
- if len(neck_bones) >= 2:
- # Intermediary bones
- for b in neck_bones[1:-1]: # All except 1st (neck) and last (head)
- mch_name = copy_bone(self.obj, org(b), make_mechanism_name(b))
- eb[mch_name].length /= 4
- align_bone_y_axis(self.obj, mch_name, eb[neck].y_axis)
- align_bone_x_axis(self.obj, mch_name, eb[neck].x_axis)
- eb[mch_name].use_inherit_scale = False
- mch += [mch_name]
-
- # Tweak bones
- for b in neck_bones[:-1]: # All except last bone
- twk_name = "tweak_" + b
- twk_name = copy_bone(self.obj, org(b), twk_name)
-
- eb[twk_name].length /= 2
-
- twk += [twk_name]
-
- return {
- 'ctrl_neck': neck,
- 'ctrl': head,
- 'mch_str': mch_str,
- 'mch_neck': mch_neck,
- 'mch_head': mch_head,
- 'mch': mch,
- 'tweak': twk,
- 'neck_bend': neck_bend,
- 'original_names': neck_bones
- }
-
- def create_chest(self, chest_bones):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # get total spine length
-
- # Create chest control bone
- chest = copy_bone(self.obj, org(chest_bones[0]), 'chest')
- self.orient_bone(eb[chest], 'y', self.spine_length / 3)
-
- # create chest mch_wgt
- mch_wgt = copy_bone(
- self.obj, org(chest_bones[-1]),
- make_mechanism_name('WGT-chest')
- )
-
- # Create mch and twk bones
- twk, mch = [], []
-
- for b in chest_bones:
- mch_name = copy_bone( self.obj, org(b), make_mechanism_name(b) )
- self.orient_bone( eb[mch_name], 'y', self.spine_length / 10 )
-
- twk_name = "tweak_" + b
- twk_name = copy_bone( self.obj, org(b), twk_name )
- eb[twk_name].length /= 2
-
- mch += [ mch_name ]
- twk += [ twk_name ]
-
- return {
- 'ctrl' : chest,
- 'mch' : mch,
- 'tweak' : twk,
- 'mch_wgt' : mch_wgt
- }
-
- def create_hips(self, hip_bones):
- org_bones = self.org_bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Create hips control bone
- hips = copy_bone(self.obj, org(hip_bones[-1]), 'hips')
- self.orient_bone(
- eb[hips],
- 'y',
- self.spine_length / 4,
- reverse = True
- )
-
- # create hips mch_wgt
- mch_wgt = copy_bone(
- self.obj, org(hip_bones[0]),
- make_mechanism_name('WGT-hips')
- )
-
- # Create mch and tweak bones
- twk, mch = [], []
- for b in hip_bones:
- mch_name = copy_bone( self.obj, org(b), make_mechanism_name(b) )
- self.orient_bone(
- eb[mch_name], 'y', self.spine_length / 10, reverse = True
- )
-
- twk_name = "tweak_" + b
- twk_name = copy_bone( self.obj, org(b), twk_name )
-
- eb[twk_name].length /= 2
-
- mch += [ mch_name ]
- twk += [ twk_name ]
-
- return {
- 'ctrl' : hips,
- 'mch' : mch,
- 'tweak' : twk,
- 'mch_wgt' : mch_wgt
- }
-
- def create_tail(self, tail_bones):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
- org_bones = self.org_bones
-
- ctrl_chain = []
- for i in range(len(tail_bones)):
- name = tail_bones[i]
-
- ctrl_bone = copy_bone(
- self.obj,
- org(name),
- strip_org(name)
- )
-
- flip_bone(self.obj, ctrl_bone)
- ctrl_chain.append(ctrl_bone)
-
- # Main ctrl
- name = tail_bones[-1]
- main_ctrl_bone = copy_bone(
- self.obj,
- org(name),
- strip_org(name).split('.')[0] + "_master"
- )
- flip_bone(self.obj, main_ctrl_bone)
-
- mch_tail = ''
- tail_first = org_bones[self.tail_pos-1]
- mch_rot_tail = copy_bone(
- self.obj,
- org(tail_first),
- make_mechanism_name("ROT-tail")
- )
-
- self.orient_bone(eb[mch_rot_tail], 'y', eb[tail_first].length)
- put_bone(self.obj, mch_rot_tail, eb[tail_first].tail)
- mch_tail = mch_rot_tail
-
- tweak_chain = []
- for i in range(len(tail_bones)):
- name = tail_bones[i]
-
- tweak_bone = copy_bone(
- self.obj,
- org(name),
- "tweak_" + strip_org(name)
- )
-
- tweak_e = eb[tweak_bone]
- tweak_e.length /= 2 # Set size to half
-
- # Position tweaks
- flip_bone(self.obj, tweak_bone)
- put_bone(self.obj, tweak_bone, eb[org(name)].head)
-
- tweak_chain.append(tweak_bone)
-
- return {
- 'ctrl': ctrl_chain,
- 'ctrl_tail': main_ctrl_bone,
- 'mch_tail': mch_tail,
- 'tweak': tweak_chain,
- 'original_names': tail_bones
- }
-
- def parent_bones(self, bones):
- org_bones = self.org_bones
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
-
- # Parent deform bones
- for i, b in enumerate(bones['def']):
- if i > 0: # For all bones but the first (which has no parent)
- eb[b].parent = eb[bones['def'][i-1]] # to previous
- eb[b].use_connect = True
-
- # Parent control bones
- # Head control => MCH-rotation_head
- if self.use_head:
- eb[bones['neck']['ctrl']].parent = eb[bones['neck']['mch_head']]
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+# <pep8 compliant>
- # Tail control chain
- if self.use_tail:
- tail_ctrl = bones['tail']['ctrl']
- for i, b in enumerate(tail_ctrl[:-1]):
- eb[b].parent = eb[tail_ctrl[i+1]]
- eb[tail_ctrl[-1]].parent = eb[bones['tail']['mch_tail']]
- eb[bones['tail']['ctrl_tail']].parent = eb[org_bones[self.tail_pos]]
-
- if bones['neck']['ctrl_neck']:
- # MCH stretch => neck ctrl
- eb[ bones['neck']['mch_str']].parent = eb[ bones['neck']['ctrl_neck']]
-
- # Neck control => MCH-rotation_neck
- eb[bones['neck']['ctrl_neck']].parent = eb[bones['neck']['mch_neck']]
-
- # Neck pivot => MCH-rotation_neck
- if bones['neck']['neck_bend']:
- # eb[bones['neck']['neck_bend']].parent = eb[bones['neck']['ctrl_neck']]
- eb[bones['neck']['neck_bend']].parent = eb[bones['neck']['mch_str']]
-
- # Parent hips and chest controls to torso
- eb[bones['chest']['ctrl']].parent = eb[bones['pivot']['ctrl']]
- eb[bones['hips']['ctrl']].parent = eb[bones['pivot']['ctrl']]
-
- # Parent mch bones
- if bones['neck']['ctrl_neck']:
- # Neck mch
- eb[bones['neck']['mch_head']].parent = eb[bones['neck']['ctrl_neck']]
- elif self.use_head:
- eb[bones['neck']['mch_head']].parent = eb[bones['chest']['mch'][-1]]
-
- for i, b in enumerate([eb[n] for n in bones['neck']['mch']]):
- b.parent = eb[bones['neck']['mch_str']]
- # for org_b in bones['neck']['original_names']:
- # if org_b in b.name:
- # b.parent = eb[org(org_b)]
-
- # Chest mch bones and neck mch
- chest_mch = bones['chest']['mch'] + [bones['neck']['mch_neck']]
- for i, b in enumerate(chest_mch):
- if i == 0:
- eb[b].parent = eb[bones['pivot']['ctrl']]
- elif b:
- eb[b].parent = eb[chest_mch[i-1]]
-
- # Hips mch bones
- for i, b in enumerate(bones['hips']['mch']):
- if i == len(bones['hips']['mch']) - 1:
- eb[b].parent = eb[bones['pivot']['ctrl']]
- else:
- eb[b].parent = eb[bones['hips']['mch'][i+1]]
-
- # mch pivot
- eb[bones['pivot']['mch']].parent = eb[bones['chest']['mch'][0]]
-
- # MCH widgets
- eb[bones['chest']['mch_wgt']].parent = eb[bones['chest']['mch'][-1]]
- eb[bones['hips']['mch_wgt']].parent = eb[bones['hips']['mch'][0]]
-
- # Neck Tweaks
- if bones['neck']['tweak']:
- # Neck tweaks
- for i, twk in enumerate( bones['neck']['tweak']):
- if i == 0:
- eb[twk].parent = eb[ bones['neck']['ctrl_neck']]
- else:
- eb[twk].parent = eb[ bones['neck']['mch'][i-1]]
-
- # Chest tweaks
- for twk, mch in zip( bones['chest']['tweak'], bones['chest']['mch']):
- if bones['chest']['tweak'].index(twk) == 0:
- eb[twk].parent = eb[bones['pivot']['mch']]
- else:
- eb[twk].parent = eb[mch]
-
- # Hips tweaks
- for i, twk in enumerate(bones['hips']['tweak']):
- if i == 0:
- eb[twk].parent = eb[bones['hips']['mch'][i]]
- else:
- eb[twk].parent = eb[bones['hips']['mch'][i-1]]
-
- # Tail mchs
- if self.use_tail:
- mch_rot_tail = bones['tail']['mch_tail']
- eb[mch_rot_tail].parent = eb[bones['hips']['tweak'][0]]
-
- # Tail tweaks
- if self.use_tail:
- for i, twk in enumerate(bones['tail']['tweak']):
- if i == 0:
- eb[twk].parent = eb[bones['tail']['ctrl'][i]]
- else:
- eb[twk].parent = eb[bones['tail']['ctrl'][i-1]]
-
- # Parent orgs to matching tweaks
- tweaks = []
- if self.use_tail:
- tweaks += bones['tail']['tweak']
-
- tweaks += bones['hips']['tweak'] + bones['chest']['tweak']
- if self.use_head:
- tweaks += bones['neck']['tweak'] + [bones['neck']['ctrl']]
-
- original_neck_bones = [org(b) for b in bones['neck']['original_names']]
- original_neck_bones = original_neck_bones[1:-1] # exclude first neck bone and head
- for b, twk in zip(org_bones[:-1], tweaks):
- if b in original_neck_bones and len(bones['neck']['original_names']) > 3:
- idx = org_bones.index(b)
- org_parent = org_bones[idx-1]
- eb[b].parent = eb[org_parent]
- else:
- eb[b].parent = eb[twk]
-
- if self.use_head:
- eb[org_bones[-1]].parent = eb[bones['neck']['ctrl']]
-
- def make_constraint(self, bone, constraint):
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- owner_pb = pb[bone]
- const = owner_pb.constraints.new(constraint['constraint'])
- const.target = self.obj
-
- # filter constraint props to those that actually exist in the currnet
- # type of constraint, then assign values to each
- for p in [k for k in constraint.keys() if k in dir(const)]:
- setattr(const, p, constraint[p])
-
- def constrain_bones(self, bones):
- # MCH bones
-
- # head and neck MCH bones
- for b in [bones['neck']['mch_head'], bones['neck']['mch_neck']]:
- if b:
- self.make_constraint(b, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': bones['pivot']['ctrl'],
- })
- self.make_constraint(b, {
- 'constraint': 'COPY_SCALE',
- 'subtarget': bones['pivot']['ctrl'],
- })
-
- if bones['neck']['mch_str']:
- # Neck MCH Stretch
- self.make_constraint(bones['neck']['mch_str'], {
- 'constraint': 'DAMPED_TRACK',
- 'subtarget': bones['neck']['ctrl'],
- })
- self.make_constraint(bones['neck']['mch_str'], {
- 'constraint': 'STRETCH_TO',
- 'subtarget': bones['neck']['ctrl'],
- })
-
- # Intermediary mch bones
- intermediaries = [bones['neck'], bones['chest'], bones['hips']]
-
- for i, l in enumerate(intermediaries):
- mch = l['mch']
-
- for j, b in enumerate(mch):
-
- if i == 0: # Neck mch-s
- if len(bones['neck']['original_names']) > 3:
- self.make_constraint(b, {
- 'constraint': 'COPY_LOCATION',
- 'subtarget': org(l['original_names'][j+1]),
- 'influence': 1.0
- })
- else:
- nfactor = float((j + 1) / len(mch))
- self.make_constraint(b, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': l['ctrl'],
- 'influence': nfactor
- })
-
- step = 2/(len(mch)+1)
- xval = (j+1)*step
- influence = 2*xval - xval**2 #parabolic influence of pivot
-
- if bones['neck']['neck_bend']:
- self.make_constraint(b, {
- 'constraint': 'COPY_LOCATION',
- 'subtarget': l['neck_bend'],
- 'influence': influence,
- 'use_offset': True,
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
-
- if len(bones['neck']['original_names']) > 3:
- self.make_constraint(b, {
- 'constraint': 'COPY_SCALE',
- 'subtarget': bones['neck']['ctrl_neck'],
- 'influence': 1.0
- })
-
- else:
- factor = float(1 / len(l['tweak']))
- self.make_constraint(b, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': l['ctrl'],
- 'influence': factor,
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
-
- # Tail ctrls
- if self.use_tail:
- tail_ctrl = bones['tail']['ctrl']
- tail_ctrl.append(bones['tail']['ctrl_tail'])
-
- for i, b in enumerate(tail_ctrl[:-1]):
- self.make_constraint(b, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': tail_ctrl[i+1],
- 'influence': 1.0,
- 'use_x': self.copy_rotation_axes[0],
- 'use_y': self.copy_rotation_axes[1],
- 'use_z': self.copy_rotation_axes[2],
- 'use_offset': True,
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
-
- b = bones['tail']['mch_tail']
- self.make_constraint(b, {
- 'constraint': 'COPY_ROTATION',
- 'subtarget': bones['pivot']['ctrl'],
- 'influence': 1.0,
- })
-
- # MCH pivot
- self.make_constraint(bones['pivot']['mch'], {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': bones['hips']['mch'][-1],
- 'owner_space': 'LOCAL',
- 'target_space': 'LOCAL'
- })
-
- # DEF bones
- deform = bones['def']
- tweaks = []
- if self.use_tail:
- tweaks += bones['tail']['tweak']
-
- tweaks += bones['hips']['tweak'] + bones['chest']['tweak']
- if self.use_head:
- tweaks += bones['neck']['tweak'] + [bones['neck']['ctrl']]
-
- for d, t in zip(deform, tweaks):
- tidx = tweaks.index(t)
-
- self.make_constraint(d, {
- 'constraint': 'COPY_TRANSFORMS',
- 'subtarget': t
- })
-
- if tidx != len(tweaks) - 1:
- if self.use_tail and t in bones['tail']['tweak']:
- self.make_constraint(d, {
- 'constraint': 'DAMPED_TRACK',
- 'subtarget': tweaks[tidx + 1],
- 'track_axis': 'TRACK_NEGATIVE_Y'
- })
- else:
- self.make_constraint(d, {
- 'constraint': 'DAMPED_TRACK',
- 'subtarget': tweaks[tidx + 1],
- })
-
- self.make_constraint(d, {
- 'constraint': 'STRETCH_TO',
- 'subtarget': tweaks[tidx + 1],
- })
-
- pb = self.obj.pose.bones
-
- if bones['neck']['neck_bend']:
- pb[bones['neck']['neck_bend']].rotation_mode = 'ZXY'
- pb[bones['neck']['neck_bend']].lock_rotation[0] = True
- pb[bones['neck']['neck_bend']].lock_rotation[2] = True
-
- for t in tweaks:
- if t != bones['neck']['ctrl']:
- pb[t].rotation_mode = 'ZXY'
-
- original_neck_bones = [org(b) for b in bones['neck']['original_names']]
- # make IK on neck ORGs
- if len(original_neck_bones) > 3:
- last_neck = original_neck_bones[-2]
- self.make_constraint(last_neck, {
- 'constraint': 'IK',
- 'subtarget': bones['neck']['ctrl'],
- 'chain_count': len(original_neck_bones) - 1
- })
-
- for b in original_neck_bones[:-1]:
- pb[b].ik_stretch = 0.1
-
- def create_drivers(self, bones):
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- # Setting the torso's props
- torso = pb[bones['pivot']['ctrl']]
-
- props = []
- owners = []
-
- if self.use_head:
- props += ["head_follow"]
- owners += [bones['neck']['mch_head']]
- if bones['neck']['mch_neck']:
- props += ["neck_follow"]
- owners += [bones['neck']['mch_neck']]
- if self.use_tail:
- props += ["tail_follow"]
- owners += [bones['tail']['mch_tail']]
-
- for prop in props:
- if prop == 'neck_follow':
- defval = 0.5
- else:
- defval = 0.0
-
- make_property(torso, prop, defval)
-
- # driving the follow rotation switches for neck and head
- for bone, prop, in zip(owners, props):
- # Add driver to copy rotation constraint
- make_driver(pb[bone].constraints[0], "influence", variables=[(self.obj, torso, prop)], polynomial=[1.0, -1.0])
-
- def locks_and_widgets(self, bones):
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- # deform bones bbone segments
- for bone in bones['def'][:-1]:
- self.obj.data.bones[bone].bbone_segments = 8
-
- self.obj.data.bones[bones['def'][0]].bbone_easein = 0.0
- self.obj.data.bones[bones['def'][-2]].bbone_easeout = 1.0
-
- # Locks
- tweaks = bones['neck']['tweak'] + bones['chest']['tweak']
- tweaks += bones['hips']['tweak']
-
- if self.use_tail:
- tweaks += bones['tail']['tweak']
- pb[bones['tail']['ctrl_tail']].lock_location = True, True, True
-
- # Tweak bones locks
- for bone in tweaks:
- pb[bone].lock_rotation = True, False, True
- pb[bone].lock_scale = False, True, False
-
- # Widgets
-
- # Assigning a widget to torso bone
- create_cube_widget(
- self.obj,
- bones['pivot']['ctrl'],
- radius=0.5,
- bone_transform_name=None
- )
-
- # Assigning widgets to control bones
- gen_ctrls = [
- bones['chest']['ctrl'],
- bones['hips']['ctrl']
- ]
-
- tail_ctrls = []
- if self.use_tail and bones['tail']['ctrl']:
- tail_ctrls = bones['tail']['ctrl'] + [bones['tail']['ctrl_tail']]
- gen_ctrls.extend(bones['tail']['ctrl'])
-
- create_ballsocket_widget(
- self.obj,
- bones['tail']['ctrl_tail'],
- size=0.7,
- bone_transform_name=None
- )
-
- for bone in gen_ctrls:
-
- if bone in tail_ctrls:
- radius = 0.5
- else:
- radius = 1.0
-
- # place chest on neck-base for very long necks
- if bone == bones['chest']['ctrl'] and len(bones['neck']['original_names']) > 3:
- head_tail = 0.0
- else:
- head_tail = 0.75
-
- create_circle_widget(
- self.obj,
- bone,
- radius=radius,
- head_tail=head_tail,
- with_line=False,
- bone_transform_name=None
- )
-
- if bones['neck']['ctrl_neck']:
- # Neck ctrl widget
- if len(bones['neck']['mch']) == 0:
- radius = 1
- else:
- radius = 1/(len(bones['neck']['mch']))
- create_circle_widget(
- self.obj,
- bones['neck']['ctrl_neck'],
- radius=radius,
- head_tail=0.5,
- bone_transform_name=None
- )
-
- if bones['neck']['neck_bend']:
- # Neck pivot widget
- if len(bones['neck']['mch']) == 0:
- radius = 0.5
- else:
- radius = 1/(2*len(bones['neck']['mch']))
- create_neck_bend_widget(
- self.obj,
- bones['neck']['neck_bend'],
- radius=radius,
- head_tail=0.0,
- bone_transform_name=None
- )
+import bpy
- # Head widget
- # place wgt @ middle of head bone for long necks
- if len(bones['neck']['original_names']) > 3:
- head_tail = 0.5
- else:
- head_tail = 1.0
- if self.use_head:
- create_circle_widget(
- self.obj,
- bones['neck']['ctrl'],
- radius = 0.5,
- head_tail = head_tail,
- with_line = False,
- bone_transform_name = None
- )
+from ...utils.rig import connected_children_names
+from ...utils.layers import ControlLayersOption
+from ...utils.bones import BoneUtilityMixin, flip_bone_chain
- # place widgets on correct bones
- chest_widget_loc = pb[bones['chest']['mch_wgt']]
- pb[bones['chest']['ctrl']].custom_shape_transform = chest_widget_loc
+from ...base_generate import SubstitutionRig
- hips_widget_loc = pb[bones['hips']['mch_wgt']]
+from . import basic_spine, basic_tail, super_head
- if self.use_tail:
- hips_widget_loc = pb[bones['def'][self.tail_pos]]
- pb[bones['tail']['ctrl_tail']].custom_shape_transform = pb[bones['tail']['tweak'][0]]
- pb[bones['hips']['ctrl']].custom_shape_transform = hips_widget_loc
+class Rig(SubstitutionRig, BoneUtilityMixin):
+ """Compatibility proxy for the monolithic super_spine rig that splits it into parts."""
- # Assigning widgets to tweak bones and layers
- for bone in tweaks:
+ def substitute(self):
+ params_copy = dict(self.params)
+ orgs = [self.base_bone] + connected_children_names(self.obj, self.base_bone)
- if bones['neck']['tweak'] and bone == bones['neck']['tweak'][0] \
- and len(bones['neck']['original_names']) > 3:
- create_neck_tweak_widget(self.obj, bone, size=1.0, bone_transform_name=None)
- continue
- create_sphere_widget(self.obj, bone, bone_transform_name=None)
+ # Split the bone list according to the settings
+ spine_orgs = orgs
+ head_orgs = None
+ tail_orgs = None
- ControlLayersOption.TWEAK.assign(self.params, pb, tweaks)
+ pivot_pos = self.params.pivot_pos
- def generate(self):
- # Torso Rig Anatomy:
- # Neck: all bones above neck point, last bone is head
- # Upper torso: all bones between pivot and neck start
- # Lower torso: all bones below pivot until tail point
- # Tail: all bones below tail point
+ if self.params.use_head:
+ neck_pos = self.params.neck_pos
+ if neck_pos <= pivot_pos:
+ self.raise_error("Neck cannot be below or the same as pivot.")
+ if neck_pos >= len(orgs):
+ self.raise_error("Neck is too short.")
- bone_chains = self.build_bone_structure()
+ spine_orgs = orgs[0 : neck_pos-1]
+ head_orgs = orgs[neck_pos-1 : ]
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ if self.params.use_tail:
+ tail_pos = self.params.tail_pos
+ if tail_pos < 2:
+ self.raise_error("Tail is too short.")
+ if tail_pos >= pivot_pos:
+ self.raise_error("Tail cannot be above or the same as pivot.")
- # Clear parents for org bones
- for bone in self.org_bones:
- eb[bone].use_connect = False
- eb[bone].parent = None
+ tail_orgs = list(reversed(spine_orgs[0 : tail_pos]))
+ spine_orgs = spine_orgs[tail_pos : ]
+ pivot_pos -= tail_pos
- if bone_chains != 'ERROR':
+ # Split the bone chain and flip the tail
+ if head_orgs or tail_orgs:
+ bpy.ops.object.mode_set(mode='EDIT')
- # Create lists of bones and strip "ORG" from their names
- neck_bones = [strip_org(b) for b in bone_chains['neck']]
- upper_torso_bones = [strip_org(b) for b in bone_chains['upper']]
- lower_torso_bones = [strip_org(b) for b in bone_chains['lower']]
- tail_bones = [strip_org(b) for b in bone_chains['tail']]
+ if spine_orgs[0] != orgs[0]:
+ self.set_bone_parent(spine_orgs[0], self.get_bone_parent(orgs[0]))
- bones = {}
+ if head_orgs:
+ self.get_bone(head_orgs[0]).use_connect = False
- bones['def'] = self.create_deform() # Gets org bones from self
- bones['pivot'] = self.create_pivot(self.pivot_pos)
- bones['neck'] = self.create_neck(neck_bones)
- bones['chest'] = self.create_chest(upper_torso_bones)
- bones['hips'] = self.create_hips(lower_torso_bones)
+ if tail_orgs:
+ flip_bone_chain(self.obj, reversed(tail_orgs))
+ self.set_bone_parent(tail_orgs[0], spine_orgs[0])
- # Register viable parent bones
- pbuilder = SwitchParentBuilder(self.rigify_generator)
- pbuilder.register_parent(self.rigify_wrapper, bones['pivot']['ctrl'], name='Torso')
- pbuilder.register_parent(self.rigify_wrapper, bone_chains['lower'][0], name='Hips')
- pbuilder.register_parent(self.rigify_wrapper, bone_chains['upper'][-1], name='Chest')
- if self.use_head:
- pbuilder.register_parent(self.rigify_wrapper, bone_chains['neck'][-1], name='Head')
+ bpy.ops.object.mode_set(mode='OBJECT')
- # TODO: Add create tail
- if tail_bones:
- bones['tail'] = self.create_tail(tail_bones)
+ # Create the parts
+ self.assign_params(spine_orgs[0], params_copy, pivot_pos=pivot_pos)
- # TEST
- bpy.ops.object.mode_set(mode='EDIT')
- eb = self.obj.data.edit_bones
+ result = [ self.instantiate_rig(basic_spine.Rig, spine_orgs[0]) ]
- self.parent_bones(bones)
- self.constrain_bones(bones)
- self.create_drivers(bones)
- self.locks_and_widgets(bones)
+ if tail_orgs:
+ self.assign_params(tail_orgs[0], params_copy, connect_chain=True)
- else:
- return
+ result += [ self.instantiate_rig(basic_tail.Rig, tail_orgs[0]) ]
- controls = [bones['neck']['ctrl'], bones['neck']['ctrl_neck']]
- controls += [bones['chest']['ctrl'], bones['hips']['ctrl']]
- controls += [bones['pivot']['ctrl']]
+ if head_orgs:
+ self.assign_params(head_orgs[0], params_copy, connect_chain=True)
- if self.use_tail:
- controls.extend(bones['tail']['ctrl'])
+ result += [ self.instantiate_rig(super_head.Rig, head_orgs[0]) ]
- # Create UI
- controls_string = ", ".join(["'" + x + "'" for x in controls])
- return [script % (
- controls_string,
- bones['pivot']['ctrl'],
- 'head_follow',
- 'head_follow',
- 'neck_follow',
- 'neck_follow',
- 'tail_follow',
- 'tail_follow',
- )]
+ return result
def add_parameters(params):
- """ Add the parameters of this rig type to the
- RigifyParameters PropertyGroup
- """
+ basic_spine.Rig.add_parameters(params)
+ basic_tail.Rig.add_parameters(params)
+ super_head.Rig.add_parameters(params)
+
params.neck_pos = bpy.props.IntProperty(
name = 'neck_position',
default = 6,
@@ -1009,19 +110,6 @@ def add_parameters(params):
description = 'Neck start position'
)
- params.pivot_pos = bpy.props.IntProperty(
- name='pivot_position',
- default=2,
- min=0,
- description='Position of the torso control and pivot point'
- )
-
- params.copy_rotation_axes = bpy.props.BoolVectorProperty(
- size=3,
- description="Automation axes",
- default=tuple([i == 0 for i in range(0, 3)])
- )
-
params.tail_pos = bpy.props.IntProperty(
name='tail_position',
default=2,
@@ -1041,9 +129,6 @@ def add_parameters(params):
description='Create head and neck bones'
)
- # Setting up extra layers for the FK and tweak
- ControlLayersOption.TWEAK.add_parameters(params)
-
def parameters_ui(layout, params):
""" Create the ui for the rig parameters."""
@@ -1074,136 +159,6 @@ def parameters_ui(layout, params):
def create_sample(obj):
- # generated by rigify.utils.write_metarig
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- bones = {}
-
- bone = arm.edit_bones.new('spine')
- bone.head[:] = 0.0000, 0.0552, 1.0099
- bone.tail[:] = 0.0000, 0.0172, 1.1573
- bone.roll = 0.0000
- bone.use_connect = False
- bones['spine'] = bone.name
-
- bone = arm.edit_bones.new('spine.001')
- bone.head[:] = 0.0000, 0.0172, 1.1573
- bone.tail[:] = 0.0000, 0.0004, 1.2929
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine']]
- bones['spine.001'] = bone.name
-
- bone = arm.edit_bones.new('spine.002')
- bone.head[:] = 0.0000, 0.0004, 1.2929
- bone.tail[:] = 0.0000, 0.0059, 1.4657
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine.001']]
- bones['spine.002'] = bone.name
-
- bone = arm.edit_bones.new('spine.003')
- bone.head[:] = 0.0000, 0.0059, 1.4657
- bone.tail[:] = 0.0000, 0.0114, 1.6582
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine.002']]
- bones['spine.003'] = bone.name
-
- bone = arm.edit_bones.new('spine.004')
- bone.head[:] = 0.0000, 0.0114, 1.6582
- bone.tail[:] = 0.0000, -0.013, 1.7197
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine.003']]
- bones['spine.004'] = bone.name
-
- bone = arm.edit_bones.new('spine.005')
- bone.head[:] = 0.0000, -0.013, 1.7197
- bone.tail[:] = 0.0000, -0.0247, 1.7813
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine.004']]
- bones['spine.005'] = bone.name
-
- bone = arm.edit_bones.new('spine.006')
- bone.head[:] = 0.0000, -0.0247, 1.7813
- bone.tail[:] = 0.0000, -0.0247, 1.9796
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones[bones['spine.005']]
- bones['spine.006'] = bone.name
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones[bones['spine']]
- pbone.rigify_type = 'spines.super_spine'
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
-
- try:
- pbone.rigify_parameters.neck_pos = 5
- except AttributeError:
- pass
- try:
- pbone.rigify_parameters.tweak_layers = [False, False, False, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False]
- except AttributeError:
- pass
- pbone = obj.pose.bones[bones['spine.001']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['spine.002']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['spine.003']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['spine.004']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['spine.005']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
- pbone = obj.pose.bones[bones['spine.006']]
- pbone.rigify_type = ''
- pbone.lock_location = (False, False, False)
- pbone.lock_rotation = (False, False, False)
- pbone.lock_rotation_w = False
- pbone.lock_scale = (False, False, False)
- pbone.rotation_mode = 'QUATERNION'
-
- bpy.ops.object.mode_set(mode='EDIT')
- for bone in arm.edit_bones:
- bone.select = False
- bone.select_head = False
- bone.select_tail = False
- for b in bones:
- bone = arm.edit_bones[bones[b]]
- bone.select = True
- bone.select_head = True
- bone.select_tail = True
- arm.edit_bones.active = bone
+ bones = basic_spine.create_sample(obj)
+ basic_tail.create_sample(obj, parent=bones['spine'])
+ super_head.create_sample(obj, parent=bones['spine.003'])
diff --git a/rigify/rigs/utils.py b/rigify/rigs/utils.py
index c08cb8f9..12dcbb26 100644
--- a/rigify/rigs/utils.py
+++ b/rigify/rigs/utils.py
@@ -1,8 +1,158 @@
-from .limbs.super_limb import Rig as LimbRig
from ..utils import connected_children_names
+from ..utils.naming import strip_mch, strip_org, make_mechanism_name
import re
+def get_future_names_arm(bones):
+ if len(bones) != 3:
+ return
+
+ names = dict()
+
+ uarm = strip_mch(strip_org(bones[0].name))
+ farm = strip_mch(strip_org(bones[1].name))
+ hand = strip_mch(strip_org(bones[2].name))
+
+ suffix=''
+ if uarm[-2:] == '.L' or uarm[-2:] == '.R':
+ suffix = uarm[-2:]
+ uarm = uarm.rstrip(suffix)
+ farm = farm.rstrip(suffix)
+ hand = hand.rstrip(suffix)
+
+ # the following is declared in rig_ui
+ # controls = ['upper_arm_ik.L', 'upper_arm_fk.L', 'forearm_fk.L', 'hand_fk.L', 'hand_ik.L', 'MCH-hand_fk.L',
+ # 'upper_arm_parent.L']
+ # tweaks = ['upper_arm_tweak.L.001', 'forearm_tweak.L', 'forearm_tweak.L.001']
+ # ik_ctrl = ['hand_ik.L', 'MCH-upper_arm_ik.L', 'MCH-upper_arm_ik_target.L']
+ # fk_ctrl = 'upper_arm_fk.L'
+ # parent = 'upper_arm_parent.L'
+ # hand_fk = 'hand_fk.L'
+ # pole = 'upper_arm_ik_target.L'
+
+ names['controls'] = [uarm + '_ik', uarm + '_fk', farm + '_fk', hand + '_fk', hand + '_ik',
+ make_mechanism_name(hand + '_fk'), uarm + '_parent']
+ names['ik_ctrl'] = [hand + '_ik', make_mechanism_name(uarm) + '_ik', make_mechanism_name(uarm) + '_ik_target']
+ names['fk_ctrl'] = uarm + '_fk' + suffix
+ names['parent'] = uarm + '_parent' + suffix
+ names['hand_fk'] = hand + '_fk' + suffix
+ names['pole'] = uarm + '_ik_target' + suffix
+ names['limb_type'] = 'arm'
+
+ if suffix:
+ for i, name in enumerate(names['controls']):
+ names['controls'][i] = name + suffix
+ for i, name in enumerate(names['ik_ctrl']):
+ names['ik_ctrl'][i] = name + suffix
+
+ return names
+
+
+def get_future_names_leg(bones):
+ if len(bones) != 4:
+ return
+
+ names = dict()
+
+ thigh = strip_mch(strip_org(bones[0].name))
+ shin = strip_mch(strip_org(bones[1].name))
+ foot = strip_mch(strip_org(bones[2].name))
+ toe = strip_mch(strip_org(bones[3].name))
+
+ suffix = ''
+ if thigh[-2:] == '.L' or thigh[-2:] == '.R':
+ suffix = thigh[-2:]
+ thigh = thigh.rstrip(suffix)
+ shin = shin.rstrip(suffix)
+ foot = foot.rstrip(suffix)
+ toe = toe.rstrip(suffix)
+
+ # the following is declared in rig_ui
+ # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R',
+ # 'MCH-foot_fk.R', 'thigh_parent.R']
+ # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001']
+ # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R']
+ # fk_ctrl = 'thigh_fk.R'
+ # parent = 'thigh_parent.R'
+ # foot_fk = 'foot_fk.R'
+ # pole = 'thigh_ik_target.R'
+
+ names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik',
+ foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent']
+ names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target']
+ names['fk_ctrl'] = thigh + '_fk' + suffix
+ names['parent'] = thigh + '_parent' + suffix
+ names['foot_fk'] = foot + '_fk' + suffix
+ names['pole'] = thigh + '_ik_target' + suffix
+
+ names['limb_type'] = 'leg'
+
+ if suffix:
+ for i, name in enumerate(names['controls']):
+ names['controls'][i] = name + suffix
+ for i, name in enumerate(names['ik_ctrl']):
+ names['ik_ctrl'][i] = name + suffix
+
+ return names
+
+
+def get_future_names_paw(bones):
+ if len(bones) != 4:
+ return
+
+ names = dict()
+
+ thigh = strip_mch(strip_org(bones[0].name))
+ shin = strip_mch(strip_org(bones[1].name))
+ foot = strip_mch(strip_org(bones[2].name))
+ toe = strip_mch(strip_org(bones[3].name))
+
+ suffix = ''
+ if thigh[-2:] == '.L' or thigh[-2:] == '.R':
+ suffix = thigh[-2:]
+ thigh = thigh.rstrip(suffix)
+ shin = shin.rstrip(suffix)
+ foot = foot.rstrip(suffix)
+ toe = toe.rstrip(suffix)
+
+ # the following is declared in rig_ui
+ # controls = ['thigh_ik.R', 'thigh_fk.R', 'shin_fk.R', 'foot_fk.R', 'toe.R', 'foot_heel_ik.R', 'foot_ik.R',
+ # 'MCH-foot_fk.R', 'thigh_parent.R']
+ # tweaks = ['thigh_tweak.R.001', 'shin_tweak.R', 'shin_tweak.R.001']
+ # ik_ctrl = ['foot_ik.R', 'MCH-thigh_ik.R', 'MCH-thigh_ik_target.R']
+ # fk_ctrl = 'thigh_fk.R'
+ # parent = 'thigh_parent.R'
+ # foot_fk = 'foot_fk.R'
+ # pole = 'thigh_ik_target.R'
+
+ names['controls'] = [thigh + '_ik', thigh + '_fk', shin + '_fk', foot + '_fk', toe, foot + '_heel_ik',
+ foot + '_ik', make_mechanism_name(foot + '_fk'), thigh + '_parent']
+ names['ik_ctrl'] = [foot + '_ik', make_mechanism_name(thigh) + '_ik', make_mechanism_name(thigh) + '_ik_target']
+ names['fk_ctrl'] = thigh + '_fk' + suffix
+ names['parent'] = thigh + '_parent' + suffix
+ names['foot_fk'] = foot + '_fk' + suffix
+ names['pole'] = thigh + '_ik_target' + suffix
+
+ names['limb_type'] = 'paw'
+
+ if suffix:
+ for i, name in enumerate(names['controls']):
+ names['controls'][i] = name + suffix
+ for i, name in enumerate(names['ik_ctrl']):
+ names['ik_ctrl'][i] = name + suffix
+
+ return names
+
+
+def get_future_names(bones):
+ if bones[0].rigify_parameters.limb_type == 'arm':
+ return get_future_names_arm(bones)
+ elif bones[0].rigify_parameters.limb_type == 'leg':
+ return get_future_names_leg(bones)
+ elif bones[0].rigify_parameters.limb_type == 'paw':
+ return get_future_names_paw(bones)
+
+
def get_limb_generated_names(rig):
pbones = rig.pose.bones
@@ -16,6 +166,6 @@ def get_limb_generated_names(rig):
for child in children:
if re.match('^ORG', child) or re.match('^MCH', child):
super_limb_orgs.append(pbones[child])
- names[b.name] = LimbRig.get_future_names(super_limb_orgs)
+ names[b.name] = get_future_names(super_limb_orgs)
return names