Quaternion operator bugs

  1. This implementation of Quaternion multiplication looks backwards/inverse to me:
    const ofQuaternion ofQuaternion::operator*(const ofQuaternion& rhs) const {
    return ofQuaternion(rhs._v.w*_v.x + rhs._v.x*_v.w + rhs._v.y*_v.z - rhs._v.z*_v.y,
    rhs._v.w*_v.y - rhs._v.x*_v.z + rhs._v.y*_v.w + rhs._v.z*_v.x,
    rhs._v.w*_v.z + rhs._v.x*_v.y - rhs._v.y*_v.x + rhs._v.z*_v.w,
    rhs._v.w*_v.w - rhs._v.x*_v.x - rhs._v.y*_v.y - rhs._v.z*_v.z);
    }
    This looks like rhs * this, instead of this * rhs.
    Given that quaternions are non-commutative, this is important.

  2. I’m not sure where this implementation of Quaternion-Vector multiplication came from:
    ofVec3f ofQuaternion::operator*(const ofVec3f& v) const {
    // nVidia SDK implementation
    ofVec3f uv, uuv;
    ofVec3f qvec(_v.x, _v.y, _v.z);
    uv = qvec.getCrossed(v); //uv = qvec ^ v;
    uuv = qvec.getCrossed(uv); //uuv = qvec ^ uv;
    uv = (2.0f * _v.w);
    uuv = 2.0f;
    return v + uv + uuv;
    }
    It says it came from the NVIDIA implementation, but this is what I found for the NVIDIA implementation:
    const PxVec3 rotate(const PxVec3& v)
    {
    const float vx = 2.0f * v.x;
    const float vy = 2.0f * v.y;
    const float vz = 2.0f * v.z;
    const float w2 = w * w - 0.5f;
    const float dot2 = (x * vx + y * vy + z * vz);
    return PxVec3((vx * w2 + (y * vz - z * vy) * w + x * dot2), (vy * w2 + (z * vx - x * vz) * w + y * dot2),
    (vz * w2 + (x * vy - y * vx) * w + z * dot2));
    }
    For one, these two algorithms might look similar if you squint, but they are different (as far as I can tell).
    Furthermore, the OF implementation doesn’t even use w at all. It disregards it altogether. NVIDIA uses w.
    Last but not least, I’m not familiar with this sort of implementation. I’m more familiar with the q
    v
    q^{-1} method of rotating a vector with a quaternion. So both of the above implementations don’t make sense to me.

Any relevant feedback is highly appreciated. Thanks!
Also, if I wanted to help improve the source code, how would I go about doing that?

References:
OpenFrameworks Quaternion: https://openframeworks.cc/documentation/math/ofQuaternion/#show_operator*
NVIDIA Quaternion: https://docs.nvidia.com/gameworks/content/gameworkslibrary/physx/apireference/files/PxQuat_8h-source.html

Hi,
the ofQuaternion has been deprecated along with all the ofVec*f in favor of GLM.
It is no longer used in the core, it is still there for backwards compatibility.
That function is fine, as it was heavily used before and it behaved as expected.
read this post http://blog.openframeworks.cc/post/173546759884/glm
it will clarify your doubts.
Thanks for pointing this out anyways.
Cheers

Thanks for the feedback! Really appreciate it.

  1. This still looks inverse to me. Easy to miss, since the rotation still looks right, but it’s just in the wrong direction.
  2. I see now that the unknown implementation is just a simplification of qvq^{-1}:
    https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion
    Still seems slightly different, but oh well – the math is probably equivalent,

Looks like I should have been using GLM. Luckily, it hasn’t been too long since 10.0 came out in ?May 2018.
Looks like the examples haven’t caught up which is fine. Thanks again for the heads up!

  • Luis

Hi Luis,
GLM was first introduced into OF a while ago in the development version but it was not until 0.10 that it became oficial and OF’s vector and quaternion math implementations were deprecated.
Yes, the examples still need to be updated.

How can you tel that it is inverse? is it somehow numerically incorrect?
cheers

I suppose it is using the same convention as ofMatrix multiplication, where this is correct:

ofVec3 v;
ofVec3f projected = v * model * view * projection;

instead of what you would see written down in normal mathematics, which is more consistent with:

glm::vec3 v;
glm::vec3 projected = projection * view * model * v;

So instead of q1* q2 in normal math, it is q2 * q1 in ofQuaternion parlance.
But I suppose it is consistent with the matrix multiplication ordering.

How can I tell that it is inverse?
I looked at the matrix that it should be (from a textbook):


If you follow the math in the code, it looks inverse to what’s in the textbook to me.

Reference: Aircraft Control and Simulation: Dynamics, Controls Design, and Autonomous Systems: Dynamics, Controls Design, and Autonomous Systems, Third Edition

Author(s):

  • Brian L. Stevens
  • Frank L. Lewis
  • Eric N. Johnson

hi, I see. Thanks for explaining.
Personally, I wouldnt spend time trying to fix this as we’ve moved to GLM.
Maybe @arturo or @bakercp can give you a better answer.
Cheers

Sounds good, thanks! I’ll try to move to GLM asap.
(hopefully sooner rather than later, we’ll see)

Just to confirm that the apparent inverse is just cause the matrices are row major instead of column so the order of multiplication is reversed to that of glsl or glm. Quaternions follow that same order of multiplication and so their implementation looks backwards

I think this was kind of the standard in old opengl, that’s why the combination of projection * view * model is usually called modelViewProjection in old glsl.

If you are starting a new project it’s recommended to use glm but ofVec will be there as a way to keep old projects working, even in the case we removed it from the core it’ll be turn into an addon

btw this is only conceptually, the layout in memory of matrices is column major so when uploading them to a shader the order of multiplication in glsl is still projection * view * model * vertex not the other way around.

1 Like