diff options
author | Alexander Gavrilov <angavrilov@gmail.com> | 2019-09-14 09:17:30 +0300 |
---|---|---|
committer | Alexander Gavrilov <angavrilov@gmail.com> | 2019-09-14 09:30:00 +0300 |
commit | 8b1df843703fdb51ffa5758625c117c4f10bc6dd (patch) | |
tree | 949e84f80116132eab3ad5f3bac46e745c3a9195 /rigify/rigs/spines/super_spine.py | |
parent | 9b693a6be0aa2b0b4825d30ac5034655dce9c0dd (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/spines/super_spine.py')
-rw-r--r-- | rigify/rigs/spines/super_spine.py | 1205 |
1 files changed, 80 insertions, 1125 deletions
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']) |