Okay, then. That’s fine by me.
One thing, though. I tried your nlerpRecursive with this
= (x=0, y=0, z=0, w=1) and q
= (0, 1, 0, -4.371E-8).
The -4.371E-8 is due to inaccuracies when building a rotation of 180 degrees around the Y axis, like so: Quaternionf q = new Quaternionf().rotateY((float) Math.PI)
This resulted in the normalization factor s
(that 1.0/sqrt(...)
in nlerp) to become NaN in the first iteration of your while loop and then the whole result became NaN.
EDIT: Ah, it was an error on my side when translating and inlining that.
Now, the final version is:
public Quaternionf nlerpIterative(Quaternionf q, float alpha, float dotThreshold, Quaternionf dest) {
float q1x = x, q1y = y, q1z = z, q1w = w;
float q2x = q.x, q2y = q.y, q2z = q.z, q2w = q.w;
float dot = q1x * q2x + q1y * q2y + q1z * q2z + q1w * q2w;
float alphaN = alpha;
while (Math.abs(dot) < dotThreshold) {
float scale0 = 0.5f;
float scale1 = dot >= 0.0f ? alphaN : -alphaN;
if (alphaN < 0.5f) {
q2x = scale0 * q2x + scale1 * q1x;
q2y = scale0 * q2y + scale1 * q1y;
q2z = scale0 * q2z + scale1 * q1z;
q2w = scale0 * q2w + scale1 * q1w;
float s = (float) (1.0 / Math.sqrt(q2x * q2x + q2y * q2y + q2z * q2z + q2w * q2w));
q2x *= s;
q2y *= s;
q2z *= s;
q2w *= s;
alphaN = alphaN * 2.0f;
} else {
q1x = scale0 * q1x + scale1 * q2x;
q1y = scale0 * q1y + scale1 * q2y;
q1z = scale0 * q1z + scale1 * q2z;
q1w = scale0 * q1w + scale1 * q2w;
float s = (float) (1.0 / Math.sqrt(q1x * q1x + q1y * q1y + q1z * q1z + q1w * q1w));
q1x *= s;
q1y *= s;
q1z *= s;
q1w *= s;
alphaN = alphaN * 2.0f - 1.0f;
}
dot = q1x * q2x + q1y * q2y + q1z * q2z + q1w * q2w;
}
float scale0 = 1.0f - alphaN;
float scale1 = dot >= 0.0f ? alphaN : -alphaN;
dest.x = scale0 * q1x + scale1 * q2x;
dest.y = scale0 * q1y + scale1 * q2y;
dest.z = scale0 * q1z + scale1 * q2z;
dest.w = scale0 * q1w + scale1 * q2w;
float s = (float) (1.0 / Math.sqrt(dest.x * dest.x + dest.y * dest.y + dest.z * dest.z + dest.w * dest.w));
dest.x *= s;
dest.y *= s;
dest.z *= s;
dest.w *= s;
return dest;
}
Seems to work.