1

I would like to build on top of this question about rotating an object towards specific target with quaternions. My particular use case would be to orient a joint in 3d space towards another or a target point, as the stepping stone for implementing inverse kinematics.

I use glm math library to calculate dot and cross products. I also use its defined structs, vec3 and quat.

Here is the relevant code:

quat AxisAngleToQuat(float angle, vec3 axis) {
    quat myquat = quat(cos(angle/2), axis.x*sin(angle/2), axis.y*sin(angle/2), axis.z*sin(angle/2));
    return myquat;
}

vec3 direction = normalize(targetPos-sourcePos);
float dotProduct = dot(sourceForward, direction);
float angle = acos(dotProduct);
vec3 axis = normalize(cross(sourceForward, direction));

quat myquat;
//Handle special case where dotProduct is 1
if (Math.Abs(dotProduct-1.0f) < 0.000001f) {
    myquat = quat(1, 0, 0, 0); //create identity quaternion
}

//Handle special case where dotProduct is -1
else if (Math.Abs(dotProduct+1.0f) < 0.000001f) {
    vec3 arbitraryAxis = vec3(0, 1, 0); //we can choose global up as the arbitrary axis
    myquat = AxisAngleToQuat((float)M_PI, arbitraryAxis);
}
else {
    myquat = AxisAngleToQuat(angle, axis);
}

Now after implementing this and handling all special cases, there's still a problem. When the angle comes close to 180 degrees (we get close to source object's original backwards direction -sourceForward), small changes in angle (small translations of target object) result in extreme changes to the source object orientation's.

My question is why does this happen and what can we do dampen this effect?

Lenny White
  • 406
  • 4
  • 8
  • Can you elaborate on what you do with the quaternion and where the extreme change happens? Btw, in the case of dot product -1, you cannot choose an arbitrary axis. The axis has to be perpendicular to the direction. – Nico Schertler May 08 '19 at 15:26
  • @NicoSchertler: Right, thanks! Would this be a better way to calculate that axis `perpAxis = cross(vec3(1, 0, 0), sourceForward)`? So basically I convert the quaternion to 4x4 rotation matrix and feed it to GPU to rotate the source object and all it's vertices with that rotation matrix. – Lenny White May 08 '19 at 15:44
  • Yes, that would be better. Although you should check if the direction lies on the x-axis. Is this used in a CCD framework? Obviously, if you need a bone to turn around completely, it is ambiguous what path it would take. Usually, these situations are avoided since only small movements are required from the previous solution. – Nico Schertler May 08 '19 at 15:47
  • @NicoSchertler: No I use FABRIK algorithm. I think even if I'll end up not needing to have the bones turn around at such an angle, I would still like to know how to handle such cases, i.e. applying dampening for when the angle approaches 180 degrees. – Lenny White May 08 '19 at 15:51
  • 2
    As far as I know, there is no way because there must inevitably be a point where orientation switches. Smooth vector fields on a sphere (for which you basically search a flowline) must contain at least one singularity (hairy ball theorem). If you don't want the orientation to behave weirdly at the source direction, you will need two, which is exactly what you get (one at the source direction, one at the opposite direction). – Nico Schertler May 08 '19 at 15:56
  • @NicoSchertler: Could I ask, what would be a good way to change the point where the orientation switches? If say I wanted to have it at the object's up direction, how would I do that with a quaternion? – Lenny White May 14 '19 at 22:28
  • I haven't figured out a complete solution, but your rotation would have an axis that lies in the bisector between source direction and up direction. From the available paths on the sphere, you would need to find the one where your target direction lies on and return the according rotation. But I doubt that you really want to do this. – Nico Schertler May 14 '19 at 23:41

0 Answers0