5

I am working on my first real OpenGL Project. It is a 3x3x3 Rubiks Cube. Here is a link to a simple screenshot of what i have so far(my rubiks cube)

Rotating the cube is done with dragging the mouse while holding the right mouse button. This works using the example of a arcball from NeHe Tutorials(NeHe Arcball)

I have the class singleCubes which represents one cube via 6 actual quads, stored in a display list that can be used in it´s draw method. Class ComplexCube has an array of 3x3x3 singleCubes and is used as interface when interacting with the complete rubiks cube.

Now i want to rotate each specific face according to the mousedragging with left mouse button down. I use picking to get the id of the corresponding side of the single cube the user clicked on. This works also. So i click on a side of one cube on a face and depending on the direction of the dragging i set a rotation and offset factor of the cubes that get affected. (i also want to implement that u actually see the face rotate instead of just changing the color)

Now my Problem is that when i rotate the rubiks cube in any direction with right mouse dragging, it becomes upside down for example. So when i click on a side and want to rotate the face to the right, it´s going the wrong direction because i can´t keep track if the cube is upside down or whatever. Due to the use of the arcball rotation i dont have a x- or y-rotation angle which i could use to determine this.

Question 1: How can i keep track or later on get the information if the cube is upside down, tilted etc in order to translate the mouse dragging information(when rotating one face) when using the arcball example linked above?

// In render function
glPushMatrix();
{
    glMultMatrixf(Transform.M); // Rotation applied by arcball object
    complCube.draw();           // Draw all the cubes using display lists
}
glPopMatrix();

Setup: C++ with Microsoft Visual Studio 2008, GLEW, freeglut

genpfault
  • 51,148
  • 11
  • 85
  • 139
VanillaBear
  • 63
  • 1
  • 4
  • 5
    OpenGL is not a scene graph, where you put "object into it". It just draws things. It's your job to do the bookkeeping. – datenwolf Oct 27 '11 at 13:01
  • Yes you are right. Maybe its my fault my not completely understanding the arcball example from NeHe and therefore not beeing able to save the rotation state of the cube. – VanillaBear Oct 28 '11 at 07:42

2 Answers2

4

You could use gluUnProject to convert mouse coordinates to 3d space and get a vector (difference between two points). This vector could then be used to apply a "force" to the selected face. Since gluUnProject uses the projection matrix, it would automatically deal with the orientation of the camera.

Basically, once you get your "force" vector, you project it onto the three axes (so onto (1,0,0), (0,1,0), (0,0,1)). Then choose the one with the largest magnitude. Then you have to convert this direction into a rotation axis as in the diagram below (sorry for the bad paint skills):

Example of the vectors used in the explanation

So what we have is the "force" vector in black and the selected rubiks face in grey. To get the rotation axis, just take the cross product the "force" vector with the normal of the selected face. This gives the red arrow. From that, you should be able to rotate your cubes in the right direction.

Edit to answer the question in more detail

So continuing from my explanation, I will give an example of how this will help you. Let's first assume your screen is 800x800 pixels and your rubiks cube is always centred. Now lets also assume that, as per your drawings in the comments, that we are in the case on the left.

We drag the mouse and get two positions which using gluUnProject are transformed into world coordinates (the numbers were chosen to show my point, not by any calculation):

p1 : (600, 600) -> (1, -0.5, 0)
p2 : (630, 605) -> (1.3, -0.505, 0)

