Rigify: support uniform scaling of limbs via the master control.

Existing IK & FK controls only allowed squash and stretch scaling.
This commit is contained in:
Alexander Gavrilov 2022-01-02 19:48:39 +03:00
parent 7f4c2d5e48
commit 2f1c38fd50
2 changed files with 48 additions and 15 deletions

View File

@ -181,31 +181,35 @@ 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_socket'), scale=1/12)
self.bones.mch.master = name = 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
@stage.parent_bones
def parent_master_control(self):
self.set_bone_parent(self.bones.ctrl.master, self.bones.mch.master)
self.set_bone_parent(self.bones.mch.master, self.bones.mch.follow)
self.set_bone_parent(self.bones.ctrl.master, self.rig_parent_bone, inherit_scale='NONE')
self.set_bone_parent(self.bones.mch.master, self.bones.org.main[0], inherit_scale='NONE')
@stage.configure_bones
def configure_master_control(self):
bone = self.get_bone(self.bones.ctrl.master)
bone.lock_location = (True, True, True)
bone.lock_rotation = (True, True, True)
bone.lock_scale = (True, True, True)
bone.lock_scale = (False, False, False)
bone.lock_rotation_w = True
@stage.rig_bones
def rig_master_control(self):
self.make_constraint(self.bones.mch.master, 'COPY_ROTATION', self.bones.org.main[0])
mch = self.bones.mch
self.make_constraint(mch.master, 'COPY_SCALE', 'root', use_make_uniform=True)
self.make_constraint(mch.master, 'COPY_SCALE', self.bones.ctrl.master, use_offset=True, space='LOCAL')
@stage.generate_widgets
def make_master_control_widget(self):
create_gear_widget(self.obj, self.bones.ctrl.master, radius=1)
master = self.bones.ctrl.master
set_bone_widget_transform(self.obj, master, self.bones.mch.master)
create_gear_widget(self.obj, master, radius=1)
####################################################
@ -235,6 +239,10 @@ class BaseLimbRig(BaseRig):
mch = self.bones.mch.follow
self.make_constraint(mch, 'COPY_SCALE', 'root', use_make_uniform=True)
self.make_constraint(
mch, 'COPY_SCALE', self.bones.ctrl.master,
use_make_uniform=True, use_offset=True, space='LOCAL'
)
con = self.make_constraint(mch, 'COPY_ROTATION', 'root')
@ -325,7 +333,9 @@ class BaseLimbRig(BaseRig):
def rig_fk_parent_bone(self, i, parent_mch, org):
if i >= 2:
self.make_constraint(parent_mch, 'COPY_SCALE', 'root', use_make_uniform=True)
self.make_constraint(
parent_mch, 'COPY_SCALE', self.bones.mch.follow, use_make_uniform=True
)
####################################################
@ -435,6 +445,13 @@ class BaseLimbRig(BaseRig):
@stage.rig_bones
def rig_ik_controls(self):
self.rig_hide_pole_control(self.bones.ctrl.ik_pole)
self.rig_ik_control_scale(self.bones.ctrl.ik)
def rig_ik_control_scale(self, ctrl):
self.make_constraint(
ctrl, 'COPY_SCALE', self.bones.ctrl.master,
use_make_uniform=True, use_offset=True, space='LOCAL',
)
@stage.generate_widgets
def make_ik_control_widgets(self):
@ -801,7 +818,7 @@ class BaseLimbRig(BaseRig):
self.make_constraint(tweak, 'DAMPED_TRACK', next_tweak)
elif entry.seg_idx is not None:
self.make_constraint(tweak, 'COPY_SCALE', 'root', use_make_uniform=True)
self.make_constraint(tweak, 'COPY_SCALE', self.bones.mch.follow, use_make_uniform=True)
if i == 0:
self.make_constraint(tweak, 'COPY_LOCATION', entry.org)
@ -1007,7 +1024,8 @@ class RigifyLimbIk2FkBase:
endmat = convert_pose_matrix_via_rest_delta(matrices[-1], ik_bones[-1], ctrl_bones[-1])
set_transform_from_matrix(
obj, self.ctrl_bone_list[-1], endmat, keyflags=self.keyflags
obj, self.ctrl_bone_list[-1], endmat, keyflags=self.keyflags,
undo_copy_scale=True,
)
# Remove foot heel transform, if present

View File

@ -182,18 +182,33 @@ def undo_copy_scale_with_offset(obj, bone, con, old_matrix):
"Undo the effects of Copy Scale with Offset constraint on a bone matrix."
inf = con.influence
if con.mute or inf == 0 or not con.is_valid or not con.use_offset or con.use_add or con.use_make_uniform:
if con.mute or inf == 0 or not con.is_valid or not con.use_offset or con.use_add:
return old_matrix
tgt_matrix = get_constraint_target_matrix(con)
tgt_scale = tgt_matrix.to_scale()
use = [con.use_x, con.use_y, con.use_z]
if con.use_make_uniform:
if con.use_x and con.use_y and con.use_z:
total = tgt_matrix.determinant()
else:
total = 1
for i, use in enumerate(use):
if use:
total *= tgt_scale[i]
tgt_scale = [abs(total)**(1./3.)]*3
else:
for i, use in enumerate(use):
if not use:
tgt_scale[i] = 1
scale_delta = [
1 / (1 + (math.pow(x, con.power) - 1) * inf)
for x in get_constraint_target_matrix(con).to_scale()
for x in tgt_scale
]
for i, use in enumerate([con.use_x, con.use_y, con.use_z]):
if not use:
scale_delta[i] = 1
return old_matrix @ Matrix.Diagonal([*scale_delta, 1])
def undo_copy_scale_constraints(obj, bone, matrix):