From ad83e136bf700f936c3d76d4e3f938e51fcc2cc5 Mon Sep 17 00:00:00 2001 From: Nathan Vegdahl Date: Mon, 29 Nov 2010 23:24:13 +0000 Subject: - 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. --- rigify/rigs/biped/arm/ik.py | 44 +++++++++++++++++++++++++++++++--------- rigify/rigs/biped/leg/ik.py | 49 ++++++++++++++++++++++++++++++++------------- rigify/rigs/finger.py | 4 ++++ 3 files changed, 74 insertions(+), 23 deletions(-) (limited to 'rigify') diff --git a/rigify/rigs/biped/arm/ik.py b/rigify/rigs/biped/arm/ik.py index c341ede6..2b941b9e 100644 --- a/rigify/rigs/biped/arm/ik.py +++ b/rigify/rigs/biped/arm/ik.py @@ -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 diff --git a/rigify/rigs/biped/leg/ik.py b/rigify/rigs/biped/leg/ik.py index 5697a2b6..a04b57dc 100644 --- a/rigify/rigs/biped/leg/ik.py +++ b/rigify/rigs/biped/leg/ik.py @@ -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 diff --git a/rigify/rigs/finger.py b/rigify/rigs/finger.py index de028f36..f5788d02 100644 --- a/rigify/rigs/finger.py +++ b/rigify/rigs/finger.py @@ -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) -- cgit v1.2.3