Hi
I have written a first person camera class for android.
The class is really simple , the camera object has its three axes
X,y and Z
and there are functions to create the ModelView matrix ( i.e. calculateModelViewMatrix() ),
rotate the camera along its X and Y axis
and Translate the camera along its Z-axis.
I think that my ModelViewMatrix calulation is correct and i can also translate the camera along the Z-axis.
Rotation along x-axis seems to work but along Y-axis it gives strange results.
Also another problem with the rotation seems to be that instead of the camera being rotated, my 3d model starts to rotate instead along its axis.
I have written another implementation based on the look at point and using the openGL ES’s GLU.gluLookAt( ) function to obtain the ModelView matrix but that too seems to suffer from the exactly the same problems.
Any help or ideas on the matter will be greatly appreciated.
Here is what the class looks like:
package com.droidnova.android.games.vortex;
import javax.microedition.khronos.opengles.GL10;
import android.util.Log;
import com.surrealtech.math.util.Vector3;
public class Camera4 implements ICamera {
Vector3 _X = new Vector3(1,0,0); // x-axis of the camera frame
Vector3 _Y = new Vector3(0,1,0); // y-axis of the camera frame
Vector3 _Z = new Vector3(0,0,1); // z-axis of the camera frame
Vector3 _T = new Vector3(0,1,2); // translation vector representing the position of camera frame from the world
// frame's origin.
float[] _matrixModelView = new float[16]; // the model-view matrix that represents the
// coordinate transformation between
// camera's frame & world frame
float[] _matrixRotation = new float[9]; // a temporary matrix to store the rotation
// matrix each time it is calculated
float[] _vecTemp = new float[3]; // a temporary vector to store results
/**
* Constructor
*/
public Camera4(){
}
@Override
public void applyModelViewTransform(GL10 gl) {
this.calculateModelViewMatrix();
gl.glMatrixMode(gl.GL_MODELVIEW);
gl.glLoadMatrixf(_matrixModelView, 0);
}
@Override
public void pitch(GL10 gl, float angle) {
// calculate the 3-by-3 rotation matrix along the camera's x-axis
_matrixRotation = getRotationMatrixAlong(_X, angle);
// rotate the camera's y-axis
float[] result = this.multiplyMV(_matrixRotation, _Y);
_Y.setFloat(result);
Log.e(""+this.getClass(), "|Y| = "+_Y.Magnitude());
// rotate the camera's Z-axis
result = this.multiplyMV(_matrixRotation, _Z);
_Z.setFloat(result);
Log.e(""+this.getClass(), "|Z| = "+_Z.Magnitude());
this.applyModelViewTransform(gl);
Log.e(""+this.getClass(), "X,Y,Z axes: ("+_X.x + ","+_X.y + "," + _X.z+ ") , ("+_Y.x+","+_Y.y+","+_Y.z+"), (" +_Z.x+","+_Z.y+","+_Z.z+")" );
}
@Override
public void yaw(GL10 gl, float angle) {
// calculate the 3-by-3 rotation matrix along the camera's Y-axis
_matrixRotation = getRotationMatrixAlong(_Y, angle);
// rotate the camera's x-axis
float[] result = this.multiplyMV(_matrixRotation, _X);
_X.setFloat(result);
_X.Normalise();
Log.e(""+this.getClass(), "|X| = "+_X.Magnitude());
// rotate the camera's Z-axis
result = this.multiplyMV(_matrixRotation, _Z);
_Z.setFloat(result);
_Z.Normalise();
Log.e(""+this.getClass(), "|Z| = "+_Z.Magnitude());
this.applyModelViewTransform(gl);
Log.e(""+this.getClass(), "X,Y,Z axes: ("+_X.x + ","+_X.y + "," + _X.z+ ") , ("+_Y.x+","+_Y.y+","+_Y.z+"), (" +_Z.x+","+_Z.y+","+_Z.z+")" );
}
@Override
public void translateZ(GL10 gl, float dist) {
_T.z += dist;
this.applyModelViewTransform(gl);
}
/**
* Private method to calculate the model-view matrix based on the camera's frame axes.
*/
private void calculateModelViewMatrix(){
// 1st column
_matrixModelView[0] = _X.x;
_matrixModelView[1] = _Y.x;
_matrixModelView[2] = _Z.x;
_matrixModelView[3] = 0;
// 2nd column
_matrixModelView[4] = _X.y;
_matrixModelView[5] = _Y.y;
_matrixModelView[6] = _Z.y;
_matrixModelView[7] = 0;
// 3rd column
_matrixModelView[8] = _X.z;
_matrixModelView[9] = _Y.z;
_matrixModelView[10] = _Z.z;
_matrixModelView[11] = 0;
// 4th column
_matrixModelView[12] = (_T.x);
_matrixModelView[13] = (_T.y);
_matrixModelView[14] = (_T.z);
_matrixModelView[15] = 1;
}
/**
*
* @param r An arbitrary vector in 3D space, representing the rotation axis.
* @param angle The angle in degrees.
* @return
*/
private float[] getRotationMatrixAlong(Vector3 r, double angle){
double cos = Math.cos(angle); // argument should be in radians
double sin = Math.sin(angle); // argument should be in radians
double t = (1-cos);
// 1st column
_matrixRotation[0] = (float)( cos+ t*(r.x)*(r.x) );
_matrixRotation[1] = (float)( t*(r.x)*(r.y) + r.z*sin );
_matrixRotation[2] = (float)( t*(r.x)*(r.z) - r.y*sin );
// 2nd column
_matrixRotation[3] = (float)( t*(r.x)*(r.y) - r.z*sin );
_matrixRotation[4] = (float)( cos+ t*(r.y)*(r.y) );
_matrixRotation[5] = (float)( t*(r.y)*(r.z) + r.x*sin );
// 1st column
_matrixRotation[6] = (float)( t*(r.x)*(r.z) + r.y*sin );
_matrixRotation[7] = (float)( t*(r.y)*(r.z) - r.x*sin );
_matrixRotation[8] = (float)( cos+ t*(r.z)*(r.z) );
return _matrixRotation;
}
/**
* Multiply a 3-by-3 matrix with a 3_by_1 vector and return the result
* as a 3-by-1 column vector
* @param matrix A 3-by-3 matrix.
* @param v A 3-by-1 column vector.
* @return
*/
private float[] multiplyMV(float[] matrix, Vector3 v){
_vecTemp[0] = matrix[0]*v.x + matrix[3]*v.y +matrix[6]*v.z;
_vecTemp[1] = matrix[1]*v.x + matrix[4]*v.y +matrix[7]*v.z;
_vecTemp[2] = matrix[2]*v.x + matrix[5]*v.y +matrix[8]*v.z;
return _vecTemp;
}
}