Now we get the difference vector: p2 - p1 = v = (0.3, -0.05, 0). The reason that I was saying to "project onto the three axes" is so that you extract your major movement (which in this case is 0.3 in the x axis) (since the rubiks cube can't rotate along diagonals). To do the "projection" you just have to take the x, y, z axes individually and create vectors from them so you wind up with:

v1 = (0.3, 0, 0)
v2 = (0, -0.05, 0)
v3 = (0, 0, 0)

Now take the magnitudes and discard the smallest vectors, so we are left with the vector v1 = (0.3, 0, 0). This is your movement vector in world space. Now you take the cross product of that vector, with the normal vector of the selected face (which in this case would be (0, 0, 1)). This gives you a vector which points down (0, 1, 0) (after normalization) (in this step you will probably also have to extract the largest component only (0.02, 1.2, 0.8) -> (0, 1, 0) otherwise you would get bizarre rotations if your camera was not pointing directly along the main axes). You can now use that vector as the rotation axis and use 0.3 as your rotation amount (if it rotates in the opposite direciton to that expected, just put a -).

Now how does this help if your cube is upside down? Suppose we click on the screen in the same way. We now get:

p1 : (600, 600) -> (-1, 0.5, 0)
p2 : (630, 605) -> (-1.3, 0.505, 0)

See the difference in the world coordinates? They are inverted! So when you take the difference vector p2 - p1 = v = (-0.3, 0.05, 0). Extracting the largest component vector gives (-0.3, 0, 0). Doing the cross product once again gives you the rotation axis, but now the rotation is in the opposite direction, which is what you want.

Another reason for the cross product with the normal of the face is that if you were to select the faces on the top (in our drawings), then it would either give a rotation axis along the x or z axes (to the left, or into the screen) which is what you want for the top faces.

NickLH
  • 2,643
  • 17
  • 28
  • I assumed your cubes were always aligned with the main axes, hence the choice of (1,0,0) (0,1,0) (0,0,1) for the projection axes. – NickLH Oct 27 '11 at 13:27
  • I must admit iam having trouble completely understanding your explanation. So i basically get a vector from point where i click to where i drag it to. I then project it onto the three axes(not sure how though) and largest magnitute is my hint for the rotation? Iam not sure if that solves my problem. [Here an example](http://i.imgur.com/Xf4vV.jpg) of my problem again. Iam thankful for your explanation but would you mind explaining in more detail? I know iam in charge of keeping track of the rotation, but that itself is also the problem while using the arcball implementation. – VanillaBear Oct 28 '11 at 07:34
  • Thx for the explanation in more detail. It kinda works when i have not rotated the cube. As soon as I rotate the whole cube it doesnt work anymore. Is it ok to use gluPerspective or does that cause problems(though it doesnt work exactly with glOrtho either)? Maybe Iam missing something. Wont give up yet. – VanillaBear Oct 30 '11 at 13:13
  • gluPerspective is fine to use. What do you mean by it kind of works when you don't rotate the cube? – NickLH Oct 30 '11 at 13:14
  • Well for example if the cube is in startposition and i move cursor from right middle([6](http://i.imgur.com/Xf4vV.jpg)) one single cubesize to the right i get difference of like 15 on x-axis(about 3 when using ortho instead of perspective). So when i rotate the cube to me so i can see also the top face, and do the same mousemove, I get a quite bigger(-70) diff on y-axis not resulting in same rotation. Also confusing that of course the z-point of mouse my click becomes -70 when i am not on cube again, making it the biggest magnitude(so i kinda ignored this). – VanillaBear Oct 30 '11 at 13:35
  • I am out of ideas by now, sorry. I suggest you head over to http://www.gamedev.net and try asking your question there since they will probably have more experience dealing with problems like the one you are having. – NickLH Oct 30 '11 at 14:46
0

Like most of us, you will encounter the famous problem called Gimbal Lock.

see: http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=208925

This problem is extremely well documented so there is not much point for me to go into details here. I am sure you will find a ton of information about it.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
Martin
  • 282
  • 2
  • 6
  • 2
    I don't see how this could be an answer to his question in **any** way. Even if gimbal lock **would** be a problem for him (which is not predetermined, given his statements), then this might better be a comment, as at the moment it surely **is** not his problem. – Christian Rau Oct 27 '11 at 13:18
  • I did experiment with quaternions(which are supposed to be one way to avoid gimbal lock) and the rotation with it worked. But it wasnt exactly arcball like for me.(the farther away from mid-point the higher the rotation rate etc) I then used the arcball example from NeHe Tutorials(link in my first post) which i thought would avoid it the same way. Even though i have to admit i couldnt follow it completely on the mathematical side and therefore judge whether it truly avoids gimbal lock like my quaternions class in before. But it seemed to me like it would. Any judge on that would be appreciated – VanillaBear Oct 27 '11 at 13:44