Rigify: annotate and cleanup warnings in limb rigs.
- Fix uses of BaseRig.ToplevelBones to work correctly in subclasses. - Enhance parameter annotations for bone and mechanism mixins. - Annotate types and fix warnings in limb rigs.
This commit is contained in:
parent
b4adc4100d
commit
4e7ed6259a
|
@ -180,9 +180,13 @@ class BaseRigMixin(RaiseErrorMixin, BoneUtilityMixin, MechanismUtilityMixin):
|
|||
class MchBones(TypedBoneDict):
|
||||
pass
|
||||
|
||||
# Subclass and use the above CtrlBones and MchBones classes in overrides.
|
||||
# It is necessary to reference them via absolute strings, e.g. 'Rig.CtrlBones',
|
||||
# because when using just CtrlBones the annotation won't work fully in subclasses
|
||||
# of the rig class in PyCharm (no warnings about unknown attribute access).
|
||||
bones: ToplevelBones[str | list[str] | BoneDict,
|
||||
str | list[str] | BoneDict, # Use CtrlBones in overrides
|
||||
str | list[str] | BoneDict, # Use MchBones in overrides
|
||||
str | list[str] | BoneDict,
|
||||
str | list[str] | BoneDict,
|
||||
str | list[str] | BoneDict]
|
||||
|
||||
|
||||
|
|
|
@ -10,4 +10,5 @@ def _install_path():
|
|||
import os
|
||||
return os.path.join(bpy.utils.script_path_user(), 'rigify')
|
||||
|
||||
__path__ = [ _install_path() ]
|
||||
|
||||
__path__ = [_install_path()]
|
||||
|
|
|
@ -21,7 +21,12 @@ class Rig(BaseRig):
|
|||
class MchBones(BaseRig.MchBones):
|
||||
pass
|
||||
|
||||
bones: BaseRig.ToplevelBones[str, CtrlBones, MchBones, str]
|
||||
bones: BaseRig.ToplevelBones[
|
||||
str,
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
str
|
||||
]
|
||||
|
||||
make_control: bool
|
||||
make_pivot: bool
|
||||
|
|
|
@ -45,7 +45,12 @@ class SimpleChainRig(BaseRig):
|
|||
class MchBones(BaseRig.MchBones):
|
||||
pass
|
||||
|
||||
bones: BaseRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: BaseRig.ToplevelBones[
|
||||
list[str],
|
||||
'SimpleChainRig.CtrlBones',
|
||||
'SimpleChainRig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
##############################
|
||||
# Control chain
|
||||
|
@ -130,7 +135,12 @@ class TweakChainRig(SimpleChainRig):
|
|||
class MchBones(SimpleChainRig.MchBones):
|
||||
pass
|
||||
|
||||
bones: BaseRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: BaseRig.ToplevelBones[
|
||||
list[str],
|
||||
'TweakChainRig.CtrlBones',
|
||||
'TweakChainRig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
##############################
|
||||
# Tweak chain
|
||||
|
|
|
@ -7,6 +7,7 @@ from ...utils import strip_org, make_deformer_name, connected_children_names
|
|||
from ...utils import create_chain_widget
|
||||
from ...utils import make_mechanism_name
|
||||
from ...utils import ControlLayersOption
|
||||
from ...utils.mechanism import make_property, make_driver
|
||||
from ..limbs.limb_utils import get_bone_name
|
||||
|
||||
|
||||
|
@ -306,9 +307,11 @@ class Rig:
|
|||
eb[twk].parent = eb[bones['chain']['mch_ctrl'][i+1]]
|
||||
eb[twk].inherit_scale = 'NONE'
|
||||
|
||||
eb[bones['chain']['ctrl'][0]].parent = eb[bones['chain']['mch_ctrl'][0]] if bones['chain']['mch_ctrl'] else None
|
||||
eb[bones['chain']['ctrl'][0]].parent =\
|
||||
eb[bones['chain']['mch_ctrl'][0]] if bones['chain']['mch_ctrl'] else None
|
||||
eb[bones['chain']['ctrl'][0]].inherit_scale = 'NONE'
|
||||
eb[bones['chain']['ctrl'][1]].parent = eb[bones['chain']['mch_ctrl'][-1]] if bones['chain']['mch_ctrl'] else None
|
||||
eb[bones['chain']['ctrl'][1]].parent =\
|
||||
eb[bones['chain']['mch_ctrl'][-1]] if bones['chain']['mch_ctrl'] else None
|
||||
eb[bones['chain']['ctrl'][1]].inherit_scale = 'NONE'
|
||||
|
||||
if 'pivot' in bones.keys():
|
||||
|
@ -405,8 +408,8 @@ class Rig:
|
|||
if 'pivot' in bones.keys():
|
||||
step = 2/(len(self.org_bones))
|
||||
for i, b in enumerate(mch_ctrl):
|
||||
xval = i*step
|
||||
influence = 2*xval - xval**2 # parabolic influence of pivot
|
||||
x_val = i*step
|
||||
influence = 2*x_val - x_val**2 # parabolic influence of pivot
|
||||
if (i != 0) and (i != len(mch_ctrl)-1):
|
||||
self.make_constraint(b, {
|
||||
'constraint': 'COPY_TRANSFORMS',
|
||||
|
@ -493,16 +496,19 @@ class Rig:
|
|||
|
||||
for prop in props:
|
||||
if prop == 'neck_follow':
|
||||
defval = 0.5
|
||||
def_val = 0.5
|
||||
else:
|
||||
defval = 0.0
|
||||
def_val = 0.0
|
||||
|
||||
make_property(torso, prop, defval)
|
||||
make_property(torso, prop, def_val)
|
||||
|
||||
# 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])
|
||||
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')
|
||||
|
@ -603,22 +609,22 @@ class Rig:
|
|||
all_ctrls.extend(bones['chain']['ctrl'])
|
||||
all_ctrls.extend(bones['chain']['tweak'])
|
||||
all_ctrls.extend(bones['chain']['conv'])
|
||||
for bname in eb.keys():
|
||||
if bname not in all_ctrls and (bname.startswith('tweak') or 'ctrl' in bname):
|
||||
other_ctrls.append(bname)
|
||||
for bone_name in eb.keys():
|
||||
if bone_name not in all_ctrls and (bone_name.startswith('tweak') or 'ctrl' in bone_name):
|
||||
other_ctrls.append(bone_name)
|
||||
|
||||
for bname in other_ctrls:
|
||||
if eb[bname].head == head_start:
|
||||
for bone_name in other_ctrls:
|
||||
if eb[bone_name].head == head_start:
|
||||
for child in eb[bones['chain']['ctrl'][0]].children:
|
||||
child.parent = eb[bname]
|
||||
child.parent = eb[bone_name]
|
||||
eb.remove(eb[bones['chain']['ctrl'][0]])
|
||||
bones['chain']['ctrl'][0] = bname
|
||||
bones['chain']['ctrl'][0] = bone_name
|
||||
break
|
||||
|
||||
for bname in other_ctrls:
|
||||
if eb[bname].head == head_tip:
|
||||
for bone_name in other_ctrls:
|
||||
if eb[bone_name].head == head_tip:
|
||||
eb.remove(eb[bones['chain']['ctrl'][-1]])
|
||||
bones['chain']['ctrl'][-1] = bname
|
||||
bones['chain']['ctrl'][-1] = bone_name
|
||||
break
|
||||
|
||||
def generate(self):
|
||||
|
@ -647,7 +653,7 @@ class Rig:
|
|||
self.parent_bones(bones)
|
||||
|
||||
# ctrls snapping pass
|
||||
#self.aggregate_ctrls(bones)
|
||||
# self.aggregate_ctrls(bones)
|
||||
|
||||
self.constrain_bones(bones)
|
||||
self.stick_to_bendy_bones(bones)
|
||||
|
@ -715,10 +721,10 @@ def add_parameters(params):
|
|||
)
|
||||
|
||||
params.bbones = bpy.props.IntProperty(
|
||||
name = 'B-Bone Segments',
|
||||
default = 10,
|
||||
min = 1,
|
||||
description = 'Number of B-Bone segments'
|
||||
name='B-Bone Segments',
|
||||
default=10,
|
||||
min=1,
|
||||
description='Number of B-Bone segments'
|
||||
)
|
||||
|
||||
params.wgt_offset = bpy.props.FloatProperty(
|
||||
|
@ -759,8 +765,8 @@ def parameters_ui(layout, params):
|
|||
r = layout.row()
|
||||
r.prop(params, 'def_parenting')
|
||||
|
||||
#r = layout.row()
|
||||
#r.prop(params, 'cluster_ctrls')
|
||||
# r = layout.row()
|
||||
# r.prop(params, 'cluster_ctrls')
|
||||
|
||||
ControlLayersOption.TWEAK.parameters_ui(layout, params)
|
||||
|
||||
|
@ -808,7 +814,10 @@ def create_sample(obj):
|
|||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone.bone.layers = [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, False, False, False, False]
|
||||
pbone.bone.layers = [
|
||||
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, False, False, False, False]
|
||||
pbone = obj.pose.bones[bones['spine.001']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
|
@ -816,7 +825,10 @@ def create_sample(obj):
|
|||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone.bone.layers = [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, False, False, False, False]
|
||||
pbone.bone.layers = [
|
||||
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, False, False, False, False]
|
||||
pbone = obj.pose.bones[bones['spine.002']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
|
@ -824,7 +836,10 @@ def create_sample(obj):
|
|||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone.bone.layers = [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, False, False, False, False]
|
||||
pbone.bone.layers = [
|
||||
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, False, False, False, False]
|
||||
pbone = obj.pose.bones[bones['spine.003']]
|
||||
pbone.rigify_type = ''
|
||||
pbone.lock_location = (False, False, False)
|
||||
|
@ -832,7 +847,10 @@ def create_sample(obj):
|
|||
pbone.lock_rotation_w = False
|
||||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
pbone.bone.layers = [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, False, False, False, False]
|
||||
pbone.bone.layers = [
|
||||
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, False, False, False, False]
|
||||
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
for bone in arm.edit_bones:
|
||||
|
|
|
@ -21,9 +21,10 @@ class Rig(BaseLimbRig):
|
|||
|
||||
min_valid_orgs = max_valid_orgs = 3
|
||||
|
||||
make_wrist_pivot: bool
|
||||
|
||||
def initialize(self):
|
||||
super().initialize()
|
||||
|
||||
self.make_wrist_pivot = self.params.make_ik_wrist_pivot
|
||||
|
||||
def prepare_bones(self):
|
||||
|
@ -40,6 +41,22 @@ class Rig(BaseLimbRig):
|
|||
|
||||
align_bone_z_axis(self.obj, orgs[2], axis)
|
||||
|
||||
####################################################
|
||||
# BONES
|
||||
|
||||
class CtrlBones(BaseLimbRig.CtrlBones):
|
||||
ik_wrist: str # Wrist pivot control (if enabled)
|
||||
|
||||
class MchBones(BaseLimbRig.MchBones):
|
||||
ik_wrist: str # Wrist pivot control output (if enabled)
|
||||
|
||||
bones: BaseLimbRig.ToplevelBones[
|
||||
'Rig.OrgBones',
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Overrides
|
||||
|
||||
|
@ -104,7 +121,7 @@ class Rig(BaseLimbRig):
|
|||
# Settings
|
||||
|
||||
@classmethod
|
||||
def add_parameters(self, params):
|
||||
def add_parameters(cls, params):
|
||||
super().add_parameters(params)
|
||||
|
||||
params.make_ik_wrist_pivot = bpy.props.BoolProperty(
|
||||
|
@ -113,10 +130,10 @@ class Rig(BaseLimbRig):
|
|||
)
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params):
|
||||
def parameters_ui(cls, layout, params, end='Hand'):
|
||||
layout.prop(params, "make_ik_wrist_pivot")
|
||||
|
||||
super().parameters_ui(layout, params, 'Hand')
|
||||
super().parameters_ui(layout, params, end)
|
||||
|
||||
|
||||
def create_sample(obj, limb=False):
|
||||
|
@ -155,11 +172,17 @@ def create_sample(obj, limb=False):
|
|||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
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]
|
||||
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]
|
||||
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:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import bpy
|
||||
|
||||
from ...utils.bones import align_bone_roll, put_bone, copy_bone_position, flip_bone
|
||||
from ...utils.bones import align_bone_roll, put_bone, copy_bone_position
|
||||
from ...utils.naming import make_derived_name
|
||||
from ...utils.misc import map_list
|
||||
|
||||
|
@ -18,17 +18,23 @@ class Rig(pawRig):
|
|||
"""Front paw rig with special IK automation."""
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# mch:
|
||||
# ik2_chain[2]
|
||||
# Second IK system (pre-driving heel)
|
||||
# heel_track
|
||||
# Bone tracking IK2 to rotate heel
|
||||
# heel_parent
|
||||
# Parent of the heel control
|
||||
#
|
||||
####################################################
|
||||
# BONES
|
||||
|
||||
class CtrlBones(pawRig.CtrlBones):
|
||||
pass
|
||||
|
||||
class MchBones(pawRig.MchBones):
|
||||
ik2_chain: list[str] # Second IK system (pre-driving heel)
|
||||
ik2_target: str # Second IK system target (if heel2)
|
||||
heel_track: str # Bone tracking IK2 to rotate heel
|
||||
heel_parent: str # Parent of the heel control
|
||||
|
||||
bones: pawRig.ToplevelBones[
|
||||
pawRig.OrgBones,
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
@ -50,7 +56,6 @@ class Rig(pawRig):
|
|||
def get_ik_pole_parents(self):
|
||||
return [(self.get_ik2_target_bone(), self.bones.ctrl.ik)]
|
||||
|
||||
|
||||
####################################################
|
||||
# Second IK system (pre-driving heel)
|
||||
|
||||
|
@ -72,10 +77,10 @@ class Rig(pawRig):
|
|||
self.get_bone(chain[1]).tail = self.get_bone(orgs[2]).tail
|
||||
align_bone_roll(self.obj, chain[1], orgs[1])
|
||||
|
||||
def make_ik2_mch_target_bone(self, orgs):
|
||||
def make_ik2_mch_target_bone(self, orgs: list[str]):
|
||||
return self.copy_bone(orgs[3], make_derived_name(orgs[0], 'mch', '_ik2_target'), scale=1/2)
|
||||
|
||||
def make_ik2_mch_bone(self, i, org):
|
||||
def make_ik2_mch_bone(self, _i: int, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik2'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -91,7 +96,7 @@ class Rig(pawRig):
|
|||
for i, mch in enumerate(self.bones.mch.ik2_chain):
|
||||
self.configure_ik2_mch_bone(i, mch)
|
||||
|
||||
def configure_ik2_mch_bone(self, i, mch):
|
||||
def configure_ik2_mch_bone(self, i: int, mch: str):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 1:
|
||||
|
@ -103,7 +108,6 @@ class Rig(pawRig):
|
|||
target_bone = self.get_ik2_target_bone()
|
||||
self.rig_ik_mch_end_bone(self.bones.mch.ik2_chain[-1], target_bone, self.bones.ctrl.ik_pole)
|
||||
|
||||
|
||||
####################################################
|
||||
# Heel tracking from IK2
|
||||
|
||||
|
@ -150,28 +154,27 @@ class Rig(pawRig):
|
|||
# Complete the parent chain.
|
||||
self.set_bone_parent(self.bones.mch.heel_parent, self.bones.mch.heel_track)
|
||||
|
||||
|
||||
####################################################
|
||||
# Settings
|
||||
|
||||
@classmethod
|
||||
def add_parameters(self, params):
|
||||
def add_parameters(cls, params):
|
||||
super().add_parameters(params)
|
||||
|
||||
params.front_paw_heel_influence = bpy.props.FloatProperty(
|
||||
name = 'Heel IK Influence',
|
||||
default = 0.8,
|
||||
min = 0,
|
||||
max = 1,
|
||||
description = 'Influence of the secondary IK on the heel control rotation'
|
||||
name='Heel IK Influence',
|
||||
default=0.8,
|
||||
min=0,
|
||||
max=1,
|
||||
description='Influence of the secondary IK on the heel control rotation'
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params):
|
||||
def parameters_ui(cls, layout, params, end='Claw'):
|
||||
r = layout.row()
|
||||
r.prop(params, "front_paw_heel_influence", slider=True)
|
||||
|
||||
super().parameters_ui(layout, params)
|
||||
super().parameters_ui(layout, params, end)
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
|
@ -222,11 +225,17 @@ def create_sample(obj):
|
|||
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]
|
||||
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]
|
||||
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['front_shin.L']]
|
||||
|
|
|
@ -28,6 +28,13 @@ class Rig(BaseLimbRig):
|
|||
|
||||
min_valid_orgs = max_valid_orgs = 4
|
||||
|
||||
pivot_type: str
|
||||
heel_euler_order: str
|
||||
use_ik_toe: bool
|
||||
|
||||
ik_matrix: Matrix
|
||||
roll_matrix: Matrix
|
||||
|
||||
def find_org_bones(self, bone):
|
||||
bones = super().find_org_bones(bone)
|
||||
|
||||
|
@ -86,25 +93,26 @@ class Rig(BaseLimbRig):
|
|||
self.roll_matrix = matrix_from_axis_pair(ik_y_axis, foot_x, self.main_axis)
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# org:
|
||||
# heel:
|
||||
# Heel location marker bone
|
||||
# ctrl:
|
||||
# ik_spin:
|
||||
# Toe spin control.
|
||||
# heel:
|
||||
# Foot roll control
|
||||
# ik_toe:
|
||||
# If enabled, toe control for IK chain.
|
||||
# mch:
|
||||
# heel[]:
|
||||
# Chain of bones implementing foot roll.
|
||||
# ik_toe_parent:
|
||||
# If using split IK toe, parent of the IK toe control.
|
||||
#
|
||||
####################################################
|
||||
# BONES
|
||||
|
||||
class OrgBones(BaseLimbRig.OrgBones):
|
||||
heel: str # Heel location marker bone
|
||||
|
||||
class CtrlBones(BaseLimbRig.CtrlBones):
|
||||
ik_spin: str # Toe spin control
|
||||
heel: str # Foot roll control
|
||||
ik_toe: str # If enabled, toe control for IK chain.
|
||||
|
||||
class MchBones(BaseLimbRig.MchBones):
|
||||
heel: list[str] # Chain of bones implementing foot roll.
|
||||
ik_toe_parent: str # If using split IK toe, parent of the IK toe control.
|
||||
|
||||
bones: BaseLimbRig.ToplevelBones[
|
||||
'Rig.OrgBones',
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
@ -162,7 +170,7 @@ class Rig(BaseLimbRig):
|
|||
if self.pivot_type == 'ANKLE_TOE':
|
||||
self.bones.ctrl.ik_spin = self.make_ik_spin_bone(self.bones.org.main)
|
||||
|
||||
def make_ik_spin_bone(self, orgs):
|
||||
def make_ik_spin_bone(self, orgs: list[str]):
|
||||
name = self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_spin_ik'))
|
||||
put_bone(self.obj, name, self.get_bone(orgs[3]).head, matrix=self.ik_matrix, scale=0.5)
|
||||
return name
|
||||
|
@ -176,8 +184,8 @@ class Rig(BaseLimbRig):
|
|||
def make_ik_spin_control_widget(self):
|
||||
if self.pivot_type == 'ANKLE_TOE':
|
||||
obj = create_ballsocket_widget(self.obj, self.bones.ctrl.ik_spin, size=0.75)
|
||||
rotfix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper())
|
||||
adjust_widget_transform_mesh(obj, rotfix, local=True)
|
||||
rot_fix = Matrix.Rotation(math.pi/2, 4, self.main_axis.upper())
|
||||
adjust_widget_transform_mesh(obj, rot_fix, local=True)
|
||||
|
||||
####################################################
|
||||
# Heel control
|
||||
|
@ -214,10 +222,10 @@ class Rig(BaseLimbRig):
|
|||
self.bones.ctrl.ik_toe = self.make_ik_toe_control_bone(toe)
|
||||
self.bones.mch.ik_toe_parent = self.make_ik_toe_parent_mch_bone(toe)
|
||||
|
||||
def make_ik_toe_control_bone(self, org):
|
||||
def make_ik_toe_control_bone(self, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'ctrl', '_ik'))
|
||||
|
||||
def make_ik_toe_parent_mch_bone(self, org):
|
||||
def make_ik_toe_parent_mch_bone(self, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik_parent'), scale=1/3)
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -255,8 +263,7 @@ class Rig(BaseLimbRig):
|
|||
orgs = self.bones.org.main
|
||||
self.bones.mch.heel = self.make_roll_mch_bones(orgs[2], orgs[3], self.bones.org.heel)
|
||||
|
||||
def make_roll_mch_bones(self, foot, toe, heel):
|
||||
foot_bone = self.get_bone(foot)
|
||||
def make_roll_mch_bones(self, foot: str, toe: str, heel: str):
|
||||
heel_bone = self.get_bone(heel)
|
||||
|
||||
heel_middle = (heel_bone.head + heel_bone.tail) / 2
|
||||
|
@ -273,7 +280,7 @@ class Rig(BaseLimbRig):
|
|||
put_bone(self.obj, rock1, heel_bone.tail, matrix=self.roll_matrix, scale=0.5)
|
||||
put_bone(self.obj, rock2, heel_bone.head, matrix=self.roll_matrix, scale=0.5)
|
||||
|
||||
return [ rock2, rock1, roll2, roll1, result ]
|
||||
return [rock2, rock1, roll2, roll1, result]
|
||||
|
||||
@stage.parent_bones
|
||||
def parent_roll_mch_chain(self):
|
||||
|
@ -285,7 +292,7 @@ class Rig(BaseLimbRig):
|
|||
def rig_roll_mch_chain(self):
|
||||
self.rig_roll_mch_bones(self.bones.mch.heel, self.bones.ctrl.heel, self.bones.org.heel)
|
||||
|
||||
def rig_roll_mch_bones(self, chain, heel, org_heel):
|
||||
def rig_roll_mch_bones(self, chain: list[str], heel: str, org_heel: str):
|
||||
rock2, rock1, roll2, roll1, result = chain
|
||||
|
||||
# This order is required for correct working of the constraints
|
||||
|
@ -318,7 +325,6 @@ class Rig(BaseLimbRig):
|
|||
self.make_constraint(rock1, 'LIMIT_ROTATION', max_y=DEG_360, space='LOCAL')
|
||||
self.make_constraint(rock2, 'LIMIT_ROTATION', min_y=-DEG_360, space='LOCAL')
|
||||
|
||||
|
||||
####################################################
|
||||
# FK parents MCH chain
|
||||
|
||||
|
@ -356,12 +362,11 @@ class Rig(BaseLimbRig):
|
|||
|
||||
self.set_bone_parent(self.bones.mch.ik_target, self.bones.mch.heel[-1])
|
||||
|
||||
|
||||
####################################################
|
||||
# Settings
|
||||
|
||||
@classmethod
|
||||
def add_parameters(self, params):
|
||||
def add_parameters(cls, params):
|
||||
super().add_parameters(params)
|
||||
|
||||
items = [
|
||||
|
@ -374,9 +379,9 @@ class Rig(BaseLimbRig):
|
|||
]
|
||||
|
||||
params.foot_pivot_type = bpy.props.EnumProperty(
|
||||
items = items,
|
||||
name = "Foot Pivot",
|
||||
default = 'ANKLE_TOE'
|
||||
items=items,
|
||||
name="Foot Pivot",
|
||||
default='ANKLE_TOE'
|
||||
)
|
||||
|
||||
params.extra_ik_toe = bpy.props.BoolProperty(
|
||||
|
@ -385,13 +390,12 @@ class Rig(BaseLimbRig):
|
|||
description="Generate a separate IK toe control for better IK/FK snapping"
|
||||
)
|
||||
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params):
|
||||
def parameters_ui(cls, layout, params, end='Foot'):
|
||||
layout.prop(params, 'foot_pivot_type')
|
||||
layout.prop(params, 'extra_ik_toe')
|
||||
|
||||
super().parameters_ui(layout, params, 'Foot')
|
||||
super().parameters_ui(layout, params, end)
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
|
@ -436,7 +440,6 @@ def create_sample(obj):
|
|||
bone.parent = arm.edit_bones[bones['foot.L']]
|
||||
bones['heel.02.L'] = bone.name
|
||||
|
||||
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pbone = obj.pose.bones[bones['thigh.L']]
|
||||
pbone.rigify_type = 'limbs.leg'
|
||||
|
@ -450,7 +453,10 @@ def create_sample(obj):
|
|||
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]
|
||||
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:
|
||||
|
@ -458,7 +464,10 @@ def create_sample(obj):
|
|||
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.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]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
|
@ -466,11 +475,17 @@ def create_sample(obj):
|
|||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
pbone.rigify_parameters.fk_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]
|
||||
pbone.rigify_parameters.fk_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.tweak_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, True, False, False, False, False, False, False, False, False,
|
||||
False, False, False, False, False, False, False, False]
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
|
@ -523,8 +538,12 @@ def create_sample(obj):
|
|||
arm.edit_bones.active = bone
|
||||
|
||||
for eb in arm.edit_bones:
|
||||
eb.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)
|
||||
eb.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)
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
return bones
|
||||
|
|
|
@ -3,9 +3,12 @@
|
|||
import bpy
|
||||
import json
|
||||
|
||||
from typing import Optional, NamedTuple
|
||||
from bpy.types import PoseBone, EditBone
|
||||
|
||||
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, align_bone_orientation, set_bone_widget_transform
|
||||
from ...utils.bones import put_bone, align_bone_orientation, set_bone_widget_transform, TypedBoneDict
|
||||
from ...utils.naming import strip_org, make_derived_name
|
||||
from ...utils.layers import ControlLayersOption
|
||||
from ...utils.misc import pairwise_nozip, padnone, map_list
|
||||
|
@ -17,26 +20,47 @@ 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 ...rig_ui_template import UTILITIES_FUNC_COMMON_IKFK, PanelLayout
|
||||
|
||||
from math import pi
|
||||
from itertools import count, chain
|
||||
from itertools import count
|
||||
from mathutils import Vector
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
SegmentEntry = namedtuple('SegmentEntry', ['org', 'org_idx', 'seg_idx', 'pos'])
|
||||
class SegmentEntry(NamedTuple):
|
||||
org: str # ORG bone
|
||||
org_idx: int # Index in the ORG chain
|
||||
seg_idx: int | None # Segment index within ORG bone
|
||||
pos: Vector # Position of the segment start
|
||||
|
||||
|
||||
class BaseLimbRig(BaseRig):
|
||||
"""Common base for limb rigs."""
|
||||
|
||||
segmented_orgs = 2 # Number of org bones to segment
|
||||
segmented_orgs = 2 # Number of org bones to segment
|
||||
min_valid_orgs = None
|
||||
max_valid_orgs = None
|
||||
|
||||
def find_org_bones(self, bone):
|
||||
return BoneDict(
|
||||
segments: int # Number of tweak segments per org bone
|
||||
bbone_segments: int # Number of B-Bone segments per def bone
|
||||
use_ik_pivot: bool
|
||||
use_uniform_scale: bool
|
||||
|
||||
main_axis: str
|
||||
aux_axis: str
|
||||
|
||||
segment_table: list[SegmentEntry]
|
||||
segment_table_end: list[SegmentEntry]
|
||||
segment_table_full: list[SegmentEntry]
|
||||
segment_table_tweak: list[SegmentEntry]
|
||||
|
||||
rig_parent_bone: str
|
||||
prop_bone: str
|
||||
elbow_vector: Vector
|
||||
pole_angle: float
|
||||
|
||||
def find_org_bones(self, bone: PoseBone) -> 'BaseLimbRig.OrgBones':
|
||||
return self.OrgBones(
|
||||
main=[bone.name] + connected_children_names(self.obj, bone.name),
|
||||
)
|
||||
|
||||
|
@ -83,22 +107,22 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
# noinspection PyMethodMayBeStatic
|
||||
def compute_elbow_vector(self, bones: list[EditBone]) -> Vector:
|
||||
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):
|
||||
def get_main_axis(self, bone: PoseBone | EditBone) -> Vector:
|
||||
return getattr(bone, self.main_axis + '_axis')
|
||||
|
||||
def get_aux_axis(self, bone):
|
||||
def get_aux_axis(self, bone: PoseBone | EditBone) -> Vector:
|
||||
return getattr(bone, self.aux_axis + '_axis')
|
||||
|
||||
def compute_pole_angle(self, bones, elbow_vector):
|
||||
def compute_pole_angle(self, bones: list[PoseBone | EditBone], elbow_vector: Vector) -> float:
|
||||
if self.params.rotation_axis == 'z':
|
||||
return 0
|
||||
|
||||
|
@ -109,56 +133,49 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
return pi/2
|
||||
|
||||
def get_segment_pos(self, org, seg):
|
||||
def get_segment_pos(self, org: str, seg: int):
|
||||
bone = self.get_bone(org)
|
||||
return bone.head + bone.vector * (seg / self.segments)
|
||||
|
||||
@staticmethod
|
||||
def vector_without_z(vector):
|
||||
return Vector((vector[0], vector[1], 0))
|
||||
def vector_without_z(vector: Vector) -> Vector:
|
||||
return Vector((vector.x, vector.y, 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.
|
||||
# ik_pivot
|
||||
# Custom IK pivot (optional).
|
||||
# mch:
|
||||
# master:
|
||||
# Parent of the master control.
|
||||
# follow:
|
||||
# FK follow behavior.
|
||||
# fk[]:
|
||||
# FK chain parents (or None)
|
||||
# ik_pivot
|
||||
# Custom IK pivot result (optional).
|
||||
# ik_scale
|
||||
# Helper bone that implements uniform scaling.
|
||||
# ik_swing
|
||||
# Bone that tracks ik_target to manually handle limb swing.
|
||||
# ik_target
|
||||
# Corrected target position.
|
||||
# ik_base
|
||||
# Optionally the base of the ik chain (otherwise ctrl.ik_base)
|
||||
# ik_end
|
||||
# End of the IK chain: [ik_base, ik_end]
|
||||
# deform[]:
|
||||
# DEF bones
|
||||
#
|
||||
####################################################
|
||||
|
||||
class OrgBones(TypedBoneDict):
|
||||
main: list[str]
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
class CtrlBones(BaseRig.CtrlBones):
|
||||
master: str # Main property control.
|
||||
fk: list[str] # FK control chain.
|
||||
tweak: list[str] # Tweak control chain.
|
||||
ik_base: str # IK base control.
|
||||
ik_pole: str # IK pole control.
|
||||
ik: str # IK limb end control.
|
||||
ik_vispole: str # IK pole visualization line.
|
||||
ik_pivot: str # Custom IK pivot (optional).
|
||||
|
||||
class MchBones(BaseRig.MchBones):
|
||||
master: str # Parent of the master control.
|
||||
follow: str # FK follow behavior.
|
||||
fk: list[str | None] # FK chain parents.
|
||||
tweak: list[str] # Tweak chain parents.
|
||||
ik_pivot: str # Custom IK pivot result (optional).
|
||||
ik_scale: str # Helper bone that implements uniform scaling.
|
||||
ik_swing: str # Bone that tracks ik_target to manually handle limb swing.
|
||||
ik_target: str # Corrected target position.
|
||||
ik_base: str # Optionally the base of the ik chain (over ctrl.ik_base)
|
||||
ik_end: str # End of the IK chain: [ik_base, ik_end]
|
||||
|
||||
bones: BaseRig.ToplevelBones[
|
||||
'BaseLimbRig.OrgBones',
|
||||
'BaseLimbRig.CtrlBones',
|
||||
'BaseLimbRig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Master control
|
||||
|
@ -166,7 +183,7 @@ class BaseLimbRig(BaseRig):
|
|||
@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_widget'), scale=1/12)
|
||||
self.bones.mch.master = self.copy_bone(org, make_derived_name(org, 'mch', '_parent_widget'), scale=1/12)
|
||||
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
|
||||
|
@ -197,7 +214,6 @@ class BaseLimbRig(BaseRig):
|
|||
set_bone_widget_transform(self.obj, master, self.bones.mch.master)
|
||||
create_gear_widget(self.obj, master, radius=1)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK follow MCH
|
||||
|
||||
|
@ -236,7 +252,6 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
self.make_driver(con, 'influence', variables=[(self.prop_bone, 'FK_limb_follow')])
|
||||
|
||||
|
||||
####################################################
|
||||
# FK control chain
|
||||
|
||||
|
@ -247,10 +262,10 @@ class BaseLimbRig(BaseRig):
|
|||
fk_name_suffix_cutoff = 2
|
||||
fk_ik_layer_cutoff = 3
|
||||
|
||||
def get_fk_name(self, i, org, kind):
|
||||
def get_fk_name(self, i: int, org: str, kind: str):
|
||||
return make_derived_name(org, kind, '_fk' if i <= self.fk_name_suffix_cutoff else '')
|
||||
|
||||
def make_fk_control_bone(self, i, org):
|
||||
def make_fk_control_bone(self, i: int, org: str):
|
||||
return self.copy_bone(org, self.get_fk_name(i, org, 'ctrl'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -259,7 +274,7 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def parent_fk_control_bone(self, i: int, ctrl: str, prev: str, _org: str, parent_mch: str | None):
|
||||
if parent_mch:
|
||||
self.set_bone_parent(ctrl, parent_mch)
|
||||
elif i == 0:
|
||||
|
@ -276,7 +291,7 @@ class BaseLimbRig(BaseRig):
|
|||
ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[0:cut])
|
||||
ControlLayersOption.FK.assign_rig(self, self.bones.ctrl.fk[cut:], combine=True, priority=1)
|
||||
|
||||
def configure_fk_control_bone(self, i, ctrl, org):
|
||||
def configure_fk_control_bone(self, i: int, ctrl: str, org: str):
|
||||
self.copy_bone_properties(org, ctrl)
|
||||
|
||||
if i == 2:
|
||||
|
@ -287,7 +302,7 @@ class BaseLimbRig(BaseRig):
|
|||
for args in zip(count(0), self.bones.ctrl.fk):
|
||||
self.make_fk_control_widget(*args)
|
||||
|
||||
def make_fk_control_widget(self, i, ctrl):
|
||||
def make_fk_control_widget(self, i: int, ctrl: str):
|
||||
if i < 2:
|
||||
create_limb_widget(self.obj, ctrl)
|
||||
elif i == 2:
|
||||
|
@ -295,7 +310,6 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.5)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK parents MCH chain
|
||||
|
||||
|
@ -303,7 +317,7 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def make_fk_parent_bone(self, i: int, org: str):
|
||||
if i >= 2:
|
||||
return self.copy_bone(org, self.get_fk_name(i, org, 'mch'), parent=True, scale=1/4)
|
||||
|
||||
|
@ -311,10 +325,11 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
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):
|
||||
def parent_fk_parent_bone(self, i: int, parent_mch: str | None,
|
||||
prev_ctrl: str, org: str, prev_org: str | None):
|
||||
if i >= 2:
|
||||
self.set_bone_parent(parent_mch, prev_ctrl, use_connect=True, inherit_scale='NONE')
|
||||
|
||||
|
@ -323,13 +338,12 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def rig_fk_parent_bone(self, i: int, parent_mch: str | None, org: str):
|
||||
if i >= 2:
|
||||
self.make_constraint(
|
||||
parent_mch, 'COPY_SCALE', self.bones.mch.follow, use_make_uniform=True
|
||||
)
|
||||
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
||||
|
@ -361,6 +375,8 @@ class BaseLimbRig(BaseRig):
|
|||
*self.get_extra_ik_controls(),
|
||||
]
|
||||
|
||||
component_ik_pivot: CustomPivotControl | None
|
||||
|
||||
@stage.generate_bones
|
||||
def make_ik_controls(self):
|
||||
orgs = self.bones.org.main
|
||||
|
@ -375,10 +391,10 @@ class BaseLimbRig(BaseRig):
|
|||
self.component_ik_pivot = self.build_ik_pivot(ik_name, parent=parent)
|
||||
self.build_ik_parent_switch(SwitchParentBuilder(self.generator))
|
||||
|
||||
def make_ik_base_bone(self, orgs):
|
||||
def make_ik_base_bone(self, orgs: list[str]):
|
||||
return self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik'))
|
||||
|
||||
def make_ik_pole_bone(self, orgs):
|
||||
def make_ik_pole_bone(self, orgs: list[str]):
|
||||
name = self.copy_bone(orgs[0], make_derived_name(orgs[0], 'ctrl', '_ik_target'))
|
||||
|
||||
pole = self.get_bone(name)
|
||||
|
@ -388,17 +404,17 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
return name
|
||||
|
||||
def make_ik_control_bone(self, orgs):
|
||||
def make_ik_control_bone(self, orgs: list[str]):
|
||||
return self.copy_bone(orgs[2], make_derived_name(orgs[2], 'ctrl', '_ik'))
|
||||
|
||||
def make_ik_scale_bone(self, ctrl, orgs):
|
||||
def make_ik_scale_bone(self, ctrl: str, orgs: list[str]):
|
||||
return self.copy_bone(ctrl, make_derived_name(orgs[2], 'mch', '_ik_scale'), scale=1/2)
|
||||
|
||||
def build_ik_pivot(self, ik_name, **args):
|
||||
def build_ik_pivot(self, ik_name: str, **args) -> CustomPivotControl | None:
|
||||
if self.use_ik_pivot:
|
||||
return CustomPivotControl(self, 'ik_pivot', ik_name, **args)
|
||||
|
||||
def get_ik_control_output(self):
|
||||
def get_ik_control_output(self) -> str:
|
||||
if self.component_ik_pivot:
|
||||
return self.component_ik_pivot.output
|
||||
elif self.use_uniform_scale:
|
||||
|
@ -406,10 +422,10 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
return self.bones.ctrl.ik
|
||||
|
||||
def get_ik_pole_parents(self):
|
||||
def get_ik_pole_parents(self) -> list[tuple[str, str] | str]:
|
||||
return [(self.bones.mch.ik_target, self.bones.ctrl.ik)]
|
||||
|
||||
def register_switch_parents(self, pbuilder):
|
||||
def register_switch_parents(self, pbuilder: SwitchParentBuilder):
|
||||
if self.rig_parent_bone:
|
||||
pbuilder.register_parent(self, self.rig_parent_bone)
|
||||
|
||||
|
@ -418,22 +434,22 @@ class BaseLimbRig(BaseRig):
|
|||
exclude_self=True, tags={'limb_ik', 'child'},
|
||||
)
|
||||
|
||||
def build_ik_parent_switch(self, pbuilder):
|
||||
def build_ik_parent_switch(self, pbuilder: SwitchParentBuilder):
|
||||
ctrl = self.bones.ctrl
|
||||
|
||||
master = lambda: self.bones.ctrl.master
|
||||
pcontrols = lambda: [ ctrl.master ] + self.get_all_ik_controls()
|
||||
def master(): return self.bones.ctrl.master
|
||||
def controls(): return [ctrl.master] + self.get_all_ik_controls()
|
||||
|
||||
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,
|
||||
prop_id='IK_parent', prop_name='IK Parent', controls=controls,
|
||||
)
|
||||
|
||||
pbuilder.build_child(
|
||||
self, ctrl.ik_pole, prop_bone=master, extra_parents=self.get_ik_pole_parents,
|
||||
prop_id='pole_parent', prop_name='Pole Parent', controls=pcontrols,
|
||||
prop_id='pole_parent', prop_name='Pole Parent', controls=controls,
|
||||
no_fix_rotation=True, no_fix_scale=True,
|
||||
)
|
||||
|
||||
|
@ -450,7 +466,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.set_ik_local_location(self.bones.ctrl.ik)
|
||||
self.set_ik_local_location(self.bones.ctrl.ik_pole)
|
||||
|
||||
def set_ik_local_location(self, ctrl):
|
||||
def set_ik_local_location(self, ctrl: str):
|
||||
self.get_bone(ctrl).use_local_location = self.params.ik_local_location
|
||||
|
||||
@stage.configure_bones
|
||||
|
@ -466,7 +482,7 @@ class BaseLimbRig(BaseRig):
|
|||
if self.use_uniform_scale:
|
||||
self.rig_ik_control_scale(self.bones.mch.ik_scale)
|
||||
|
||||
def rig_ik_control_scale(self, mch):
|
||||
def rig_ik_control_scale(self, mch: str):
|
||||
self.make_constraint(
|
||||
mch, 'COPY_SCALE', self.bones.ctrl.master,
|
||||
use_make_uniform=True, use_offset=True, space='LOCAL',
|
||||
|
@ -485,7 +501,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.make_ik_pole_widget(ctrl.ik_pole)
|
||||
self.make_ik_ctrl_widget(ctrl.ik)
|
||||
|
||||
def make_ik_base_widget(self, ctrl):
|
||||
def make_ik_base_widget(self, ctrl: str):
|
||||
if self.main_axis == 'x':
|
||||
roll = 0
|
||||
else:
|
||||
|
@ -493,13 +509,12 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
create_ikarrow_widget(self.obj, ctrl, roll=roll)
|
||||
|
||||
def make_ik_pole_widget(self, ctrl):
|
||||
def make_ik_pole_widget(self, ctrl: str):
|
||||
create_sphere_widget(self.obj, ctrl)
|
||||
|
||||
def make_ik_ctrl_widget(self, ctrl):
|
||||
def make_ik_ctrl_widget(self, ctrl: str):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
####################################################
|
||||
# IK pole visualization
|
||||
|
||||
|
@ -529,7 +544,6 @@ class BaseLimbRig(BaseRig):
|
|||
def make_ik_vispole_widget(self):
|
||||
create_line_widget(self.obj, self.bones.ctrl.ik_vispole)
|
||||
|
||||
|
||||
####################################################
|
||||
# IK system MCH
|
||||
|
||||
|
@ -611,7 +625,7 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
self.add_ik_only_buttons(panel, rig_name)
|
||||
|
||||
def add_global_buttons(self, panel, rig_name):
|
||||
def add_global_buttons(self, panel: PanelLayout, rig_name: str):
|
||||
ctrl = self.bones.ctrl
|
||||
ik_chain, tail_chain, fk_chain = self.get_ik_fk_position_chains()
|
||||
|
||||
|
@ -622,7 +636,6 @@ class BaseLimbRig(BaseRig):
|
|||
rig_name=rig_name
|
||||
)
|
||||
|
||||
|
||||
add_limb_snap_ik_to_fk(
|
||||
panel,
|
||||
master=ctrl.master,
|
||||
|
@ -632,7 +645,7 @@ class BaseLimbRig(BaseRig):
|
|||
rig_name=rig_name
|
||||
)
|
||||
|
||||
def add_ik_only_buttons(self, panel, rig_name):
|
||||
def add_ik_only_buttons(self, panel: PanelLayout, rig_name: str):
|
||||
ctrl = self.bones.ctrl
|
||||
ik_chain, tail_chain, fk_chain = self.get_ik_fk_position_chains()
|
||||
|
||||
|
@ -650,10 +663,12 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
self.make_constraint(mch.ik_swing, 'DAMPED_TRACK', mch.ik_target)
|
||||
|
||||
self.rig_ik_mch_stretch_limit(mch.ik_target, mch.follow, input_bone, self.ik_input_head_tail, 2)
|
||||
self.rig_ik_mch_stretch_limit(
|
||||
mch.ik_target, mch.follow, input_bone, self.ik_input_head_tail, 2)
|
||||
self.rig_ik_mch_end_bone(mch.ik_end, mch.ik_target, self.bones.ctrl.ik_pole)
|
||||
|
||||
def rig_ik_mch_stretch_limit(self, mch_target, base_bone, input_bone, head_tail, org_count, bias=1.035):
|
||||
def rig_ik_mch_stretch_limit(self, mch_target: str, base_bone: str, input_bone: str,
|
||||
head_tail: float, org_count: int, bias=1.035):
|
||||
# Compute increase in length to fully straighten
|
||||
orgs = self.bones.org.main[0:org_count]
|
||||
len_full = sum(self.get_bone(org).length for org in orgs)
|
||||
|
@ -662,6 +677,7 @@ class BaseLimbRig(BaseRig):
|
|||
self.make_constraint(mch_target, 'COPY_LOCATION', input_bone, head_tail=head_tail)
|
||||
|
||||
# Limit distance from the base of the limb
|
||||
# noinspection SpellCheckingInspection
|
||||
con = self.make_constraint(
|
||||
mch_target, 'LIMIT_DISTANCE', base_bone,
|
||||
limit_mode='LIMITDIST_INSIDE', distance=len_full*bias,
|
||||
|
@ -669,29 +685,31 @@ class BaseLimbRig(BaseRig):
|
|||
space='CUSTOM', space_object=self.obj, space_subtarget=self.bones.mch.follow,
|
||||
)
|
||||
|
||||
self.make_driver(con, "influence", variables=[(self.prop_bone, 'IK_Stretch')], polynomial=[1.0, -1.0])
|
||||
self.make_driver(con, "influence",
|
||||
variables=[(self.prop_bone, 'IK_Stretch')], polynomial=[1.0, -1.0])
|
||||
|
||||
def rig_ik_mch_end_bone(self, mch_ik, mch_target, ctrl_pole, chain=2):
|
||||
def rig_ik_mch_end_bone(self, mch_ik: str, mch_target: str, ctrl_pole: str, chain=2):
|
||||
con = self.make_constraint(
|
||||
mch_ik, 'IK', mch_target, chain_count=chain,
|
||||
)
|
||||
|
||||
self.make_driver(con, "mute", variables=[(self.prop_bone, 'pole_vector')], polynomial=[0.0, 1.0])
|
||||
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=chain,
|
||||
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])
|
||||
self.make_driver(con_pole, "mute",
|
||||
variables=[(self.prop_bone, 'pole_vector')], polynomial=[1.0, -1.0])
|
||||
|
||||
def rig_hide_pole_control(self, name):
|
||||
def rig_hide_pole_control(self, name: str):
|
||||
self.make_driver(
|
||||
self.get_bone(name).bone, "hide",
|
||||
variables=[(self.prop_bone, 'pole_vector')], polynomial=[1.0, -1.0],
|
||||
)
|
||||
|
||||
|
||||
####################################################
|
||||
# ORG chain
|
||||
|
||||
|
@ -707,14 +725,14 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def rig_org_bone(self, i: int, org: str, fk: str, ik: str | None):
|
||||
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])
|
||||
|
||||
self.make_driver(con, 'influence',
|
||||
variables=[(self.prop_bone, 'IK_FK')], polynomial=[1.0, -1.0])
|
||||
|
||||
####################################################
|
||||
# Tweak control chain
|
||||
|
@ -723,7 +741,7 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def make_tweak_bone(self, _i: int, entry: SegmentEntry):
|
||||
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)
|
||||
|
@ -741,7 +759,7 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
ControlLayersOption.TWEAK.assign_rig(self, self.bones.ctrl.tweak)
|
||||
|
||||
def configure_tweak_bone(self, i, tweak, entry):
|
||||
def configure_tweak_bone(self, i: int, tweak: str, entry: SegmentEntry):
|
||||
tweak_pb = self.get_bone(tweak)
|
||||
tweak_pb.lock_rotation = (True, False, True)
|
||||
tweak_pb.lock_scale = (False, True, False)
|
||||
|
@ -750,11 +768,11 @@ class BaseLimbRig(BaseRig):
|
|||
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
|
||||
def make_rubber_tweak_property(self, _i: int, tweak: str, entry: SegmentEntry):
|
||||
def_val = 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)
|
||||
self.make_property(tweak, 'rubber_tweak', def_val, 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)
|
||||
|
@ -764,10 +782,9 @@ class BaseLimbRig(BaseRig):
|
|||
for tweak in self.bones.ctrl.tweak:
|
||||
self.make_tweak_widget(tweak)
|
||||
|
||||
def make_tweak_widget(self, tweak):
|
||||
def make_tweak_widget(self, tweak: str):
|
||||
create_sphere_widget(self.obj, tweak)
|
||||
|
||||
|
||||
####################################################
|
||||
# Tweak MCH chain
|
||||
|
||||
|
@ -775,7 +792,7 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def make_tweak_mch_bone(self, _i: int, entry: SegmentEntry):
|
||||
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)
|
||||
|
@ -786,7 +803,7 @@ class BaseLimbRig(BaseRig):
|
|||
for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak):
|
||||
self.parent_tweak_mch_bone(*args)
|
||||
|
||||
def parent_tweak_mch_bone(self, i, mch, entry):
|
||||
def parent_tweak_mch_bone(self, i: int, mch: str, entry: SegmentEntry):
|
||||
if i == 0:
|
||||
self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='FIX_SHEAR')
|
||||
else:
|
||||
|
@ -797,7 +814,7 @@ class BaseLimbRig(BaseRig):
|
|||
for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak):
|
||||
self.apply_tweak_mch_bone(*args)
|
||||
|
||||
def apply_tweak_mch_bone(self, i, tweak, entry):
|
||||
def apply_tweak_mch_bone(self, i: int, tweak: str, entry: SegmentEntry):
|
||||
if entry.seg_idx:
|
||||
prev_tweak, next_tweak, fac = self.get_tweak_blend(i, entry)
|
||||
|
||||
|
@ -816,7 +833,7 @@ class BaseLimbRig(BaseRig):
|
|||
for args in zip(count(0), self.bones.mch.tweak, self.segment_table_tweak):
|
||||
self.rig_tweak_mch_bone(*args)
|
||||
|
||||
def get_tweak_blend(self, i, entry):
|
||||
def get_tweak_blend(self, i: int, entry: SegmentEntry):
|
||||
assert entry.seg_idx
|
||||
|
||||
tweaks = self.bones.ctrl.tweak
|
||||
|
@ -826,7 +843,7 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
return prev_tweak, next_tweak, fac
|
||||
|
||||
def rig_tweak_mch_bone(self, i, tweak, entry):
|
||||
def rig_tweak_mch_bone(self, i: int, tweak: str, entry: SegmentEntry):
|
||||
if entry.seg_idx:
|
||||
prev_tweak, next_tweak, fac = self.get_tweak_blend(i, entry)
|
||||
|
||||
|
@ -841,7 +858,6 @@ class BaseLimbRig(BaseRig):
|
|||
self.make_constraint(tweak, 'COPY_LOCATION', entry.org)
|
||||
self.make_constraint(tweak, 'DAMPED_TRACK', entry.org, head_tail=1)
|
||||
|
||||
|
||||
####################################################
|
||||
# Deform chain
|
||||
|
||||
|
@ -849,7 +865,7 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def make_deform_bone(self, _i: int, entry: SegmentEntry):
|
||||
name = make_derived_name(entry.org, 'def')
|
||||
|
||||
if entry.seg_idx is None:
|
||||
|
@ -874,7 +890,9 @@ class BaseLimbRig(BaseRig):
|
|||
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):
|
||||
def rig_deform_bone(self, i: int, deform: str,
|
||||
entry: SegmentEntry, next_entry: SegmentEntry | None,
|
||||
tweak: str | None, next_tweak: str | None):
|
||||
if tweak:
|
||||
self.make_constraint(deform, 'COPY_TRANSFORMS', tweak)
|
||||
|
||||
|
@ -889,7 +907,8 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
self.make_constraint(deform, 'COPY_TRANSFORMS', entry.org)
|
||||
|
||||
def rig_deform_easing(self, i, deform, tweak, next_tweak):
|
||||
# noinspection SpellCheckingInspection
|
||||
def rig_deform_easing(self, _i: int, deform: str, tweak: str, next_tweak: str):
|
||||
pbone = self.get_bone(deform)
|
||||
|
||||
if 'rubber_tweak' in self.get_bone(tweak):
|
||||
|
@ -902,12 +921,11 @@ class BaseLimbRig(BaseRig):
|
|||
else:
|
||||
pbone.bone.bbone_easeout = 0.0
|
||||
|
||||
|
||||
####################################################
|
||||
# Settings
|
||||
|
||||
@classmethod
|
||||
def add_parameters(self, params):
|
||||
def add_parameters(cls, params):
|
||||
""" Add the parameters of this rig type to the
|
||||
RigifyParameters PropertyGroup
|
||||
"""
|
||||
|
@ -919,9 +937,9 @@ class BaseLimbRig(BaseRig):
|
|||
]
|
||||
|
||||
params.rotation_axis = bpy.props.EnumProperty(
|
||||
items = items,
|
||||
name = "Rotation Axis",
|
||||
default = 'automatic'
|
||||
items=items,
|
||||
name="Rotation Axis",
|
||||
default='automatic'
|
||||
)
|
||||
|
||||
params.auto_align_extremity = bpy.props.BoolProperty(
|
||||
|
@ -931,35 +949,37 @@ class BaseLimbRig(BaseRig):
|
|||
)
|
||||
|
||||
params.segments = bpy.props.IntProperty(
|
||||
name = 'Limb Segments',
|
||||
default = 2,
|
||||
min = 1,
|
||||
description = 'Number of limb segments'
|
||||
name='Limb Segments',
|
||||
default=2,
|
||||
min=1,
|
||||
description='Number of limb segments'
|
||||
)
|
||||
|
||||
params.bbones = bpy.props.IntProperty(
|
||||
name = 'B-Bone Segments',
|
||||
default = 10,
|
||||
min = 1,
|
||||
description = 'Number of B-Bone segments'
|
||||
name='B-Bone Segments',
|
||||
default=10,
|
||||
min=1,
|
||||
description='Number of B-Bone segments'
|
||||
)
|
||||
|
||||
params.make_custom_pivot = bpy.props.BoolProperty(
|
||||
name = "Custom Pivot Control",
|
||||
default = False,
|
||||
description = "Create a rotation pivot control that can be repositioned arbitrarily"
|
||||
name="Custom Pivot Control",
|
||||
default=False,
|
||||
description="Create a rotation pivot control that can be repositioned arbitrarily"
|
||||
)
|
||||
|
||||
params.ik_local_location = bpy.props.BoolProperty(
|
||||
name = "IK Local Location",
|
||||
default = True,
|
||||
description = "Specifies the value of the Local Location option for IK controls, which decides if the location channels are aligned to the local control orientation or world",
|
||||
name="IK Local Location",
|
||||
default=True,
|
||||
description="Specifies the value of the Local Location option for IK controls, which "
|
||||
"decides if the location channels are aligned to the local control "
|
||||
"orientation or world",
|
||||
)
|
||||
|
||||
params.limb_uniform_scale = bpy.props.BoolProperty(
|
||||
name = "Support Uniform Scaling",
|
||||
default = False,
|
||||
description = "Support uniformly scaling the limb via the gear control at the base"
|
||||
name="Support Uniform Scaling",
|
||||
default=False,
|
||||
description="Support uniformly scaling the limb via the gear control at the base"
|
||||
)
|
||||
|
||||
# Setting up extra layers for the FK and tweak
|
||||
|
@ -967,7 +987,7 @@ class BaseLimbRig(BaseRig):
|
|||
ControlLayersOption.TWEAK.add_parameters(params)
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params, end='End'):
|
||||
def parameters_ui(cls, layout, params, end='End'):
|
||||
""" Create the ui for the rig parameters."""
|
||||
|
||||
r = layout.row()
|
||||
|
@ -997,6 +1017,7 @@ class BaseLimbRig(BaseRig):
|
|||
|
||||
SCRIPT_REGISTER_OP_SNAP_IK_FK = ['POSE_OT_rigify_limb_ik2fk', 'POSE_OT_rigify_limb_ik2fk_bake']
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
SCRIPT_UTILITIES_OP_SNAP_IK_FK = UTILITIES_FUNC_COMMON_IKFK + ['''
|
||||
########################
|
||||
## Limb Snap IK to FK ##
|
||||
|
@ -1130,7 +1151,14 @@ class POSE_OT_rigify_limb_ik2fk_bake(RigifyLimbIk2FkBase, RigifyBakeKeyframesMix
|
|||
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=[], tail_bones=[], ik_ctrl_bones=[], ik_extra_ctrls=[], rig_name=''):
|
||||
|
||||
# noinspection PyDefaultArgument
|
||||
def add_limb_snap_ik_to_fk(panel: 'PanelLayout', *,
|
||||
master: Optional[str] = None,
|
||||
fk_bones: list[str] = [],
|
||||
ik_bones: list[str] = [], tail_bones: list[str] = [],
|
||||
ik_ctrl_bones: list[str] = [], ik_extra_ctrls: list[str] = [],
|
||||
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)
|
||||
|
@ -1152,12 +1180,14 @@ def add_limb_snap_ik_to_fk(panel, *, master=None, fk_bones=[], ik_bones=[], tail
|
|||
clear_bones=ik_ctrl_bones + tail_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']
|
||||
|
||||
# noinspection SpellCheckingInspection
|
||||
SCRIPT_UTILITIES_OP_TOGGLE_POLE = SCRIPT_UTILITIES_OP_SNAP_IK_FK + ['''
|
||||
####################
|
||||
## Toggle IK Pole ##
|
||||
|
@ -1230,7 +1260,12 @@ class POSE_OT_rigify_limb_toggle_pole_bake(RigifyLimbTogglePoleBase, RigifyBakeK
|
|||
self.layout.prop(self, 'use_pole')
|
||||
''']
|
||||
|
||||
def add_limb_toggle_pole(panel, *, master=None, ik_bones=[], ik_ctrl_bones=[], ik_extra_ctrls=[]):
|
||||
|
||||
# noinspection PyDefaultArgument
|
||||
def add_limb_toggle_pole(panel: 'PanelLayout', *,
|
||||
master: Optional[str] = None,
|
||||
ik_bones: list[str] = [], ik_ctrl_bones: list[str] = [],
|
||||
ik_extra_ctrls: list[str] = []):
|
||||
panel.use_bake_settings()
|
||||
panel.script.add_utilities(SCRIPT_UTILITIES_OP_TOGGLE_POLE)
|
||||
panel.script.register_classes(SCRIPT_REGISTER_OP_TOGGLE_POLE)
|
||||
|
@ -1243,7 +1278,9 @@ def add_limb_toggle_pole(panel, *, master=None, ik_bones=[], ik_ctrl_bones=[], i
|
|||
}
|
||||
|
||||
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)
|
||||
left_split = row.split(factor=0.75, align=True)
|
||||
left_split.operator('pose.rigify_limb_toggle_pole_{rig_id}',
|
||||
icon='FORCE_MAGNETIC', properties=op_props)
|
||||
left_split.custom_prop(master, 'pole_vector', text='')
|
||||
row.operator('pose.rigify_limb_toggle_pole_bake_{rig_id}',
|
||||
text='', icon='ACTION_TWEAK', properties=op_props)
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import bpy, re
|
||||
import bpy
|
||||
import re
|
||||
|
||||
from mathutils import Vector
|
||||
from ...utils import org, strip_org, make_mechanism_name, make_deformer_name
|
||||
from ...utils import MetarigError
|
||||
|
||||
bilateral_suffixes = ['.L','.R']
|
||||
bilateral_suffixes = ['.L', '.R']
|
||||
|
||||
def orient_bone( cls, eb, axis, scale = 1.0, reverse = False ):
|
||||
v = Vector((0,0,0))
|
||||
|
||||
setattr(v,axis,scale)
|
||||
def orient_bone(cls, eb, axis, scale=1.0, reverse=False):
|
||||
v = Vector((0, 0, 0))
|
||||
|
||||
setattr(v, axis, scale)
|
||||
|
||||
if reverse:
|
||||
tail_vec = v @ cls.obj.matrix_world
|
||||
|
@ -22,51 +25,52 @@ def orient_bone( cls, eb, axis, scale = 1.0, reverse = False ):
|
|||
|
||||
eb.roll = 0.0
|
||||
|
||||
def make_constraint( cls, bone, constraint ):
|
||||
bpy.ops.object.mode_set(mode = 'OBJECT')
|
||||
|
||||
def make_constraint(cls, bone, constraint):
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
pb = cls.obj.pose.bones
|
||||
|
||||
owner_pb = pb[bone]
|
||||
const = owner_pb.constraints.new( constraint['constraint'] )
|
||||
const = owner_pb.constraints.new(constraint['constraint'])
|
||||
|
||||
constraint['target'] = cls.obj
|
||||
|
||||
# filter constraint props to those that actually exist in the current
|
||||
# type of constraint, then assign values to each
|
||||
for p in [ k for k in constraint.keys() if k in dir(const) ]:
|
||||
if p in dir( const ):
|
||||
setattr( const, p, constraint[p] )
|
||||
for p in [k for k in constraint.keys() if k in dir(const)]:
|
||||
if p in dir(const):
|
||||
setattr(const, p, constraint[p])
|
||||
else:
|
||||
raise MetarigError(
|
||||
"RIGIFY ERROR: property %s does not exist in %s constraint" % (
|
||||
p, constraint['constraint']
|
||||
))
|
||||
))
|
||||
|
||||
def get_bone_name( name, btype, suffix = '' ):
|
||||
|
||||
def get_bone_name(name, btype, suffix=''):
|
||||
# RE pattern match right or left parts
|
||||
# match the letter "L" (or "R"), followed by an optional dot (".")
|
||||
# and 0 or more digits at the end of the the string
|
||||
# and 0 or more digits at the end of the string
|
||||
pattern = r'^(\S+)(\.\S+)$'
|
||||
|
||||
name = strip_org( name )
|
||||
name = strip_org(name)
|
||||
|
||||
types = {
|
||||
'mch' : make_mechanism_name( name ),
|
||||
'org' : org( name ),
|
||||
'def' : make_deformer_name( name ),
|
||||
'ctrl' : name
|
||||
'mch': make_mechanism_name(name),
|
||||
'org': org(name),
|
||||
'def': make_deformer_name(name),
|
||||
'ctrl': name
|
||||
}
|
||||
|
||||
name = types[btype]
|
||||
|
||||
if suffix:
|
||||
results = re.match( pattern, name )
|
||||
bname, addition = ('','')
|
||||
results = re.match(pattern, name)
|
||||
|
||||
if results:
|
||||
bname, addition = results.groups()
|
||||
name = bname + "_" + suffix + addition
|
||||
bone_name, addition = results.groups()
|
||||
name = bone_name + "_" + suffix + addition
|
||||
else:
|
||||
name = name + "_" + suffix
|
||||
name = name + "_" + suffix
|
||||
|
||||
return name
|
||||
|
|
|
@ -22,6 +22,8 @@ class Rig(BaseLimbRig):
|
|||
max_valid_orgs = 5
|
||||
toe_bone_index = 3
|
||||
|
||||
use_heel2: bool
|
||||
|
||||
def initialize(self):
|
||||
self.use_heel2 = len(self.bones.org.main) > 4
|
||||
|
||||
|
@ -54,7 +56,7 @@ class Rig(BaseLimbRig):
|
|||
####################################################
|
||||
# Utilities
|
||||
|
||||
def align_ik_control_bone(self, name):
|
||||
def align_ik_control_bone(self, name: str):
|
||||
if self.params.rotation_axis == 'automatic' or self.params.auto_align_extremity:
|
||||
align_bone_to_axis(self.obj, name, 'y', flip=True)
|
||||
|
||||
|
@ -65,22 +67,23 @@ class Rig(BaseLimbRig):
|
|||
bone.tail[2] = bone.head[2]
|
||||
bone.roll = 0
|
||||
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# ctrl:
|
||||
# heel:
|
||||
# Foot heel control
|
||||
# heel2 (optional):
|
||||
# Second foot heel control
|
||||
# mch:
|
||||
# toe_socket:
|
||||
# IK toe orientation bone.
|
||||
# ik_heel2 (optional):
|
||||
# Final position of heel2 in the IK output.
|
||||
#
|
||||
####################################################
|
||||
|
||||
class CtrlBones(BaseLimbRig.CtrlBones):
|
||||
heel: str # Foot heel control
|
||||
heel2: str # Second foot heel control (optional)
|
||||
|
||||
class MchBones(BaseLimbRig.MchBones):
|
||||
toe_socket: str # IK toe orientation bone
|
||||
ik_heel2: str # Final position of heel2 in the IK output
|
||||
|
||||
bones: BaseLimbRig.ToplevelBones[
|
||||
BaseLimbRig.OrgBones,
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
@ -92,10 +95,10 @@ class Rig(BaseLimbRig):
|
|||
extra = [self.bones.ctrl.heel2] if self.use_heel2 else [self.bones.ctrl.heel]
|
||||
return super().get_extra_ik_controls() + extra
|
||||
|
||||
def make_ik_control_bone(self, orgs):
|
||||
def make_ik_control_bone(self, orgs: list[str]):
|
||||
return self.make_paw_ik_control_bone(orgs[-2], orgs[-1], orgs[2])
|
||||
|
||||
def make_paw_ik_control_bone(self, org_one, org_two, org_name):
|
||||
def make_paw_ik_control_bone(self, org_one: str, org_two: str, org_name: str):
|
||||
name = self.copy_bone(org_two, make_derived_name(org_name, 'ctrl', '_ik'))
|
||||
|
||||
self.align_ik_control_bone(name)
|
||||
|
@ -113,7 +116,6 @@ class Rig(BaseLimbRig):
|
|||
def make_ik_ctrl_widget(self, ctrl):
|
||||
create_foot_widget(self.obj, ctrl)
|
||||
|
||||
|
||||
####################################################
|
||||
# Heel control
|
||||
|
||||
|
@ -141,7 +143,6 @@ class Rig(BaseLimbRig):
|
|||
def generate_heel_control_widget(self):
|
||||
create_ballsocket_widget(self.obj, self.bones.ctrl.heel)
|
||||
|
||||
|
||||
####################################################
|
||||
# Second Heel control
|
||||
|
||||
|
@ -170,7 +171,6 @@ class Rig(BaseLimbRig):
|
|||
if self.use_heel2:
|
||||
create_ballsocket_widget(self.obj, self.bones.ctrl.heel2)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK control chain
|
||||
|
||||
|
@ -182,7 +182,6 @@ class Rig(BaseLimbRig):
|
|||
else:
|
||||
create_circle_widget(self.obj, ctrl, radius=0.4, head_tail=0.5)
|
||||
|
||||
|
||||
####################################################
|
||||
# FK parents MCH chain
|
||||
|
||||
|
@ -211,7 +210,6 @@ class Rig(BaseLimbRig):
|
|||
else:
|
||||
super().rig_fk_parent_bone(i, parent_mch, org)
|
||||
|
||||
|
||||
####################################################
|
||||
# IK system MCH
|
||||
|
||||
|
@ -226,7 +224,6 @@ class Rig(BaseLimbRig):
|
|||
|
||||
self.set_bone_parent(self.bones.mch.ik_target, self.bones.ctrl.heel)
|
||||
|
||||
|
||||
####################################################
|
||||
# IK heel2 output
|
||||
|
||||
|
@ -250,7 +247,6 @@ class Rig(BaseLimbRig):
|
|||
if self.use_heel2:
|
||||
self.make_constraint(self.bones.mch.ik_heel2, 'COPY_LOCATION', self.bones.mch.ik_target, head_tail=1)
|
||||
|
||||
|
||||
####################################################
|
||||
# Deform chain
|
||||
|
||||
|
@ -260,13 +256,12 @@ class Rig(BaseLimbRig):
|
|||
if tweak and not (next_tweak or next_entry):
|
||||
self.make_constraint(deform, 'STRETCH_TO', entry.org, head_tail=1.0, keep_axis='SWING_Y')
|
||||
|
||||
|
||||
####################################################
|
||||
# Settings
|
||||
|
||||
@classmethod
|
||||
def parameters_ui(self, layout, params):
|
||||
super().parameters_ui(layout, params, 'Claw')
|
||||
def parameters_ui(cls, layout, params, end='Claw'):
|
||||
super().parameters_ui(layout, params, end)
|
||||
|
||||
|
||||
def create_sample(obj):
|
||||
|
@ -313,11 +308,17 @@ def create_sample(obj):
|
|||
pbone.lock_scale = (False, False, False)
|
||||
pbone.rotation_mode = 'QUATERNION'
|
||||
try:
|
||||
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]
|
||||
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.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]
|
||||
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:
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
import bpy
|
||||
|
||||
from ...utils.bones import align_bone_roll
|
||||
from ...utils.naming import make_derived_name
|
||||
from ...utils.misc import map_list
|
||||
|
@ -18,17 +16,22 @@ class Rig(pawRig):
|
|||
"""Rear paw rig with special IK automation."""
|
||||
|
||||
####################################################
|
||||
# EXTRA BONES
|
||||
#
|
||||
# mch:
|
||||
# ik2_target
|
||||
# Three bone IK stretch limit
|
||||
# ik2_chain[2]
|
||||
# Second IK system (pre-driving thigh and ik3)
|
||||
# ik3_chain[2]
|
||||
# Third IK system (pre-driving heel)
|
||||
#
|
||||
####################################################
|
||||
# BONES
|
||||
|
||||
class CtrlBones(pawRig.CtrlBones):
|
||||
pass
|
||||
|
||||
class MchBones(pawRig.MchBones):
|
||||
ik2_target: str # Three bone IK stretch limit
|
||||
ik2_chain: list[str] # Second IK system (pre-driving thigh and ik3)
|
||||
ik3_chain: list[str] # Third IK system (pre-driving heel)
|
||||
|
||||
bones: pawRig.ToplevelBones[
|
||||
pawRig.OrgBones,
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# IK controls
|
||||
|
@ -50,7 +53,6 @@ class Rig(pawRig):
|
|||
def get_ik_pole_parents(self):
|
||||
return [(self.bones.mch.ik2_target, self.bones.ctrl.ik)]
|
||||
|
||||
|
||||
####################################################
|
||||
# Heel control
|
||||
|
||||
|
@ -58,7 +60,6 @@ class Rig(pawRig):
|
|||
def parent_heel_control_bone(self):
|
||||
self.set_bone_parent(self.bones.ctrl.heel, self.bones.mch.ik3_chain[-1])
|
||||
|
||||
|
||||
####################################################
|
||||
# Second IK system (pre-driving thigh)
|
||||
|
||||
|
@ -73,7 +74,7 @@ class Rig(pawRig):
|
|||
|
||||
self.bones.mch.ik2_target = self.make_ik2_mch_target_bone(orgs)
|
||||
|
||||
def make_ik2_mch_target_bone(self, orgs):
|
||||
def make_ik2_mch_target_bone(self, orgs: list[str]):
|
||||
return self.copy_bone(orgs[3], make_derived_name(orgs[0], 'mch', '_ik2_target'), scale=1/2)
|
||||
|
||||
@stage.generate_bones
|
||||
|
@ -91,7 +92,7 @@ class Rig(pawRig):
|
|||
chain_bones[1].tail = org_bones[2].tail
|
||||
align_bone_roll(self.obj, chain[1], orgs[1])
|
||||
|
||||
def make_ik2_mch_bone(self, i, org):
|
||||
def make_ik2_mch_bone(self, _i: int, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik2'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -106,7 +107,7 @@ class Rig(pawRig):
|
|||
for i, mch in enumerate(self.bones.mch.ik2_chain):
|
||||
self.configure_ik2_mch_bone(i, mch)
|
||||
|
||||
def configure_ik2_mch_bone(self, i, mch):
|
||||
def configure_ik2_mch_bone(self, i: int, mch: str):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 1:
|
||||
|
@ -122,7 +123,6 @@ class Rig(pawRig):
|
|||
self.rig_ik_mch_stretch_limit(mch.ik2_target, mch.follow, input_bone, head_tail, 3)
|
||||
self.rig_ik_mch_end_bone(mch.ik2_chain[-1], mch.ik2_target, self.bones.ctrl.ik_pole)
|
||||
|
||||
|
||||
####################################################
|
||||
# Third IK system (pre-driving heel control)
|
||||
|
||||
|
@ -130,7 +130,7 @@ class Rig(pawRig):
|
|||
def make_ik3_mch_chain(self):
|
||||
self.bones.mch.ik3_chain = map_list(self.make_ik3_mch_bone, count(0), self.bones.org.main[1:3])
|
||||
|
||||
def make_ik3_mch_bone(self, i, org):
|
||||
def make_ik3_mch_bone(self, _i: int, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_ik3'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -145,7 +145,7 @@ class Rig(pawRig):
|
|||
for i, mch in enumerate(self.bones.mch.ik3_chain):
|
||||
self.configure_ik3_mch_bone(i, mch)
|
||||
|
||||
def configure_ik3_mch_bone(self, i, mch):
|
||||
def configure_ik3_mch_bone(self, i: int, mch: str):
|
||||
bone = self.get_bone(mch)
|
||||
bone.ik_stretch = 0.1
|
||||
if i == 0:
|
||||
|
|
|
@ -50,7 +50,7 @@ class Rig(TweakChainRig):
|
|||
@stage.rig_bones
|
||||
def rig_control_chain(self):
|
||||
ctrls = self.bones.ctrl.fk
|
||||
for args in zip(count(0), ctrls, [None] + ctrls):
|
||||
for args in zip(count(0), ctrls, [None, *ctrls]):
|
||||
self.rig_control_bone(*args)
|
||||
|
||||
def rig_control_bone(self, _i: int, ctrl: str, prev_ctrl: Optional[str]):
|
||||
|
|
|
@ -50,7 +50,12 @@ class Rig(SimpleChainRig):
|
|||
stretch: list[str] # Stretch system
|
||||
bend: list[str] # Bend system
|
||||
|
||||
bones: SimpleChainRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: SimpleChainRig.ToplevelBones[
|
||||
list[str],
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
##############################
|
||||
# Master Control
|
||||
|
|
|
@ -9,12 +9,12 @@ from .limb_rigs import BaseLimbRig
|
|||
from . import arm, leg, paw
|
||||
|
||||
|
||||
RIGS = { 'arm': arm.Rig, 'leg': leg.Rig, 'paw': paw.Rig }
|
||||
RIGS = {'arm': arm.Rig, 'leg': leg.Rig, 'paw': paw.Rig}
|
||||
|
||||
|
||||
class Rig(SubstitutionRig):
|
||||
def substitute(self):
|
||||
return [ self.instantiate_rig(RIGS[self.params.limb_type], self.base_bone) ]
|
||||
return [self.instantiate_rig(RIGS[self.params.limb_type], self.base_bone)]
|
||||
|
||||
|
||||
def add_parameters(params):
|
||||
|
@ -25,9 +25,9 @@ def add_parameters(params):
|
|||
]
|
||||
|
||||
params.limb_type = bpy.props.EnumProperty(
|
||||
items = items,
|
||||
name = "Limb Type",
|
||||
default = 'arm'
|
||||
items=items,
|
||||
name="Limb Type",
|
||||
default='arm'
|
||||
)
|
||||
|
||||
BaseLimbRig.add_parameters(params)
|
||||
|
|
|
@ -4,18 +4,20 @@ import bpy
|
|||
import re
|
||||
|
||||
from math import cos, pi
|
||||
from itertools import count, repeat
|
||||
from itertools import count
|
||||
|
||||
from bpy.types import PoseBone
|
||||
|
||||
from rigify.utils.rig import is_rig_base_bone
|
||||
from rigify.utils.naming import strip_org, make_derived_name, choose_derived_bone
|
||||
from rigify.utils.widgets import widget_generator, register_widget
|
||||
from rigify.utils.widgets_basic import create_bone_widget
|
||||
from rigify.utils.misc import map_list
|
||||
from rigify.utils.misc import map_list, ArmatureObject
|
||||
|
||||
from rigify.base_rig import BaseRig, stage
|
||||
|
||||
|
||||
def bone_siblings(obj, bone):
|
||||
def bone_siblings(obj: ArmatureObject, bone: str) -> list[str]:
|
||||
""" Returns a list of the siblings of the given bone.
|
||||
This requires that the bones has a parent.
|
||||
"""
|
||||
|
@ -38,7 +40,15 @@ class Rig(BaseRig):
|
|||
This is a control and deformation rig.
|
||||
"""
|
||||
|
||||
def find_org_bones(self, bone):
|
||||
palm_rotation_axis: str
|
||||
make_secondary: bool
|
||||
make_fk: bool
|
||||
|
||||
rig_parent_bone: str
|
||||
order: str
|
||||
ctrl_name: str
|
||||
|
||||
def find_org_bones(self, bone: PoseBone) -> list[str]:
|
||||
base_head = bone.bone.head
|
||||
siblings = bone_siblings(self.obj, bone.name)
|
||||
|
||||
|
@ -72,23 +82,21 @@ class Rig(BaseRig):
|
|||
|
||||
####################################################
|
||||
# BONES
|
||||
#
|
||||
# org[]:
|
||||
# Original bones in order of distance.
|
||||
# ctrl:
|
||||
# master:
|
||||
# Main control.
|
||||
# secondary:
|
||||
# Control for the other side.
|
||||
# fk[]:
|
||||
# Optional individual FK controls
|
||||
# mch:
|
||||
# fk_parents[]:
|
||||
# Parents for the individual FK controls
|
||||
# deform[]:
|
||||
# DEF bones
|
||||
#
|
||||
####################################################
|
||||
|
||||
class CtrlBones(BaseRig.CtrlBones):
|
||||
master: str # Main control.
|
||||
secondary: str # Control for the other side.
|
||||
fk: list[str] # Optional individual FK controls
|
||||
|
||||
class MchBones(BaseRig.MchBones):
|
||||
fk_parents: list[str] # Parents for the individual FK controls
|
||||
|
||||
bones: BaseRig.ToplevelBones[
|
||||
list[str], # Original bones in order of distance.
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Master control
|
||||
|
@ -117,7 +125,7 @@ class Rig(BaseRig):
|
|||
if self.make_secondary:
|
||||
self.configure_control_bone(self.bones.ctrl.secondary, self.bones.org[0])
|
||||
|
||||
def configure_control_bone(self, ctrl, org):
|
||||
def configure_control_bone(self, ctrl: str, org: str):
|
||||
self.copy_bone_properties(org, ctrl)
|
||||
self.get_bone(ctrl).lock_scale = (True, True, True)
|
||||
|
||||
|
@ -128,7 +136,7 @@ class Rig(BaseRig):
|
|||
if self.make_secondary:
|
||||
self.make_control_widget(self.bones.ctrl.secondary)
|
||||
|
||||
def make_control_widget(self, ctrl):
|
||||
def make_control_widget(self, ctrl: str):
|
||||
make_palm_widget(self.obj, ctrl, axis=self.palm_rotation_axis, radius=0.4)
|
||||
|
||||
####################################################
|
||||
|
@ -139,7 +147,7 @@ class Rig(BaseRig):
|
|||
if self.make_fk:
|
||||
self.bones.ctrl.fk = map_list(self.make_fk_control_bone, count(0), self.bones.org)
|
||||
|
||||
def make_fk_control_bone(self, i, org):
|
||||
def make_fk_control_bone(self, _i: int, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'ctrl', '_fk'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -168,7 +176,7 @@ class Rig(BaseRig):
|
|||
if self.make_fk:
|
||||
self.bones.mch.fk_parents = map_list(self.make_fk_parent_bone, count(0), self.bones.org)
|
||||
|
||||
def make_fk_parent_bone(self, i, org):
|
||||
def make_fk_parent_bone(self, _i: int, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'mch', '_fk_parent'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -177,7 +185,7 @@ class Rig(BaseRig):
|
|||
for i, mch in enumerate(self.bones.mch.fk_parents):
|
||||
self.parent_mch_fk_parent_bone(i, mch)
|
||||
|
||||
def parent_mch_fk_parent_bone(self, i, mch):
|
||||
def parent_mch_fk_parent_bone(self, _i: int, mch: str):
|
||||
self.set_bone_parent(mch, self.rig_parent_bone, inherit_scale='NONE')
|
||||
|
||||
@stage.rig_bones
|
||||
|
@ -186,7 +194,7 @@ class Rig(BaseRig):
|
|||
for i, mch in enumerate(self.bones.mch.fk_parents):
|
||||
self.rig_mch_fk_parent_bone(i, mch)
|
||||
|
||||
def rig_mch_fk_parent_bone(self, i, org):
|
||||
def rig_mch_fk_parent_bone(self, i: int, org: str):
|
||||
num_orgs = len(self.bones.org)
|
||||
ctrl = self.bones.ctrl
|
||||
fac = i / (num_orgs - 1)
|
||||
|
@ -219,20 +227,20 @@ class Rig(BaseRig):
|
|||
if self.make_secondary:
|
||||
self.rig_mch_back_rotation(org, ctrl.secondary, 1 - fac)
|
||||
|
||||
def rig_mch_back_rotation(self, org, ctrl, fac):
|
||||
def rig_mch_back_rotation(self, org: str, ctrl: str, fac: float):
|
||||
if 0 < fac < 1:
|
||||
inf = (fac + 1) * (fac + cos(fac * pi / 2) - 1)
|
||||
|
||||
if 'X' in self.palm_rotation_axis:
|
||||
self.make_constraint(
|
||||
org, 'COPY_ROTATION', ctrl, space='LOCAL',
|
||||
invert_x=True, use_xyz=(True,False,False),
|
||||
invert_x=True, use_xyz=(True, False, False),
|
||||
euler_order=self.order, mix_mode='ADD', influence=inf
|
||||
)
|
||||
else:
|
||||
self.make_constraint(
|
||||
org, 'COPY_ROTATION', ctrl, space='LOCAL',
|
||||
invert_z=True, use_xyz=(False,False,True),
|
||||
invert_z=True, use_xyz=(False, False, True),
|
||||
euler_order=self.order, mix_mode='ADD', influence=inf
|
||||
)
|
||||
|
||||
|
@ -261,7 +269,7 @@ class Rig(BaseRig):
|
|||
def make_def_chain(self):
|
||||
self.bones.deform = map_list(self.make_deform_bone, self.bones.org)
|
||||
|
||||
def make_deform_bone(self, org):
|
||||
def make_deform_bone(self, org: str):
|
||||
return self.copy_bone(org, make_derived_name(org, 'def'))
|
||||
|
||||
@stage.parent_bones
|
||||
|
@ -286,9 +294,9 @@ class Rig(BaseRig):
|
|||
description="Create controls for both sides of the palm"
|
||||
)
|
||||
params.make_extra_control = bpy.props.BoolProperty(
|
||||
name = "Extra Control",
|
||||
default = False,
|
||||
description = "Create an optional control"
|
||||
name="Extra Control",
|
||||
default=False,
|
||||
description="Create an optional control"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -309,7 +317,7 @@ def make_palm_widget(geom, axis='X', radius=0.5):
|
|||
(0.1578, 0.25, -0.275), (-0.1578, 0.25, -0.275), (0.1578, 0.75, -0.225), (-0.1578, 0.75, -0.225),
|
||||
(0.1578, 0.75, 0.225), (0.1578, 0.25, 0.275), (-0.1578, 0.25, 0.275), (-0.1578, 0.75, 0.225)]
|
||||
|
||||
geom.verts = [(x*sx, y, z*sz) for x,y,z in v]
|
||||
geom.verts = [(x*sx, y, z*sz) for x, y, z in v]
|
||||
|
||||
if 'Z' in axis:
|
||||
# Flip x/z coordinates
|
||||
|
@ -318,6 +326,7 @@ def make_palm_widget(geom, axis='X', radius=0.5):
|
|||
geom.edges = [(1, 2), (0, 3), (4, 7), (5, 6), (8, 0), (9, 3), (10, 1), (11, 2), (12, 6),
|
||||
(13, 7), (4, 14), (15, 5), (10, 8), (11, 9), (15, 14), (12, 13)]
|
||||
|
||||
|
||||
register_widget("palm_z", make_palm_widget, axis='Z')
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,12 @@ class Rig(BaseSpineRig):
|
|||
wgt_hips: str # Hip widget position bone.
|
||||
wgt_chest: str # Chest widget position bone.
|
||||
|
||||
bones: BaseSpineRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: BaseSpineRig.ToplevelBones[
|
||||
list[str],
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Master control bone
|
||||
|
|
|
@ -30,6 +30,22 @@ class Rig(BaseHeadTailRig):
|
|||
if self.connected_tweak and self.use_connect_reverse:
|
||||
self.rig_parent_bone = self.connected_tweak
|
||||
|
||||
####################################################
|
||||
# BONES
|
||||
|
||||
class CtrlBones(BaseHeadTailRig.CtrlBones):
|
||||
master: str # Master control.
|
||||
|
||||
class MchBones(BaseHeadTailRig.MchBones):
|
||||
rot_tail: str # Tail follow system.
|
||||
|
||||
bones: BaseHeadTailRig.ToplevelBones[
|
||||
list[str],
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Master control
|
||||
|
||||
|
|
|
@ -44,7 +44,12 @@ class BaseSpineRig(TweakChainRig):
|
|||
class MchBones(TweakChainRig.MchBones):
|
||||
master_pivot: str # Final output of the custom pivot (conditional)
|
||||
|
||||
bones: TweakChainRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: TweakChainRig.ToplevelBones[
|
||||
list[str],
|
||||
'BaseSpineRig.CtrlBones',
|
||||
'BaseSpineRig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Master control bone
|
||||
|
|
|
@ -48,7 +48,12 @@ class Rig(BaseHeadTailRig):
|
|||
ik: list[str] # Long neck IK system
|
||||
chain: list[str] # Tweak parents
|
||||
|
||||
bones: BaseHeadTailRig.ToplevelBones[list[str], CtrlBones, MchBones, list[str]]
|
||||
bones: BaseHeadTailRig.ToplevelBones[
|
||||
list[str],
|
||||
'Rig.CtrlBones',
|
||||
'Rig.MchBones',
|
||||
list[str]
|
||||
]
|
||||
|
||||
####################################################
|
||||
# Main control bones
|
||||
|
|
|
@ -404,9 +404,8 @@ class BoneUtilityMixin(object):
|
|||
return name
|
||||
|
||||
def copy_bone_properties(self, src_name: str, tgt_name: str, *,
|
||||
props=True,
|
||||
ui_controls: list[str] | bool | None = None,
|
||||
**kwargs):
|
||||
transforms=True, props=True, widget=True,
|
||||
ui_controls: list[str] | bool | None = None):
|
||||
"""Copy pose-mode properties of the bone. For using ui_controls, self must be a Rig."""
|
||||
|
||||
if ui_controls:
|
||||
|
@ -420,7 +419,10 @@ class BoneUtilityMixin(object):
|
|||
ui_controls = self.bones.flatten('ctrl')
|
||||
|
||||
copy_bone_properties(
|
||||
self.obj, src_name, tgt_name, props=props and not ui_controls, **kwargs)
|
||||
self.obj, src_name, tgt_name,
|
||||
props=props and not ui_controls,
|
||||
transforms=transforms, widget=widget,
|
||||
)
|
||||
|
||||
if props and ui_controls:
|
||||
from .mechanism import copy_custom_properties_with_ui
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import bpy
|
||||
import re
|
||||
|
||||
from typing import TYPE_CHECKING, Optional, Any, Collection
|
||||
from typing import TYPE_CHECKING, Optional, Any, Sequence
|
||||
|
||||
from bpy.types import (bpy_prop_collection, Material, Object, PoseBone, Driver, FCurve,
|
||||
DriverTarget, ID, bpy_struct, FModifierGenerator, Constraint, AnimData,
|
||||
|
@ -12,7 +12,7 @@ from bpy.types import (bpy_prop_collection, Material, Object, PoseBone, Driver,
|
|||
from rna_prop_ui import rna_idprop_ui_create
|
||||
from rna_prop_ui import rna_idprop_quote_path as quote_property
|
||||
|
||||
from .misc import force_lazy, ArmatureObject, Lazy
|
||||
from .misc import force_lazy, ArmatureObject, Lazy, OptionalLazy
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..base_rig import BaseRig
|
||||
|
@ -37,14 +37,14 @@ def _set_default_attr(obj, options, attr, value):
|
|||
def make_constraint(
|
||||
owner: Object | PoseBone, con_type: str,
|
||||
target: Optional[Object] = None,
|
||||
subtarget: Optional[str] = None, *,
|
||||
subtarget: OptionalLazy[str] = None, *,
|
||||
insert_index: Optional[int] = None,
|
||||
space: Optional[str] = None,
|
||||
track_axis: Optional[str] = None,
|
||||
use_xyz: Optional[Collection[bool]] = None,
|
||||
use_limit_xyz: Optional[Collection[bool]] = None,
|
||||
invert_xyz: Optional[Collection[bool]] = None,
|
||||
targets: list[Lazy[str | tuple | dict]] = None,
|
||||
use_xyz: Optional[Sequence[bool]] = None,
|
||||
use_limit_xyz: Optional[Sequence[bool]] = None,
|
||||
invert_xyz: Optional[Sequence[bool]] = None,
|
||||
targets: Optional[list[Lazy[str | tuple | dict]]] = None,
|
||||
**options):
|
||||
"""
|
||||
Creates and initializes constraint of the specified type for the owner bone.
|
||||
|
@ -130,8 +130,9 @@ def make_constraint(
|
|||
|
||||
# noinspection PyShadowingBuiltins
|
||||
def make_property(
|
||||
owner, name: str, default, *, min=0.0, max=1.0, soft_min=None, soft_max=None,
|
||||
description: Optional[str] = None, overridable=True, **options):
|
||||
owner: bpy_struct, name: str, default, *, min=0.0, max=1.0, soft_min=None, soft_max=None,
|
||||
description: Optional[str] = None, overridable=True, subtype: Optional[str] = None,
|
||||
**options):
|
||||
"""
|
||||
Creates and initializes a custom property of owner.
|
||||
|
||||
|
@ -145,7 +146,8 @@ def make_property(
|
|||
min=min, max=max, soft_min=soft_min, soft_max=soft_max,
|
||||
description=description or name,
|
||||
overridable=overridable,
|
||||
**options
|
||||
subtype=subtype,
|
||||
**options # noqa
|
||||
)
|
||||
|
||||
|
||||
|
@ -593,17 +595,49 @@ class MechanismUtilityMixin(object):
|
|||
Requires self.obj to be the armature object being worked on.
|
||||
"""
|
||||
|
||||
def make_constraint(self, bone: str, con_type: str,
|
||||
subtarget: OptionalLazy[str] = None, *,
|
||||
insert_index: Optional[int] = None,
|
||||
space: Optional[str] = None,
|
||||
track_axis: Optional[str] = None,
|
||||
use_xyz: Optional[Sequence[bool]] = None,
|
||||
use_limit_xyz: Optional[Sequence[bool]] = None,
|
||||
invert_xyz: Optional[Sequence[bool]] = None,
|
||||
targets: Optional[list[Lazy[str | tuple | dict]]] = None,
|
||||
**args):
|
||||
assert(self.obj.mode == 'OBJECT')
|
||||
return make_constraint(
|
||||
self.obj.pose.bones[bone], con_type, self.obj, subtarget,
|
||||
insert_index=insert_index, space=space, track_axis=track_axis,
|
||||
use_xyz=use_xyz, use_limit_xyz=use_limit_xyz, invert_xyz=invert_xyz,
|
||||
targets=targets,
|
||||
**args)
|
||||
|
||||
# noinspection PyShadowingBuiltins
|
||||
def make_constraint(self, bone, type, subtarget=None, **args):
|
||||
def make_property(self, bone: str, name: str, default, *,
|
||||
min=0.0, max=1.0, soft_min=None, soft_max=None,
|
||||
description: Optional[str] = None, overridable=True,
|
||||
subtype: Optional[str] = None,
|
||||
**args):
|
||||
assert(self.obj.mode == 'OBJECT')
|
||||
return make_constraint(self.obj.pose.bones[bone], type, self.obj, subtarget, **args)
|
||||
return make_property(
|
||||
self.obj.pose.bones[bone], name, default,
|
||||
min=min, max=max, soft_min=soft_min, soft_max=soft_max,
|
||||
description=description, overridable=overridable, subtype=subtype,
|
||||
**args
|
||||
)
|
||||
|
||||
def make_property(self, bone, name, default, **args):
|
||||
assert(self.obj.mode == 'OBJECT')
|
||||
return make_property(self.obj.pose.bones[bone], name, default, **args)
|
||||
|
||||
def make_driver(self, owner, prop, **args):
|
||||
# noinspection PyShadowingBuiltins,PyDefaultArgument
|
||||
def make_driver(self, owner: str | bpy_struct, prop: str,
|
||||
index=-1, type='SUM',
|
||||
expression: Optional[str] = None,
|
||||
variables: list | dict = {},
|
||||
polynomial: Optional[list[float]] = None):
|
||||
assert(self.obj.mode == 'OBJECT')
|
||||
if isinstance(owner, str):
|
||||
owner = self.obj.pose.bones[owner]
|
||||
return make_driver(owner, prop, target_id=self.obj, **args)
|
||||
return make_driver(
|
||||
owner, prop, target_id=self.obj,
|
||||
index=index, type=type, expression=expression,
|
||||
variables=variables, polynomial=polynomial,
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue