What I am trying to do is to create a Rubik's Cube game using LWJGL in Java. I have a lot of it done already, the only problem is the rotating. It just isn't working. I've tried multiple ways of rotating the cube but none of them seem to be working. Here's an image of what I've done so far:
It works fine as you can see.
Now if I rotate the front slice, it also works well.
It seems to be messing up when the rotation is more that one. What I mean by that is when I rotate "F R D", this is front, right, and down. Like so:
But the problem occurs when I rotate the front side one more time, the rotation completely messes up:
As you can see, the cube rotates the wrong way. I don't know how to fix this.
What I've tried is calling three separate GL11.glRotatef( ... )
functions but that hasn't worked. I've tried storing the rotations in a Matrix4f and then GL11.glMultMatrix( ... )
and that has had the same output. I finally gave up and settled on this code here:
GL11.glPushMatrix();
GL11.glTranslatef(pos.offsetX * 1.1F, pos.offsetY * 1.1F, pos.offsetZ * 1.1F);
GL11.glRotatef(realRotation.x * 90F, 1F, 0F, 0F);
GL11.glRotatef(realRotation.y * 90F, 0F, 1F, 0F);
GL11.glRotatef(realRotation.z * 90F, 0F, 0F, 1F);
for (int i = 0; i < 6; i++)
{
if (quads[i] != null)
{
quads[i].renderQuad();
}
}
GL11.glPopMatrix();
I am at a loss now. If you need the variables and code up there defined:
realRotation
is a javax.vecmath.Point3i
instance. All it has are the values from 0 to 3. It will never be greater than three, or less that zero. This is also the same reason why I am multiplying the values by 90 to rotate it 90 degrees each time. The quads
array is just for rendering, it doesn't matter and has not caused a problem. Now the pos
variable is an enum value that I have created to keep track of all the pieces in the game and where they are. Again, probably not the problem, but I don't know. It just might be the problem.
EDIT #1: I still haven't found any answer to the problem. The only other idea that I have gotten is that I can manually set the rotation to what it is actually supposed to be. I assumed that this will be EXTREMELY tedious and inefficient, so I've left that as a last resort. If I'm incorrect about this method, please feel free to let me know. I have a deadline for this project and I haven't gotten any progress beyond this.
EDIT #2: I have had an (I think) epiphany! I believe the problem for this peculiar rotational behavior is the cause of the Gimbal Lock. This is when an object is rotated in an axis, and the other axis pretty much becomes useless because of the previous rotation. This is explained very well with this GIF:
As you can see, once the plane is pitched to a 90 degree angle, roll and yaw are seemingly the same because of the pitch's rotation. On the wikipedia page, it is stated that a solution to this would be to use Quaternions, or so. I have not worked with Quaternions too much and still would like to hear if anyone has anything to say about this. I'm just guessing that this is the problem.
EDIT #3: After hours of studying and looking for an explanation as to what is going on. I have come up with nothing. I have still not solved the problem and I think I might have even made it worse. The code I have to render each cube is as follows:
GL11.glPushMatrix();
GL11.glTranslatef(pos.offsetX * 1.1F, pos.offsetY * 1.1F, pos.offsetZ * 1.1F);
//GL11.glRotatef(realRotation.z * 90F, 0F, 0F, 1F); // Roll
//GL11.glRotatef(realRotation.x * 90F, 1F, 0F, 0F); // Pitch
//GL11.glRotatef(realRotation.y * 90F, 0F, 1F, 0F); // Yaw
Quaternion roll = new Quaternion();
roll.setFromAxisAngle(new Vector4f(0F, 0F, -1F, rotation.z * 90F * DEG_TO_RAD));
roll.normalise();
Quaternion pitch = new Quaternion();
pitch.setFromAxisAngle(new Vector4f(-1F, 0F, 0F, rotation.x * 90F * DEG_TO_RAD));
pitch.normalise();
Quaternion yaw = new Quaternion();
yaw.setFromAxisAngle(new Vector4f(0F, -1F, 0F, rotation.y * 90F * DEG_TO_RAD));
yaw.normalise();
Quaternion change = Quaternion.mul(Quaternion.mul(roll, pitch, null), yaw, null);
FloatBuffer buff = BufferUtils.createFloatBuffer(16);
toFloatBuffer(change, buff);
GL11.glMultMatrix(buff);
for (int i = 0; i < 6; i++)
{
if (quads[i] != null)
{
quads[i].renderQuad();
}
}
GL11.glPopMatrix();
This is the toFloatBuffer method: dest.clear();
float x = quat.x;
float y = quat.y;
float z = quat.z;
float w = quat.w;
float x2 = x * x;
float y2 = y * y;
float z2 = z * z;
float xy = x * y;
float xz = x * z;
float yz = y * z;
float wx = w * x;
float wy = w * y;
float wz = w * z;
dest.put(1.0f - 2.0f * (y2 + z2));
dest.put(2.0f * (xy - wz));
dest.put(2.0f * (xz + wy));
dest.put(0.0f);
dest.put(2.0f * (xy + wz));
dest.put(1.0f - 2.0f * (x2 + z2));
dest.put(2.0f * (yz - wx));
dest.put(0.0f);
dest.put(2.0f * (xz - wy));
dest.put(2.0f * (yz + wx));
dest.put(1.0f - 2.0f * (x2 + y2));
dest.put(0.0f);
dest.put(0.0f);
dest.put(0.0f);
dest.put(0.0f);
dest.put(1.0f);
dest.rewind();
Again, this isn't working and I (once again) am absolutely clueless. The page I am looking at to figure out this stuff is this page. Don't even know if it's right. I got it from my Physics teacher who is also working on Quaternions. Once again, I have a deadline for this project and I would love it if I can get this done by then. I am willing to accept anything anyone says, I really need a lead on this. I keep hitting walls after walls.