Cube Rotation Issues

Hey guys –

I have a pretty robust cube drawing method that works fine but I’ve got some logic problems in my rotation. The cube stays where it started and will always return to origin position, but it sort of collapses on itself as it goes. This seems to be because one half of each face getting rotated goes in the wrong direction on one axis.


/** Draws a cube with six different textures covering it with a
     * rotation of rotx, roty, and rotz, and shaded color c.
     * The textures are ordered FrontBackTopBottomLeftRight in the array
     * WARNING - Array must be at least length 6
     * WARNING - Make sure to be in 3D mode first!
     * @param texts An array of texture locations for each side
     * @param c The color to draw the cube
     * @param x The x location of the bottom left corner
     * @param y The y location of the bottom left corner
     * @param z The z location of the bottom left corner
     * @param w The width along the x axis
     * @param h The height along the y axis
     * @param d The depth along the z axis
     * @param rotx The X rotation
     * @param roty The Y rotation
     * @param rotz The Z rotation        */
    public static void glCube(String[] texs, Color c, float x, float y, float z, float w, float h, float d, float rotx, float roty, float rotz)
    {
    		try
		{
    			//Recover the textures from the TextureLoader
    			Texture[] texture = new Texture[texs.length];
    			for (int i = 0; i < texture.length; i++)
    				texture[i] = BestGameEver.textureLoader.getTexture(texs[i]);
    			//Set the drawing color for the cube
	    		glColor(c);
	    		
	    		//Construct arrays to represent the drawing points, orders of sides are below
	    		//0 = Front   1 = Back   2 = Top   3 = Bottom   4 = Right   5 = Left
	    		float[] xs = {x,x+w,x+w,x, x+w,x+w,x,x, x,x,x+w,x+w, x+w,x,x,x+w, x+w,x+w,x+w,x+w, x,x,x,x};
	    		float[] ys = {y+h,y+h,y,y, y+h,y,y,y+h, y,y,y,y, y+h,y+h,y+h,y+h, y+h,y,y,y+h, y+h,y+h,y,y};
	    		float[] zs = {z,z,z,z, z-d,z-d,z-d,z-d, z-d,z,z,z-d, z-d,z-d,z,z, z,z,z-d,z-d, z-d,z,z,z-d};
	    		
	    		//Apply any rotations that should be done
	    		//Calculate the rotation point (the center) of this face
	    		float centerX = x+w/2;
	    		float centerY = y+h/2;
	    		float centerZ = z-d/2;
	    		for (int i = 0; i < 6 && (rotx != 0 || roty != 0 || rotz != 0); i++)
	    		{
		    		for (int j = 0; j < 4; j++)
		    		{
		    			//Store the original points for calculating rotation
		    			float oldX = xs[4*i+j] - centerX;
		    			float oldY = ys[4*i+j] - centerY;
		    			float oldZ = zs[4*i+j] - centerZ;
		    			//X Axis Rotation
		    			ys[4*i+j] = (float)((oldY*Math.cos(rotx)) - (oldZ*Math.sin(rotx))) + centerY;
		    			zs[4*i+j] = (float)((oldZ*Math.cos(rotx)) - (oldY*Math.sin(rotx))) + centerZ;
		    			oldY = ys[4*i+j] - centerY; oldZ = zs[4*i+j] - centerZ;
		    			//Y Axis Rotation
		    			zs[4*i+j] = (float)((oldZ*Math.cos(roty)) - (oldX*Math.sin(roty))) + centerZ;
		    			xs[4*i+j] = (float)((oldX*Math.cos(roty)) - (oldZ*Math.sin(roty))) + centerX;
		    			oldZ = zs[4*i+j] - centerZ; oldX = xs[4*i+j] - centerX;
		    			//Z Axis Rotation
		    			xs[4*i+j] = (float)((oldX*Math.cos(rotz)) - (oldY*Math.sin(rotz))) + centerX;
		    			ys[4*i+j] = (float)((oldY*Math.cos(rotz)) - (oldX*Math.sin(rotz))) + centerY;
		    		}
	    		}
	    		
	    		//Draw the cube using our final points and textures
	    		for (int i = 0; i < 6; i++)
	    		{
		    		texture[i].bind();
		    		GL11.glBegin(GL11.GL_QUADS);
		    		GL11.glTexCoord2f(0.0f, 0.0f);
		    		GL11.glVertex3f(xs[4*i+0],ys[4*i+0],zs[4*i+0]); // Bottom Left Of The Texture and Quad
		    		GL11.glTexCoord2f(texture[i].getWidth(), 0.0f);
		    		GL11.glVertex3f(xs[4*i+1],ys[4*i+1],zs[4*i+1]); // Bottom Right Of The Texture and Quad
		    		GL11.glTexCoord2f(texture[i].getWidth(), texture[i].getHeight());
		    		GL11.glVertex3f(xs[4*i+2],ys[4*i+2],zs[4*i+2]); // Top Right Of The Texture and Quad
		    		GL11.glTexCoord2f(0.0f, texture[i].getHeight());
		    		GL11.glVertex3f(xs[4*i+3],ys[4*i+3],zs[4*i+3]); // Top Left Of The Texture and Quad
		    		GL11.glEnd();
	    		}
		}
		catch (Exception e) {e.printStackTrace();}
    }

Run it and you’ll see what I mean.

You cannot rotate over multiple axis like that. If the math scares you, try a pre-built matrix-lib.

Why not? Yes you can. It rotates just fine, it’s just that every face goes in the wrong direction, basically. As in the front quad may be rotating so its left side comes out and its right side slides back along the z axis, while the back quad is doing the exact same thing rather than the opposite. That makes it flatten itself.

My only problem is some sign issue or something like that. I just thought someone who was familiar with this rotation method might be able to point me towards the problem faster than I can figure it out.

You shouldnt rotate like that. just have a method that draws a cube centered around the origin. then in ur rendering method load the identity matrix, transform the matrix some negative number so it is fully visible on the screen, use glRotatef to rotate on each axis one at a time, then call the cube drawing method.

I actually did that method first and although it rotated correctly it would not rotate around the correct point.

Also, I may want to have multiple cubes on screen at once all rotating in different ways, in which case wouldn’t it be more efficient to have them rotating themselves rather than moving the camera around?

IMHO, you need to read up more OpenGL in general.

The vertices of the are multiplied by the modelview matrix to convert from object space to world space. If its not rotating around the right point, then offset the vertices in object space.

Also, there is a reason why its called ModelView matrix, because moving an object 10 paces to the right, is like moving the camera 10 paces to the left. There is no real concept of a camera in OpenGL, its abstracted away in game APIs to provide you with a camera like object.

DP

to do something like this:

-enter render method, clear buffers etc, make sure modelview matrix selected, load identity
for each cube drawn
-push matrix
-translate to cube position
-rotate to cube rotation
-draw cube
-popmatrix
end for

about the camera, in opengl it is always located at (0, 0, 0) looking down -ve z, if you wanted to rotate/translate the camera around the world you would instead transform the modelview matrix(that transforms all the vertices) in the opposite direction.

Yeah I actually did exactly that: translated the camera to the center of the cube and rotated it there, but first pushing the matrix and then popping it after. For some reason no matter where I translated the camera to the cube would rotate around the exact same point (it refused to rotate around its center), just different relative to the camera.

I do have a question though: in huge games using OpenGL do people have every single one of their 3D objects at 0,0,0 and then rather than moving them around they move the camera around to each and every object separately? It seems like it would be incredibly inefficient to me, and counter intuitive.

And you’re probably right darkprophet about me needing more OpenGL experience – I’m just teaching myself as I go along. It’s why I’m only dealing with cubes now and not complicated 3D objects.

Thanks for the Insight guys.

I fixed it on my own. I stupidly put both of the points in each rotation part rotating the same way, which is why they were rotating exactly equally, rather than complimenting each other like natural rotation should look. I also made sure each side was deciding where each of its points was in the same order, because this may cause problems in the future. The fixed code:


/** Draws a cube with six different textures covering it with a
     * rotation of rotx, roty, and rotz, and shaded color c.
     * The textures are ordered FrontBackTopBottomLeftRight in the array
     * WARNING - Array must be at least length 6
     * WARNING - Make sure to be in 3D mode first!
     * @param texts An array of texture locations for each side
     * @param c The color to draw the cube
     * @param x The x location of the bottom left corner
     * @param y The y location of the bottom left corner
     * @param z The z location of the bottom left corner
     * @param w The width along the x axis
     * @param h The height along the y axis
     * @param d The depth along the z axis
     * @param rotx The X rotation
     * @param roty The Y rotation
     * @param rotz The Z rotation        */
    public static void glCube(String[] texs, Color c, float x, float y, float z, float w, float h, float d, float rotx, float roty, float rotz)
    {
    		try
		{
    			//Recover the textures from the TextureLoader
    			Texture[] texture = new Texture[texs.length];
    			for (int i = 0; i < texture.length; i++)
    				texture[i] = BestGameEver.textureLoader.getTexture(texs[i]);
    			//Set the drawing color for the cube
	    		glColor(c);
	    		
	    		//Construct arrays to represent the drawing points, orders of sides are below
	    		//0 = Front   1 = Back   2 = Top   3 = Bottom   4 = Right   5 = Left
	    		float[] xs = {x,x+w,x+w,x, x,x+w,x+w,x, x,x+w,x+w,x, x,x+w,x+w,x, x+w,x+w,x+w,x+w, x,x,x,x};
	    		float[] ys = {y+h,y+h,y,y, y,y,y+h,y+h, y,y,y,y, y+h,y+h,y+h,y+h, y+h,y+h,y,y, y+h,y+h,y,y};
	    		float[] zs = {z,z,z,z, z-d,z-d,z-d,z-d, z,z,z-d,z-d, z-d,z-d,z,z, z,z-d,z-d,z, z-d,z,z,z-d};
	    		
	    		//Apply any rotations that should be done
	    		//Calculate the rotation point (the center) of this face
	    		float centerX = x+w/2;
	    		float centerY = y+h/2;
	    		float centerZ = z-d/2;
	    		for (int i = 0; i < 6 && (rotx != 0 || roty != 0 || rotz != 0); i++)
	    		{
		    		for (int j = 0; j < 4; j++)
		    		{
		    			//Store the original points for calculating rotation
		    			float oldX = xs[4*i+j] - centerX;
		    			float oldY = ys[4*i+j] - centerY;
		    			float oldZ = zs[4*i+j] - centerZ;
		    			//X Axis Rotation
		    			ys[4*i+j] = (float)((oldY*Math.cos(rotx)) - (oldZ*Math.sin(rotx))) + centerY;
		    			zs[4*i+j] = (float)((oldZ*Math.cos(rotx)) + (oldY*Math.sin(rotx))) + centerZ;
		    			oldY = ys[4*i+j] - centerY; oldZ = zs[4*i+j] - centerZ;
		    			//Y Axis Rotation
		    			zs[4*i+j] = (float)((oldZ*Math.cos(roty)) - (oldX*Math.sin(roty))) + centerZ;
		    			xs[4*i+j] = (float)((oldX*Math.cos(roty)) + (oldZ*Math.sin(roty))) + centerX;
		    			oldZ = zs[4*i+j] - centerZ; oldX = xs[4*i+j] - centerX;
		    			//Z Axis Rotation
		    			xs[4*i+j] = (float)((oldX*Math.cos(rotz)) - (oldY*Math.sin(rotz))) + centerX;
		    			ys[4*i+j] = (float)((oldY*Math.cos(rotz)) + (oldX*Math.sin(rotz))) + centerY;
		    		}
	    		}
	    		
	    		//Draw the cube using our final points and textures
	    		for (int i = 0; i < 6; i++)
	    		{
		    		texture[i].bind();
		    		GL11.glBegin(GL11.GL_QUADS);
		    		GL11.glTexCoord2f(0.0f, 0.0f);
		    		GL11.glVertex3f(xs[4*i+0],ys[4*i+0],zs[4*i+0]); // Bottom Left Of The Texture and Quad
		    		GL11.glTexCoord2f(texture[i].getWidth(), 0.0f);
		    		GL11.glVertex3f(xs[4*i+1],ys[4*i+1],zs[4*i+1]); // Bottom Right Of The Texture and Quad
		    		GL11.glTexCoord2f(texture[i].getWidth(), texture[i].getHeight());
		    		GL11.glVertex3f(xs[4*i+2],ys[4*i+2],zs[4*i+2]); // Top Right Of The Texture and Quad
		    		GL11.glTexCoord2f(0.0f, texture[i].getHeight());
		    		GL11.glVertex3f(xs[4*i+3],ys[4*i+3],zs[4*i+3]); // Top Left Of The Texture and Quad
		    		GL11.glEnd();
	    		}
		}
		catch (Exception e) {e.printStackTrace();}
    }