Using Quaternions for Opengl Rotations

Using Quaternions for OpenGL Rotations

All you have done is effectively implement Euler angles with quaternions. That's not helping.

The problem with Euler angles is that, when you compute the matrices, each angle is relative to the rotation of the matrix that came before it. What you want is to take an object's current orientation, and apply a rotation along some axis, producing a new orientation.

You can't do that with Euler angles. You can with matrices, and you can with quaternions (as they're just the rotation part of a matrix). But you can't do it by pretending they are Euler angles.

This is done by not storing angles at all. Instead, you just have a quaternion which represents the current orientation of the object. When you decide to apply a rotation to it (of some angle by some axis), you construct a quaternion that represents that rotation by an angle around that axis. Then you right-multiply that quaternion with the current orientation quaternion, producing a new current orientation.

When you render the object, you use the current orientation as... the orientation.

OpenGL cube rotation using quaternions

As said before, you're probably best off using a library that already does the math for you.

The problem here is that you've swapped signs for w_x on matrix[6] and matrix[9].

The relevant lines should read thusly:

matrix[1] = 2*(x_y+w_z);     matrix[5] = 1-2*(x_x+z_z);   matrix[9] = 2*(y_z-w_x);     matrix[13] = 0;
matrix[2] = 2*(x_z-w_y); matrix[6] = 2*(y_z+w_x); matrix[10] = 1-2*(x_x+y_y); matrix[14] = 0;

From quaternions to OpenGL rotations

The most important is to implement method that will build rotation matrices from quaternion. Then, as you'll do with normal rotation matrix, just multiply it with your modelview matrix.

This is simple example that was used to rotate cube with mouse movement. As you see I've needed to implement three methods: toMatrix, quaternionFromAxis, multiplyWith. Assuming that you understand quaternions, this should be clear what they do.

void display() {

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();

// Multiply quaternion with current modelview matrix
glMultMatrixf(cameraQuaternion.toMatrix());

// Some other transformations
glTranslatef(-0.5f, -0.5f, -0.5f);

// Draw something, i.e. cube
glDrawArrays(GL_TRIANGLES, 0, 36);
glDrawArrays(GL_TRIANGLES, 0, 36);

glPopMatrix();
}

void mouseMoved(float dx, float dy) {
float axisY[] = { 0, 1, 0 },
axisX[] = { 1, 0, 0 };

float sensitivity = 0.005f;
Quaternion *q1 = Quaternion.quaternionFromAxis(axisY, dx * sensitivity];
Quaternion *q2 = Quaternion.quaternionFromAxis(axisX, dy * sensitivity];

// Multiply two quaternions with camera
cameraQuaternion = (q1.multiplyWith(q2)).multiplyWith(cameraQuaternion);
}

Problem rotating with quaternions in OpenGL (GLM/C++)

Changing, or setting orientation, is not the same as rotating:

To set your orientation, you want to do it like this:

void setOrientation(glm::vec3 eular)
{
m_Orientation = glm::quat(eular); // very simple
}

void setRotation(glm::vec3 eular)
{
m_Rotation = glm::quat(eular); // very simple
}

To rotate, we want to integrate the rotation quaternion, using SLERP:

void update(float deltaTimeS)
{
glm::quat ident(1.0f);
glm::quat rotation = glm::mix(ident, m_Rotation, deltaTimeS);
m_Orientation = rotation * m_Orientation;
}

And to get your rotation matrix:

void setTransform()
{
m_RotationMatrix = glm::gtx::quaternion::toMat4(quaternion);
}

See here for more information on quaternion rotations.

What is wrong with my Quaternion rotation in OpenGL?

glRotatef(qRot.x, 1., 0, 0);
glRotatef(qRot.y, 0, 1., 0);
glRotatef(qRot.z, 0, 0, 1.);

That's not how you apply a quaternion rotation to the GL state. You have to convert it to a matrix following the formula from here and then call glMultMatrix or glMultTransposeMatrix. After that approach number #3 will work as expected.


Code that converts any non-zero quaternion to a matrix, from Stannum libs:

template<class T>
mat<T,3,3> mat_rotation(const quat<T> &x)
{
T s = 2/norm2(x); // cheap renormalization even of non-unit quaternions
T wx = x.w*x.x, wy = x.w*x.y, wz = x.w*x.z;
T xx = x.x*x.x, xy = x.x*x.y, xz = x.x*x.z;
T yy = x.y*x.y, yz = x.y*x.z;
T zz = x.z*x.z;

return mat<T,3,3>(
1 - s*(yy+zz), s*(xy-wz), s*(xz+wy),
s*(xy+wz), 1 - s*(xx+zz), s*(yz-wx),
s*(xz-wy), s*(yz+wx), 1 - s*(xx+yy)
);
}

Quaternion based camera

The problem is the way that you are accumulating rotations. This would be the same whether you use quaternions or matrices. Combining a rotation representing pitch and yaw with another will introduce roll.

By far the easiest way to implement an FPS camera is to simply accumulate changes to the heading and pitch, then convert to a quaterion (or matrix) when you need to. I would change the methods in your camera class to:

void Camera::SetOrientation(float rightAngle, float upAngle)//in degrees
{
_rightAngle = rightAngle;
_upAngle = upAngle;
}

void Camera::OffsetOrientation(float rightAngle, float upAngle)//in degrees
{
_rightAngle += rightAngle;
_upAngle += upAngle;
}

glm::mat4 Camera::GetOrientation() const
{
glm::quat q = glm::angleAxis(glm::radians(-_upAngle), glm::vec3(1,0,0));
q*= glm::angleAxis(glm::radians(_rightAngle), glm::vec3(0,1,0));
return glm::mat4_cast(q);
}

Recommended way to approach rotations in OpenGL

A great resource to understand rotations in modern OpenGL is reading Tutorial 17: rotations from opengl-tutorial.org. I won't copy the page word for word, but in short,

You don't use quaternions inside GLSL. Convert your quaternion to a rotation matrix, and use it in the Model matrix. Your vertices will be rotated as usual with your Model - View - Projection Matrix.



Related Topics



Leave a reply



Submit