I have a jointed character and I'm trying to use some IK-type logic for generating procedural walking animations. I'm using a very constrained set up which means I can solve the resulting equations analytically. Each section of the leg is a GameObject with the usual parenting relationships (i.e. hip->knee->ankle). I'm considering each joint in the leg as being able to rotate only through 1 axis, effectively the the x-axis of the body (in my case, body y is up, body z is forward). This means that my character's knees can hinge in the expected manner (i.e. forward and back), and the hips are similarly only allowed to swing forwards and back (no side-to-side movement or rotation is permitted).
I'm doing the rotation of the knee like so:
private Transform knee;
...
float currentAngle = calculateCurrentRotationAngleToWorldVertical(knee);
float desiredAngle = calculateDesiredRotationAngleToWorldVertical(knee);
float delta = Mathf.DeltaAngle(currentAngle, desiredAngle);
Vector3 rotationAxisInLocalSpace = knee.InverseTransformDirection(rotationAxisInWorldSpace);
Quaternion q = Quaternion.AngleAxis(delta, rotationAxisInLocalSpace);
knee.localRotation *= q;
i.e. I first measure the angle of the knee relative to vertical (with all vectors projected into the plane of the rotation axis), then calculate the desired angle of the knee relative to vertical, figure the change in angle and apply that rotation about the rotation axis to the knee's local rotation quaternion. I haven't supplied details of how I calculate the current and desired rotation angles as I don't think they are directly relevant, but I can add them if required.
This works most of the time, but occasionally seems to generate rather odd results. Sometimes it seems to rotate the wrong way around the rotation axis. For example, the knee is initially rotated such that the angle between it and the world y axis is 143.9 degrees. The desired angle is 170 degrees, so the delta is +26.1 degrees (i.e. 170 - 143.9 = 26.1). When I do the rotation as above, it goes the wrong way, and if I measure the angle afterwards, I see that it is actually 117.8 degrees, i.e. it has subtracted the delta, not added it.
Does anyone know why this is happening? Is it some subtlety of quaternion maths that I'm ignorant of?
Any help much appreciated.
Edit - the issue seems to surface if the stride length decreases (i.e. if the character is trying to move his foot back towards his body).