Android opengl: Arbitrary axis rotation fails to apply rotation - android

I'm working in android with opengles 2.0 to render out an object and allow the user to manipulate the object. The user can rotate the object correctly around the fixed axis that the object begins at, but after an initial rotation has been applied, I'm unable to rotate the object around a new arbitrary axis.
As soon as there is a touch event, I reset the modelMatrix and apply the rotations that were already inputted by the user. The variable angle is a three element vector that contains the angle rotation for each axis.
Matrix.setIdentityM(modelMatrix,0);
Matrix.rotateM(modelMatrix,0,angle[0],1.0f,0.0f,0.0f);
Matrix.rotateM(modelMatrix,0,angle[1],0.0f,1.0f,0.0f);
Matrix.rotateM(modelMatrix,0,angle[2],0.0f,0.0f,1.0f);
Then, I apply a new incremental rotation that was inputted during the touch event. This seems to work.
Matrix.rotateM(modelMatrix,0,newYAngle,1.0f,0.0f,0.0f);
Matrix.rotateM(modelMatrix,0,newXAngle,0.0f,1.0f,0.0f);
Afterwards, I try and calculate the arbitrary axis to add the incremental rotation into the angle variable. This seems to be where problems arise.
Matrix.multiplyMV(newAxisX,0,modelMatrix,0,new float[] {0.0f,1.0f,0.0f,1.0f},0);
Matrix.multiplyMV(newAxisY,0,modelMatrix,0,new float[] {1.0f,0.0f,0.0f,1.0f},0);
float lengthX = (float) Math.sqrt(Math.pow(newAxisX[0]/newAxisX[3],2)+Math.pow(newAxisX[1]/newAxisX[3],2)+Math.pow(newAxisX[2]/newAxisX[3],2));
float lengthY = (float) Math.sqrt(Math.pow(newAxisY[0]/newAxisY[3],2)+Math.pow(newAxisY[1]/newAxisY[3],2)+Math.pow(newAxisY[2]/newAxisY[3],2));
angleChanges[0] = (newXAngle*((newAxisX[0]/newAxisX[3])/lengthX)) + (newYAngle*((newAxisY[0]/newAxisY[3])/lengthY));
angleChanges[1] = (newXAngle*((newAxisX[1]/newAxisX[3])/lengthX)) + (newYAngle*((newAxisY[1]/newAxisY[3])/lengthY));
angleChanges[2] = (newXAngle*((newAxisX[2]/newAxisX[3])/lengthX)) + (newYAngle*((newAxisY[2]/newAxisY[3])/lengthY));
After this code executes, the onDraw() method is called and the modelMatrix is multipled by the viewMatrix. That is then multiplied by the projection matrix and the result is fed into my shape class.
This causes a curving when rotating. For example, if I were to rotate the object 90° upwards with a y angle (on the 0.0,1.0,0.0 axis), then attempt to rotate the object 90° to the right (from the user perspective after the first rotation was applied), the object will curve downwards. I've logged the data from the axis vectors I'm using when applying the rotation, and what seems to happen (with the x axis vector) is that it starts out close to 0,0,1, which is correct, then slowly transforms to 1,0,0, which causes problems.
This is my current approach, but I've tried reversing the initial rotation and then applying the incremental rotation based on the vectors generated from that with no success.
Any help would be greatly appreciated.

I was able to solve this problem in the short time since posting (even though it has stumped me for several days).
All I had to do was create a global rotation matrix that stored all the rotations performed on the object. I passed the changes in x and y in as a global variable from my touch event. These are then fed into a temporary rotation matrix, which is then multiplied by the global rotation matrix. The global rotation matrix is them multiplied by the model matrix.
Matrix.setIdentityM(tempRotMatrix,0);
Matrix.rotateM(tempRotMatrix,0,newX,0.0f,1.0f,0.0f);
Matrix.rotateM(tempRotMatrix,0,newY,1.0f,0.0f,0.0f);
newX = 0.0f;
newY = 0.0f;
Matrix.setIdentityM(modelMatrix,0);
Matrix.multiplyMM(rotationMatrix,0,tempRotMatrix,0,rotationMatrix,0);
Matrix.multiplyMM(modelMatrix,0,modelMatrix,0,rotationMatrix,0);

Related

glRotatef is backing to central position

I'm having some issues with glRotateF. The problem is the following:
i'm drawing 3 lines that represent a Cartesian coordinate system, they represent the point of view of a camera.
This camera can rotate its point of view. When it rotates, it sends a message with the angles and the axis that had rotated.
My app gets this message and sends it to a method, this method gets the axis that was rotated and its angle and sends it to this method:
So far everything is working, the problem starts after this.
if I send a message to rotate the angle X on any angle and angle Z on any angle too, it just rotates the z axis.
In Debugging I noticed that first it rotated the X angle in the given angle, but when it rotates the Z in the angle, it goes back to the original position and then it rotates Z, losing the X's rotation.
Like this example:
Initial position:
rotate X on 90º:
rotate Z on 90º (What should be):
rotate Z on 90º (What is really happening):
What i want is rotate x and then z without lose x rotation.
This is how i call to rotate an axis:
openGl.rotateX((float) x);
openGl.rotateZ((float) z);
The method rotateX and rotateZ
public void rotateX(float grau) {
mCubeRotation = grau;
eixoX = 1.0f;
eixoY = 0.0f;
eixoZ = 0.0f;
surfaceView.requestRender(); // line to call onDrawFrame
}
public void rotateZ(float grau) {
mCubeRotation = grau;
eixoX = 0.0f;
eixoY = 0.0f;
eixoZ = 1.0f;
surfaceView.requestRender(); // line to call onDrawFrame
}
This is the code of rotation:
#Override
public void onDrawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -8.0f);
// When i rotate x eixoX equal 1 and the other axis is 0.
// When i rotate z eixoZ equal 1 and the other axis is 0.
gl.glRotatef(mCubeRotation, eixoX, eixoY, eixoZ);
mCube.draw(gl);
gl.glLoadIdentity();
lock = false;
}
if someone help me, I will appreciate.
Your rotate methods are explicitly clobbering the global eixo* variables set by the "other" rotate method, and your draw method is resetting the rendering state matrix via glLoadIdentity, so that is why you only ever get a single rotation.
In general you can't do what you're trying to do with three simple variables and a single call to glRotatef on top of an identity matrix; rotation doesn't concatenate that neatly unless your rotations are trivial because you need to order them correctly (applying two rotations around world-space X then Y is not the same thing as two rotations around world-space Y and then X - ordering matters). This is especially true across frames where you generally want to start from an arbitrary starting rotation. In general you want to apply a series of glRotatef calls on top of an existing matrix to generate the rotation incrementally.
Slightly off topic - if you have any choice here I would really suggest switching to use OpenGL ES 2.x and maintaining the complete translation matrix locally in your application. The OpenGL ES 1.1 API is old and relatively inefficient, and it's push/pop matrix stack assumes a very specific way of writing a scene graph rendering engine; OpenGL ES 2.x and shaders is the way forward and available on all modern devices.

Visually correct rotation with OpenGl and touch screen capabilities

I have been trying to do Cube of Rubik for android. I have one question about rotations. I want to rotate a figure visually correct. It means if user touch screen and after move his finger to right a figure rotate to right from side of observation point. But when I make some rotations the figure start move in not correct direction. I understand that it depends on that axis are change their situation. But I tried to use inverse model matrix to get necessary coordinates, but I haven't already result. Could anybody give me example or link of visually correct rotation of 3D figure with help of mouse or touch screen?
//get vector 3D of touch
Vector3f touchVector = getRubikSystemCoordinates(mTouchX,mTouchY,square.rubikRotationMatrix);
//Get vector 3D of move
Vector3f moveVector = getRubikSystemCoordinates(mMoveX,mMoveY,square.rubikRotationMatrix);
//get direction of motion
float direction = touchVector.substractFrom(moveVector);
//get axis for rotation
Vector3f axis = touchVector.vectorProductTo(moveVector);
//normalize axis
axis.normalize();
//get angle of rotation
float angle = direction.length;
//make identity Quad
Quaternion quad = new Quaternion();
//make rotation quad
quad.makeRotationKvaternion(angle,axis);
//from quad recieve matrix
Matrix4f matrix = quad.toMatrix();
//multiply to current modelview matrix
gl.glMultMatrixf(matrix.returnArray(),0);
//save rotation matrix
square.rotationMatrix = square.rotationMatrix.multiply(matrix);
//save modelView matrix
square.saveModelView(square.initMatrix.returnArray());
// touch coords to current modelView coords
private Vector3f getRubikSystemCoordinates(float x, float y, Matrix4f matrix){
// touch coords to normal coords of screen
Vector2f normalCoords = (new Vector2f(x,y)).toNormalScreenCoordinates(Settings.viewPort[2],Settings.viewPort[3]);
// to sphere coords in 3D
Vector3f sphereVector = new Vector3f(normalCoords.x,normalCoords.y, FloatMath.sqrt(2-normalCoords.x*normalCoords.x-normalCoords.y*normalCoords.y));
//Get inverse matrix from ModelView Matrix
Matrix4f m = matrix.inverseMatrix();
//Get vector for current modelView 3D coords
Vector3f vector = m.multiplyToVector(vector);
// make normalize vector
vector.normalize();
return vector;
}
What you're looking for is named arcball rotation. You'll find plenty of resources in java around the internet on this.
You are probably storing your rotation as three angles. Use matrix instead. Create a separate transformation matrix just for this rotation. Every time user rotates the object apply the rotation to this matrix. This way the movement will always be relative to current orientation.

Cube rotation issue in opengl android

I want to rotate the cube when the user is touching it. To rotate it,is quite simple but actual problem is if the user is tilting it then always it should stop in particuler face(cube has 6 faces and i mean that only one face should be visible at one time). Please give your suggetion if anyone worked on that.
In the case of a cube this is simple: Face normals are the cartesian axes. So one looks straigt on a face if you constrain the rotations around the cartesian axes (X, Y, Z) and the rotation angles are multiple of pi/2 = 90°.
So in your code when the user stops interacting, set the rotation angles to the next multiple of 90°
fmod(round(angle/90) * 90, 360); // degrees
fmod(round(angle/(pi/2)) * pi/2, 2*pi); // radians
Either do it hard, or animate it.
If your object is not a cube, but arbitrary, you need to find the additional rotation for the face to get perpendicular to the view axis. This angle is determined by acos( scalar_product(normalize(face_normal), normalize(view_axis)) ) the axis of rotation is given by cross_product(normalize(face_normal), normalize(view_axis))

Billboarding in Android OpenGL ES 1.0

I'm trying to get billboarding to work, but having trouble with the last step.
After following these directions from NeHe's tutorials (http://nehe.gamedev.net/data/articles/article.asp?article=19) I have my look, right, and up vectors, and I have already translated the modelview matrix to the centerpoint of the billboard by using glTranslatef().
float[] m = {right.x,right.y,right.z,0f,
up.x,up.y,up.z,0f,
look.x,look.y,look.z,0f,
pos.x,pos.y,pos.z,1f}; //pos is the centerpoint position
gl.glMultMatrixf(m, 0);
When I try to create a multiplication matrix out of these like so, the billboards are displayed all over the place in the wrong positions and orientations.
I guess my problem is that I don't know how to correctly create and multiply the matrix. I tried doing this instead, but then half the lines (the ones that need to rotate counter-clockwise) are rotated in the wrong direction:
//normal is the vector that the billboard faces before any manipulations.
float angle = look.getAngleDeg(normal); //returns angle between 0 and 180.
gl.glRotatef(angle, up.x,up.y,up.z);
Got it, using my second method. Calculating the angle between vectors (arccos of the dot product) can only give an angle between 0 and 180, so half the time you want to negate the angle so the rotation is in the opposite direction.
This is easy to check...since I already have the right vector, I can just check if the angle between the right vector and the normal is acute. If it's acute, then you want to negate the original angle.

3D rotation while object being translated

I've been playing with Android animation framework and I found the following 3D rotation sample code:
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/animation/Transition3d.html
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/animation/Rotate3dAnimation.html
It does pretty much what I want but I want the ImageView to rotate while it's being translated from point A to point B and the it should rotate along it's own center(which is moving) instead of the center of the container of screen.
Does anyone know how to do that?
-Rachel
Well it's pretty close to what you posted. Essentially you're multiplying the rotational matrix by the translation matrix. That's essentially what happens under the covers. Android hides that detail from you with it's API:
Matrix matrix = transformation.getMatrix();
matrix.rotate( rotateX, rotateY );
matrix.postTranslate( transX, transY );
Rotate first then translate will rotate the image around it's own axis first before translating it.

Categories

Resources