Rigify: add more parent switching and 2.81 inherit scale features.

- Add a parent switch to the main spine control, to allow using the
  key baking operator to convert between moving and fixed root bone.
- Add hips, chest and head as parents for children of the spine.
- Use 'Fix Shear' Inherit Scale and 'Make Uniform' Copy Scale in limbs.
- Switch code to use the new inherit_scale parameter of set_bone_parent.
- Allow local matrices in adjust_widget_transform_mesh.
This commit is contained in:
Alexander Gavrilov 2019-10-01 09:59:51 +03:00
parent e57714f3a2
commit 50c493fb22
6 changed files with 60 additions and 32 deletions

View File

@ -218,7 +218,7 @@ class BaseLimbRig(BaseRig):
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)
self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='FIX_SHEAR')
@stage.configure_bones
def configure_mch_follow_bone(self):
@ -232,8 +232,9 @@ class BaseLimbRig(BaseRig):
def rig_mch_follow_bone(self):
mch = self.bones.mch.follow
self.make_constraint(mch, 'COPY_SCALE', 'root', use_make_uniform=True)
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')])
@ -311,7 +312,7 @@ class BaseLimbRig(BaseRig):
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)
self.set_bone_parent(parent_mch, prev_ctrl, use_connect=True, inherit_scale='NONE')
@stage.rig_bones
def rig_fk_parent_chain(self):
@ -320,7 +321,7 @@ class BaseLimbRig(BaseRig):
def rig_fk_parent_bone(self, i, parent_mch, org):
if i == 2:
self.make_constraint(parent_mch, 'COPY_SCALE', 'root')
self.make_constraint(parent_mch, 'COPY_SCALE', 'root', use_make_uniform=True)
####################################################
@ -691,7 +692,7 @@ class BaseLimbRig(BaseRig):
self.make_constraint(tweak, 'DAMPED_TRACK', next_tweak)
elif entry.seg_idx is not None:
self.make_constraint(tweak, 'COPY_SCALE', 'root')
self.make_constraint(tweak, 'COPY_SCALE', 'root', use_make_uniform=True)
####################################################

View File

@ -115,17 +115,21 @@ class Rig(BaseRig):
@stage.parent_bones
def parent_master_control(self):
self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone)
self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone, inherit_scale='AVERAGE')
if self.make_secondary:
self.set_bone_parent(self.bones.ctrl.secondary, self.rig_parent_bone)
self.set_bone_parent(self.bones.ctrl.secondary, self.rig_parent_bone, inherit_scale='AVERAGE')
@stage.configure_bones
def configure_master_control(self):
self.copy_bone_properties(self.bones.org[-1], self.bones.ctrl.master)
self.configure_control_bone(self.bones.ctrl.master, self.bones.org[-1])
if self.make_secondary:
self.copy_bone_properties(self.bones.org[0], self.bones.ctrl.secondary)
self.configure_control_bone(self.bones.ctrl.secondary, self.bones.org[0])
def configure_control_bone(self, ctrl, org):
self.copy_bone_properties(org, ctrl)
self.get_bone(ctrl).lock_scale = (True, True, True)
@stage.generate_widgets
def make_master_control_widgets(self):
@ -179,8 +183,7 @@ class Rig(BaseRig):
@stage.parent_bones
def parent_org_chain(self):
for org in self.bones.org:
self.set_bone_parent(org, self.rig_parent_bone)
self.get_bone(org).inherit_scale = 'NONE'
self.set_bone_parent(org, self.rig_parent_bone, inherit_scale='NONE')
@stage.rig_bones
def rig_org_chain(self):

View File

@ -64,11 +64,26 @@ class BaseSpineRig(TweakChainRig):
align_bone_to_axis(self.obj, name, 'y', length=self.length * 0.6)
SwitchParentBuilder(self.generator).register_parent(self, name)
self.build_parent_switch(name)
def build_parent_switch(self, master_name):
pbuilder = SwitchParentBuilder(self.generator)
pbuilder.register_parent(self, master_name, name='Torso')
pbuilder.build_child(
self, master_name, exclude_self=True,
prop_id='torso_parent', prop_name='Torso Parent',
controls=lambda: self.bones.flatten('ctrl'),
)
self.register_parent_bones(pbuilder)
def register_parent_bones(self, pbuilder):
pbuilder.register_parent(self, self.bones.org[0], name='Hips', exclude_self=True)
pbuilder.register_parent(self, self.bones.org[-1], name='Chest', exclude_self=True)
@stage.parent_bones
def parent_master_control(self):
self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone)
pass
@stage.configure_bones
def configure_master_control(self):

View File

@ -26,6 +26,7 @@ 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.switch_parent import SwitchParentBuilder
from ...utils.misc import map_list
from ...base_rig import stage
@ -253,8 +254,7 @@ class Rig(BaseHeadTailRig):
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).inherit_scale = 'NONE'
self.set_bone_parent(bone, mch.stretch, inherit_scale='NONE')
@stage.rig_bones
def rig_mch_chain(self):
@ -318,6 +318,12 @@ class Rig(BaseHeadTailRig):
####################################################
# ORG and DEF bones
@stage.generate_bones
def register_parent_bones(self):
rig = self.rigify_parent or self
builder = SwitchParentBuilder(self.generator)
builder.register_parent(rig, self.bones.org[-1], name='Head', exclude_self=True)
@stage.configure_bones
def configure_bbone_chain(self):
self.get_bone(self.bones.deform[-1]).bone.bbone_segments = 1

View File

@ -96,6 +96,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
use_parent_mch Create an intermediate MCH bone for the constraints and parent the child to it.
select_parent Select the specified bone instead of the last one.
ignore_global Ignore the is_global flag of potential parents.
exclude_self Ignore parents registered by the rig itself.
context_rig Rig to use for selecting parents.
prop_bone Name of the bone to add the property to.
@ -158,7 +159,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
child_option_table = {
'extra_parents': None,
'prop_bone': None, 'prop_id': None, 'prop_name': None, 'controls': None,
'select_parent': None, 'ignore_global': False, 'context_rig': None,
'select_parent': None, 'ignore_global': False, 'exclude_self': False, 'context_rig': None,
'ctrl_bone': None,
'no_fix_location': False, 'no_fix_rotation': False, 'no_fix_scale': False,
'copy_location': None, 'copy_rotation': None, 'copy_scale': None,
@ -186,7 +187,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
for parent in self.parent_list:
if parent['rig'] is child_rig:
if parent['exclude_self']:
if parent['exclude_self'] or child['exclude_self']:
continue
elif parent['is_global'] and not child['ignore_global']:
# Can't use parents from own children, even if global (cycle risk)
@ -218,8 +219,7 @@ class SwitchParentBuilder(GeneratorPlugin, MechanismUtilityMixin):
# Parent child to the MCH proxy
if mch != child['bone']:
rig.set_bone_parent(child['bone'], mch)
rig.get_bone(child['bone']).inherit_scale = child['inherit_scale']
rig.set_bone_parent(child['bone'], mch, inherit_scale=child['inherit_scale'])
def configure_bones(self):
for child in self.child_list:

View File

@ -50,16 +50,8 @@ def obj_to_bone(obj, rig, bone_name, bone_transform_name=None):
elif bone.custom_shape_transform:
bone = bone.custom_shape_transform
mat = rig.matrix_world @ bone.bone.matrix_local
obj.location = mat.to_translation()
obj.rotation_mode = 'XYZ'
obj.rotation_euler = mat.to_euler()
scl = mat.to_scale()
scl_avg = (scl[0] + scl[1] + scl[2]) / 3
obj.scale = (scale * scl_avg), (scale * scl_avg), (scale * scl_avg)
obj.matrix_basis = rig.matrix_world @ bone.bone.matrix_local @ Matrix.Scale(scale, 4)
def create_widget(rig, bone_name, bone_transform_name=None):
@ -159,11 +151,22 @@ def adjust_widget_axis(obj, axis='y', offset=0.0):
vert.co = matrix @ vert.co
def adjust_widget_transform(obj, matrix):
"""Adjust the generated widget by applying a world space correction matrix to the mesh."""
def adjust_widget_transform_mesh(obj, matrix, local=None):
"""Adjust the generated widget by applying a correction matrix to the mesh.
If local is false, the matrix is in world space.
If local is True, it's in the local space of the widget.
If local is a bone, it's in the local space of the bone.
"""
if obj:
obmat = obj.matrix_basis
matrix = obmat.inverted() @ matrix @ obmat
if local is not True:
if local:
assert isinstance(local, bpy.types.PoseBone)
bonemat = local.id_data.matrix_world @ local.bone.matrix_local
matrix = bonemat @ matrix @ bonemat.inverted()
obmat = obj.matrix_basis
matrix = obmat.inverted() @ matrix @ obmat
obj.data.transform(matrix)