Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Vegdahl <cessen@cessen.com>2013-03-01 04:17:14 +0400
committerNathan Vegdahl <cessen@cessen.com>2013-03-01 04:17:14 +0400
commit3e316aace81f6305f61e9ac1d87ebc1717079429 (patch)
tree1ca9d980b3ed359d67534f7bd7baa9f376d2b3ad /rigify/rigs
parent38cc068b90491ddd4bb2d8dc5fefa251cfd64ba4 (diff)
Rigify: significant upgrade to arm and leg rigs, and misc changes/bugfixes.
Arm/leg rig upgrades: - Arms and legs no longer scale with their parents, which was problematic when e.g. the torso of a character did squash-and-stretch causing the arms/legs to distort and shear. - Squash-and-stretch for both FK and IK rigs. - Rubber hose controls. Misc changes/bugfixes: - Rigify now locks all pose transforms for non-control bones automatically. - The README file now correctly reflects the new rig-type API. - Scrubbed the code for unused variables and imports. - PEP8 cleanups.
Diffstat (limited to 'rigify/rigs')
-rw-r--r--rigify/rigs/biped/arm/__init__.py116
-rw-r--r--rigify/rigs/biped/arm/deform.py203
-rw-r--r--rigify/rigs/biped/arm/fk.py166
-rw-r--r--rigify/rigs/biped/arm/ik.py290
-rw-r--r--rigify/rigs/biped/leg/__init__.py119
-rw-r--r--rigify/rigs/biped/leg/deform.py218
-rw-r--r--rigify/rigs/biped/leg/fk.py162
-rw-r--r--rigify/rigs/biped/leg/ik.py325
-rw-r--r--rigify/rigs/biped/limb_common.py1139
-rw-r--r--rigify/rigs/misc/delta.py2
-rw-r--r--rigify/rigs/neck_short.py6
-rw-r--r--rigify/rigs/spine.py11
12 files changed, 1454 insertions, 1303 deletions
diff --git a/rigify/rigs/biped/arm/__init__.py b/rigify/rigs/biped/arm/__init__.py
index 81b5535c..3235645e 100644
--- a/rigify/rigs/biped/arm/__init__.py
+++ b/rigify/rigs/biped/arm/__init__.py
@@ -31,13 +31,6 @@ fk_arm = ["%s", "%s", "%s"]
ik_arm = ["%s", "%s", "%s", "%s"]
if is_selected(fk_arm+ik_arm):
layout.prop(pose_bones[ik_arm[2]], '["ikfk_switch"]', text="FK / IK (" + ik_arm[2] + ")", slider=True)
-if is_selected(fk_arm):
- try:
- pose_bones[fk_arm[0]]["isolate"]
- layout.prop(pose_bones[fk_arm[0]], '["isolate"]', text="Isolate Rotation (" + fk_arm[0] + ")", slider=True)
- except KeyError:
- pass
-if is_selected(fk_arm+ik_arm):
props = layout.operator("pose.rigify_arm_fk2ik_" + rig_id, text="Snap FK->IK (" + fk_arm[0] + ")")
props.uarm_fk = fk_arm[0]
props.farm_fk = fk_arm[1]
@@ -53,7 +46,27 @@ if is_selected(fk_arm+ik_arm):
props.farm_ik = ik_arm[1]
props.hand_ik = ik_arm[2]
props.pole = ik_arm[3]
+if is_selected(fk_arm):
+ try:
+ pose_bones[fk_arm[0]]["isolate"]
+ layout.prop(pose_bones[fk_arm[0]], '["isolate"]', text="Isolate Rotation (" + fk_arm[0] + ")", slider=True)
+ except KeyError:
+ pass
+ layout.prop(pose_bones[fk_arm[0]], '["stretch_length"]', text="Length FK (" + fk_arm[0] + ")", slider=True)
+if is_selected(ik_arm):
+ layout.prop(pose_bones[ik_arm[2]], '["stretch_length"]', text="Length IK (" + ik_arm[2] + ")", slider=True)
+ layout.prop(pose_bones[ik_arm[2]], '["auto_stretch"]', text="Auto-Stretch IK (" + ik_arm[2] + ")", slider=True)
+"""
+hose_script = """
+hose_arm = ["%s", "%s", "%s"]
+if is_selected(hose_arm):
+ layout.prop(pose_bones[hose_arm[1]], '["smooth_bend"]', text="Smooth Elbow (" + hose_arm[1] + ")", slider=True)
+"""
+
+end_script = """
+if is_selected(fk_arm+ik_arm):
+ layout.separator()
"""
@@ -68,6 +81,9 @@ class Rig:
Do NOT change any data in the scene. This is a gathering phase only.
"""
+ self.obj = obj
+ self.params = params
+
# Gather deform rig
self.deform_rig = deform.Rig(obj, bone, params)
@@ -83,10 +99,14 @@ class Rig:
The main armature should be selected and active before this is called.
"""
- self.deform_rig.generate()
+ hose_controls = self.deform_rig.generate()
fk_controls = self.fk_rig.generate()
ik_controls = self.ik_rig.generate()
- return [script % (fk_controls[0], fk_controls[1], fk_controls[2], ik_controls[0], ik_controls[1], ik_controls[2], ik_controls[3])]
+ ui_script = script % (fk_controls[0], fk_controls[1], fk_controls[2], ik_controls[0], ik_controls[1], ik_controls[2], ik_controls[3])
+ if self.params.use_complex_arm:
+ ui_script += hose_script % (hose_controls[0], hose_controls[1], hose_controls[2])
+ ui_script += end_script
+ return [ui_script]
def add_parameters(params):
@@ -94,25 +114,37 @@ def add_parameters(params):
RigifyParameters PropertyGroup
"""
+ params.use_complex_arm = bpy.props.BoolProperty(name="Complex Arm Rig", default=True, description="Generate the full, complex arm rig with twist bones and rubber-hose controls")
+ params.bend_hint = bpy.props.BoolProperty(name="Bend Hint", default=True, description="Give IK chain a hint about which way to bend. Useful for perfectly straight chains")
+
items = [('X', 'X', ''), ('Y', 'Y', ''), ('Z', 'Z', ''), ('-X', '-X', ''), ('-Y', '-Y', ''), ('-Z', '-Z', '')]
params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='X')
- params.bend_hint = bpy.props.BoolProperty(name="Bend Hint", default=True, description="Give IK chain a hint about which way to bend. Useful for perfectly straight chains")
- params.elbow_target_base_name = bpy.props.StringProperty(name="Elbow Target Name", default="elbow_target", description="Base name for the generated elbow target")
+ params.elbow_base_name = bpy.props.StringProperty(name="Elbow Name", default="elbow", description="Base name for the generated elbow-related controls")
params.separate_ik_layers = bpy.props.BoolProperty(name="Separate IK Control Layers:", default=False, description="Enable putting the ik controls on a separate layer from the fk controls")
params.ik_layers = bpy.props.BoolVectorProperty(size=32, description="Layers for the ik controls to be on")
- params.use_upper_arm_twist = bpy.props.BoolProperty(name="Upper Arm Twist", default=True, description="Generate the dual-bone twist setup for the upper arm")
- params.use_forearm_twist = bpy.props.BoolProperty(name="Forearm Twist", default=True, description="Generate the dual-bone twist setup for the forearm")
+ params.separate_hose_layers = bpy.props.BoolProperty(name="Separate Rubber-hose Control Layers:", default=False, description="Enable putting the rubber-hose controls on a separate layer from the other controls")
+ params.hose_layers = bpy.props.BoolVectorProperty(size=32, description="Layers for the rubber-hose controls to be on")
def parameters_ui(layout, params):
""" Create the ui for the rig parameters.
"""
+ col = layout.column()
+ col.prop(params, "use_complex_arm")
+
+ r = layout.row()
+ r.label(text="Elbow rotation axis:")
+ r.prop(params, "primary_rotation_axis", text="")
+
r = layout.row()
- r.prop(params, "elbow_target_base_name")
+ r.prop(params, "elbow_base_name")
+
+ r = layout.row()
+ r.prop(params, "bend_hint")
r = layout.row()
r.prop(params, "separate_ik_layers")
@@ -160,16 +192,52 @@ def parameters_ui(layout, params):
row.prop(params, "ik_layers", index=30, toggle=True, text="")
row.prop(params, "ik_layers", index=31, toggle=True, text="")
- r = layout.row()
- r.label(text="Elbow rotation axis:")
- r.prop(params, "primary_rotation_axis", text="")
-
- r = layout.row()
- r.prop(params, "bend_hint")
-
- col = layout.column()
- col.prop(params, "use_upper_arm_twist")
- col.prop(params, "use_forearm_twist")
+ if params.use_complex_arm:
+ r = layout.row()
+ r.prop(params, "separate_hose_layers")
+
+ r = layout.row()
+ r.active = params.separate_hose_layers
+
+ col = r.column(align=True)
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=0, toggle=True, text="")
+ row.prop(params, "hose_layers", index=1, toggle=True, text="")
+ row.prop(params, "hose_layers", index=2, toggle=True, text="")
+ row.prop(params, "hose_layers", index=3, toggle=True, text="")
+ row.prop(params, "hose_layers", index=4, toggle=True, text="")
+ row.prop(params, "hose_layers", index=5, toggle=True, text="")
+ row.prop(params, "hose_layers", index=6, toggle=True, text="")
+ row.prop(params, "hose_layers", index=7, toggle=True, text="")
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=16, toggle=True, text="")
+ row.prop(params, "hose_layers", index=17, toggle=True, text="")
+ row.prop(params, "hose_layers", index=18, toggle=True, text="")
+ row.prop(params, "hose_layers", index=19, toggle=True, text="")
+ row.prop(params, "hose_layers", index=20, toggle=True, text="")
+ row.prop(params, "hose_layers", index=21, toggle=True, text="")
+ row.prop(params, "hose_layers", index=22, toggle=True, text="")
+ row.prop(params, "hose_layers", index=23, toggle=True, text="")
+
+ col = r.column(align=True)
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=8, toggle=True, text="")
+ row.prop(params, "hose_layers", index=9, toggle=True, text="")
+ row.prop(params, "hose_layers", index=10, toggle=True, text="")
+ row.prop(params, "hose_layers", index=11, toggle=True, text="")
+ row.prop(params, "hose_layers", index=12, toggle=True, text="")
+ row.prop(params, "hose_layers", index=13, toggle=True, text="")
+ row.prop(params, "hose_layers", index=14, toggle=True, text="")
+ row.prop(params, "hose_layers", index=15, toggle=True, text="")
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=24, toggle=True, text="")
+ row.prop(params, "hose_layers", index=25, toggle=True, text="")
+ row.prop(params, "hose_layers", index=26, toggle=True, text="")
+ row.prop(params, "hose_layers", index=27, toggle=True, text="")
+ row.prop(params, "hose_layers", index=28, toggle=True, text="")
+ row.prop(params, "hose_layers", index=29, toggle=True, text="")
+ row.prop(params, "hose_layers", index=30, toggle=True, text="")
+ row.prop(params, "hose_layers", index=31, toggle=True, text="")
def create_sample(obj):
diff --git a/rigify/rigs/biped/arm/deform.py b/rigify/rigs/biped/arm/deform.py
index ad6d8634..a5444207 100644
--- a/rigify/rigs/biped/arm/deform.py
+++ b/rigify/rigs/biped/arm/deform.py
@@ -18,58 +18,13 @@
# <pep8 compliant>
-from math import acos
-
import bpy
-from mathutils import Vector, Matrix
+
+from .. import limb_common
from ....utils import MetarigError
-from ....utils import copy_bone, put_bone
from ....utils import connected_children_names
-from ....utils import strip_org, make_mechanism_name, make_deformer_name
-
-
-def align_roll(obj, bone1, bone2):
- bone1_e = obj.data.edit_bones[bone1]
- bone2_e = obj.data.edit_bones[bone2]
-
- bone1_e.roll = 0.0
-
- # Get the directions the bones are pointing in, as vectors
- y1 = bone1_e.y_axis
- x1 = bone1_e.x_axis
- y2 = bone2_e.y_axis
- x2 = bone2_e.x_axis
-
- # Get the shortest axis to rotate bone1 on to point in the same direction as bone2
- axis = y1.cross(y2)
- axis.normalize()
-
- # Angle to rotate on that shortest axis
- angle = y1.angle(y2)
-
- # Create rotation matrix to make bone1 point in the same direction as bone2
- rot_mat = Matrix.Rotation(angle, 3, axis)
-
- # Roll factor
- x3 = rot_mat * x1
- dot = x2 * x3
- if dot > 1.0:
- dot = 1.0
- elif dot < -1.0:
- dot = -1.0
- roll = acos(dot)
-
- # Set the roll
- bone1_e.roll = roll
-
- # Check if we rolled in the right direction
- x3 = rot_mat * bone1_e.x_axis
- check = x2 * x3
-
- # If not, reverse
- if check < 0.9999:
- bone1_e.roll = -roll
+from ....utils import strip_org
class Rig:
@@ -77,13 +32,6 @@ class Rig:
"""
def __init__(self, obj, bone, params):
- """ Gather and validate data about the rig.
- Store any data or references to data that will be needed later on.
- In particular, store references to bones that will be needed, and
- store names of bones that will be needed.
- Do NOT change any data in the scene. This is a gathering phase only.
-
- """
self.obj = obj
self.params = params
@@ -94,140 +42,17 @@ class Rig:
raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 3 bones" % (strip_org(bone)))
# Get rig parameters
- self.use_upper_arm_twist = params.use_upper_arm_twist
- self.use_forearm_twist = params.use_forearm_twist
-
- def generate(self):
- """ Generate the rig.
- Do NOT modify any of the original bones, except for adding constraints.
- The main armature should be selected and active before this is called.
-
- """
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create upper arm bones
- if self.use_upper_arm_twist:
- uarm1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01")))
- uarm2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02")))
- utip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip")))
+ if params.separate_hose_layers:
+ layers = list(params.hose_layers)
else:
- uarm = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0])))
+ layers = None
+ use_complex_rig = params.use_complex_arm
+ elbow_base_name = params.elbow_base_name
+ primary_rotation_axis = params.primary_rotation_axis
- # Create forearm bones
- if self.use_forearm_twist:
- farm1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01")))
- farm2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02")))
- ftip = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip")))
- else:
- farm = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1])))
-
- # Create hand bone
- hand = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))
-
- # Get edit bones
- eb = self.obj.data.edit_bones
-
- org_uarm_e = eb[self.org_bones[0]]
- if self.use_upper_arm_twist:
- uarm1_e = eb[uarm1]
- uarm2_e = eb[uarm2]
- utip_e = eb[utip]
- else:
- uarm_e = eb[uarm]
+ # Based on common limb
+ self.rubber_hose_limb = limb_common.RubberHoseLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], use_complex_rig, elbow_base_name, primary_rotation_axis, layers)
- org_farm_e = eb[self.org_bones[1]]
- if self.use_forearm_twist:
- farm1_e = eb[farm1]
- farm2_e = eb[farm2]
- ftip_e = eb[ftip]
- else:
- farm_e = eb[farm]
-
- org_hand_e = eb[self.org_bones[2]]
- hand_e = eb[hand]
-
- # Parent and position upper arm bones
- if self.use_upper_arm_twist:
- uarm1_e.use_connect = False
- uarm2_e.use_connect = False
- utip_e.use_connect = False
-
- uarm1_e.parent = org_uarm_e.parent
- uarm2_e.parent = org_uarm_e
- utip_e.parent = org_uarm_e
-
- center = Vector((org_uarm_e.head + org_uarm_e.tail) / 2)
-
- uarm1_e.tail = center
- uarm2_e.head = center
- put_bone(self.obj, utip, org_uarm_e.tail)
- utip_e.length = org_uarm_e.length / 8
- else:
- uarm_e.use_connect = False
- uarm_e.parent = org_uarm_e
-
- # Parent and position forearm bones
- if self.use_forearm_twist:
- farm1_e.use_connect = False
- farm2_e.use_connect = False
- ftip_e.use_connect = False
-
- farm1_e.parent = org_farm_e
- farm2_e.parent = org_farm_e
- ftip_e.parent = org_farm_e
-
- center = Vector((org_farm_e.head + org_farm_e.tail) / 2)
-
- farm1_e.tail = center
- farm2_e.head = center
- put_bone(self.obj, ftip, org_farm_e.tail)
- ftip_e.length = org_farm_e.length / 8
-
- # Align roll of farm2 with hand
- align_roll(self.obj, farm2, hand)
- else:
- farm_e.use_connect = False
- farm_e.parent = org_farm_e
-
- # Parent hand
- hand_e.use_connect = False
- hand_e.parent = org_hand_e
-
- # Object mode, get pose bones
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- if self.use_upper_arm_twist:
- uarm1_p = pb[uarm1]
- if self.use_forearm_twist:
- farm2_p = pb[farm2]
- # hand_p = pb[hand] # UNUSED
-
- # Upper arm constraints
- if self.use_upper_arm_twist:
- con = uarm1_p.constraints.new('COPY_LOCATION')
- con.name = "copy_location"
- con.target = self.obj
- con.subtarget = self.org_bones[0]
-
- con = uarm1_p.constraints.new('COPY_SCALE')
- con.name = "copy_scale"
- con.target = self.obj
- con.subtarget = self.org_bones[0]
-
- con = uarm1_p.constraints.new('DAMPED_TRACK')
- con.name = "track_to"
- con.target = self.obj
- con.subtarget = utip
-
- # Forearm constraints
- if self.use_forearm_twist:
- con = farm2_p.constraints.new('COPY_ROTATION')
- con.name = "copy_rotation"
- con.target = self.obj
- con.subtarget = hand
-
- con = farm2_p.constraints.new('DAMPED_TRACK')
- con.name = "track_to"
- con.target = self.obj
- con.subtarget = ftip
+ def generate(self):
+ bone_list = self.rubber_hose_limb.generate()
+ return bone_list
diff --git a/rigify/rigs/biped/arm/fk.py b/rigify/rigs/biped/arm/fk.py
index 54b1a459..740b3277 100644
--- a/rigify/rigs/biped/arm/fk.py
+++ b/rigify/rigs/biped/arm/fk.py
@@ -19,14 +19,14 @@
# <pep8 compliant>
import bpy
-from rna_prop_ui import rna_idprop_ui_prop_get
+
+from .. import limb_common
from ....utils import MetarigError
-from ....utils import copy_bone
from ....utils import connected_children_names
-from ....utils import strip_org, make_mechanism_name, insert_before_lr
+from ....utils import create_widget
+from ....utils import strip_org
from ....utils import get_layers
-from ....utils import create_widget, create_limb_widget
class Rig:
@@ -42,27 +42,23 @@ class Rig:
"""
self.obj = obj
- self.params = params
# Get the chain of 3 connected bones
self.org_bones = [bone] + connected_children_names(self.obj, bone)[:2]
if len(self.org_bones) != 3:
- raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 3 bones" % (strip_org(bone)))
-
- # Get (optional) parent
- if self.obj.data.bones[bone].parent is None:
- self.org_parent = None
- else:
- self.org_parent = self.obj.data.bones[bone].parent.name
+ raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of at least 3 bones" % (strip_org(bone)))
- # Get the rig parameters
+ # Get params
if "layers" in params:
- self.layers = get_layers(params["layers"])
+ layers = get_layers(params["layers"])
else:
- self.layers = None
+ layers = None
- self.primary_rotation_axis = params.primary_rotation_axis
+ primary_rotation_axis = params.primary_rotation_axis
+
+ # Arm is based on common limb
+ self.fk_limb = limb_common.FKLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], primary_rotation_axis, layers)
def generate(self):
""" Generate the rig.
@@ -70,140 +66,12 @@ class Rig:
The main armature should be selected and active before this is called.
"""
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create the control bones
- uarm = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], ".fk")))
- farm = copy_bone(self.obj, self.org_bones[1], strip_org(insert_before_lr(self.org_bones[1], ".fk")))
- hand = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".fk")))
-
- # Create the hinge bones
- if self.org_parent != None:
- hinge = copy_bone(self.obj, self.org_parent, make_mechanism_name(uarm + ".hinge"))
- socket1 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket1"))
- socket2 = copy_bone(self.obj, uarm, make_mechanism_name(uarm + ".socket2"))
-
- # Get edit bones
- eb = self.obj.data.edit_bones
-
- uarm_e = eb[uarm]
- farm_e = eb[farm]
- hand_e = eb[hand]
-
- if self.org_parent != None:
- hinge_e = eb[hinge]
- socket1_e = eb[socket1]
- socket2_e = eb[socket2]
-
- # Parenting
- farm_e.parent = uarm_e
- hand_e.parent = farm_e
-
- if self.org_parent != None:
- hinge_e.use_connect = False
- socket1_e.use_connect = False
- socket2_e.use_connect = False
-
- uarm_e.parent = hinge_e
- hinge_e.parent = socket2_e
- socket2_e.parent = None
-
- # Positioning
- if self.org_parent != None:
- center = (hinge_e.head + hinge_e.tail) / 2
- hinge_e.head = center
- socket1_e.length /= 4
- socket2_e.length /= 3
-
- # Object mode, get pose bones
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- uarm_p = pb[uarm]
- farm_p = pb[farm]
- hand_p = pb[hand]
- if self.org_parent != None:
- hinge_p = pb[hinge]
-
- if self.org_parent != None:
- # socket1_p = pb[socket1] # UNUSED
- socket2_p = pb[socket2]
-
- # Set the elbow to only bend on the x-axis.
- farm_p.rotation_mode = 'XYZ'
- if 'X' in self.primary_rotation_axis:
- farm_p.lock_rotation = (False, True, True)
- elif 'Y' in self.primary_rotation_axis:
- farm_p.lock_rotation = (True, False, True)
- else:
- farm_p.lock_rotation = (True, True, False)
-
- # Hinge transforms are locked, for auto-ik
- if self.org_parent != None:
- hinge_p.lock_location = True, True, True
- hinge_p.lock_rotation = True, True, True
- hinge_p.lock_rotation_w = True
- hinge_p.lock_scale = True, True, True
-
- # Set up custom properties
- if self.org_parent != None:
- prop = rna_idprop_ui_prop_get(uarm_p, "isolate", create=True)
- uarm_p["isolate"] = 0.0
- prop["soft_min"] = prop["min"] = 0.0
- prop["soft_max"] = prop["max"] = 1.0
-
- # Hinge constraints / drivers
- if self.org_parent != None:
- con = socket2_p.constraints.new('COPY_LOCATION')
- con.name = "copy_location"
- con.target = self.obj
- con.subtarget = socket1
-
- con = socket2_p.constraints.new('COPY_TRANSFORMS')
- con.name = "isolate_off"
- con.target = self.obj
- con.subtarget = socket1
-
- # Driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = uarm_p.path_from_id() + '["isolate"]'
- mod = fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- # Constrain org bones to controls
- con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = uarm
-
- con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = farm
-
- con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = hand
-
- # Set layers if specified
- if self.layers:
- uarm_p.bone.layers = self.layers
- farm_p.bone.layers = self.layers
- hand_p.bone.layers = self.layers
-
- # Create control widgets
- create_limb_widget(self.obj, uarm)
- create_limb_widget(self.obj, farm)
+ bone_list = self.fk_limb.generate()
+ uarm = bone_list[0]
+ farm = bone_list[1]
+ hand = bone_list[2]
+ # Create hand widget
ob = create_widget(self.obj, hand)
if ob != None:
verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
diff --git a/rigify/rigs/biped/arm/ik.py b/rigify/rigs/biped/arm/ik.py
index 8f288601..d5c9509f 100644
--- a/rigify/rigs/biped/arm/ik.py
+++ b/rigify/rigs/biped/arm/ik.py
@@ -18,44 +18,14 @@
# <pep8 compliant>
-from math import pi, acos
-
import bpy
-from rna_prop_ui import rna_idprop_ui_prop_get
-from mathutils import Vector
+
+from .. import limb_common
from ....utils import MetarigError
-from ....utils import copy_bone
from ....utils import connected_children_names
-from ....utils import strip_org, make_mechanism_name, insert_before_lr
-from ....utils import create_widget, create_line_widget, create_sphere_widget
-
-
-def angle_on_plane(plane, vec1, vec2):
- """ Return the angle between two vectors projected onto a plane.
- """
- plane.normalize()
- vec1 = vec1 - (plane * (vec1.dot(plane)))
- vec2 = vec2 - (plane * (vec2.dot(plane)))
- vec1.normalize()
- vec2.normalize()
-
- # Determine the angle
- angle = acos(max(-1.0, min(1.0, vec1.dot(vec2))))
-
- if angle < 0.00001: # close enough to zero that sign doesn't matter
- return angle
-
- # Determine the sign of the angle
- vec3 = vec2.cross(vec1)
- vec3.normalize()
- sign = vec3.dot(plane)
- if sign >= 0:
- sign = 1
- else:
- sign = -1
-
- return angle * sign
+from ....utils import strip_org
+from ....utils import create_widget
class Rig:
@@ -73,23 +43,23 @@ class Rig:
"""
self.obj = obj
self.params = params
- self.switch = ikfk_switch
# Get the chain of 3 connected bones
self.org_bones = [bone] + connected_children_names(self.obj, bone)[:2]
-
if len(self.org_bones) != 3:
raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 3 bones" % (strip_org(bone)))
# Get the rig parameters
if params.separate_ik_layers:
- self.layers = list(params.ik_layers)
+ layers = list(params.ik_layers)
else:
- self.layers = None
-
- self.bend_hint = params.bend_hint
+ layers = None
+ bend_hint = params.bend_hint
+ primary_rotation_axis = params.primary_rotation_axis
+ pole_target_base_name = self.params.elbow_base_name + "_target"
- self.primary_rotation_axis = params.primary_rotation_axis
+ # Arm is based on common limb
+ self.ik_limb = limb_common.IKLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], pole_target_base_name, primary_rotation_axis, bend_hint, layers, ikfk_switch)
def generate(self):
""" Generate the rig.
@@ -97,236 +67,14 @@ class Rig:
The main armature should be selected and active before this is called.
"""
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create the bones
- uarm = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".ik"))))
- farm = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".ik"))))
-
- hand = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".ik")))
- pole_target_name = self.params.elbow_target_base_name + "." + insert_before_lr(self.org_bones[0], ".ik").split(".", 1)[1]
- pole = copy_bone(self.obj, self.org_bones[0], pole_target_name)
-
- vishand = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], ".ik")))
- vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole.ik")))
-
- # Get edit bones
- eb = self.obj.data.edit_bones
-
- uarm_e = eb[uarm]
- farm_e = eb[farm]
- hand_e = eb[hand]
- pole_e = eb[pole]
- vishand_e = eb[vishand]
- vispole_e = eb[vispole]
-
- # Parenting
- farm_e.parent = uarm_e
-
- hand_e.use_connect = False
- hand_e.parent = None
-
- pole_e.use_connect = False
-
- vishand_e.use_connect = False
- vishand_e.parent = None
-
- vispole_e.use_connect = False
- vispole_e.parent = None
-
- # Misc
- hand_e.use_local_location = False
-
- vishand_e.hide_select = True
- vispole_e.hide_select = True
-
- # Positioning
- v1 = farm_e.tail - uarm_e.head
- if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
- v2 = v1.cross(farm_e.x_axis)
- if (v2 * farm_e.z_axis) > 0.0:
- v2 *= -1.0
- else:
- v2 = v1.cross(farm_e.z_axis)
- if (v2 * farm_e.x_axis) < 0.0:
- v2 *= -1.0
- v2.normalize()
- v2 *= v1.length
-
- if '-' in self.primary_rotation_axis:
- v2 *= -1
-
- pole_e.head = farm_e.head + v2
- pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8))
- pole_e.roll = 0.0
-
- vishand_e.tail = vishand_e.head + Vector((0, 0, v1.length / 32))
- vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32))
-
- # Determine the pole offset value
- plane = (farm_e.tail - uarm_e.head).normalized()
- vec1 = uarm_e.x_axis.normalized()
- vec2 = (pole_e.head - uarm_e.head).normalized()
- pole_offset = angle_on_plane(plane, vec1, vec2)
-
- # Object mode, get pose bones
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- # uarm_p = pb[uarm] # UNUSED
- farm_p = pb[farm]
- hand_p = pb[hand]
- pole_p = pb[pole]
- vishand_p = pb[vishand]
- vispole_p = pb[vispole]
-
- # Set the elbow to only bend on the primary axis
- if 'X' in self.primary_rotation_axis:
- farm_p.lock_ik_y = True
- farm_p.lock_ik_z = True
- elif 'Y' in self.primary_rotation_axis:
- farm_p.lock_ik_x = True
- farm_p.lock_ik_z = True
- else:
- farm_p.lock_ik_x = True
- farm_p.lock_ik_y = True
-
- # Pole target only translates
- pole_p.lock_location = False, False, False
- pole_p.lock_rotation = True, True, True
- pole_p.lock_rotation_w = True
- pole_p.lock_scale = True, True, True
-
- # Set up custom properties
- if self.switch is True:
- prop = rna_idprop_ui_prop_get(hand_p, "ikfk_switch", create=True)
- hand_p["ikfk_switch"] = 0.0
- prop["soft_min"] = prop["min"] = 0.0
- prop["soft_max"] = prop["max"] = 1.0
-
- # Bend direction hint
- if self.bend_hint:
- con = farm_p.constraints.new('LIMIT_ROTATION')
- con.name = "bend_hint"
- con.owner_space = 'LOCAL'
- if self.primary_rotation_axis == 'X':
- con.use_limit_x = True
- con.min_x = pi / 10
- con.max_x = pi / 10
- elif self.primary_rotation_axis == '-X':
- con.use_limit_x = True
- con.min_x = -pi / 10
- con.max_x = -pi / 10
- elif self.primary_rotation_axis == 'Y':
- con.use_limit_y = True
- con.min_y = pi / 10
- con.max_y = pi / 10
- elif self.primary_rotation_axis == '-Y':
- con.use_limit_y = True
- con.min_y = -pi / 10
- con.max_y = -pi / 10
- elif self.primary_rotation_axis == 'Z':
- con.use_limit_z = True
- con.min_z = pi / 10
- con.max_z = pi / 10
- elif self.primary_rotation_axis == '-Z':
- con.use_limit_z = True
- con.min_z = -pi / 10
- con.max_z = -pi / 10
-
- # IK Constraint
- con = farm_p.constraints.new('IK')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = hand
- con.pole_target = self.obj
- con.pole_subtarget = pole
- con.pole_angle = pole_offset
- con.chain_count = 2
-
- # Constrain org bones to controls
- con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = uarm
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = hand_p.path_from_id() + '["ikfk_switch"]'
-
- con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = farm
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = hand_p.path_from_id() + '["ikfk_switch"]'
-
- con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = hand
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = hand_p.path_from_id() + '["ikfk_switch"]'
-
- # VIS hand constraints
- con = vishand_p.constraints.new('COPY_LOCATION')
- con.name = "copy_loc"
- con.target = self.obj
- con.subtarget = self.org_bones[2]
-
- con = vishand_p.constraints.new('STRETCH_TO')
- con.name = "stretch_to"
- con.target = self.obj
- con.subtarget = hand
- con.volume = 'NO_VOLUME'
- con.rest_length = vishand_p.length
-
- # VIS pole constraints
- con = vispole_p.constraints.new('COPY_LOCATION')
- con.name = "copy_loc"
- con.target = self.obj
- con.subtarget = self.org_bones[1]
-
- con = vispole_p.constraints.new('STRETCH_TO')
- con.name = "stretch_to"
- con.target = self.obj
- con.subtarget = pole
- con.volume = 'NO_VOLUME'
- con.rest_length = vispole_p.length
-
- # Set layers if specified
- if self.layers:
- hand_p.bone.layers = self.layers
- pole_p.bone.layers = self.layers
- vishand_p.bone.layers = self.layers
- vispole_p.bone.layers = self.layers
-
- # Create widgets
- create_line_widget(self.obj, vispole)
- create_line_widget(self.obj, vishand)
- create_sphere_widget(self.obj, pole)
+ bone_list = self.ik_limb.generate()
+ uarm = bone_list[0]
+ farm = bone_list[1]
+ hand = bone_list[2]
+ # hand_mch = bone_list[3]
+ pole = bone_list[4]
+ # vispole = bone_list[5]
+ # vishand = bone_list[6]
ob = create_widget(self.obj, hand)
if ob != None:
diff --git a/rigify/rigs/biped/leg/__init__.py b/rigify/rigs/biped/leg/__init__.py
index 36619c98..0a9f0ac7 100644
--- a/rigify/rigs/biped/leg/__init__.py
+++ b/rigify/rigs/biped/leg/__init__.py
@@ -31,13 +31,6 @@ fk_leg = ["%s", "%s", "%s", "%s"]
ik_leg = ["%s", "%s", "%s", "%s", "%s", "%s"]
if is_selected(fk_leg+ik_leg):
layout.prop(pose_bones[ik_leg[2]], '["ikfk_switch"]', text="FK / IK (" + ik_leg[2] + ")", slider=True)
-if is_selected(fk_leg):
- try:
- pose_bones[fk_leg[0]]["isolate"]
- layout.prop(pose_bones[fk_leg[0]], '["isolate"]', text="Isolate Rotation (" + fk_leg[0] + ")", slider=True)
- except KeyError:
- pass
-if is_selected(fk_leg+ik_leg):
p = layout.operator("pose.rigify_leg_fk2ik_" + rig_id, text="Snap FK->IK (" + fk_leg[0] + ")")
p.thigh_fk = fk_leg[0]
p.shin_fk = fk_leg[1]
@@ -45,6 +38,7 @@ if is_selected(fk_leg+ik_leg):
p.mfoot_fk = fk_leg[3]
p.thigh_ik = ik_leg[0]
p.shin_ik = ik_leg[1]
+ p.foot_ik = ik_leg[2]
p.mfoot_ik = ik_leg[5]
p = layout.operator("pose.rigify_leg_ik2fk_" + rig_id, text="Snap IK->FK (" + fk_leg[0] + ")")
p.thigh_fk = fk_leg[0]
@@ -56,6 +50,27 @@ if is_selected(fk_leg+ik_leg):
p.pole = ik_leg[3]
p.footroll = ik_leg[4]
p.mfoot_ik = ik_leg[5]
+if is_selected(fk_leg):
+ try:
+ pose_bones[fk_leg[0]]["isolate"]
+ layout.prop(pose_bones[fk_leg[0]], '["isolate"]', text="Isolate Rotation (" + fk_leg[0] + ")", slider=True)
+ except KeyError:
+ pass
+ layout.prop(pose_bones[fk_leg[0]], '["stretch_length"]', text="Length FK (" + fk_leg[0] + ")", slider=True)
+if is_selected(ik_leg):
+ layout.prop(pose_bones[ik_leg[2]], '["stretch_length"]', text="Length IK (" + ik_leg[2] + ")", slider=True)
+ layout.prop(pose_bones[ik_leg[2]], '["auto_stretch"]', text="Auto-Stretch IK (" + ik_leg[2] + ")", slider=True)
+"""
+
+hose_script = """
+hose_leg = ["%s", "%s", "%s"]
+if is_selected(hose_leg):
+ layout.prop(pose_bones[hose_leg[1]], '["smooth_bend"]', text="Smooth Knee (" + hose_leg[1] + ")", slider=True)
+"""
+
+end_script = """
+if is_selected(fk_leg+ik_leg):
+ layout.separator()
"""
@@ -70,6 +85,9 @@ class Rig:
Do NOT change any data in the scene. This is a gathering phase only.
"""
+ self.obj = obj
+ self.params = params
+
# Gather deform rig
self.deform_rig = deform.Rig(obj, bone, params)
@@ -85,10 +103,14 @@ class Rig:
The main armature should be selected and active before this is called.
"""
- self.deform_rig.generate()
+ hose_controls = self.deform_rig.generate()
fk_controls = self.fk_rig.generate()
ik_controls = self.ik_rig.generate()
- return [script % (fk_controls[0], fk_controls[1], fk_controls[2], fk_controls[3], ik_controls[0], ik_controls[1], ik_controls[2], ik_controls[3], ik_controls[4], ik_controls[5])]
+ ui_script = script % (fk_controls[0], fk_controls[1], fk_controls[2], fk_controls[3], ik_controls[0], ik_controls[1], ik_controls[2], ik_controls[3], ik_controls[4], ik_controls[5])
+ if self.params.use_complex_leg:
+ ui_script += hose_script % (hose_controls[0], hose_controls[1], hose_controls[2])
+ ui_script += end_script
+ return [ui_script]
def add_parameters(params):
@@ -96,26 +118,37 @@ def add_parameters(params):
RigifyParameters PropertyGroup
"""
+ params.use_complex_leg = bpy.props.BoolProperty(name="Complex Leg Rig", default=True, description="Generate the full, complex leg rig with twist bones and rubber-hose controls")
+ params.bend_hint = bpy.props.BoolProperty(name="Bend Hint", default=True, description="Give IK chain a hint about which way to bend (useful for perfectly straight chains)")
+
items = [('X', 'X', ''), ('Y', 'Y', ''), ('Z', 'Z', ''), ('-X', '-X', ''), ('-Y', '-Y', ''), ('-Z', '-Z', '')]
params.primary_rotation_axis = bpy.props.EnumProperty(items=items, name="Primary Rotation Axis", default='X')
- params.bend_hint = bpy.props.BoolProperty(name="Bend Hint", default=True, description="Give IK chain a hint about which way to bend (useful for perfectly straight chains)")
- params.knee_target_base_name = bpy.props.StringProperty(name="Knee Target Name", default="knee_target", description="Base name for the generated knee target")
-
+ params.knee_base_name = bpy.props.StringProperty(name="Knee Name", default="knee", description="Base name for the generated knee-related controls")
params.separate_ik_layers = bpy.props.BoolProperty(name="Separate IK Control Layers:", default=False, description="Enable putting the ik controls on a separate layer from the fk controls")
params.ik_layers = bpy.props.BoolVectorProperty(size=32, description="Layers for the ik controls to be on")
- params.use_thigh_twist = bpy.props.BoolProperty(name="Thigh Twist", default=True, description="Generate the dual-bone twist setup for the thigh")
- params.use_shin_twist = bpy.props.BoolProperty(name="Shin Twist", default=True, description="Generate the dual-bone twist setup for the shin")
+ params.separate_hose_layers = bpy.props.BoolProperty(name="Separate Rubber-hose Control Layers:", default=False, description="Enable putting the rubber-hose controls on a separate layer from the other controls")
+ params.hose_layers = bpy.props.BoolVectorProperty(size=32, description="Layers for the rubber-hose controls to be on")
def parameters_ui(layout, params):
""" Create the ui for the rig parameters.
"""
+ col = layout.column()
+ col.prop(params, "use_complex_leg")
+
+ r = layout.row()
+ r.label(text="Knee rotation axis:")
+ r.prop(params, "primary_rotation_axis", text="")
+
+ r = layout.row()
+ r.prop(params, "knee_base_name")
+
r = layout.row()
- r.prop(params, "knee_target_base_name")
+ r.prop(params, "bend_hint")
r = layout.row()
r.prop(params, "separate_ik_layers")
@@ -163,16 +196,52 @@ def parameters_ui(layout, params):
row.prop(params, "ik_layers", index=30, toggle=True, text="")
row.prop(params, "ik_layers", index=31, toggle=True, text="")
- r = layout.row()
- r.label(text="Knee rotation axis:")
- r.prop(params, "primary_rotation_axis", text="")
-
- r = layout.row()
- r.prop(params, "bend_hint")
-
- col = layout.column()
- col.prop(params, "use_thigh_twist")
- col.prop(params, "use_shin_twist")
+ if params.use_complex_leg:
+ r = layout.row()
+ r.prop(params, "separate_hose_layers")
+
+ r = layout.row()
+ r.active = params.separate_hose_layers
+
+ col = r.column(align=True)
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=0, toggle=True, text="")
+ row.prop(params, "hose_layers", index=1, toggle=True, text="")
+ row.prop(params, "hose_layers", index=2, toggle=True, text="")
+ row.prop(params, "hose_layers", index=3, toggle=True, text="")
+ row.prop(params, "hose_layers", index=4, toggle=True, text="")
+ row.prop(params, "hose_layers", index=5, toggle=True, text="")
+ row.prop(params, "hose_layers", index=6, toggle=True, text="")
+ row.prop(params, "hose_layers", index=7, toggle=True, text="")
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=16, toggle=True, text="")
+ row.prop(params, "hose_layers", index=17, toggle=True, text="")
+ row.prop(params, "hose_layers", index=18, toggle=True, text="")
+ row.prop(params, "hose_layers", index=19, toggle=True, text="")
+ row.prop(params, "hose_layers", index=20, toggle=True, text="")
+ row.prop(params, "hose_layers", index=21, toggle=True, text="")
+ row.prop(params, "hose_layers", index=22, toggle=True, text="")
+ row.prop(params, "hose_layers", index=23, toggle=True, text="")
+
+ col = r.column(align=True)
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=8, toggle=True, text="")
+ row.prop(params, "hose_layers", index=9, toggle=True, text="")
+ row.prop(params, "hose_layers", index=10, toggle=True, text="")
+ row.prop(params, "hose_layers", index=11, toggle=True, text="")
+ row.prop(params, "hose_layers", index=12, toggle=True, text="")
+ row.prop(params, "hose_layers", index=13, toggle=True, text="")
+ row.prop(params, "hose_layers", index=14, toggle=True, text="")
+ row.prop(params, "hose_layers", index=15, toggle=True, text="")
+ row = col.row(align=True)
+ row.prop(params, "hose_layers", index=24, toggle=True, text="")
+ row.prop(params, "hose_layers", index=25, toggle=True, text="")
+ row.prop(params, "hose_layers", index=26, toggle=True, text="")
+ row.prop(params, "hose_layers", index=27, toggle=True, text="")
+ row.prop(params, "hose_layers", index=28, toggle=True, text="")
+ row.prop(params, "hose_layers", index=29, toggle=True, text="")
+ row.prop(params, "hose_layers", index=30, toggle=True, text="")
+ row.prop(params, "hose_layers", index=31, toggle=True, text="")
def create_sample(obj):
diff --git a/rigify/rigs/biped/leg/deform.py b/rigify/rigs/biped/leg/deform.py
index 0d0bb2a7..cde73250 100644
--- a/rigify/rigs/biped/leg/deform.py
+++ b/rigify/rigs/biped/leg/deform.py
@@ -18,58 +18,14 @@
# <pep8 compliant>
-from math import acos
-
import bpy
-from mathutils import Vector, Matrix
+
+from .. import limb_common
from ....utils import MetarigError
-from ....utils import copy_bone, put_bone
+from ....utils import copy_bone
from ....utils import connected_children_names, has_connected_children
-from ....utils import strip_org, make_mechanism_name, make_deformer_name
-
-
-def align_roll(obj, bone1, bone2):
- bone1_e = obj.data.edit_bones[bone1]
- bone2_e = obj.data.edit_bones[bone2]
-
- bone1_e.roll = 0.0
-
- # Get the directions the bones are pointing in, as vectors
- y1 = bone1_e.y_axis
- x1 = bone1_e.x_axis
- y2 = bone2_e.y_axis
- x2 = bone2_e.x_axis
-
- # Get the shortest axis to rotate bone1 on to point in the same direction as bone2
- axis = y1.cross(y2)
- axis.normalize()
-
- # Angle to rotate on that shortest axis
- angle = y1.angle(y2)
-
- # Create rotation matrix to make bone1 point in the same direction as bone2
- rot_mat = Matrix.Rotation(angle, 3, axis)
-
- # Roll factor
- x3 = rot_mat * x1
- dot = x2 * x3
- if dot > 1.0:
- dot = 1.0
- elif dot < -1.0:
- dot = -1.0
- roll = acos(dot)
-
- # Set the roll
- bone1_e.roll = roll
-
- # Check if we rolled in the right direction
- x3 = rot_mat * bone1_e.x_axis
- check = x2 * x3
-
- # If not, reverse
- if check < 0.9999:
- bone1_e.roll = -roll
+from ....utils import strip_org, make_deformer_name
class Rig:
@@ -77,13 +33,6 @@ class Rig:
"""
def __init__(self, obj, bone, params):
- """ Gather and validate data about the rig.
- Store any data or references to data that will be needed later on.
- In particular, store references to bones that will be needed, and
- store names of bones that will be needed.
- Do NOT change any data in the scene. This is a gathering phase only.
-
- """
self.obj = obj
self.params = params
@@ -104,9 +53,9 @@ class Rig:
heel = b.name
if foot is None:
- raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type -- could not find foot bone (that is, a bone with >1 children connected) attached to bone '%s'" % (strip_org(bone), strip_org(shin)))
+ raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type -- could not find foot bone (that is, a bone with >1 children connected) attached to bone '%s'" % (strip_org(bone), strip_org(leg_bones[1])))
if heel is None:
- raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type -- could not find heel bone (that is, a bone with no childrenconnected) attached to bone '%s'" % (strip_org(bone), strip_org(shin)))
+ raise MetarigError("RIGIFY ERROR: Bone '%s': incorrect bone configuration for rig type -- could not find heel bone (that is, a bone with no children connected) attached to bone '%s'" % (strip_org(bone), strip_org(leg_bones[1])))
# Get the toe
toe = None
for b in self.obj.data.bones[foot].children:
@@ -119,150 +68,25 @@ class Rig:
self.org_bones = leg_bones + [foot, toe, heel]
# Get rig parameters
- self.use_thigh_twist = params.use_thigh_twist
- self.use_shin_twist = params.use_shin_twist
-
- def generate(self):
- """ Generate the rig.
- Do NOT modify any of the original bones, except for adding constraints.
- The main armature should be selected and active before this is called.
-
- """
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create upper arm bones
- if self.use_thigh_twist:
- thigh1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".01")))
- thigh2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0] + ".02")))
- utip = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(self.org_bones[0] + ".tip")))
+ if params.separate_hose_layers:
+ layers = list(params.hose_layers)
else:
- thigh = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0])))
+ layers = None
+ use_complex_rig = params.use_complex_leg
+ knee_base_name = params.knee_base_name
+ primary_rotation_axis = params.primary_rotation_axis
- # Create forearm bones
- if self.use_shin_twist:
- shin1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".01")))
- shin2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1] + ".02")))
- stip = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(self.org_bones[1] + ".tip")))
- else:
- shin = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1])))
+ # Based on common limb
+ self.rubber_hose_limb = limb_common.RubberHoseLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], use_complex_rig, knee_base_name, primary_rotation_axis, layers)
- # Create foot bone
- foot = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))
+ def generate(self):
+ bone_list = self.rubber_hose_limb.generate()
- # Create toe bone
+ # Set up toe
+ bpy.ops.object.mode_set(mode='EDIT')
toe = copy_bone(self.obj, self.org_bones[3], make_deformer_name(strip_org(self.org_bones[3])))
-
- # Get edit bones
eb = self.obj.data.edit_bones
+ eb[toe].use_connect = False
+ eb[toe].parent = eb[self.org_bones[3]]
- org_thigh_e = eb[self.org_bones[0]]
- if self.use_thigh_twist:
- thigh1_e = eb[thigh1]
- thigh2_e = eb[thigh2]
- utip_e = eb[utip]
- else:
- thigh_e = eb[thigh]
-
- org_shin_e = eb[self.org_bones[1]]
- if self.use_shin_twist:
- shin1_e = eb[shin1]
- shin2_e = eb[shin2]
- stip_e = eb[stip]
- else:
- shin_e = eb[shin]
-
- org_foot_e = eb[self.org_bones[2]]
- foot_e = eb[foot]
-
- org_toe_e = eb[self.org_bones[3]]
- toe_e = eb[toe]
-
- # Parent and position thigh bones
- if self.use_thigh_twist:
- thigh1_e.use_connect = False
- thigh2_e.use_connect = False
- utip_e.use_connect = False
-
- thigh1_e.parent = org_thigh_e.parent
- thigh2_e.parent = org_thigh_e
- utip_e.parent = org_thigh_e
-
- center = Vector((org_thigh_e.head + org_thigh_e.tail) / 2)
-
- thigh1_e.tail = center
- thigh2_e.head = center
- put_bone(self.obj, utip, org_thigh_e.tail)
- utip_e.length = org_thigh_e.length / 8
- else:
- thigh_e.use_connect = False
- thigh_e.parent = org_thigh_e
-
- # Parent and position shin bones
- if self.use_shin_twist:
- shin1_e.use_connect = False
- shin2_e.use_connect = False
- stip_e.use_connect = False
-
- shin1_e.parent = org_shin_e
- shin2_e.parent = org_shin_e
- stip_e.parent = org_shin_e
-
- center = Vector((org_shin_e.head + org_shin_e.tail) / 2)
-
- shin1_e.tail = center
- shin2_e.head = center
- put_bone(self.obj, stip, org_shin_e.tail)
- stip_e.length = org_shin_e.length / 8
-
- # Align roll of shin2 with foot
- align_roll(self.obj, shin2, foot)
- else:
- shin_e.use_connect = False
- shin_e.parent = org_shin_e
-
- # Parent foot
- foot_e.use_connect = False
- foot_e.parent = org_foot_e
-
- # Parent toe
- toe_e.use_connect = False
- toe_e.parent = org_toe_e
-
- # Object mode, get pose bones
- bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- if self.use_thigh_twist:
- thigh1_p = pb[thigh1]
- if self.use_shin_twist:
- shin2_p = pb[shin2]
- # foot_p = pb[foot] # UNUSED
-
- # Thigh constraints
- if self.use_thigh_twist:
- con = thigh1_p.constraints.new('COPY_LOCATION')
- con.name = "copy_location"
- con.target = self.obj
- con.subtarget = self.org_bones[0]
-
- con = thigh1_p.constraints.new('COPY_SCALE')
- con.name = "copy_scale"
- con.target = self.obj
- con.subtarget = self.org_bones[0]
-
- con = thigh1_p.constraints.new('DAMPED_TRACK')
- con.name = "track_to"
- con.target = self.obj
- con.subtarget = utip
-
- # Shin constraints
- if self.use_shin_twist:
- con = shin2_p.constraints.new('COPY_ROTATION')
- con.name = "copy_rotation"
- con.target = self.obj
- con.subtarget = foot
-
- con = shin2_p.constraints.new('DAMPED_TRACK')
- con.name = "track_to"
- con.target = self.obj
- con.subtarget = stip
+ return bone_list
diff --git a/rigify/rigs/biped/leg/fk.py b/rigify/rigs/biped/leg/fk.py
index 4e224ceb..743e3a19 100644
--- a/rigify/rigs/biped/leg/fk.py
+++ b/rigify/rigs/biped/leg/fk.py
@@ -19,15 +19,15 @@
# <pep8 compliant>
import bpy
-from rna_prop_ui import rna_idprop_ui_prop_get
from mathutils import Vector
+from .. import limb_common
+
from ....utils import MetarigError
-from ....utils import copy_bone
from ....utils import connected_children_names, has_connected_children
-from ....utils import strip_org, make_mechanism_name, insert_before_lr
+from ....utils import strip_org
from ....utils import get_layers
-from ....utils import create_widget, create_limb_widget
+from ....utils import create_widget
class Rig:
@@ -84,11 +84,14 @@ class Rig:
# Get rig parameters
if "layers" in params:
- self.layers = get_layers(params["layers"])
+ layers = get_layers(params["layers"])
else:
- self.layers = None
+ layers = None
+
+ primary_rotation_axis = params.primary_rotation_axis
- self.primary_rotation_axis = params.primary_rotation_axis
+ # Leg is based on common limb
+ self.fk_limb = limb_common.FKLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], primary_rotation_axis, layers)
def generate(self):
""" Generate the rig.
@@ -96,152 +99,23 @@ class Rig:
The main armature should be selected and active before this is called.
"""
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create the control bones
- thigh = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], ".fk")))
- shin = copy_bone(self.obj, self.org_bones[1], strip_org(insert_before_lr(self.org_bones[1], ".fk")))
- foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".fk")))
+ ctrl_bones = self.fk_limb.generate()
+ thigh = ctrl_bones[0]
+ shin = ctrl_bones[1]
+ foot = ctrl_bones[2]
+ foot_mch = ctrl_bones[3]
- # Create the foot mechanism bone
- foot_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))
-
- # Create the hinge bones
- if self.org_parent != None:
- hinge = copy_bone(self.obj, self.org_parent, make_mechanism_name(thigh + ".hinge"))
- socket1 = copy_bone(self.obj, thigh, make_mechanism_name(thigh + ".socket1"))
- socket2 = copy_bone(self.obj, thigh, make_mechanism_name(thigh + ".socket2"))
-
- # Get edit bones
+ # Position foot control
+ bpy.ops.object.mode_set(mode='EDIT')
eb = self.obj.data.edit_bones
-
- thigh_e = eb[thigh]
- shin_e = eb[shin]
foot_e = eb[foot]
- foot_mch_e = eb[foot_mch]
-
- if self.org_parent != None:
- hinge_e = eb[hinge]
- socket1_e = eb[socket1]
- socket2_e = eb[socket2]
-
- # Parenting
- shin_e.parent = thigh_e
- foot_e.parent = shin_e
-
- foot_mch_e.use_connect = False
- foot_mch_e.parent = foot_e
-
- if self.org_parent != None:
- hinge_e.use_connect = False
- socket1_e.use_connect = False
- socket2_e.use_connect = False
-
- thigh_e.parent = hinge_e
- hinge_e.parent = socket2_e
- socket2_e.parent = None
-
- # Positioning
vec = Vector(eb[self.org_bones[3]].vector)
vec.normalize()
foot_e.tail = foot_e.head + (vec * foot_e.length)
foot_e.roll = eb[self.org_bones[3]].roll
-
- if self.org_parent != None:
- center = (hinge_e.head + hinge_e.tail) / 2
- hinge_e.head = center
- socket1_e.length /= 4
- socket2_e.length /= 3
-
- # Object mode, get pose bones
bpy.ops.object.mode_set(mode='OBJECT')
- pb = self.obj.pose.bones
-
- thigh_p = pb[thigh]
- shin_p = pb[shin]
- foot_p = pb[foot]
- if self.org_parent != None:
- hinge_p = pb[hinge]
-
- if self.org_parent != None:
- # socket1_p = pb[socket1] # UNUSED
- socket2_p = pb[socket2]
-
- # Set the knee to only bend on the x-axis.
- shin_p.rotation_mode = 'XYZ'
- if 'X' in self.primary_rotation_axis:
- shin_p.lock_rotation = (False, True, True)
- elif 'Y' in self.primary_rotation_axis:
- shin_p.lock_rotation = (True, False, True)
- else:
- shin_p.lock_rotation = (True, True, False)
-
- # Hinge transforms are locked, for auto-ik
- if self.org_parent != None:
- hinge_p.lock_location = True, True, True
- hinge_p.lock_rotation = True, True, True
- hinge_p.lock_rotation_w = True
- hinge_p.lock_scale = True, True, True
-
- # Set up custom properties
- if self.org_parent != None:
- prop = rna_idprop_ui_prop_get(thigh_p, "isolate", create=True)
- thigh_p["isolate"] = 0.0
- prop["soft_min"] = prop["min"] = 0.0
- prop["soft_max"] = prop["max"] = 1.0
-
- # Hinge constraints / drivers
- if self.org_parent != None:
- con = socket2_p.constraints.new('COPY_LOCATION')
- con.name = "copy_location"
- con.target = self.obj
- con.subtarget = socket1
-
- con = socket2_p.constraints.new('COPY_TRANSFORMS')
- con.name = "isolate_off"
- con.target = self.obj
- con.subtarget = socket1
-
- # Driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = thigh_p.path_from_id() + '["isolate"]'
- mod = fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- # Constrain org bones to controls
- con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = thigh
-
- con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = shin
-
- con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
- con.name = "fk"
- con.target = self.obj
- con.subtarget = foot_mch
-
- # Set layers if specified
- if self.layers:
- thigh_p.bone.layers = self.layers
- shin_p.bone.layers = self.layers
- foot_p.bone.layers = self.layers
-
- # Create control widgets
- create_limb_widget(self.obj, thigh)
- create_limb_widget(self.obj, shin)
+ # Create foot widget
ob = create_widget(self.obj, foot)
if ob != None:
verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
diff --git a/rigify/rigs/biped/leg/ik.py b/rigify/rigs/biped/leg/ik.py
index 52eae332..aea8502b 100644
--- a/rigify/rigs/biped/leg/ik.py
+++ b/rigify/rigs/biped/leg/ik.py
@@ -18,67 +18,17 @@
# <pep8 compliant>
-from math import pi, acos
-
import bpy
-from rna_prop_ui import rna_idprop_ui_prop_get
from mathutils import Vector
+from .. import limb_common
+
from ....utils import MetarigError
+from ....utils import align_bone_x_axis
from ....utils import copy_bone, flip_bone, put_bone
from ....utils import connected_children_names, has_connected_children
from ....utils import strip_org, make_mechanism_name, insert_before_lr
-from ....utils import create_widget, create_line_widget, create_sphere_widget, create_circle_widget
-
-
-def align_x_axis(obj, bone, vec):
- """ Aligns the x-axis of a bone to the given vector. This only works if it
- can be an exact match.
- Must be in edit mode.
-
- """
- vec.normalize()
- bone_e = obj.data.edit_bones[bone]
- dot = max(-1.0, min(1.0, bone_e.x_axis.dot(vec)))
- angle = acos(dot)
-
- bone_e.roll += angle
-
- dot1 = bone_e.x_axis.dot(vec)
-
- bone_e.roll -= angle * 2
-
- dot2 = bone_e.x_axis.dot(vec)
-
- if dot1 > dot2:
- bone_e.roll += angle * 2
-
-
-def angle_on_plane(plane, vec1, vec2):
- """ Return the angle between two vectors projected onto a plane.
- """
- plane.normalize()
- vec1 = vec1 - (plane * (vec1.dot(plane)))
- vec2 = vec2 - (plane * (vec2.dot(plane)))
- vec1.normalize()
- vec2.normalize()
-
- # Determine the angle
- angle = acos(max(-1.0, min(1.0, vec1.dot(vec2))))
-
- if angle < 0.00001: # close enough to zero that sign doesn't matter
- return angle
-
- # Determine the sign of the angle
- vec3 = vec2.cross(vec1)
- vec3.normalize()
- sign = vec3.dot(plane)
- if sign >= 0:
- sign = 1
- else:
- sign = -1
-
- return angle * sign
+from ....utils import create_widget, create_circle_widget
class Rig:
@@ -136,32 +86,35 @@ class Rig:
self.layers = list(params.ik_layers)
else:
self.layers = None
+ bend_hint = params.bend_hint
+ primary_rotation_axis = params.primary_rotation_axis
+ pole_target_base_name = self.params.knee_base_name + "_target"
- self.bend_hint = params.bend_hint
-
- self.primary_rotation_axis = params.primary_rotation_axis
+ # Leg is based on common limb
+ self.ik_limb = limb_common.IKLimb(obj, self.org_bones[0], self.org_bones[1], self.org_bones[2], pole_target_base_name, primary_rotation_axis, bend_hint, self.layers, ikfk_switch)
def generate(self):
""" Generate the rig.
Do NOT modify any of the original bones, except for adding constraints.
The main armature should be selected and active before this is called.
-
"""
+ # Generate base IK limb
+ bone_list = self.ik_limb.generate()
+ thigh = bone_list[0]
+ shin = bone_list[1]
+ foot = bone_list[2]
+ foot_mch = bone_list[3]
+ pole = bone_list[4]
+ # vispole = bone_list[5]
+ # visfoot = bone_list[6]
+
+ # Build IK foot rig
bpy.ops.object.mode_set(mode='EDIT')
-
make_rocker = False
if self.org_bones[5] is not None:
make_rocker = True
# Create the bones
- thigh = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".ik"))))
- shin = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".ik"))))
-
- foot = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".ik")))
- foot_ik_target = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[2], "_ik_target"))))
- pole_target_name = self.params.knee_target_base_name + "." + insert_before_lr(self.org_bones[0], ".ik").split(".", 1)[1]
- pole = copy_bone(self.obj, self.org_bones[0], pole_target_name)
-
toe = copy_bone(self.obj, self.org_bones[3], strip_org(self.org_bones[3]))
toe_parent = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".parent")))
toe_parent_socket1 = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[3] + ".socket1")))
@@ -175,18 +128,12 @@ class Rig:
rocker1 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.01")))
rocker2 = copy_bone(self.obj, self.org_bones[5], make_mechanism_name(strip_org(self.org_bones[2] + ".rocker.02")))
- visfoot = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], ".ik")))
- vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole.ik")))
-
# Get edit bones
eb = self.obj.data.edit_bones
org_foot_e = eb[self.org_bones[2]]
- thigh_e = eb[thigh]
- shin_e = eb[shin]
foot_e = eb[foot]
- foot_ik_target_e = eb[foot_ik_target]
- pole_e = eb[pole]
+ foot_ik_target_e = eb[foot_mch]
toe_e = eb[toe]
toe_parent_e = eb[toe_parent]
toe_parent_socket1_e = eb[toe_parent_socket1]
@@ -197,20 +144,11 @@ class Rig:
if make_rocker:
rocker1_e = eb[rocker1]
rocker2_e = eb[rocker2]
- visfoot_e = eb[visfoot]
- vispole_e = eb[vispole]
# Parenting
- shin_e.parent = thigh_e
-
- foot_e.use_connect = False
- foot_e.parent = None
foot_ik_target_e.use_connect = False
foot_ik_target_e.parent = roll2_e
- pole_e.use_connect = False
- pole_e.parent = foot_e
-
toe_e.parent = toe_parent_e
toe_parent_e.use_connect = False
toe_parent_e.parent = toe_parent_socket1_e
@@ -228,12 +166,6 @@ class Rig:
roll2_e.use_connect = False
roll2_e.parent = roll1_e
- visfoot_e.use_connect = False
- visfoot_e.parent = None
-
- vispole_e.use_connect = False
- vispole_e.parent = None
-
if make_rocker:
rocker1_e.use_connect = False
rocker2_e.use_connect = False
@@ -242,38 +174,12 @@ class Rig:
rocker2_e.parent = rocker1_e
rocker1_e.parent = foot_e
- # Misc
- foot_e.use_local_location = False
-
- visfoot_e.hide_select = True
- vispole_e.hide_select = True
-
# Positioning
vec = Vector(toe_e.vector)
vec.normalize()
foot_e.tail = foot_e.head + (vec * foot_e.length)
foot_e.roll = toe_e.roll
- v1 = shin_e.tail - thigh_e.head
-
- if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
- v2 = v1.cross(shin_e.x_axis)
- if (v2 * shin_e.z_axis) > 0.0:
- v2 *= -1.0
- else:
- v2 = v1.cross(shin_e.z_axis)
- if (v2 * shin_e.x_axis) < 0.0:
- v2 *= -1.0
- v2.normalize()
- v2 *= v1.length
-
- if '-' in self.primary_rotation_axis:
- v2 *= -1
-
- pole_e.head = shin_e.head + v2
- pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8))
- pole_e.roll = 0.0
-
flip_bone(self.obj, toe_parent_socket1)
flip_bone(self.obj, toe_parent_socket2)
toe_parent_socket1_e.head = Vector(org_foot_e.tail)
@@ -292,13 +198,10 @@ class Rig:
foot_roll_e.length /= 2
roll_axis = roll1_e.vector.cross(org_foot_e.vector)
- align_x_axis(self.obj, roll1, roll_axis)
- align_x_axis(self.obj, roll2, roll_axis)
+ align_bone_x_axis(self.obj, roll1, roll_axis)
+ align_bone_x_axis(self.obj, roll2, roll_axis)
foot_roll_e.roll = roll2_e.roll
- visfoot_e.tail = visfoot_e.head + Vector((0, 0, v1.length / 32))
- vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32))
-
if make_rocker:
d = toe_e.y_axis.dot(rocker1_e.x_axis)
if d >= 0.0:
@@ -306,30 +209,11 @@ class Rig:
else:
flip_bone(self.obj, rocker1)
- # Weird alignment issues. Fix.
- toe_parent_e.head = Vector(org_foot_e.head)
- toe_parent_e.tail = Vector(org_foot_e.tail)
- toe_parent_e.roll = org_foot_e.roll
-
- foot_e.head = Vector(org_foot_e.head)
-
- foot_ik_target_e.head = Vector(org_foot_e.head)
- foot_ik_target_e.tail = Vector(org_foot_e.tail)
-
- # Determine the pole offset value
- plane = (shin_e.tail - thigh_e.head).normalized()
- vec1 = thigh_e.x_axis.normalized()
- vec2 = (pole_e.head - thigh_e.head).normalized()
- pole_offset = angle_on_plane(plane, vec1, vec2)
-
# Object mode, get pose bones
bpy.ops.object.mode_set(mode='OBJECT')
pb = self.obj.pose.bones
- # thigh_p = pb[thigh] # UNUSED
- shin_p = pb[shin]
foot_p = pb[foot]
- pole_p = pb[pole]
foot_roll_p = pb[foot_roll]
roll1_p = pb[roll1]
roll2_p = pb[roll2]
@@ -337,21 +221,8 @@ class Rig:
rocker1_p = pb[rocker1]
rocker2_p = pb[rocker2]
toe_p = pb[toe]
- toe_parent_p = pb[toe_parent]
+ # toe_parent_p = pb[toe_parent]
toe_parent_socket1_p = pb[toe_parent_socket1]
- visfoot_p = pb[visfoot]
- vispole_p = pb[vispole]
-
- # Set the knee to only bend on the primary axis.
- if 'X' in self.primary_rotation_axis:
- shin_p.lock_ik_y = True
- shin_p.lock_ik_z = True
- elif 'Y' in self.primary_rotation_axis:
- shin_p.lock_ik_x = True
- shin_p.lock_ik_z = True
- else:
- shin_p.lock_ik_x = True
- shin_p.lock_ik_y = True
# Foot roll control only rotates on x-axis, or x and y if rocker.
foot_roll_p.rotation_mode = 'XYZ'
@@ -369,59 +240,6 @@ class Rig:
rocker1_p.rotation_mode = 'XYZ'
rocker2_p.rotation_mode = 'XYZ'
- # Pole target only translates
- pole_p.lock_location = False, False, False
- pole_p.lock_rotation = True, True, True
- pole_p.lock_rotation_w = True
- pole_p.lock_scale = True, True, True
-
- # Set up custom properties
- if self.switch is True:
- prop = rna_idprop_ui_prop_get(foot_p, "ikfk_switch", create=True)
- foot_p["ikfk_switch"] = 0.0
- prop["soft_min"] = prop["min"] = 0.0
- prop["soft_max"] = prop["max"] = 1.0
-
- # Bend direction hint
- if self.bend_hint:
- con = shin_p.constraints.new('LIMIT_ROTATION')
- con.name = "bend_hint"
- con.owner_space = 'LOCAL'
- if self.primary_rotation_axis == 'X':
- con.use_limit_x = True
- con.min_x = pi / 10
- con.max_x = pi / 10
- elif self.primary_rotation_axis == '-X':
- con.use_limit_x = True
- con.min_x = -pi / 10
- con.max_x = -pi / 10
- elif self.primary_rotation_axis == 'Y':
- con.use_limit_y = True
- con.min_y = pi / 10
- con.max_y = pi / 10
- elif self.primary_rotation_axis == '-Y':
- con.use_limit_y = True
- con.min_y = -pi / 10
- con.max_y = -pi / 10
- elif self.primary_rotation_axis == 'Z':
- con.use_limit_z = True
- con.min_z = pi / 10
- con.max_z = pi / 10
- elif self.primary_rotation_axis == '-Z':
- con.use_limit_z = True
- con.min_z = -pi / 10
- con.max_z = -pi / 10
-
- # IK Constraint
- con = shin_p.constraints.new('IK')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = foot_ik_target
- con.pole_target = self.obj
- con.pole_subtarget = pole
- con.pole_angle = pole_offset
- con.chain_count = 2
-
# toe_parent constraint
con = toe_parent_socket1_p.constraints.new('COPY_LOCATION')
con.name = "copy_location"
@@ -493,103 +311,24 @@ class Rig:
var.targets[0].id = self.obj
var.targets[0].data_path = foot_roll_p.path_from_id() + '.rotation_euler[1]'
- # Constrain org bones to controls
- con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = thigh
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'
-
- con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = shin
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'
-
- con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
- con.name = "ik"
- con.target = self.obj
- con.subtarget = foot_ik_target
- if self.switch is True:
- # IK/FK switch driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- var = driver.variables.new()
- driver.type = 'AVERAGE'
- var.name = "var"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = self.obj
- var.targets[0].data_path = foot_p.path_from_id() + '["ikfk_switch"]'
-
+ # Constrain toe bone to toe control
con = pb[self.org_bones[3]].constraints.new('COPY_TRANSFORMS')
con.name = "copy_transforms"
con.target = self.obj
con.subtarget = toe
- # VIS foot constraints
- con = visfoot_p.constraints.new('COPY_LOCATION')
- con.name = "copy_loc"
- con.target = self.obj
- con.subtarget = self.org_bones[2]
-
- con = visfoot_p.constraints.new('STRETCH_TO')
- con.name = "stretch_to"
- con.target = self.obj
- con.subtarget = foot
- con.volume = 'NO_VOLUME'
- con.rest_length = visfoot_p.length
-
- # VIS pole constraints
- con = vispole_p.constraints.new('COPY_LOCATION')
- con.name = "copy_loc"
- con.target = self.obj
- con.subtarget = self.org_bones[1]
-
- con = vispole_p.constraints.new('STRETCH_TO')
- con.name = "stretch_to"
- con.target = self.obj
- con.subtarget = pole
- con.volume = 'NO_VOLUME'
- con.rest_length = vispole_p.length
-
# Set layers if specified
if self.layers:
- foot_p.bone.layers = self.layers
- pole_p.bone.layers = self.layers
foot_roll_p.bone.layers = self.layers
- visfoot_p.bone.layers = self.layers
- vispole_p.bone.layers = self.layers
-
toe_p.bone.layers = [(i[0] or i[1]) for i in zip(toe_p.bone.layers, self.layers)] # Both FK and IK layers
# Create widgets
- create_line_widget(self.obj, vispole)
- create_line_widget(self.obj, visfoot)
- create_sphere_widget(self.obj, pole)
create_circle_widget(self.obj, toe, radius=0.7, head_tail=0.5)
- ob = create_widget(self.obj, foot)
+ ob = create_widget(self.obj, foot_roll)
if ob != None:
- verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
- edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)]
+ verts = [(0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247)]
+ edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)]
mesh = ob.data
mesh.from_pydata(verts, edges, [])
mesh.update()
@@ -597,10 +336,10 @@ class Rig:
mod = ob.modifiers.new("subsurf", 'SUBSURF')
mod.levels = 2
- ob = create_widget(self.obj, foot_roll)
+ ob = create_widget(self.obj, foot)
if ob != None:
- verts = [(0.3999999761581421, 0.766044557094574, 0.6427875757217407), (0.17668449878692627, 3.823702598992895e-08, 3.2084670920085046e-08), (-0.17668461799621582, 9.874240447516058e-08, 8.285470443070153e-08), (-0.39999961853027344, 0.7660449147224426, 0.6427879333496094), (0.3562471270561218, 0.6159579753875732, 0.5168500542640686), (-0.35624682903289795, 0.6159582138061523, 0.5168502926826477), (0.20492683351039886, 0.09688037633895874, 0.0812922865152359), (-0.20492687821388245, 0.0968804731965065, 0.08129236847162247)]
- edges = [(1, 2), (0, 3), (0, 4), (3, 5), (1, 6), (4, 6), (2, 7), (5, 7)]
+ verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
+ edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)]
mesh = ob.data
mesh.from_pydata(verts, edges, [])
mesh.update()
@@ -608,4 +347,4 @@ class Rig:
mod = ob.modifiers.new("subsurf", 'SUBSURF')
mod.levels = 2
- return [thigh, shin, foot, pole, foot_roll, foot_ik_target]
+ return [thigh, shin, foot, pole, foot_roll, foot_mch]
diff --git a/rigify/rigs/biped/limb_common.py b/rigify/rigs/biped/limb_common.py
new file mode 100644
index 00000000..ec29a510
--- /dev/null
+++ b/rigify/rigs/biped/limb_common.py
@@ -0,0 +1,1139 @@
+#====================== BEGIN GPL LICENSE BLOCK ======================
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+#======================= END GPL LICENSE BLOCK ========================
+
+from math import pi
+
+import bpy
+from rna_prop_ui import rna_idprop_ui_prop_get
+from mathutils import Vector
+
+from ...utils import angle_on_plane, align_bone_roll, align_bone_z_axis
+from ...utils import new_bone, copy_bone, put_bone, make_nonscaling_child
+from ...utils import strip_org, make_mechanism_name, make_deformer_name, insert_before_lr
+from ...utils import create_widget, create_limb_widget, create_line_widget, create_sphere_widget
+
+
+class FKLimb:
+ def __init__(self, obj, bone1, bone2, bone3, primary_rotation_axis, layers):
+ self.obj = obj
+
+ self.org_bones = [bone1, bone2, bone3]
+
+ # Get (optional) parent
+ if self.obj.data.bones[bone1].parent is None:
+ self.org_parent = None
+ else:
+ self.org_parent = self.obj.data.bones[bone1].parent.name
+
+ # Get the rig parameters
+ self.layers = layers
+ self.primary_rotation_axis = primary_rotation_axis
+
+ def generate(self):
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create non-scaling parent bone
+ if self.org_parent != None:
+ loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
+ parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_fk")
+ else:
+ parent = None
+
+ # Create the control bones
+ ulimb = copy_bone(self.obj, self.org_bones[0], strip_org(insert_before_lr(self.org_bones[0], ".fk")))
+ flimb = copy_bone(self.obj, self.org_bones[1], strip_org(insert_before_lr(self.org_bones[1], ".fk")))
+ elimb = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".fk")))
+
+ # Create the anti-stretch bones
+ fantistr = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], "_antistr.fk"))))
+ eantistr = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], "_antistr.fk"))))
+
+ # Create the end-limb mechanism bone
+ elimb_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))
+
+ # Create the hinge bones
+ if parent != None:
+ socket1 = copy_bone(self.obj, ulimb, make_mechanism_name(ulimb + ".socket1"))
+ socket2 = copy_bone(self.obj, ulimb, make_mechanism_name(ulimb + ".socket2"))
+
+ # Get edit bones
+ eb = self.obj.data.edit_bones
+
+ ulimb_e = eb[ulimb]
+ flimb_e = eb[flimb]
+ elimb_e = eb[elimb]
+
+ fantistr_e = eb[fantistr]
+ eantistr_e = eb[eantistr]
+
+ elimb_mch_e = eb[elimb_mch]
+
+ if parent != None:
+ socket1_e = eb[socket1]
+ socket2_e = eb[socket2]
+
+ # Parenting
+ elimb_mch_e.use_connect = False
+ elimb_mch_e.parent = elimb_e
+
+ elimb_e.use_connect = False
+ elimb_e.parent = eantistr_e
+
+ eantistr_e.use_connect = False
+ eantistr_e.parent = flimb_e
+
+ flimb_e.use_connect = False
+ flimb_e.parent = fantistr_e
+
+ fantistr_e.use_connect = False
+ fantistr_e.parent = ulimb_e
+
+ if parent != None:
+ socket1_e.use_connect = False
+ socket1_e.parent = eb[parent]
+
+ socket2_e.use_connect = False
+ socket2_e.parent = None
+
+ ulimb_e.use_connect = False
+ ulimb_e.parent = socket2_e
+
+ # Positioning
+ fantistr_e.length /= 8
+ put_bone(self.obj, fantistr, Vector(ulimb_e.tail))
+ eantistr_e.length /= 8
+ put_bone(self.obj, eantistr, Vector(flimb_e.tail))
+
+ if parent != None:
+ socket1_e.length /= 4
+ socket2_e.length /= 3
+
+ # Object mode, get pose bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pb = self.obj.pose.bones
+
+ ulimb_p = pb[ulimb]
+ flimb_p = pb[flimb]
+ elimb_p = pb[elimb]
+
+ fantistr_p = pb[fantistr]
+ eantistr_p = pb[eantistr]
+
+ if parent != None:
+ socket2_p = pb[socket2]
+
+ # Lock axes
+ ulimb_p.lock_location = (True, True, True)
+ flimb_p.lock_location = (True, True, True)
+ elimb_p.lock_location = (True, True, True)
+
+ # Set the elbow to only bend on the x-axis.
+ flimb_p.rotation_mode = 'XYZ'
+ if 'X' in self.primary_rotation_axis:
+ flimb_p.lock_rotation = (False, True, True)
+ elif 'Y' in self.primary_rotation_axis:
+ flimb_p.lock_rotation = (True, False, True)
+ else:
+ flimb_p.lock_rotation = (True, True, False)
+
+ # Set up custom properties
+ if parent != None:
+ prop = rna_idprop_ui_prop_get(ulimb_p, "isolate", create=True)
+ ulimb_p["isolate"] = 0.0
+ prop["soft_min"] = prop["min"] = 0.0
+ prop["soft_max"] = prop["max"] = 1.0
+
+ prop = rna_idprop_ui_prop_get(ulimb_p, "stretch_length", create=True)
+ ulimb_p["stretch_length"] = 1.0
+ prop["min"] = 0.05
+ prop["max"] = 20.0
+ prop["soft_min"] = 0.25
+ prop["soft_max"] = 4.0
+
+ # Stretch drivers
+ def add_stretch_drivers(pose_bone):
+ driver = pose_bone.driver_add("scale", 1).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "stretch_length"
+
+ driver = pose_bone.driver_add("scale", 0).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "1/sqrt(stretch_length)"
+
+ driver = pose_bone.driver_add("scale", 2).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "1/sqrt(stretch_length)"
+
+ def add_antistretch_drivers(pose_bone):
+ driver = pose_bone.driver_add("scale", 1).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "1/stretch_length"
+
+ driver = pose_bone.driver_add("scale", 0).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "sqrt(stretch_length)"
+
+ driver = pose_bone.driver_add("scale", 2).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "sqrt(stretch_length)"
+
+ add_stretch_drivers(ulimb_p)
+ add_stretch_drivers(flimb_p)
+ add_antistretch_drivers(fantistr_p)
+ add_antistretch_drivers(eantistr_p)
+
+ # Hinge constraints / drivers
+ if parent != None:
+ con = socket2_p.constraints.new('COPY_LOCATION')
+ con.name = "copy_location"
+ con.target = self.obj
+ con.subtarget = socket1
+
+ con = socket2_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "isolate_off"
+ con.target = self.obj
+ con.subtarget = socket1
+
+ # Driver
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = ulimb_p.path_from_id() + '["isolate"]'
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ # Constrain org bones to controls
+ con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
+ con.name = "fk"
+ con.target = self.obj
+ con.subtarget = ulimb
+
+ con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
+ con.name = "fk"
+ con.target = self.obj
+ con.subtarget = flimb
+
+ con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
+ con.name = "fk"
+ con.target = self.obj
+ con.subtarget = elimb_mch
+
+ # Set layers if specified
+ if self.layers:
+ ulimb_p.bone.layers = self.layers
+ flimb_p.bone.layers = self.layers
+ elimb_p.bone.layers = self.layers
+
+ # Create control widgets
+ create_limb_widget(self.obj, ulimb)
+ create_limb_widget(self.obj, flimb)
+
+ ob = create_widget(self.obj, elimb)
+ if ob != None:
+ verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
+ edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)]
+ mesh = ob.data
+ mesh.from_pydata(verts, edges, [])
+ mesh.update()
+
+ mod = ob.modifiers.new("subsurf", 'SUBSURF')
+ mod.levels = 2
+
+ return [ulimb, flimb, elimb, elimb_mch]
+
+
+class IKLimb:
+ """ An IK limb rig, with an optional ik/fk switch.
+
+ """
+ def __init__(self, obj, bone1, bone2, bone3, pole_target_base_name, primary_rotation_axis, bend_hint, layers, ikfk_switch=False):
+ self.obj = obj
+ self.switch = ikfk_switch
+
+ # Get the chain of 3 connected bones
+ self.org_bones = [bone1, bone2, bone3]
+
+ # Get (optional) parent
+ if self.obj.data.bones[bone1].parent is None:
+ self.org_parent = None
+ else:
+ self.org_parent = self.obj.data.bones[bone1].parent.name
+
+ # Get the rig parameters
+ self.pole_target_base_name = pole_target_base_name
+ self.layers = layers
+ self.bend_hint = bend_hint
+ self.primary_rotation_axis = primary_rotation_axis
+
+ def generate(self):
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create non-scaling parent bone
+ if self.org_parent != None:
+ loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
+ parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_ik")
+ else:
+ parent = None
+
+ # Create the bones
+ ulimb = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".ik"))))
+ flimb = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".ik"))))
+ elimb = copy_bone(self.obj, self.org_bones[2], strip_org(insert_before_lr(self.org_bones[2], ".ik")))
+ elimb_mch = copy_bone(self.obj, self.org_bones[2], make_mechanism_name(strip_org(self.org_bones[2])))
+
+ ulimb_nostr = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".nostr.ik"))))
+ flimb_nostr = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".nostr.ik"))))
+
+ ulimb_str = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[0], ".stretch.ik"))))
+ flimb_str = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".stretch.ik"))))
+
+ pole_target_name = self.pole_target_base_name + "." + insert_before_lr(self.org_bones[0], ".ik").split(".", 1)[1]
+ pole = copy_bone(self.obj, self.org_bones[0], pole_target_name)
+
+ viselimb = copy_bone(self.obj, self.org_bones[2], "VIS-" + strip_org(insert_before_lr(self.org_bones[2], ".ik")))
+ vispole = copy_bone(self.obj, self.org_bones[1], "VIS-" + strip_org(insert_before_lr(self.org_bones[0], "_pole.ik")))
+
+ # Get edit bones
+ eb = self.obj.data.edit_bones
+
+ if parent != None:
+ parent_e = eb[parent]
+ ulimb_e = eb[ulimb]
+ flimb_e = eb[flimb]
+ elimb_e = eb[elimb]
+ elimb_mch_e = eb[elimb_mch]
+ ulimb_nostr_e = eb[ulimb_nostr]
+ flimb_nostr_e = eb[flimb_nostr]
+ ulimb_str_e = eb[ulimb_str]
+ flimb_str_e = eb[flimb_str]
+ pole_e = eb[pole]
+ viselimb_e = eb[viselimb]
+ vispole_e = eb[vispole]
+
+ # Parenting
+ ulimb_e.use_connect = False
+ ulimb_nostr_e.use_connect = False
+ if parent != None:
+ ulimb_e.parent = parent_e
+ ulimb_nostr_e.parent = parent_e
+
+ flimb_e.parent = ulimb_e
+ flimb_nostr_e.parent = ulimb_nostr_e
+
+ elimb_e.use_connect = False
+ elimb_e.parent = None
+
+ elimb_mch_e.use_connect = False
+ elimb_mch_e.parent = elimb_e
+
+ ulimb_str_e.use_connect = False
+ ulimb_str_e.parent = ulimb_e.parent
+
+ flimb_str_e.use_connect = False
+ flimb_str_e.parent = ulimb_e.parent
+
+ pole_e.use_connect = False
+ if parent != None:
+ pole_e.parent = parent_e
+
+ viselimb_e.use_connect = False
+ viselimb_e.parent = None
+
+ vispole_e.use_connect = False
+ vispole_e.parent = None
+
+ # Misc
+ elimb_e.use_local_location = False
+
+ viselimb_e.hide_select = True
+ vispole_e.hide_select = True
+
+ # Positioning
+ v1 = flimb_e.tail - ulimb_e.head
+ if 'X' in self.primary_rotation_axis or 'Y' in self.primary_rotation_axis:
+ v2 = v1.cross(flimb_e.x_axis)
+ if (v2 * flimb_e.z_axis) > 0.0:
+ v2 *= -1.0
+ else:
+ v2 = v1.cross(flimb_e.z_axis)
+ if (v2 * flimb_e.x_axis) < 0.0:
+ v2 *= -1.0
+ v2.normalize()
+ v2 *= v1.length
+
+ if '-' in self.primary_rotation_axis:
+ v2 *= -1
+
+ pole_e.head = flimb_e.head + v2
+ pole_e.tail = pole_e.head + (Vector((0, 1, 0)) * (v1.length / 8))
+ pole_e.roll = 0.0
+
+ viselimb_e.tail = viselimb_e.head + Vector((0, 0, v1.length / 32))
+ vispole_e.tail = vispole_e.head + Vector((0, 0, v1.length / 32))
+
+ # Determine the pole offset value
+ plane = (flimb_e.tail - ulimb_e.head).normalized()
+ vec1 = ulimb_e.x_axis.normalized()
+ vec2 = (pole_e.head - ulimb_e.head).normalized()
+ pole_offset = angle_on_plane(plane, vec1, vec2)
+
+ # Object mode, get pose bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pb = self.obj.pose.bones
+
+ ulimb_p = pb[ulimb]
+ flimb_p = pb[flimb]
+ elimb_p = pb[elimb]
+ ulimb_nostr_p = pb[ulimb_nostr]
+ flimb_nostr_p = pb[flimb_nostr]
+ ulimb_str_p = pb[ulimb_str]
+ flimb_str_p = pb[flimb_str]
+ pole_p = pb[pole]
+ viselimb_p = pb[viselimb]
+ vispole_p = pb[vispole]
+
+ # Set the elbow to only bend on the primary axis
+ if 'X' in self.primary_rotation_axis:
+ flimb_p.lock_ik_y = True
+ flimb_p.lock_ik_z = True
+ flimb_nostr_p.lock_ik_y = True
+ flimb_nostr_p.lock_ik_z = True
+ elif 'Y' in self.primary_rotation_axis:
+ flimb_p.lock_ik_x = True
+ flimb_p.lock_ik_z = True
+ flimb_nostr_p.lock_ik_x = True
+ flimb_nostr_p.lock_ik_z = True
+ else:
+ flimb_p.lock_ik_x = True
+ flimb_p.lock_ik_y = True
+ flimb_nostr_p.lock_ik_x = True
+ flimb_nostr_p.lock_ik_y = True
+
+ # Limb stretches
+ ulimb_nostr_p.ik_stretch = 0.0
+ flimb_nostr_p.ik_stretch = 0.0
+
+ # This next bit is weird. The values calculated cause
+ # ulimb and flimb to preserve their relative lengths
+ # while stretching.
+ l1 = ulimb_p.length
+ l2 = flimb_p.length
+ if l1 < l2:
+ ulimb_p.ik_stretch = (l1 ** (1 / 3)) / (l2 ** (1 / 3))
+ flimb_p.ik_stretch = 1.0
+ else:
+ ulimb_p.ik_stretch = 1.0
+ flimb_p.ik_stretch = (l2 ** (1 / 3)) / (l1 ** (1 / 3))
+
+ # Pole target only translates
+ pole_p.lock_location = False, False, False
+ pole_p.lock_rotation = True, True, True
+ pole_p.lock_rotation_w = True
+ pole_p.lock_scale = True, True, True
+
+ # Set up custom properties
+ if self.switch is True:
+ prop = rna_idprop_ui_prop_get(elimb_p, "ikfk_switch", create=True)
+ elimb_p["ikfk_switch"] = 0.0
+ prop["soft_min"] = prop["min"] = 0.0
+ prop["soft_max"] = prop["max"] = 1.0
+
+ prop = rna_idprop_ui_prop_get(elimb_p, "stretch_length", create=True)
+ elimb_p["stretch_length"] = 1.0
+ prop["min"] = 0.05
+ prop["max"] = 20.0
+ prop["soft_min"] = 0.25
+ prop["soft_max"] = 4.0
+
+ prop = rna_idprop_ui_prop_get(elimb_p, "auto_stretch", create=True)
+ elimb_p["auto_stretch"] = 1.0
+ prop["soft_min"] = prop["min"] = 0.0
+ prop["soft_max"] = prop["max"] = 1.0
+
+ # Stretch parameter drivers
+ def add_stretch_drivers(pose_bone):
+ driver = pose_bone.driver_add("scale", 1).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "stretch_length"
+
+ driver = pose_bone.driver_add("scale", 0).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "stretch_length"
+
+ driver = pose_bone.driver_add("scale", 2).driver
+ var = driver.variables.new()
+ var.name = "stretch_length"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["stretch_length"]'
+ driver.type = 'SCRIPTED'
+ driver.expression = "stretch_length"
+ add_stretch_drivers(ulimb_nostr_p)
+
+ # Bend direction hint
+ def add_bend_hint(pose_bone, axis):
+ con = pose_bone.constraints.new('LIMIT_ROTATION')
+ con.name = "bend_hint"
+ con.owner_space = 'LOCAL'
+ if axis == 'X':
+ con.use_limit_x = True
+ con.min_x = pi / 10
+ con.max_x = pi / 10
+ elif axis == '-X':
+ con.use_limit_x = True
+ con.min_x = -pi / 10
+ con.max_x = -pi / 10
+ elif axis == 'Y':
+ con.use_limit_y = True
+ con.min_y = pi / 10
+ con.max_y = pi / 10
+ elif axis == '-Y':
+ con.use_limit_y = True
+ con.min_y = -pi / 10
+ con.max_y = -pi / 10
+ elif axis == 'Z':
+ con.use_limit_z = True
+ con.min_z = pi / 10
+ con.max_z = pi / 10
+ elif axis == '-Z':
+ con.use_limit_z = True
+ con.min_z = -pi / 10
+ con.max_z = -pi / 10
+ if self.bend_hint:
+ add_bend_hint(flimb_p, self.primary_rotation_axis)
+ add_bend_hint(flimb_nostr_p, self.primary_rotation_axis)
+
+ # Constrain normal IK chain to no-stretch IK chain
+ con = ulimb_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "pre_stretch"
+ con.target = self.obj
+ con.subtarget = ulimb_nostr
+
+ con = flimb_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "pre_stretch"
+ con.target = self.obj
+ con.subtarget = flimb_nostr
+
+ # IK Constraints
+ con = flimb_nostr_p.constraints.new('IK')
+ con.name = "ik"
+ con.target = self.obj
+ con.subtarget = elimb_mch
+ con.pole_target = self.obj
+ con.pole_subtarget = pole
+ con.pole_angle = pole_offset
+ con.chain_count = 2
+
+ con = flimb_p.constraints.new('IK')
+ con.name = "ik"
+ con.target = self.obj
+ con.subtarget = elimb_mch
+ con.chain_count = 2
+
+ # Driver to enable/disable auto stretching IK chain
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["auto_stretch"]'
+
+ # Stretch bone constraints
+ con = ulimb_str_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = ulimb
+ con = ulimb_str_p.constraints.new('MAINTAIN_VOLUME')
+ con.name = "stretch"
+ con.owner_space = 'LOCAL'
+
+ con = flimb_str_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = flimb
+ con = flimb_str_p.constraints.new('MAINTAIN_VOLUME')
+ con.name = "stretch"
+ con.owner_space = 'LOCAL'
+
+ # Constrain org bones
+ con = pb[self.org_bones[0]].constraints.new('COPY_TRANSFORMS')
+ con.name = "ik"
+ con.target = self.obj
+ con.subtarget = ulimb_str
+ if self.switch is True:
+ # IK/FK switch driver
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["ikfk_switch"]'
+
+ con = pb[self.org_bones[1]].constraints.new('COPY_TRANSFORMS')
+ con.name = "ik"
+ con.target = self.obj
+ con.subtarget = flimb_str
+ if self.switch is True:
+ # IK/FK switch driver
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["ikfk_switch"]'
+
+ con = pb[self.org_bones[2]].constraints.new('COPY_TRANSFORMS')
+ con.name = "ik"
+ con.target = self.obj
+ con.subtarget = elimb_mch
+ if self.switch is True:
+ # IK/FK switch driver
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = elimb_p.path_from_id() + '["ikfk_switch"]'
+
+ # VIS limb-end constraints
+ con = viselimb_p.constraints.new('COPY_LOCATION')
+ con.name = "copy_loc"
+ con.target = self.obj
+ con.subtarget = self.org_bones[2]
+
+ con = viselimb_p.constraints.new('STRETCH_TO')
+ con.name = "stretch_to"
+ con.target = self.obj
+ con.subtarget = elimb
+ con.volume = 'NO_VOLUME'
+ con.rest_length = viselimb_p.length
+
+ # VIS pole constraints
+ con = vispole_p.constraints.new('COPY_LOCATION')
+ con.name = "copy_loc"
+ con.target = self.obj
+ con.subtarget = self.org_bones[1]
+
+ con = vispole_p.constraints.new('STRETCH_TO')
+ con.name = "stretch_to"
+ con.target = self.obj
+ con.subtarget = pole
+ con.volume = 'NO_VOLUME'
+ con.rest_length = vispole_p.length
+
+ # Set layers if specified
+ if self.layers:
+ elimb_p.bone.layers = self.layers
+ pole_p.bone.layers = self.layers
+ viselimb_p.bone.layers = self.layers
+ vispole_p.bone.layers = self.layers
+
+ # Create widgets
+ create_line_widget(self.obj, vispole)
+ create_line_widget(self.obj, viselimb)
+ create_sphere_widget(self.obj, pole)
+
+ ob = create_widget(self.obj, elimb)
+ if ob != None:
+ verts = [(0.7, 1.5, 0.0), (0.7, -0.25, 0.0), (-0.7, -0.25, 0.0), (-0.7, 1.5, 0.0), (0.7, 0.723, 0.0), (-0.7, 0.723, 0.0), (0.7, 0.0, 0.0), (-0.7, 0.0, 0.0)]
+ edges = [(1, 2), (0, 3), (0, 4), (3, 5), (4, 6), (1, 6), (5, 7), (2, 7)]
+ mesh = ob.data
+ mesh.from_pydata(verts, edges, [])
+ mesh.update()
+
+ mod = ob.modifiers.new("subsurf", 'SUBSURF')
+ mod.levels = 2
+
+ return [ulimb, flimb, elimb, elimb_mch, pole, vispole, viselimb]
+
+
+class RubberHoseLimb:
+ def __init__(self, obj, bone1, bone2, bone3, use_complex_limb, junc_base_name, primary_rotation_axis, layers):
+ self.obj = obj
+
+ # Get the chain of 3 connected bones
+ self.org_bones = [bone1, bone2, bone3]
+
+ # Get (optional) parent
+ if self.obj.data.bones[bone1].parent is None:
+ self.org_parent = None
+ else:
+ self.org_parent = self.obj.data.bones[bone1].parent.name
+
+ # Get rig parameters
+ self.layers = layers
+ self.primary_rotation_axis = primary_rotation_axis
+ self.use_complex_limb = use_complex_limb
+ self.junc_base_name = junc_base_name
+
+ def generate(self):
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create non-scaling parent bone
+ if self.org_parent != None:
+ loc = Vector(self.obj.data.edit_bones[self.org_bones[0]].head)
+ parent = make_nonscaling_child(self.obj, self.org_parent, loc, "_rh")
+ else:
+ parent = None
+
+ if not self.use_complex_limb:
+ # Simple rig
+
+ # Create bones
+ ulimb = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(self.org_bones[0])))
+ flimb = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(self.org_bones[1])))
+ elimb = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))
+
+ # Get edit bones
+ eb = self.obj.data.edit_bones
+
+ ulimb_e = eb[ulimb]
+ flimb_e = eb[flimb]
+ elimb_e = eb[elimb]
+
+ # Parenting
+ elimb_e.parent = flimb_e
+ elimb_e.use_connect = True
+
+ flimb_e.parent = ulimb_e
+ flimb_e.use_connect = True
+
+ if parent != None:
+ elimb_e.use_connect = False
+ ulimb_e.parent = eb[parent]
+
+ # Object mode, get pose bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pb = self.obj.pose.bones
+
+ ulimb_p = pb[ulimb]
+ flimb_p = pb[flimb]
+ elimb_p = pb[elimb]
+
+ # Constrain def bones to org bones
+ con = ulimb_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "def"
+ con.target = self.obj
+ con.subtarget = self.org_bones[0]
+
+ con = flimb_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "def"
+ con.target = self.obj
+ con.subtarget = self.org_bones[1]
+
+ con = elimb_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "def"
+ con.target = self.obj
+ con.subtarget = self.org_bones[2]
+
+ return []
+ else:
+ # Complex rig
+
+ # Get the .R or .L off the end of the upper limb name if it exists
+ lr = self.org_bones[0].split(".", 1)
+ if len(lr) == 1:
+ lr = ""
+ else:
+ lr = lr[1]
+
+ # Create bones
+ ulimb1 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(insert_before_lr(self.org_bones[0], ".01"))))
+ ulimb2 = copy_bone(self.obj, self.org_bones[0], make_deformer_name(strip_org(insert_before_lr(self.org_bones[0], ".02"))))
+ flimb1 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(insert_before_lr(self.org_bones[1], ".01"))))
+ flimb2 = copy_bone(self.obj, self.org_bones[1], make_deformer_name(strip_org(insert_before_lr(self.org_bones[1], ".02"))))
+ elimb = copy_bone(self.obj, self.org_bones[2], make_deformer_name(strip_org(self.org_bones[2])))
+
+ junc = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(self.org_bones[1], ".junc"))))
+
+ uhose = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[0], "_hose")))
+ jhose = new_bone(self.obj, self.junc_base_name + "_hose." + lr)
+ fhose = new_bone(self.obj, strip_org(insert_before_lr(self.org_bones[1], "_hose")))
+
+ uhose_par = copy_bone(self.obj, self.org_bones[0], make_mechanism_name(strip_org(insert_before_lr(uhose, "_parent"))))
+ jhose_par = copy_bone(self.obj, junc, make_mechanism_name(strip_org(insert_before_lr(jhose, "_parent"))))
+ fhose_par = copy_bone(self.obj, self.org_bones[1], make_mechanism_name(strip_org(insert_before_lr(fhose, "_parent"))))
+
+ # Get edit bones
+ eb = self.obj.data.edit_bones
+
+ if parent != None:
+ parent_e = eb[parent]
+ else:
+ parent_e = None
+
+ ulimb1_e = eb[ulimb1]
+ ulimb2_e = eb[ulimb2]
+ flimb1_e = eb[flimb1]
+ flimb2_e = eb[flimb2]
+ elimb_e = eb[elimb]
+
+ junc_e = eb[junc]
+
+ uhose_e = eb[uhose]
+ jhose_e = eb[jhose]
+ fhose_e = eb[fhose]
+
+ uhose_par_e = eb[uhose_par]
+ jhose_par_e = eb[jhose_par]
+ fhose_par_e = eb[fhose_par]
+
+ # Parenting
+ if parent != None:
+ ulimb1_e.use_connect = False
+ ulimb1_e.parent = parent_e
+
+ ulimb2_e.use_connect = False
+ ulimb2_e.parent = eb[self.org_bones[0]]
+
+ flimb1_e.use_connect = True
+ flimb1_e.parent = ulimb2_e
+
+ flimb2_e.use_connect = False
+ flimb2_e.parent = eb[self.org_bones[1]]
+
+ elimb_e.use_connect = False
+ elimb_e.parent = eb[self.org_bones[2]]
+
+ junc_e.use_connect = False
+ junc_e.parent = eb[self.org_bones[0]]
+
+ uhose_e.use_connect = False
+ uhose_e.parent = uhose_par_e
+
+ jhose_e.use_connect = False
+ jhose_e.parent = jhose_par_e
+
+ fhose_e.use_connect = False
+ fhose_e.parent = fhose_par_e
+
+ uhose_par_e.use_connect = False
+ uhose_par_e.parent = parent_e
+
+ jhose_par_e.use_connect = False
+ jhose_par_e.parent = parent_e
+
+ fhose_par_e.use_connect = False
+ fhose_par_e.parent = parent_e
+
+ # Positioning
+ ulimb1_e.length *= 0.5
+ ulimb2_e.head = Vector(ulimb1_e.tail)
+ flimb1_e.length *= 0.5
+ flimb2_e.head = Vector(flimb1_e.tail)
+ align_bone_roll(self.obj, flimb2, elimb)
+
+ junc_e.length *= 0.2
+
+ uhose_par_e.length *= 0.25
+ jhose_par_e.length *= 0.15
+ fhose_par_e.length *= 0.25
+ put_bone(self.obj, uhose_par, Vector(ulimb1_e.tail))
+ put_bone(self.obj, jhose_par, Vector(ulimb2_e.tail))
+ put_bone(self.obj, fhose_par, Vector(flimb1_e.tail))
+
+ put_bone(self.obj, uhose, Vector(ulimb1_e.tail))
+ put_bone(self.obj, jhose, Vector(ulimb2_e.tail))
+ put_bone(self.obj, fhose, Vector(flimb1_e.tail))
+
+ if 'X' in self.primary_rotation_axis:
+ upoint = Vector(ulimb1_e.z_axis)
+ fpoint = Vector(flimb1_e.z_axis)
+ elif 'Z' in self.primary_rotation_axis:
+ upoint = Vector(ulimb1_e.x_axis)
+ fpoint = Vector(flimb1_e.x_axis)
+ else: # Y
+ upoint = Vector(ulimb1_e.z_axis)
+ fpoint = Vector(flimb1_e.z_axis)
+
+ if '-' not in self.primary_rotation_axis:
+ upoint *= -1
+ fpoint *= -1
+
+ if 'Y' in self.primary_rotation_axis:
+ uside = Vector(ulimb1_e.x_axis)
+ fside = Vector(flimb1_e.x_axis)
+ else:
+ uside = Vector(ulimb1_e.y_axis) * -1
+ fside = Vector(flimb1_e.y_axis) * -1
+
+ uhose_e.tail = uhose_e.head + upoint
+ jhose_e.tail = fhose_e.head + upoint + fpoint
+ fhose_e.tail = fhose_e.head + fpoint
+
+ align_bone_z_axis(self.obj, uhose, uside)
+ align_bone_z_axis(self.obj, jhose, uside + fside)
+ align_bone_z_axis(self.obj, fhose, fside)
+
+ l = 0.125 * (ulimb1_e.length + ulimb2_e.length + flimb1_e.length + flimb2_e.length)
+ uhose_e.length = l
+ jhose_e.length = l
+ fhose_e.length = l
+
+ # Object mode, get pose bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+ pb = self.obj.pose.bones
+
+ ulimb1_p = pb[ulimb1]
+ ulimb2_p = pb[ulimb2]
+ flimb1_p = pb[flimb1]
+ flimb2_p = pb[flimb2]
+ elimb_p = pb[elimb]
+
+ junc_p = pb[junc]
+
+ uhose_p = pb[uhose]
+ jhose_p = pb[jhose]
+ fhose_p = pb[fhose]
+
+ uhose_par_p = pb[uhose_par]
+ jhose_par_p = pb[jhose_par]
+ fhose_par_p = pb[fhose_par]
+
+ # Lock axes
+ uhose_p.lock_rotation = (True, True, True)
+ uhose_p.lock_rotation_w = True
+ uhose_p.lock_scale = (True, True, True)
+
+ jhose_p.lock_rotation = (True, True, True)
+ jhose_p.lock_rotation_w = True
+ jhose_p.lock_scale = (True, True, True)
+
+ fhose_p.lock_rotation = (True, True, True)
+ fhose_p.lock_rotation_w = True
+ fhose_p.lock_scale = (True, True, True)
+
+ # B-bone settings
+ ulimb2_p.bone.bbone_segments = 16
+ ulimb2_p.bone.bbone_in = 0.0
+ ulimb2_p.bone.bbone_out = 1.0
+
+ flimb1_p.bone.bbone_segments = 16
+ flimb1_p.bone.bbone_in = 1.0
+ flimb1_p.bone.bbone_out = 0.0
+
+ # Custom properties
+ prop = rna_idprop_ui_prop_get(jhose_p, "smooth_bend", create=True)
+ jhose_p["smooth_bend"] = 0.0
+ prop["soft_min"] = prop["min"] = 0.0
+ prop["soft_max"] = prop["max"] = 1.0
+
+ # Drivers
+ fcurve = ulimb2_p.bone.driver_add("bbone_out")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = jhose_p.path_from_id() + '["smooth_bend"]'
+
+ fcurve = flimb1_p.bone.driver_add("bbone_in")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = self.obj
+ var.targets[0].data_path = jhose_p.path_from_id() + '["smooth_bend"]'
+
+ # Constraints
+ con = ulimb1_p.constraints.new('COPY_SCALE')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = self.org_bones[0]
+ con = ulimb1_p.constraints.new('DAMPED_TRACK')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = uhose
+ con = ulimb1_p.constraints.new('STRETCH_TO')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = uhose
+ con.volume = 'NO_VOLUME'
+
+ con = ulimb2_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = uhose
+ con = ulimb2_p.constraints.new('DAMPED_TRACK')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = jhose
+ con = ulimb2_p.constraints.new('STRETCH_TO')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = jhose
+ con.volume = 'NO_VOLUME'
+
+ con = flimb1_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = self.org_bones[1]
+ con = flimb1_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = jhose
+ con = flimb1_p.constraints.new('DAMPED_TRACK')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = fhose
+ con = flimb1_p.constraints.new('STRETCH_TO')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = fhose
+ con.volume = 'NO_VOLUME'
+
+ con = flimb2_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = fhose
+ con = flimb2_p.constraints.new('COPY_ROTATION')
+ con.name = "twist"
+ con.target = self.obj
+ con.subtarget = elimb
+ con = flimb2_p.constraints.new('DAMPED_TRACK')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = self.org_bones[2]
+ con = flimb2_p.constraints.new('STRETCH_TO')
+ con.name = "track"
+ con.target = self.obj
+ con.subtarget = self.org_bones[2]
+ con.volume = 'NO_VOLUME'
+
+ con = junc_p.constraints.new('COPY_TRANSFORMS')
+ con.name = "bend"
+ con.target = self.obj
+ con.subtarget = self.org_bones[1]
+ con.influence = 0.5
+
+ con = uhose_par_p.constraints.new('COPY_ROTATION')
+ con.name = "follow"
+ con.target = self.obj
+ con.subtarget = self.org_bones[0]
+ con.influence = 1.0
+ con = uhose_par_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = self.org_bones[0]
+ con.influence = 1.0
+ con = uhose_par_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = jhose
+ con.influence = 0.5
+
+ con = jhose_par_p.constraints.new('COPY_ROTATION')
+ con.name = "follow"
+ con.target = self.obj
+ con.subtarget = junc
+ con.influence = 1.0
+ con = jhose_par_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = junc
+ con.influence = 1.0
+
+ con = fhose_par_p.constraints.new('COPY_ROTATION')
+ con.name = "follow"
+ con.target = self.obj
+ con.subtarget = self.org_bones[1]
+ con.influence = 1.0
+ con = fhose_par_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = jhose
+ con.influence = 1.0
+ con = fhose_par_p.constraints.new('COPY_LOCATION')
+ con.name = "anchor"
+ con.target = self.obj
+ con.subtarget = self.org_bones[2]
+ con.influence = 0.5
+
+ # Layers
+ if self.layers:
+ uhose_p.bone.layers = self.layers
+ jhose_p.bone.layers = self.layers
+ fhose_p.bone.layers = self.layers
+ else:
+ layers = list(pb[self.org_bones[0]].bone.layers)
+ uhose_p.bone.layers = layers
+ jhose_p.bone.layers = layers
+ fhose_p.bone.layers = layers
+
+ # Create widgets
+ create_sphere_widget(self.obj, uhose)
+ create_sphere_widget(self.obj, jhose)
+ create_sphere_widget(self.obj, fhose)
+
+ return [uhose, jhose, fhose]
diff --git a/rigify/rigs/misc/delta.py b/rigify/rigs/misc/delta.py
index a005fb61..84f3612b 100644
--- a/rigify/rigs/misc/delta.py
+++ b/rigify/rigs/misc/delta.py
@@ -90,7 +90,6 @@ if False:
con.target = self.obj
con.subtarget = delta
-
def create_sample(obj):
# generated by rigify.utils.write_metarig
bpy.ops.object.mode_set(mode='EDIT')
@@ -140,7 +139,6 @@ if False:
bone.select_tail = True
arm.edit_bones.active = bone
-
def set_mat(obj, bone_name, matrix):
""" Sets the bone to have the given transform matrix.
"""
diff --git a/rigify/rigs/neck_short.py b/rigify/rigs/neck_short.py
index 9c24832a..63174d40 100644
--- a/rigify/rigs/neck_short.py
+++ b/rigify/rigs/neck_short.py
@@ -25,7 +25,7 @@ from ..utils import MetarigError
from ..utils import copy_bone, new_bone, put_bone
from ..utils import connected_children_names
from ..utils import strip_org, make_mechanism_name, make_deformer_name
-from ..utils import obj_to_bone, create_circle_widget
+from ..utils import create_circle_widget
script1 = """
@@ -315,8 +315,8 @@ class Rig:
i += 1
# Create control widgets
- w1 = create_circle_widget(self.obj, neck_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[(len(self.org_bones) - 1) // 2])
- w2 = create_circle_widget(self.obj, head_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[-1])
+ create_circle_widget(self.obj, neck_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[(len(self.org_bones) - 1) // 2])
+ create_circle_widget(self.obj, head_ctrl, radius=1.0, head_tail=0.5, bone_transform_name=self.org_bones[-1])
# Return control bones
return (head_ctrl, neck_ctrl)
diff --git a/rigify/rigs/spine.py b/rigify/rigs/spine.py
index 0983e83e..680a4ceb 100644
--- a/rigify/rigs/spine.py
+++ b/rigify/rigs/spine.py
@@ -33,7 +33,7 @@ from ..utils import MetarigError
from ..utils import copy_bone, new_bone, flip_bone, put_bone
from ..utils import connected_children_names
from ..utils import strip_org, make_mechanism_name, make_deformer_name
-from ..utils import obj_to_bone, create_circle_widget, create_cube_widget
+from ..utils import create_circle_widget, create_cube_widget
script = """
main = "%s"
@@ -174,7 +174,6 @@ class Rig:
eb[main_control].length = sum([eb[b].length for b in self.org_bones]) / 2
# Position the controls and sub-controls
- pos = eb[controls[0]].head.copy()
for name, subname in zip(controls, subcontrols):
put_bone(self.obj, name, pivot_rest_pos)
put_bone(self.obj, subname, pivot_rest_pos)
@@ -443,23 +442,23 @@ class Rig:
# Control appearance
# Main
- w = create_cube_widget(self.obj, main_control)
+ create_cube_widget(self.obj, main_control)
# Spines
for name, i in zip(controls[1:-1], self.control_indices[1:-1]):
pb[name].custom_shape_transform = pb[self.org_bones[i]]
# Create control widgets
- w = create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[i])
+ create_circle_widget(self.obj, name, radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[i])
# Hips
pb[controls[0]].custom_shape_transform = pb[self.org_bones[0]]
# Create control widgets
- w = create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[0])
+ create_circle_widget(self.obj, controls[0], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[0])
# Ribs
pb[controls[-1]].custom_shape_transform = pb[self.org_bones[-1]]
# Create control widgets
- w = create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[-1])
+ create_circle_widget(self.obj, controls[-1], radius=1.0, head_tail=0.5, with_line=True, bone_transform_name=self.org_bones[-1])
# Layers
pb[main_control].bone.layers = pb[self.org_bones[0]].bone.layers