## Vector dot product
-Computes the dot product of two vectors. Internal accuracy must be greater than the
+Computes the dot product of two vectors. Internal accuracy must be greater than the
input vectors and the result.
## Vector length
<https://en.m.wikipedia.org/wiki/Linear_interpolation>
-## Vector SLERP
+Pseudocode:
-<https://en.m.wikipedia.org/wiki/Slerp>
+ // Imprecise method, which does not guarantee v = v1 when t = 1,
+ // due to floating-point arithmetic error.
+ // This form may be used when the hardware has a native fused
+ // multiply-add instruction.
+ float lerp(float v0, float v1, float t) {
+ return v0 + t * (v1 - v0);
+ }
-"""
-Quaternion slerp(Quaternion v0, Quaternion v1, double t) {
- // Only unit quaternions are valid rotations.
- // Normalize to avoid undefined behavior.
- v0.normalize();
- v1.normalize();
-
- // Compute the cosine of the angle between the two vectors.
- double dot = dot_product(v0, v1);
-
- // If the dot product is negative, slerp won't take
- // the shorter path. Note that v1 and -v1 are equivalent when
- // the negation is applied to all four components. Fix by
- // reversing one quaternion.
- if (dot < 0.0f) {
- v1 = -v1;
- dot = -dot;
- }
-
- const double DOT_THRESHOLD = 0.9995;
- if (dot > DOT_THRESHOLD) {
- // If the inputs are too close for comfort, linearly interpolate
- // and normalize the result.
-
- Quaternion result = v0 + t*(v1 - v0);
- result.normalize();
- return result;
+ // Precise method, which guarantees v = v1 when t = 1.
+ float lerp(float v0, float v1, float t) {
+ return (1 - t) * v0 + t * v1;
}
- // Since dot is in range [0, DOT_THRESHOLD], acos is safe
- double theta_0 = acos(dot); // theta_0 = angle between input vectors
- double theta = theta_0*t; // theta = angle between v0 and result
- double sin_theta = sin(theta); // compute this value only once
- double sin_theta_0 = sin(theta_0); // compute this value only once
+## Vector SLERP
- double s0 = cos(theta) - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0)
- double s1 = sin_theta / sin_theta_0;
+<https://en.m.wikipedia.org/wiki/Slerp>
- return (s0 * v0) + (s1 * v1);
-}
-"""
+Pseudocode:
+
+ Quaternion slerp(Quaternion v0, Quaternion v1, double t) {
+ // Only unit quaternions are valid rotations.
+ // Normalize to avoid undefined behavior.
+ v0.normalize();
+ v1.normalize();
+
+ // Compute the cosine of the angle between the two vectors.
+ double dot = dot_product(v0, v1);
+
+ // If the dot product is negative, slerp won't take
+ // the shorter path. Note that v1 and -v1 are equivalent when
+ // the negation is applied to all four components. Fix by
+ // reversing one quaternion.
+ if (dot < 0.0f) {
+ v1 = -v1;
+ dot = -dot;
+ }
+
+ const double DOT_THRESHOLD = 0.9995;
+ if (dot > DOT_THRESHOLD) {
+ // If the inputs are too close for comfort, linearly interpolate
+ // and normalize the result.
+
+ Quaternion result = v0 + t*(v1 - v0);
+ result.normalize();
+ return result;
+ }
+
+ // Since dot is in range [0, DOT_THRESHOLD], acos is safe
+ double theta_0 = acos(dot); // theta_0 = angle between input vectors
+ double theta = theta_0*t; // theta = angle between v0 and result
+ double sin_theta = sin(theta); // compute this value only once
+ double sin_theta_0 = sin(theta_0); // compute this value only once
+
+ double s0 = cos(theta) - dot * sin_theta / sin_theta_0; // == sin(theta_0 - theta) / sin(theta_0)
+ double s1 = sin_theta / sin_theta_0;
+
+ return (s0 * v0) + (s1 * v1);
+ }