Skip to content
Snippets Groups Projects
Commit ad83e136 authored by Nathan Vegdahl's avatar Nathan Vegdahl
Browse files

- Minor fix for the finger rig. It was accepting, and failing on,

single-bone chains.  Now it refuses single-bone chains.
- IK arm and leg rigs now set the pole angle offset more precisely, so that
the arm/leg doesn't shift in the default pose when switching between IK/FK.
parent 9ec6e4e5
No related branches found
No related tags found
No related merge requests found
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
import bpy import bpy
from mathutils import Vector from mathutils import Vector
from math import pi from math import pi, acos
from rigify.utils import MetarigError from rigify.utils import MetarigError
from rigify.utils import copy_bone from rigify.utils import copy_bone
from rigify.utils import connected_children_names from rigify.utils import connected_children_names
...@@ -28,6 +28,33 @@ from rigify.utils import create_widget, create_line_widget, create_sphere_widget ...@@ -28,6 +28,33 @@ from rigify.utils import create_widget, create_line_widget, create_sphere_widget
from rna_prop_ui import rna_idprop_ui_prop_get from rna_prop_ui import rna_idprop_ui_prop_get
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
class Rig: class Rig:
""" An IK arm rig, with an optional ik/fk switch. """ An IK arm rig, with an optional ik/fk switch.
...@@ -130,6 +157,12 @@ class Rig: ...@@ -130,6 +157,12 @@ class Rig:
vishand_e.tail = vishand_e.head + Vector((0, 0, v1.length / 32)) vishand_e.tail = vishand_e.head + Vector((0, 0, v1.length / 32))
vispole_e.tail = vispole_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).normalize()
vec1 = uarm_e.x_axis.normalize()
vec2 = (pole_e.head - uarm_e.head).normalize()
pole_offset = angle_on_plane(plane, vec1, vec2)
# Object mode, get pose bones # Object mode, get pose bones
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
pb = self.obj.pose.bones pb = self.obj.pose.bones
...@@ -172,14 +205,7 @@ class Rig: ...@@ -172,14 +205,7 @@ class Rig:
con.subtarget = hand con.subtarget = hand
con.pole_target = self.obj con.pole_target = self.obj
con.pole_subtarget = pole con.pole_subtarget = pole
if self.primary_rotation_axis == 'X' or self.primary_rotation_axis == 'Y': con.pole_angle = pole_offset
con.pole_angle = -pi / 2
elif self.primary_rotation_axis == '-X' or self.primary_rotation_axis == '-Y':
con.pole_angle = pi / 2
elif self.primary_rotation_axis == 'Z':
con.pole_angle = 0.0
elif self.primary_rotation_axis == '-Z':
con.pole_angle = pi
con.chain_count = 2 con.chain_count = 2
# Constrain org bones to controls # Constrain org bones to controls
......
...@@ -36,12 +36,7 @@ def align_x_axis(obj, bone, vec): ...@@ -36,12 +36,7 @@ def align_x_axis(obj, bone, vec):
""" """
vec.normalize() vec.normalize()
bone_e = obj.data.edit_bones[bone] bone_e = obj.data.edit_bones[bone]
dot = bone_e.x_axis.dot(vec) dot = max(-1.0, min(1.0, bone_e.x_axis.dot(vec)))
if dot < -1:
dot = -1
elif dot > 1:
dot = 1
angle = acos(dot) angle = acos(dot)
bone_e.roll += angle bone_e.roll += angle
...@@ -56,6 +51,33 @@ def align_x_axis(obj, bone, vec): ...@@ -56,6 +51,33 @@ def align_x_axis(obj, bone, vec):
bone_e.roll += angle * 2 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
class Rig: class Rig:
""" An IK leg rig, with an optional ik/fk switch. """ An IK leg rig, with an optional ik/fk switch.
...@@ -258,6 +280,12 @@ class Rig: ...@@ -258,6 +280,12 @@ class Rig:
foot_ik_target_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) foot_ik_target_e.tail = Vector(org_foot_e.tail)
# Determine the pole offset value
plane = (shin_e.tail - thigh_e.head).normalize()
vec1 = thigh_e.x_axis.normalize()
vec2 = (pole_e.head - thigh_e.head).normalize()
pole_offset = angle_on_plane(plane, vec1, vec2)
# Object mode, get pose bones # Object mode, get pose bones
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
pb = self.obj.pose.bones pb = self.obj.pose.bones
...@@ -312,14 +340,7 @@ class Rig: ...@@ -312,14 +340,7 @@ class Rig:
con.subtarget = foot_ik_target con.subtarget = foot_ik_target
con.pole_target = self.obj con.pole_target = self.obj
con.pole_subtarget = pole con.pole_subtarget = pole
if self.primary_rotation_axis == 'X' or self.primary_rotation_axis == 'Y': con.pole_angle = pole_offset
con.pole_angle = -pi / 2
elif self.primary_rotation_axis == '-X' or self.primary_rotation_axis == '-Y':
con.pole_angle = pi / 2
elif self.primary_rotation_axis == 'Z':
con.pole_angle = 0.0
elif self.primary_rotation_axis == '-Z':
con.pole_angle = pi
con.chain_count = 2 con.chain_count = 2
# toe_parent constraint # toe_parent constraint
......
...@@ -39,6 +39,10 @@ class Rig: ...@@ -39,6 +39,10 @@ class Rig:
self.org_bones = [bone] + connected_children_names(obj, bone) self.org_bones = [bone] + connected_children_names(obj, bone)
self.params = params self.params = params
if len(self.org_bones) <= 1:
raise MetarigError("RIGIFY ERROR: Bone '%s': input to rig type must be a chain of 2 or more bones." % (strip_org(bone)))
# Get user-specified layers, if they exist # Get user-specified layers, if they exist
if params.separate_extra_layers: if params.separate_extra_layers:
self.ex_layers = list(params.extra_layers) self.ex_layers = list(params.extra_layers)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment