Quaternion rotation does not work as excluded

In OpenGL ES 1 for android, I have a Rubic cube consisting of 27 smaller cubes. I need turns that cause a special cube that gets right in front of the point of view. therefore I need two vectors. one is a vector that comes from the beginning of an object to a specific cube. and the other is a vector that comes from the source to the point of view. then the cross product of them gives me the axis of rotation, and the point product gives me an angle.

I convert (0,0,1), which is a vector that comes from the origin to the point of view in the world coordinates of the coordinates of the object. here is the code:

matrixGrabber.getCurrentModelView(gl); temporaryMatrix.set(matrixGrabber.mModelView); inputVector[0] = 0f; inputVector[1] = 0f; inputVector[2] = 1f; inputVector[3] = 1f; Matrix.multiplyMV(resultVector, 0, temporaryMatrix.InvertMatrix(), 0, inputVector,0); resultVector[0]/=resultVector[3]; resultVector[1]/=resultVector[3]; resultVector[2]/=resultVector[3]; inputVector = ..... // appropriate vector due to user-selection axis = Vector.normalized(Vector.crossProduct(Vector.normalized(inputVector), Vector.normalized(resultVector))); degree = (float)Math.toDegrees(Math.acos(Vector.dot(Vector.normalized(inputVector), Vector.normalized(resultVector)))); 

I use two quaternions for rotation. every time the user selects an action, this should happen. here is the code:

  Quaternion currentRotation = new Quaternion(); Quaternion temporaryRotation = new Quaternion(); . . . currentRotation = (currentRotation).mulLeft(temporaryRotation.set(axis, degree)); currentRotation.toMatrix(matrix); gl.glMatrixMode(GL10.GL_MODELVIEW); gl.glMultMatrixf(matrix, 0); 

Now the problem is that it just works fine for the first rotation. regardless of the first turn. it works well, but for the next turns it seems that it gets the wrong axis and degree.

For example, if the coordinate system is

  • X-right (1,0,0)
  • Y-up (0,1,0)
  • Z-in (0,0,1)

then the first rotation around X 90 degrees counterclockwise (CCW) causes

  • X'-right (1,0,0)
  • Y'-in (0,0,1)
  • Z'-down (0, -1.0)

and a second rotation around Z 90 degrees CCW produces

  • X'-in (0,1,0)
  • Y'-left (-1,0,0)
  • Z'-down (0, -1.0)

but i expect

  • X-up (0,1,0)
  • Y-in (0,0,1)
  • Z-right (1,0,0)

I think the problem is that resultVector (the second vector that I used, which comes from the source to the point of view) is not correctly converted. Does anyone know how I can convert the coordinate of the world to the coordinate of an object? Does anyone know how we can determine the coordinates of an object when the object is rotated?

+4
source share
2 answers

Well, yesterday I decided to write down the Rubic Cube riddle, because everything I tried in the past was really inconvenient for me and finally got some mood / time to encode it myself. As I already finished, this is my knowledge:

  • Introducing Rubic Cube

    I do not see quaternions as a good choice for this. Instead, itโ€™s more convenient for me:

    So, I ended up with a list of transformation matrices 3*3*3=27 plus one extra for whole cube rotations. In the initial state, all the cubes have part of the rotation of the block, and the sources are set to cover all the combinations { -1 , 0 ,+1 } to fill the entire Rubic Cube (the size of each cell of the subcube is 1.0 and centered around (0,0,0) )

    axises

    My cubes in C ++ code are defined as follows:

     reper cube[27]; // reper is transform matrix 
  • GUI

    I wanted control and viewing to be as close to the real thing as possible. Thus, the rotation is controlled by the mouse by a simple click on the target subcube (in area0 or area1 ), and then in the direction of movement of the mouse it is determined which axis is rotated and in which direction.

    There are no problems from the initial position (since even your code works well for this). Problems begin at the next turn (especially when changing the axis of rotation), because the local coordinate systems have already changed. The same applies to the rotation of the global view, as this will ruin it all.

  • How to fix the local coordinate system?

    I come up with an obscure solution where I first map the axis to each coordinate system. To determine which of the axes is that I simply make the point product of the requested direction with respect to all the axes of the transformation matrix and select the one that has the highest abs. The sign simply indicates whether the coordinate system is the opposite (this means that the rotation must be canceled).

    On C ++ and OpenGL lines, it looks like this:

     void RubiCube::axises_unit(reper &rep,int &x,int &y,int &z,int &sx,int &sy,int &sz) { int i; double p[3],xyz[3][3],a,b; rep.axisx_get(xyz[0]); rep.axisy_get(xyz[1]); rep.axisz_get(xyz[2]); vector_ld(p,1.0,0.0,0.0); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { x=i; b=a; } } sx=+1; if (b<0) sx=-1; vector_ld(p,0.0,1.0,0.0); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { y=i; b=a; } } sy=+1; if (b<0) sy=-1; vector_ld(p,0.0,0.0,1.0); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { z=i; b=a; } } sz=+1; if (b<0) sz=-1; } 

    Where reper is a class containing a direct and inverting transformation matrix. get_axis just look inside the direct matrix and return the selected vector of the axis direction. vector_mul is a point product, and vector_ld just fills a 3D vector with x,y,z coordinates.

    As I also received the global matrix of the cube, which is not axis-aligned to the identity matrix (since it is rotated so that the view looks like the image above). Then I need to execute this axis, corresponding to special vectors (values โ€‹โ€‹of the matrix of the initial representation) In my case, this:

     void RubiCube::axises_obj(reper &rep,int &x,int &y,int &z,int &sx,int &sy,int &sz) { int i; double p[3],xyz[3][3],a,b; rep.axisx_get(xyz[0]); rep.axisy_get(xyz[1]); rep.axisz_get(xyz[2]); vector_ld(p,+0.707,-0.299,-0.641); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { x=i; b=a; } } sx=+1; if (b<0) sx=-1; vector_ld(p,-0.000,-0.906,+0.423); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { y=i; b=a; } } sy=+1; if (b<0) sy=-1; vector_ld(p,-0.707,-0.299,-0.641); for (b=0.0,i=0;i<3;i++) { a=vector_mul(xyz[i],p); if (fabs(a)>=fabs(b)) { z=i; b=a; } } sz=+1; if (b<0) sz=-1; } 

    Both functions return the axis in which x,y,z , and if the direction is opposite (sx, sy, sz) compared to the unit transformation matrix.

  • Fragment rotation

    This is the core of the puzzle. This is a simple rotation of the slice around the axis. This is used for animation, so the angle step is small (I use 9 degrees), but the whole rotation should be 90 degrees, otherwise the Rubic Cube will break.

     void RubiCube::cube_rotate(int axis,int slice,double ang) { int j,k,a[3],s[3]; double p[3],p0[3]={0.0,0.0,0.0},lang; reper *r; _redraw=true; for (k=0;k<27;k++) { r=&cube[k]; // local axis,sign axises_unit(*r,a[0],a[1],a[2],s[0],s[1],s[2]); // lang is local signed angle change lang=ang; if (s[axis]<0) lang=-lang; // select slice r->gpos_get(p); j=round(p[axis]+1.0); if (j!=slice) continue; // rotate global position if (axis==0) vector_rotx(p0,p,+ang); if (axis==1) vector_roty(p0,p,-ang); if (axis==2) vector_rotz(p0,p,+ang); r->gpos_set(p); // rotate local cube orientation if (a[axis]==0) r->lrotx(-lang); if (a[axis]==1) r->lroty(-lang); if (a[axis]==2) r->lrotz(-lang); } } 

    Where reper::gpos_get returns the beginning of the matrix as a 3D vector (point) and reper::gpos_set basically sets the new position of the matrix. vector_rotx(p0,p,a) rotates the vector p around p0 and the x axis by angle a . The signs +/- should correspond only to rotations of the reper class (I was different somewhere). reper::lrotx rotates reper around its local x axis to learn more about the first link.

    As you can see, I use each initial coordinate of the matrix directly as a topology to select slice cubes.

Here you can try your demo: Win32 + OpenGL Rubic Cube Demo

And here is an animated gif of some twists:

animation

[Edit1] I added a simple solver to my RubiCube

To implement the solver, I added a plane surface map plane (on the left ... the middle square is the name and index of the side I'm using) calculated from the RubiCube internal representation. I also add internal que commands for the solver (axes and direction to the right):

axises

Each command is represented by 2 character strings:

 edge slice CW: RLUDFB edge slice CCW: R'L'U'D'F'B' mid slice CW: R0L0U0D0F0B0 whole cube CW: RcLcUcDcFcBc 

And the map looks like this:

 int map[6][3][3]; 

Where map[side][u][v] contains the color of the square on the side s , row u and column v . I implemented a simple 7-step solution (for example, solving a real cube by a human):

decision steps

  • input status (not a step)
  • White cross with a yellow middle (yellow middle in front)
  • White cross (white middle front)
  • White corners (white side down)
  • Intermediate level (using the first 3 teams)
  • The top layer of the yellow cross (using the 4th command)
  • reorder the cross so that the sides coincide (5th command) and reordering angles (6th command)
  • orientation of the upper corners of the layer to complete the cube (7th command)

Solver is simple and works with strings (not optimized), so it is a bit slow, but in any case, the complete solution takes up to 50 ms in my setup. You can try the updated demo here:

During the solution, some undefined cases may appear (due to an error or missing code in the code). In this case, the application hangs roughly (the gatekeeper has not yet been implemented). The keys are described in a text file.

I made the solver easy (about 300 lines of code), so the solution found is far from optimal. For example, instead of testing four corners, I test only one and rotate the cube in the loop, causing unnecessary rotations. Some of them are filtered last, but the average human (mine) solution is up to 200 revolutions, and this solver returns instead of 300 revolutions (in the worst case, I have found so far).

+2
source

What happens when you apply this transformation to your model (rotation in your case), you also rotate its base vectors. Think of it as if you were also rotating your coordinate system, or as if you were looking at a glance at your model. Each transformation you do will affect the next.

Since you usually want to maintain your own coordinate system, you may need to move the camera around the cube and then rotate the cube. I'm sure you can find the "lookAt" method either in your API or on the web. It should take 3 vectors: cameraPosition, lookAtPoint, upVector. With this approach, you can position the cube to (0,0,0), which is also your "lookAtPoint", the first camera. The position should be something like (0,0, -1) and first upVector (0,1,0). Now for the movement (you probably use only left / right and up / down as input): To move up / down (rotation around X), you will follow these steps:

 originalDistance = (cameraPosition-objectPosition).lenght leftVector = normalizedVector(crossProduct(camearPosition, upVector))//generaly cameraPosition-objectPosition camearPosition = cameraPosition + upVector*inputScalar //inputScalar should be a small floating value cameraPosition = normalizedVector(cameraPosition)*originalDistance //put camera to original distance from object upVector = normalizedVector(crossProduct(cameraPosition, leftVector))//generaly cameraPosition-objectPosition 

To go left / right (rotation around X), you can do the following:

 originalDistance = (cameraPosition-objectPosition).lenght leftVector = normalizedVector(crossProduct(camearPosition, upVector))//generaly cameraPosition-objectPosition camearPosition = cameraPosition + leftVector*inputScalar //inputScalar should be a small floating value cameraPosition = normalizedVector(cameraPosition)*originalDistance //put camera to original distance from object leftVector = normalizedVector(crossProduct(cameraPosition, upVector))//generaly cameraPosition-objectPosition upVector = normalizedVector(crossProduct(cameraPosition, leftVector))//generaly cameraPosition-objectPosition 

This should generally solve the problem .. (please tell me if I made a mistake, as I write it hard)

As for your approach to the rotation of the object itself, you should find out what your quaternion is in the objectโ€™s own coordinate system and rotate it around it. It is also quite easy if you have math skills. Alternatively, you could also simply define 2 angles (X, Y) and change them directly through the input and use the quaternions (1,0,0, X) and (0,1,0, Y), but you may have problems with this approach when Y is 90 degrees.

Hope this helps.

+1
source

All Articles