OpenGL Car wheel rotation issue

Hello, so I’m having a tough time figuring out how to make my car’s wheel rotate properly. When I rotate it in one axis, it works fine, however once I rotate it around another axis as well, the wheel behaves funny. I read up a little on this issue, and it seems to be because the axes of rotation are rotated with the object when GL.glRotatef() is called.

This is the code I use to transform the wheel before I render it.


GL.glScalef(scale, scale, scale);
		if (centered) {
			GL.glTranslatef(-center[0] + translation[0], -center[1] + translation[1], -center[2] + translation[2]);
		} else {
			GL.glTranslatef(translation[0], translation[1], translation[2]);
		}
                // i read somewhere that z x y is the proper rotation order, however this hasn't helped.
		if (rotation[2] != 0) {
			GL.glRotatef(rotation[2], 0.0f, 0.0f, 1.0f);
		}
		if (rotation[0] != 0) {
			GL.glRotatef(rotation[0], 1.0f, 0.0f, 0.0f);
		}
		if (rotation[1] != 0) {
			GL.glRotatef(rotation[1], 0.0f, 1.0f, 0.0f);
		}

I’m just trying to make the wheel on the car rotate forward on the x axis (when the car moves forward) and turning on the y axis (when the car turns)

EDIT: dug around some more and found this on https://www.opengl.org/archives/resources/faq/technical/transformations.htm#tran0070

Whoops, looks like I fixed the problem already! :smiley:

For those in the future with the same issue, what you need to do is use a quaternion.


Quaternion x = Quaternion.createRotate(Util.DEG(rotx), 1, 0, 0);
Quaternion y = Quaternion.createRotate(Util.DEG(roty), 0, 1, 0);
Quaternion z = Quaternion.createRotate(Util.DEG(rotz), 0, 0, 1);
GL.glMultMatrixf(x.multiply(y).multiply(z).createMatrix());

If it works with this, then it’ll for sure also work with this:


glRotatef(Util.DEG(rotx), 1, 0, 0);
glRotatef(Util.DEG(roty), 0, 1, 0);
glRotatef(Util.DEG(rotz), 0, 0, 1);

Both things are conceptually exactly the same. Post-multiplying the rotation transformation for x, y and finally z. It does not matter whether that happens on the quaternion with the final matrix being built at the end, or on the matrix directly.

Small tip: avoid deprecated OpenGL

Just tried that, it doesn’t work :frowning:

What is that Quaternion class? Where does it come from?
What exactly does Util.DEG() do - convert from degrees to radians, or the other way around?
What exactly is the semantics of Quaternion.createRotate()? What is the meaning of its parameters?
If it is written in any sane way, then it must be the same as the three glRotatef invocations.
Otherwise either Quaternion.createRotate() or Quaternion.multiply() does not do what it’s supposed to do (does pre- instead of post-multiplication probably).

Here you go :slight_smile:



public class Quaternion {

	private float w, x, y, z;

	public Quaternion(float w, float x, float y, float z) {
		this.w = w;
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public Quaternion multiply(Quaternion other) {
		this.normalize();
		other.normalize();

		float w1 = w * other.w - x * other.x - y * other.y - z * other.z;
		float x1 = w * other.x + x * other.w + y * other.z - z * other.y;
		float y1 = w * other.y - x * other.z + y * other.w + z * other.x;
		float z1 = w * other.z + x * other.y - y * other.x + z * other.w;

		return new Quaternion(w1, x1, y1, z1);
	}

	public float[] createMatrix() {
		float[] c = new float[16];

		this.normalize();

		c[0] = 1 - 2 * y * y - 2 * z * z;
		c[1] = 2 * x * y - 2 * w * z;
		c[2] = 2 * x * z + 2 * w * y;

		c[4] = 2 * x * y + 2 * w * z;
		c[5] = 1 - 2 * x * x - 2 * z * z;
		c[6] = 2 * y * z - 2 * w * x;

		c[8] = 2 * x * z - 2 * w * y;
		c[9] = 2 * y * z + 2 * w * x;
		c[10] = 1 - 2 * x * x - 2 * y * y;

		c[15] = 1;

		return c;
	}

	public static Quaternion createRotate(float theta, float x, float y, float z) {
		float w1 = Util.COS(theta / 2);
		float x1 = x * Util.SIN(theta / 2);
		float y1 = y * Util.SIN(theta / 2);
		float z1 = z * Util.SIN(theta / 2);

		return new Quaternion(w1, x1, y1, z1);
	}

	public void normalize() {
		float mag = (float) Math.sqrt(w * w + x * x + y * y + z * z);
		w /= mag;
		x /= mag;
		y /= mag;
		z /= mag;
	}

}


	public static final float RAD(float deg) {
		return deg * 0.0174532925194f;
	}

	public static final float DEG(float rad) {
		return rad * 57.295779514719f;
	}

Looks good. One thing though:
In your example above you call Quaternion.createRotate() with a degree angle. That method however looks like it expects ‘theta’ to be in radians. But, we don’t know that exactly, because we don’t know what Util.COS() and Util.SIN() does. Does it expect the angle to be in radians, just like java.lang.Math.sin/cos?
OpenGL’s glRotatef() expects degrees, btw.

:stuck_out_tongue: yeah i realized that after i posted the code, my new code doesn’t use degrees haha. SIN and COS use radians

I found something in your createMatrix() method. It swaps some signs (+/-) operators that make it incompatible with OpenGL’s interpretation of a rotation and generally does not produce a matrix of the rotations you specified in that order via createRotation() and multiply().
If you use the following, then it’ll be correct and produce the exact same resulting matrix like OpenGL:


public float[] createMatrix() {
	float[] c = new float[16];

	this.normalize();

	c[0] = 1 - 2 * y * y - 2 * z * z;
	c[1] = 2 * x * y + 2 * w * z;
	c[2] = 2 * x * z - 2 * w * y;

	c[4] = 2 * x * y - 2 * w * z;
	c[5] = 1 - 2 * x * x - 2 * z * z;
	c[6] = 2 * y * z + 2 * w * x;

	c[8] = 2 * x * z + 2 * w * y;
	c[9] = 2 * y * z - 2 * w * x;
	c[10] = 1 - 2 * x * x - 2 * y * y;

	c[15] = 1;

	return c;
}

Reference: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/
Remember to read your indices in column-major and not row-major.

Haha yup, i just tried that and the rotation issue came up again, can you explain to me why this small change causes the matrix to rotate differently?

Well, it looks like you built the transpose of the matrix you should have gotten, which is the inverse/counter rotation.
So, to get the rotation matrix that initially worked for you, you can either flip/reverse the rotation order of the quaternions and conjugate them (can also be done by flipping the rotation axis or negating the angle); or you transpose() the resulting matrix.
This will get you the same result back again, which you had with the previously/wrong createRotation.
So, with the new createRotation method I’d suggest you do this:


Quaternion x = Quaternion.createRotate(Util.DEG(rotx), -1, 0, 0);
Quaternion y = Quaternion.createRotate(Util.DEG(roty), 0, -1, 0);
Quaternion z = Quaternion.createRotate(Util.DEG(rotz), 0, 0, -1);
GL.glMultMatrixf(z.multiply(y).multiply(x).createMatrix());

It’ll give you the same end result that you got with the previous createRotation() method and your first example code.

What this in effect means, is that your initial code was in fact equivalent to the following OpenGL call sequence:


glRotatef(zAngle, 0, 0, -1);
glRotatef(yAngle, 0, -1, 0);
glRotatef(xAngle, -1, 0, 0);