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 @@
import bpy
from mathutils import Vector
from math import pi
from math import pi, acos
from rigify.utils import MetarigError
from rigify.utils import copy_bone
from rigify.utils import connected_children_names
......@@ -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
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:
""" An IK arm rig, with an optional ik/fk switch.
......@@ -130,6 +157,12 @@ class Rig:
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).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
bpy.ops.object.mode_set(mode='OBJECT')
pb = self.obj.pose.bones
......@@ -172,14 +205,7 @@ class Rig:
con.subtarget = hand
con.pole_target = self.obj
con.pole_subtarget = pole
if self.primary_rotation_axis == 'X' or self.primary_rotation_axis == 'Y':
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.pole_angle = pole_offset
con.chain_count = 2
# Constrain org bones to controls
......
......@@ -36,12 +36,7 @@ def align_x_axis(obj, bone, vec):
"""
vec.normalize()
bone_e = obj.data.edit_bones[bone]
dot = bone_e.x_axis.dot(vec)
if dot < -1:
dot = -1
elif dot > 1:
dot = 1
dot = max(-1.0, min(1.0, bone_e.x_axis.dot(vec)))
angle = acos(dot)
bone_e.roll += angle
......@@ -56,6 +51,33 @@ def align_x_axis(obj, bone, vec):
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:
""" An IK leg rig, with an optional ik/fk switch.
......@@ -258,6 +280,12 @@ class Rig:
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).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
bpy.ops.object.mode_set(mode='OBJECT')
pb = self.obj.pose.bones
......@@ -312,14 +340,7 @@ class Rig:
con.subtarget = foot_ik_target
con.pole_target = self.obj
con.pole_subtarget = pole
if self.primary_rotation_axis == 'X' or self.primary_rotation_axis == 'Y':
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.pole_angle = pole_offset
con.chain_count = 2
# toe_parent constraint
......
......@@ -39,6 +39,10 @@ class Rig:
self.org_bones = [bone] + connected_children_names(obj, bone)
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
if params.separate_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.
Please register or to comment