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/spines/super_spine.py
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/spines/super_spine.py')
-rw-r--r--rigify/rigs/spines/super_spine.py1205
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'])