Hi,
I'm experiencing some difficulties when trying to apply a quaternion's rotation matrix to openGL and displaying a mesh's bounding box.
Although I'm quite sure that my mesh's bounding box calculation is correct, it somehow never fits around the mesh.
I carefully read the Quaternion article on
http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation and implemented it directly that way.
I do not know where to start explaining, I think I first post some code.
Note that the AABB itself should not be rotated, that's why I apply the rotation later. The AABB is recalculated after every rotation.
Code:
// within drawing function
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glPushMatrix(); // this is done because I'm rendering multiple meshes
// draw AABB
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f, 0.0f, 0.0f);
glBegin(GL_LINES);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMin);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMin, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMin, m_AABB.m_yMax, m_AABB.m_zMax);
glVertex3f(m_AABB.m_xMax, m_AABB.m_yMax, m_AABB.m_zMax);
glEnd();
glEnable(GL_TEXTURE_2D);
// rotate object
glMultMatrixd(m_orientation.getRotationMatrix()->getAsColumnMatrix());
glCallList(m_displayList); // draw object
m_orientation is a quaternion and getRotationMatrix returns a 4x4 Matrix:
Code:
// Convert to Matrix
Matrix4* Quaternion::getRotationMatrix() {
Real x2 = m_x * m_x;
Real y2 = m_y * m_y;
Real z2 = m_z * m_z;
Real xy = m_x * m_y;
Real xz = m_x * m_z;
Real yz = m_y * m_z;
Real wx = m_w * m_x;
Real wy = m_w * m_y;
Real wz = m_w * m_z;
// This calculation would be a lot more complicated for non-unit length quaternions
// Note: The constructor of Matrix4 expects the Matrix in column-major format like expected by
// OpenGL
m_rotationMatrix = Matrix4( 1.0f - 2.0f * (y2 + z2), 2.0f * (xy - wz), 2.0f * (xz + wy), 0.0f,
2.0f * (xy + wz), 1.0f - 2.0f * (x2 + z2), 2.0f * (yz - wx), 0.0f,
2.0f * (xz - wy), 2.0f * (yz + wx), 1.0f - 2.0f * (x2 + y2), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
return &m_rotationMatrix;
}
while Matrix4 contains a simple double matrix[4][4] for representing the values. I'm correctly filling the values column-aligned like desired by openGL.
The AABB itself is calculated like this:
Code:
void calculateAABB() {
m_AABB.m_xMin = std::numeric_limits<Real>::infinity();
m_AABB.m_yMin = std::numeric_limits<Real>::infinity();
m_AABB.m_zMin = std::numeric_limits<Real>::infinity();
m_AABB.m_xMax = -std::numeric_limits<Real>::infinity();
m_AABB.m_yMax = -std::numeric_limits<Real>::infinity();
m_AABB.m_zMax = -std::numeric_limits<Real>::infinity();
for (int i=0; i<m_numVertices; i++) {
Vector3 newLocation = m_orientation*m_vertices[i].m_location;
if (newLocation.m_x < m_AABB.m_xMin)
m_AABB.m_xMin = newLocation.m_x;
if (newLocation.m_x > m_AABB.m_xMax)
m_AABB.m_xMax = newLocation.m_x;
if (newLocation.m_y < m_AABB.m_yMin)
m_AABB.m_yMin = newLocation.m_y;
if (newLocation.m_y > m_AABB.m_yMax)
m_AABB.m_yMax = newLocation.m_y;
if (newLocation.m_z < m_AABB.m_zMin)
m_AABB.m_zMin = newLocation.m_z;
if (newLocation.m_z > m_AABB.m_zMax)
m_AABB.m_zMax = newLocation.m_z;
}
}
m_orientation again is a simple quaternion.
I think that there is some mistake in multiplying the matrix...
The result:

However, when I remove multiplying the quaternion with the vector in the calculateAABB function but rotate the bounding box as well, the result is right, but then isn't axis aligned any more.
I hardly suspect an error when multiplying the quaternion with the vector, but I've checked a thousand times on the gpwiki page for errors but couldn't find any...

So here's how I multiply a quaternion with a vector:
Code:
// Multiplying a quaternion q with a vector v applies the q-rotation to v
Vector3 operator* (const Vector3 &vec) {
Vector3 vn(vec);
//vn = Vector3::normalizeVector(vn);
Quaternion vecQuat, resQuat;
vecQuat.m_x = vn.m_x;
vecQuat.m_y = vn.m_y;
vecQuat.m_z = vn.m_z;
vecQuat.m_w = 0.0f;
resQuat = vecQuat * getConjugate();
resQuat = *this * resQuat;
return (Vector3(resQuat.m_x, resQuat.m_y, resQuat.m_z));
}
OK i modified the code by commenting the normalization part out, but I could as well left it in and multiply it with the inverse value when calculating the bounding box in calculateAAB, which results in the exactely same...
What am I doing wrong? There must be something very severe....
Thank you a thousand times for helping me!