Mohamed Mohamed - 3 months ago 23
Android Question

OpenGl translate the world after camera rotation

I have a basic problem I want to translate all objects (the world) with touch event the problem is if the view matrix is rotated I could not calculate the model matrix translation to move in the correct direction, I want translate on x and z axes .
I need the math logic.
I have a camera class class and its draw void is:

public void draw() {
Matrix.setIdentityM(viewMatrix, 0);
setLookAtM(viewMatrix, 0, position.getX(), position.getY(), position.getZ(), lookAt.getX(), lookAt.getY(), lookAt.getZ(), 0f, 1f, 0f);

Matrix.setIdentityM(mCurrentRotation, 0);
Matrix.rotateM(mCurrentRotation, 0, mDeltaX, 0.0f, 1.0f, 0.0f);
Matrix.rotateM(mCurrentRotation, 0, mDeltaY, 1.0f, 0.0f, 0.0f);
mDeltaX = 0.0f;
mDeltaY = 0.0f;
float[] mTemporaryMatrix = new float[16];
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation.clone(), 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);

Matrix.multiplyMM(mTemporaryMatrix, 0, viewMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, viewMatrix, 0, 16);
}


and a mesh class and its draw void is:

public void draw(float mDeltaX, float mDeltaY) {
Matrix.setIdentityM(getMatrix().getFloatArray(), 0);
multiplyMM(getMatrix().getFloatArray(), 0, containerMatrix.getFloatArray(), 0, geometry.getMatrix().getFloatArray(), 0);
multiplyMM(modelViewMatrix, 0, this.getScene().getCamera().getViewMatrix(), 0, getMatrix().getFloatArray(), 0);

Matrix.setIdentityM(mCurrentTranslation, 0);
Matrix.translateM(mCurrentTranslation, 0, -mDeltaX, 0, -mDeltaX);
float[] mTemporaryMatrix = new float[16];
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentTranslation.clone(), 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
Matrix.multiplyMM(mTemporaryMatrix, 0, modelViewMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, modelViewMatrix, 0, 16);

this.getScene().getShaderProgram().setUniforms(modelViewMatrix, this.getScene().getCamera().getProjectionMatrix(), material.getTextureid(), material.getMaterialColor(), material.getEmissiveColor(), material.getShinines());
geometry.getDataBuffer().bindData(this.getScene().getShaderProgram());
glDrawArrays(GL_TRIANGLES, 0, geometry.getDataBuffer().getVerticesCount());
}


and the
onTouchEvent
is:

if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (mainRenderer != null) {
if(event.getPointerCount()==1){
float deltaX = (x - mPreviousX) / mDensity / 2f;
float deltaY = (y - mPreviousY) / mDensity / 2f;
mainRenderer.getCamera().mDeltaX += deltaX;
mainRenderer.getCamera().mDeltaY += deltaY;
}
else if(event.getPointerCount()==2){
float deltaX = (x - mPreviousX) / mDensity / 2f;
float deltaY = (y - mPreviousY) / mDensity / 2f;
mainRenderer.getScene().mDeltaX += deltaX;
mainRenderer.getScene().mDeltaY += deltaY;
}
}
}


The camera could be rotated very well but I can not translate objects to directions related to the view matrix.

I did the following code

Vector3 camPos=new Vector3();
camPos.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),3);
Vector3 camUp=new Vector3();
camUp.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),1);
Vector3 camForward=new Vector3();
camForward.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),2);
Vector3 camRight=new Vector3();
camRight.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),0);
translateM(geometry.getMatrix().getFloatArray(), 0, mDeltaX*camRight.getX(), 0, mDeltaY*camUp.getY());


but the result is unexpected, I know it is incorrect but I tried to follow your instructions, I get the position, forward, up and right from the view matrix then apply the transaction to the model matrix.

Update
this code is near from the right results but not perfect, I get the up, forward, right and position correctly from the view matrix

Vector3 col1=new Vector3();
col1.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),3);
Vector3 col2=new Vector3();
col2.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),1);
Vector3 col3=new Vector3();
col3.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),2);
Vector3 camUp=new Vector3(col1.getY(), col2.getY(), col3.getY());
Vector3 camForward=new Vector3(col1.getZ(), col2.getZ(), col3.getZ());
Vector3 camRight=new Vector3(col1.getX(), col2.getX(), col3.getX());
camRight.setFromMatrixColumn(this.getScene().getCamera().getViewMatrix(),0);
translateM(geometry.getMatrix().getFloatArray(), 0, mDeltaX*camRight.getX(),0,mDeltaY*camForward.getZ());

Answer

If I understand your problem correctly you will need a bit better system then using matrices directly. The problem is that if you want to move the object away from the camera you need to know what way the camera is actually facing. This can actually be done with matrices by getting the 3rd column of the view matrix which represents the Z axis of your current view direction (which is the way you are facing). This is a bit complicated and hard to use so I suggest you to rather use 4 vectors (3 will do as well) which define the position and orientation of the object in your scene including the camera/user.

To do so you should construct a class that contains vectors position, forward, up, right. The vector right is optional as you may always construct it by using a cross product between forward and up. Now if each of your models/objects contains this class to define its position you will need to construct the matrices from it. You will need 2 procedures, 1 for model matrix and another for view matrix. To construct a view matrix you may simply use lookAt where the lookAt parameter is position + forward while the rest of the parameters should not be a problem (up is up, eye is position...) so this covers the camera. To construct the model matrix you can simply generate them from the vectors where the top left 3x3 part of the matrix represent the base vectors so first column is X axis right, second Y is up and third Z is forward. The 4th column is the position and the bottom row is (0,0,0,1).

Now the matrix operations that have rotation and translation work as in first person perspective. For instance rotating around X (turning up or down) means rotating up and forward around right. The translation by vector (x,y,z) means position += (x*right, y*up, z*forward) which covers most of the matrix tools you are used to.

Now to get to your specific case you want to translate the object depending on your view matrix: You need to translate the position by using the camera base vectors. So for translating it by screen coordinates (x,y) you use model.position += (camera.right.x*x, camera.up.y*y). To for instance rotate it around X depending on the view you would need to rotate all the base vectors of the model model.forward, model.up, model.right around camera.x...