I'm trying to rotate moving object, but it rotates aroud the center of the coordinates system. How to make it rotate around itself while moving? The code is:
Matrix.translateM(mMMatrix, 0, 0, -y, 0);
Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1.0f);
y += speed;
Matrix.translateM(mMMatrix, 0, 0, y, 0);
Don`t use the view matrix to rotate objects, this matrix is used as the camera for all the scene, To transform an object you should use the model matrix. To rotate if around its own center, you can use the following method:
public void transform(float[] mModelMatrix) {
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0, y, 0);
Matrix.rotateM(mModelMatrix, 0, mAngle, 0.0f, 0.0f, 1.0f);
}
Don`t forget use the identity matrix to reset the transformations in every loop.
I think your code is worng. You shoud update the value of 'y' before to apply any transformation.
public void onDrawFrame(GL10 gl) {
...
y += speed;
transform(mModelMatrix);
updateMVP(mModelMatrix, mViewMatrix, mProjectionMatrix, mMVPMatrix);
renderObject(mMVPMatrix);
...
}
The updateMVP method, will combine the model, view and projection matrices:
private void updateMVP(
float[] mModelMatrix,
float[] mViewMatrix,
float[] mProjectionMatrix,
float[] mMVPMatrix) {
// combine the model with the view matrix
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// combine the model-view with the projection matrix
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
}
And at last the render method, will execute the Shaders to paint the object:
public void renderObject(float[] mMVPMatrix) {
GLES20.glUseProgram(mProgram);
...
// Pass the MVP data into the shader
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Draw the shape
GLES20.glDrawElements (...);
}
I hope this will help you.
where do you make the object drawing?
I suppose it is after the code you have put up here, something like:
Matrix.translateM(mMMatrix, 0, 0, -y, 0);
Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1.0f);
y += speed;
Matrix.translateM(mMMatrix, 0, 0, y, 0);
drawHere();//<<<<<<<<<<<<<<<<<<<
Then, the second translate call is the issue.
You should either move your draw call before the second translate.
or
the clean way to do it is:
Matrix.setIdentityM(mMMatrix, 0);//<<<<<<<<added
Matrix.translateM(mMMatrix, 0, 0, -y, 0);
Matrix.setRotateM(mMMatrix, 0, mAngle, 0, 0, 1.0f);
y += speed;
//Matrix.translateM(mMMatrix, 0, 0, y, 0); //<<<<<<<<<removed
drawHere();
I just used view matrix instead of model matrix and everything worked out. For details on model, view and projection matrices see.
Related
I am having some problems with proper scene manipulations with OpenGL ES 2.0. On my screen I want to draw a rectangle and a cube. Rectangle should be moved to the bottom and scaled while cube should be moved to the top and scaled. What's more, I want to rotate this cube in all 3 axis.
This is what I've created so far:
#Override
public void onDrawFrame(GL10 gl) {
float[] scratch = new float[16];
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(viewMatrix, 0, 0, 0, -6, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
Matrix.multiplyMM(MVPMatrix, 0, projectionMatrix, 0, viewMatrix, 0);
Matrix.translateM(scratchMatrix1, 0, 0, -1.1f, 0);
Matrix.scaleM(scratchMatrix3, 0, 0.5f, 0.5f, 0.5f);
Matrix.multiplyMM(scratchMatrix2, 0, scratchMatrix1, 0, scratchMatrix3, 0);
Matrix.multiplyMM(scratch, 0, scratchMatrix2, 0, MVPMatrix, 0);
rectangle.draw(scratch);
Matrix.setRotateM(scratchMatrix1, 0, angleXVal, 1.0f, 0, 0);
Matrix.setRotateM(rotationMatrix, 0, angleYVal, 0, 1.0f, 0);
Matrix.multiplyMM(scratchMatrix2, 0, rotationMatrix, 0, scratchMatrix1, 0);
Matrix.setRotateM(rotationMatrix, 0, angleZVal, 0, 0, 1.0f);
Matrix.multiplyMM(scratchMatrix3, 0, rotationMatrix, 0, scratchMatrix2, 0);
Matrix.translateM(scratchMatrix1, 0, 0, 0.3f, 0);
Matrix.multiplyMM(scratchMatrix2, 0, scratchMatrix3, 0, scratchMatrix1, 0);
Matrix.scaleM(scratchMatrix1, 0, 0.8f, 0.8f, 0.8f);
Matrix.multiplyMM(scratchMatrix3, 0, scratchMatrix2, 0, scratchMatrix1, 0);
Matrix.multiplyMM(scratch, 0, scratchMatrix2, 0, MVPMatrix, 0);
cube.draw(scratch);
}
The problem is that when I am rotating the cube also the rectangle is moving. It is this same with scale and translating of cube - it is pulling the rectangle.
For me it looks like the matrices are connected somewhere but I don't see where, because the rectangle is drawn first and scratch matrix is overwritten later.
Assuming that is your complete onDrawFrame() code, scratchMatrix1 etc are class member variables that persist from frame to frame.
That means that translations from one frame will carry over to the next, because Matrix.translateM() applies a translation to an existing matrix transform by adding to it, rather than setting the matrix to a given translation matrix and overwriting the previous values. So the translations will accumulate over several frames.
That means that when you translate the cube, the translation will still be sitting in scratchMatrix1 the next time onDrawFrame is called, and the rectangle translation will be added to it rather than be set afresh.
The same goes for Matrix.scaleM().
You can rectify this by initializing all the scratch matrices to identity at the start of the function, and again before beginning the calculation of the cube transform matrix:
Matrix.setIdentityM(scratchMatrix1, 0);
Matrix.setIdentityM(scratchMatrix2, 0);
Matrix.setIdentityM(scratchMatrix3, 0);
Matrix.setIdentityM(scratch, 0);
I'm trying to implement color picking using GLES20.glReadPixels function in android OpenGL ES. The problem is that this function is always returning 0,0,0,0 as color and not the correct color values. Any idea why? My code looks like this:
public boolean onTouchEvent(MotionEvent event)
{
if (event != null)
{
float x = event.getX();
float y = event.getY();
if (event.getAction() == MotionEvent.ACTION_UP)
{
int newX = (int)x;
int newY = (int)y;
ByteBuffer pixel = ByteBuffer.allocate(4);
pixel.order(ByteOrder.nativeOrder());
pixel.position(0);
GLES20.glReadPixels(newX, (int)mRenderer.viewport[3] - newY, 1, 1,
GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixel);
}
return true;
}
else
{
return super.onTouchEvent(event);
}
So as I said before... the result of the pixel array is always 0,0,0,0. Dont know why :/ What am I doing wrong? I was using the lighthouse tutorial as a reference:
http://www.lighthouse3d.com/opengl/picking/index.php3?color2
And I really can't see the mistake at this point :/
Oh I forgot to tell that my scene contains a 3D cube which is fully BLUE so the result should be something like 0,0,1,0 when I click on it but it isn't :(
EDIT:
The code from the Renderer where the Cube is drawn (it rotates arround its y-axis)
public void onDrawFrame(GL10 unused) {
float[] scratch = new float[16];
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3.0f, 0f, -0.3f, 0.0f, 0.0f, 1.0f, 0.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
float[] mModelMatrix = new float[16];
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0, 0, -0.5f);
Matrix.setIdentityM(mRotationMatrix, 0);
Matrix.rotateM(mRotationMatrix, 0, mDeltaX, 0, 1.0f, 0);
Matrix.rotateM(mRotationMatrix, 0, -mDeltaY, 1.0f, 0, 0);
mDeltaX = 0.2f;
mDeltaY = 0.2f;
float[] mTempMatrix = new float[16];
Matrix.multiplyMM(mTempMatrix, 0, mRotationMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTempMatrix, 0, mAccumulatedRotation, 0, 16);
float[] temp = new float[16];
Matrix.multiplyMM(temp, 0, mModelMatrix, 0 , mAccumulatedRotation, 0);
Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, temp, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0, 0, 0.5f);
float[] temp2 = new float[16];
Matrix.multiplyMM(temp2, 0, scratch, 0, mModelMatrix, 0);
mCube.drawCube(temp2);
}
Like all other OpenGL calls, glReadPixels() only works if there is a current OpenGL context.
In Android, OpenGL rendering is mostly done using a GLSurfaceView, which takes care of spawning a secondary thread for rendering, creating an OpenGL context, and making that context current in the secondary rendering thread while invoking the methods in your GLSurfaceView.Renderer implementation.
onTouchEvent() is invoked in the UI thread, so you won't have a current OpenGL context here. To use glReadPixels(), you can forward the request to your rendering thread using the GLSurfaceView.queueEvent() method, and then process it asynchronously the next time your Renderer.onDraw() method is invoked.
I am trying to write an Android application that can translate a triangle a have used the
http://developer.android.com/training/graphics/opengl/motion.html code from Google but when I replaced the
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
with
Matrix.translate(mMVPMatrix,0,dx,dy,0);
the triangle was moving also on the Z axis and it did not look like a translation at all
What can i do ?
The following code:
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
means:
mRotationMatrix <-- Create a rotation matrix of mAngle degrees around axis -Z
mMVPMatrix <-- The product of mRotationMatrix and mMVPMatrix
While the following:
Matrix.translate(mMVPMatrix,0,dx,dy,0);
means:
mMVPMatrix <-- Translate mMVPMatrix of dx along X axis and dy along Y axis
I assume that mMVPMatrix is a perspective projection (and the P of MVP usually suggests that). Usually you don't translate stuff that has already been projected. Try the following instead:
Matrix.setIdentityM(mTranslationMatrix, 0);
Matrix.translateM(mTranslationMatrix, 0, dx, dy, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mTranslationMatrix, 0, mMVPMatrix, 0);
I dont think you want to translate your MVP matrix, you want to create an identity matrix, translate it, then multiply it with the mMVPMatrix.
In Android OpenGL
it has the command setLookAtM to specific the position for the camera view
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY,
lookZ, upX, upY, upZ);
If I rotate camera, by using command rotateM
Matrix.rotateM(mViewMatrix, 0 , angle , 0.0f, 1.0f, 0.0f);
Then, How could I get the 'LookAt' the exact camera view from mViewMatrix ?
the camera view position, i want is x,y,z that camera look at
Be careful, as calling rotateM doesn't technically rotate the camera, it applies a rotation to any future objects drawn. (it doesn't mean the same thing).
However in general, if you have a view matrix, and you want to see which direction it is facing, you want to transform the eye space forward vector (0,0,1) by the inverse of the view matrix.
As the view matrix transforms vectors in world space into eye space, the inverse view matrix transforms vectors from eye space into world space.
So you can:
Apply arbitrary operations to the current view matrix
Take its inverse
Multiply the inverse matrix by (0,0,1,0). (note this is the same as just pulling out the third column of the inverse matrix).
After #3 you will have the direction of the camera eye in world space. Add this to the eye's position, and you should know at what point it is pointing.
I have finished my question
and this is my solution
first, I need to made this 3 matrix to get result of x, y, z position
private float[] mRotXMatrix = new float[] {
1, 0, 0, 0,
0, 0, 1, 0,
0, 1, 0, 0,
0, 0, 0, 1 };
private float[] mRotYMatrix = new float[] {
0, 0, 1, 0,
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 1 };
private float[] mRotZMatrix = new float[] {
0, 1, 0, 0,
1, 0, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
Then in onSensorChanged(SensorEvent e) method I rotate all these 3 matrix together with my camera view like this
Matrix.multiplyMM(mViewMatrix, 0, deltaRotationMatrix, 0, mViewMatrix, 0);
Matrix.multiplyMM(mRotXMatrix, 0, deltaRotationMatrix, 0, mRotXMatrix, 0);
Matrix.multiplyMM(mRotYMatrix, 0, deltaRotationMatrix, 0, mRotYMatrix, 0);
Matrix.multiplyMM(mRotZMatrix, 0, deltaRotationMatrix, 0, mRotZMatrix, 0);
And to get the X, Y, Z of my camera view, just get it from these matrix
viewX = mRotXMatrix[2];
viewY = -mRotYMatrix[6]; // +/- up to your initial camera view
viewZ = mRotZMatrix[10];
I need to position sky sphere in 3D space right where camera is.
I set up camera as follows:
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
// Ignore the passed-in GL10 interface, and use the GLES20
// class's static methods instead.
GLES20.glViewport(0, 0, width, height);
float ratio = (float) width / height;
Matrix.frustumM(mProjMatrix, 0, -ratio, ratio, -1, 1, 2, 1000);
}
...
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
...
Sphere has a diameter of 100 units and it's center is in (0;0;0).
The method to draw a sphere:
private void drawSphere() {
//Matrix.setLookAtM(mVMatrix, 0, 0, 0, 0, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
mTriangleVerticesSphere.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesSphere);
mTriangleVerticesSphere.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVerticesSphere);
GLES20.glEnableVertexAttribArray(maTextureHandle);
Matrix.setRotateM(mMMatrix, 0, jitterX, 1.0f, 0, 0);
Matrix.rotateM(mMMatrix, 0, angleYaw + jitterY, 0, 1.0f, 0);
Matrix.scaleM(mMMatrix, 0, 0.01f, 0.01f, 0.01f);
Matrix.multiplyMM(mMVPMatrix, 0, mVMatrix, 0, mMMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, numPolysSphere);
}
This code displays a sphere. Backface culling is disabled, and I can see both sides of sphere (texture has transparent parts).
In order to display sphere right in the camera position I try to move camera. But if I uncomment Matrix.setLookAtM(mVMatrix, 0, 0, 0, 0, 0f, 0f, 0f, 0f, 1.0f, 0.0f) in the beginning of drawSphere() it doesn't display anything. May be it has something to do with clipping planes?
Please give an example how to position the sphere correctly.
I think your more looking to do something like
Matrix.setLookAtM(mvMatrix, 0, 0, 0, 10, 0, 0, 0, 0, 1, 0);
if I'm not wrong opengl doesn't know which way its looking at
your asking too look for (0,0,0) towards (0,0,0) while oriented towards (0,1.0,0)
OK, so I figured out how to do it.
1. Look at correct angle.
3. Draw sky sphere.
2. Clear Z-buffer.
3. Reposition camera.
4. Draw the rest.