I have a project featuring a 3d object. The user can rotate and zoom it in/out with finger gestures. The problem I have is while rotating a cube (other solids also cause the same error, but I'll set an example on cube), the edges of it kind of disintegrate (as shown in screenshots). The faster the rotation is the more substantial the problem becomes.
I tried to mask it by disable face culling, so that the user sees the inside of the cube, which basically has the same colour. However the project manager isn't pleased with that solution (I admitt it doesn't work that well).
The cube has 6 faces, each containing about 242 polygons.
Here are the code snippets relevant to rendering the 3d sceene (I'm using VBO):
public void onDrawFrame(GL10 glUnused)
{
GLES20.glDisable(GLES20.GL_BLEND);
isBlendingEnabled = false;
Matrix.setLookAtM(mViewMatrix, 0, mEyeX, mEyeY, mEyeZ, mLookX, mLookY, mLookZ, mUpX, mUpY, mUpZ);
if(!mSolid.equals(((ActivityMain) mContext).getSolid())){
refreshSolid();
refreshTextureData();
}
if(mSolid.hasChanged){
refreshSolid();
}
if(mSolid.hasTexturesChanged){
refreshTextureData();
mSolid.hasTexturesChanged = false;
}
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// Set per-vertex lighting program.
GLES20.glUseProgram(mProgramHandle);
// Set program handles for solid drawing.
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
mLightPosHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_LightPos");
mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
mTextureUniformHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_Texture");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
mNormalHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Normal");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
// Calculate position of the light. Handle it's rotation
Matrix.setIdentityM(mLightModelMatrix, 0);
Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, -2.0f);
Matrix.rotateM(mLightModelMatrix, 0, mAngleInDegrees, 0.0f, 1.0f, 0.0f);
Matrix.translateM(mLightModelMatrix, 0, 0.0f, 0.0f, 3.5f);
Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0, mLightPosInModelSpace, 0);
Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);
//Doing that step for each of the faces
for(int i = 0; i < mSolid.get3dMesh().size(); i++){
// Draw a solid.
// Translate the solid into the screen.
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -3.5f);
// Set a matrix that contains the current rotation.
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);
//handle inertia
if(Math.abs(mDeltaX) > 2f){
mDeltaX = Math.signum(mDeltaX);
mDeltaX = 0.5f*mDeltaX;
}else if(Math.abs(mDeltaX) > 0.05f){
mDeltaX = 0.99f*mDeltaX;
}else
mDeltaX = 0.0f;
if(Math.abs(mDeltaY) > 2f){
mDeltaY = Math.signum(mDeltaY);
mDeltaY = 0.5f*mDeltaY;
}else if(Math.abs(mDeltaY) > 0.05f){
mDeltaY = 0.99f*mDeltaY;
}else
mDeltaY = 0.0f;
// Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
// Rotate the cube taking the overall rotation into account.
Matrix.multiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[i]);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
drawCube(i);
}
if(ModelCorePrefs.getDrawMesh())
drawVertices();
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc (GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
isBlendingEnabled = true;
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, -3.5f, -3.5f);
Matrix.scaleM(mModelMatrix, 0, 2f, 1.0f, 2f);
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[mSolid.get3dMesh().size()]);
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
drawShadow();
}
The drawCube() method used above:
private void drawCube(int i)
{
// Pass in the position information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubePositionsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the color information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeColorsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mColorHandle);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the normal information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeNormalsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mNormalHandle);
GLES20.glVertexAttribPointer(mNormalHandle, mNormalDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Pass in the texture coordinate information
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mCubeTexCoordsBufferIdx[i]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, 0);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mTemporaryMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
System.arraycopy(mTemporaryMatrix, 0, mMVPMatrix, 0, 16);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
// Draw the cube.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, mSolid.get3dMesh().get(i).length/3);
}
And the screenshot of the problem:
I would strongly suggest you remove the glGet*Location (...) calls from your onDrawFrame (...) method. Those things do not change after you link your program initially, and searching for those locations by string name each frame is going to hinder your performance. Likewise, you only have to set the sampler uniform once per-program since it is always using texture image unit 0.
As for your real issue:
I see no evidence that each face in your loop has its own unique model matrix, so you should move the logic that incrementally transforms the matrix out of the loop. Otherwise you are going to rotate each face in the cube individually, which is what your diagram is showing. To be honest, I do not know why you even have to draw the faces one at a time.
// Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
GLES20.glUniform1i(mTextureUniformHandle, 0);
// ^^^^^ ONLY DO THAT ONCE!
// Translate the solid into the screen.
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -3.5f);
// Set a matrix that contains the current rotation.
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);
//handle inertia
if(Math.abs(mDeltaX) > 2f){
mDeltaX = Math.signum(mDeltaX);
mDeltaX = 0.5f*mDeltaX;
}else if(Math.abs(mDeltaX) > 0.05f){
mDeltaX = 0.99f*mDeltaX;
}else
mDeltaX = 0.0f;
if(Math.abs(mDeltaY) > 2f){
mDeltaY = Math.signum(mDeltaY);
mDeltaY = 0.5f*mDeltaY;
}else if(Math.abs(mDeltaY) > 0.05f){
mDeltaY = 0.99f*mDeltaY;
}else
mDeltaY = 0.0f;
// Multiply the current rotation by the accumulated rotation, and then set the accumulated rotation to the result.
Matrix.multiplyMM(mTemporaryMatrix, 0, mCurrentRotation, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mAccumulatedRotation, 0, 16);
// Rotate the cube taking the overall rotation into account.
Matrix.multiplyMM(mTemporaryMatrix, 0, mModelMatrix, 0, mAccumulatedRotation, 0);
System.arraycopy(mTemporaryMatrix, 0, mModelMatrix, 0, 16);
//Doing that step for each of the faces
for(int i = 0; i < mSolid.get3dMesh().size(); i++){
// Draw a solid.
// Set the active texture unit to texture unit 0.
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle[i]);
drawCube(i);
}
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 am learning open GL ES 2.0 and I just made 1 easy game for 1.0
I am following tutorials but I cant understand this thing
In OpenGL ES 1.0 if I define a square that way:
private float[] vertices = { // Vertices for a face
0.0f, 0.0f, 0.2f, // 0. left-bottom-front
1.0f, 0.0f, 0.2f, // 1. right-bottom-front
0.0f, 1.0f, 0.2f, // 2. left-top-front
1.0f, 1.0f, 0.2f // 3. right-top-front
};
and draw it that way it Works
public void draw(GL10 gl)
{
gl.glFrontFace(GL10.GL_CCW); // Front face in counter-clockwise
// orientation
gl.glEnable(GL10.GL_CULL_FACE); // Enable cull face
gl.glCullFace(GL10.GL_BACK); // Cull the back face (don't display)
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Enable
// texture-coords-array
// (NEW)
gl.glTexCoordPointer(3, GL10.GL_FLOAT, 0, texBuffer); // Define
// texture-coords
// buffer (NEW)
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
// front
gl.glBindTexture(GL10.GL_TEXTURE_2D,TextureLoader.TeclaBlancatextureIDs[0]);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); // Disable
// texture-coords-array
// (NEW)
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
gl.glDisable(GL10.GL_BLEND);
}
but in OpenGL ES 2.0 if I do this that way( with the same vertex) it only write a triangle:
private void drawSuelo(Suelo suelo)
{
// Pass in the position information
suelo.mPositions.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false,
0, suelo.mPositions);
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Pass in the color information
suelo.mColors.position(0);
GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false,
0, suelo.mColors);
GLES20.glEnableVertexAttribArray(mColorHandle);
// Pass in the normal information
cubo.mCubeNormals.position(0);
GLES20.glVertexAttribPointer(mNormalHandle, mNormalDataSize, GLES20.GL_FLOAT, false,
0, cubo.mCubeNormals);
GLES20.glEnableVertexAttribArray(mNormalHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1], mLightPosInEyeSpace[2]);
// Draw the cube.
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
It seems to need all of this vertex in order to draw a square
final float[] PositionData = {
// Top face
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f };
Why is happening this? Why I am missing? Is there any way in Open GL ES 2.0 to write a square with 4 vertex?
You're using different primitive types. In the working ES 1.0 code, you have this:
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
and in the ES 2.0 code that renders only a triangle when you give it 4 vertices:
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
So in the ES 1.0 code, you're specifying that you want to draw a triangle strip (primitive type GL_TRIANGLE_STRIP) with 4 vertices. This corresponds to 2 triangles. While in the ES 2.0 code, you specify that you want to draw 2 separate triangles (primitive type GL_TRIANGLES), which indeed needs 6 vertices.
If you want to use the original 4 vertices for the ES 2.0 code, you simply have to use the equivalent draw call with the same primitive type you used in the ES 1.0 version:
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
I am using default android sample code
http://developer.android.com/training/graphics/opengl/touch.html
In this sample we can rotate triangle by toucht events.
I want just to add movement by x,y axiss for test purposes.
The point that triangle behaviour is not as i am expecting. What i am doing wrong?
Code from tutorial with my new row hilighted:
public void onDrawFrame(GL10 unused) {
// Draw background color
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Set the camera position (View matrix)
Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mMVPMatrix, 0, mProjMatrix, 0, mVMatrix, 0);
// Draw square
mSquare.draw(mMVPMatrix);
**//Translating this matrix 'brakes' triangle
-> Matrix.translateM(mMVPMatrix, 0, 0, pos, -1.0f);
//NOTHING happens here: ??? Why?
-> Matrix.translateM(mRotationMatrix, 0, pos, 0, -1.0f);**
// Create a rotation for the triangle
// long time = SystemClock.uptimeMillis() % 4000L;
// float angle = 0.090f * ((int) time);
Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
// Combine the rotation matrix with the projection and camera view
Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mMVPMatrix, 0);
// Draw triangle
mTriangle.draw(mMVPMatrix);
}
Default behaviour:
With my code:
Thanks for a icrev comment:
You can not do translation / rotation / scaling on MVP matrix and get results as you expect.
you must translate / rotate your object in model matrix (or in View matrix for camera trans/rotation).
Look at this The purpose of Model View Projection Matrix to understand better what you need to do
These are the steps:
set M matrix to Identity matrix. Translate or rotate it. Be aware of gimbal lock (en.wikipedia.org/wiki/Gimbal_lock)
set V matrix Matrix.setLookAtM(mVMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f); 3. you already have projection matrix (in your case mProjMatrix)
multippy M * V * P to recieve final MVP matrix
Previously I did a Tutorial on OpenGL-ES 1.0. For reference, this can be found here:
SpaceInvaders (it's in german though)
My goal now is to port the game to OpenGL-ES 2.0. So far, I am able to load meshes and textures and render them.
Now I would like to have a simple rectangle as my background with a texture on it. This should be rendered in Ortho-Perspective. I then change to Projection-Perspective and draw a simple box. When I now call setLookAtM(...), I get a blank sceen. Here is the code:
public void onDrawFrame(GL10 gl) {
long currentFrameStart = System.nanoTime();
deltaTime = (currentFrameStart - lastFrameStart) / 1000000000.0f;
lastFrameStart = currentFrameStart;
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
GLES20.glUseProgram(programHandle);
checkGlError("glUseProgram");
mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "uMVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(programHandle, "uMVMatrix");
mLightPosHandle = GLES20.glGetUniformLocation(programHandle, "uLightPos");
mTextureUniformHandle = GLES20.glGetUniformLocation(programHandle, "uTexture");
mPositionHandle = GLES20.glGetAttribLocation(programHandle, "aPosition");
mColorHandle = GLES20.glGetAttribLocation(programHandle, "aColor");
mNormalHandle = GLES20.glGetAttribLocation(programHandle, "aNormal");
mTextureCoordinateHandle = GLES20.glGetAttribLocation
(programHandle,"aTexCoordinate");
Matrix.setIdentityM(mLightModelMatrix, 0);
Matrix.multiplyMV(mLightPosInWorldSpace, 0, mLightModelMatrix, 0,
mLightPosInModelSpace, 0);
Matrix.multiplyMV(mLightPosInEyeSpace, 0, mViewMatrix, 0, mLightPosInWorldSpace, 0);
Matrix.orthoM(mProjectionMatrix, 0, -width / 2, width / 2, -height / 2, height / 2,
0, 100);
drawBackground();
GLES20.glEnable(GLES20.GL_CULL_FACE);
Matrix.setIdentityM(mProjectionMatrix, 0);
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1.0f;
final float far = 100.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
Matrix.setLookAtM(mViewMatrix, 0, 0, 6, 2, 0, 0, -4, 0, 1, 0);
drawBlock();
}
Here the drawBackground method:
private void drawBackground() {
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, backgroundTextureHandle);
GLES20.glUniform1i(mTextureUniformHandle, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.setIdentityM(mProjectionMatrix, 0);
mBackgroundPositions.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT,
false, 0, mBackgroundPositions);
GLES20.glEnableVertexAttribArray(mPositionHandle);
mBackgroundColors.position(0);
GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false,
0, mBackgroundColors);
GLES20.glEnableVertexAttribArray(mColorHandle);
mBackgroundNormals.position(0);
GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT,
false, 0, mBackgroundNormals);
GLES20.glEnableVertexAttribArray(mNormalHandle);
mBackgroundTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, TEXTURE_COORD_DATA_SIZE,
GLES20.GL_FLOAT, false, 0, mBackgroundTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1],
mLightPosInEyeSpace[2]);
ShortBuffer buf =
ByteBuffer.allocateDirect(12).order(ByteOrder.nativeOrder()).asShortBuffer();
buf.put(new short[] {0, 1, 2, 0, 2, 3});
buf.position(0);
// Draw the rectangle.
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 6, GLES20.GL_UNSIGNED_SHORT, buf);
checkGlError("glDrawArrays");
}
And finally the drawBlock method:
private void drawBlocks() {
GLES20.glUseProgram(colorProgramHandle);
checkGlError("glUseProgram");
mMVPMatrixHandle = GLES20.glGetUniformLocation(colorProgramHandle, "uMVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(colorProgramHandle, "uMVMatrix");
mLightPosHandle = GLES20.glGetUniformLocation(colorProgramHandle, "uLightPos");
mTextureUniformHandle = GLES20.glGetUniformLocation(colorProgramHandle, "uTexture");
mPositionHandle = GLES20.glGetAttribLocation(colorProgramHandle, "aPosition");
mColorHandle = GLES20.glGetAttribLocation(colorProgramHandle, "aColor");
mNormalHandle = GLES20.glGetAttribLocation(colorProgramHandle, "aNormal");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(colorProgramHandle,
"aTexCoordinate");
Matrix.setIdentityM(mProjectionMatrix, 0);
Matrix.setIdentityM(mModelMatrix, 0);
blockMesh.vertexBuffer.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, POSITION_DATA_SIZE, GLES20.GL_FLOAT,
false, 0, blockMesh.vertexBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
blockMesh.colorBuffer.position(0);
GLES20.glVertexAttribPointer(mColorHandle, COLOR_DATA_SIZE, GLES20.GL_FLOAT, false,
0, blockMesh.colorBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
blockMesh.normalBuffer.position(0);
GLES20.glVertexAttribPointer(mNormalHandle, NORMAL_DATA_SIZE, GLES20.GL_FLOAT,
false, 0, blockMesh.normalBuffer);
GLES20.glEnableVertexAttribArray(mNormalHandle);
// This multiplies the view matrix by the model matrix, and stores the result in the
MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the
result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Pass in the light position in eye space.
GLES20.glUniform3f(mLightPosHandle, mLightPosInEyeSpace[0], mLightPosInEyeSpace[1],
mLightPosInEyeSpace[2]);
// Draw the cube.
GLES20.glDrawElements(GLES20.GL_TRIANGLES, 36, GLES20.GL_UNSIGNED_SHORT,
blockMesh.indexBuffer);
checkGlError("glDrawElements");
}
I am not sure what I am missing about ortho and projection perspective. Any help is appreciated.
You're wiping the projection matrix as part of drawBlocks. I don't think you want to do that, if you want to draw it using the perspective projection already computed.
...
Matrix.setIdentityM(mProjectionMatrix, 0); <-----
Matrix.setIdentityM(mModelMatrix, 0);
blockMesh.vertexBuffer.position(0);
...
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.