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.
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 qvq^{-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?
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
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!
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
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
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
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.