Android API 22 and 23 change causes flattening OpenGL 3d objects - android

I have written application which is using OpenGL ES. I was testing it on emulated and real Nexus 5, with Android 6 (API 23) on it.
During tests on older Android versions (API 22-) it came out, that my 3d object is missing one dimension.
After statring app, it looks like this in both cases (view is set to -z, and y axis is up here):
but when rotating this, there is a difference in behavior in API 22 (or lower) and 23.
Case API 22 (or lower):
Object is flat - Z axis on model seems to be missing, however light is calculated properly (with proper Z values).
Case API 23 (desired one):
All screenshots are from emulator; I have tested it only on one real device, with API 23 (Nexus 5), and it works there.
Rotation is done by touch events, and handled by code like this:
Matrix.rotateM(mCurrentRotation, 0, mDeltaRotationY, 1.0f, 0.0f, 0.0f);
Matrix.multiplyMM(mModelMatrix, 0, mModelMatrix, 0, mCurrentRotation, 0);
OpenGL version is set in AndroidManifest:
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
For me it seems that something has changed in behavior of model or view martix.
EDIT
As requested in comment:
Matrices are created in my rendered, which is extending GLSurfaceView.Renderer
I was following http://www.learnopengles.com/ tutorial to prepare this.
public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
...
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 7.0f;
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = 0.0f;
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
...
}
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
...
final float ratio = 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 = 20.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
...
}
public void onDrawFrame(GL10 glUnused) {
...
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
...
}

I know this issue is old already, but I've faced the same issue today.
So just in case somebody else encounters this, I identified the problem.
Whenever you call Matrix.multiplyMM(float[] result, ...) the 'result' float array must be equal neither to the left-hand-side matrix nor to the right-hand-side one.
On Android Marshmallow (or above) this does not seem to be a problem though... but below it might be a good idea to call the .clone() on the resulting matrix first and passing this then as the left/right-hand-side matrix instead.
Long story short, for Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0); the second mMVPMatrix needs to be replaced by mMVPMatrix.clone() for this to work properly.

Related

3-D Rotation on any axis causes mesh skew on some but not all Android devices

I am currently working on developing a 3-D game engine for Android, and everything works fine on my Lenovo TAB 10, but rotation about any axis causes the meshes to flatten (skew) during the rotation. I don't know where to start looking since it works on one device. Any ideas?
I rotate everything around arbitrary axes (right, up, and forward) relative to the objects themselves. The rotated axes are then put into a rotation matrix as follows:
mMatRotate = new cMatrix4(
mvRight.mX, mvUp.mX, mvForward.mX, 0.0f,
mvRight.mY, mvUp.mY, mvForward.mY, 0.0f,
mvRight.mZ, mvUp.mZ, mvForward.mZ, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
The actual matrix is defined as follows:
cMatrix4( float a, float b, float c, float d,
float e, float f, float g, float h,
float i, float j, float k, float l,
float m, float n, float o, float p )
{
mfMatrixData[0] = a; mfMatrixData[1] = b; mfMatrixData[2] = c; mfMatrixData[3] = d;
mfMatrixData[4] = e; mfMatrixData[5] = f; mfMatrixData[6] = g; mfMatrixData[7] = h;
mfMatrixData[8] = i; mfMatrixData[9] = j; mfMatrixData[10] = k; mfMatrixData[11] = l;
mfMatrixData[12] = m; mfMatrixData[13] = n; mfMatrixData[14] = o; mfMatrixData[15] = p;
}
Inside my draw() function looks like this:
Matrix.setIdentityM(mMesh.mModelMatrix, 0);
Matrix.translateM(mMesh.mModelMatrix, 0, mvLocation.mX, mvLocation.mY, mvLocation.mZ);
Matrix.scaleM(mMesh.mModelMatrix, 0, mfScale, mfScale, mfScale);
Matrix.multiplyMM(mMesh.mModelMatrix, 0, mMesh.mModelMatrix, 0, mMatRotate.getFloatArray(), 0);
mMesh.draw(viewMatrix, projMatrix, Renderer);
And the final transform looks like this:
Matrix.multiplyMM(mtrx, 0, viewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mtrx, 0);
Matrix.multiplyMM(mtrx, 0, projMatrix, 0, mtrx, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mtrx, 0);
I'm kind of stuck on this one. Any suggestions would be helpful.
Okay, I solved the problem myself, and I'll post it here in case anyone else is interested or encounters a similar issue. It all comes down t the fact that the Lenovo TAB 10 relies entirely on hardware, while the Samsung Galaxy Core Prime does not. The issue is in the line:
Matrix.multiplyMM(mMesh.mModelMatrix, 0, mMesh.mModelMatrix, 0, mMatRotate.getFloatArray(), 0);
In hardware, it seems, it is okay to perform a matrix multiply and place the result into one of the input matrices; but the software implementation does not function the same. This makes sense, I guess, because it would take too long to make a copy every time you do a matrix multiply.

Android OpenGL-ES: Object is showing up with wrong Chirality

I have an object that I am rendering in Android OpenGL ES 3.0, on a Nexus 9. The object has somewhere around 80000 vertices and a couple hundred thousand triangles.
I know for a fact that those vertices are in a Right-handed coordinate system. When I use my pc to view the object (using a program like Paraview), I see the object in a right-handed coordinate system. But as soon as I render the object on my app in OpenGL, the object has the wrong chirality.
As I mentioned above, I'm pretty certain that my vertices are correct. Therefore, something wrong must be occurring during the coordinate transformations. Does anyone have any idea which matrix (view, model, projection) might be a likely source of my problem? I need to maintain the integrity of my vertices and not perform any transformations (like flipping values manually) on the vertex data itself.
EDIT: Someone asked for my code: I can't post everything because it is an incredibly large project, but I'll show you the lines where my matrices have been set up:
In onSurfaceCreated():
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = -3.0f;
final float lookX = 0.0f;
final float lookY = 0.0f;
final float lookZ = 0.0f;
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
Matrix.setLookAtM(mViewMatrix2, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
Matrix.setLookAtM(mViewMatrix3, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
Matrix.setLookAtM(mViewMatrix4, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ); `
In onSurfaceChanged(GL10 glUnused, int width, int height):
GLES30.glViewport(0, 0, width, height);
viewport[0] = 0;
viewport[1] = 0;
viewport[2] = width;
viewport[3] = height;
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 = 500.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
Matrix.frustumM(mProjectionMatrix2, 0, left, right, bottom, top, near, far);
Matrix.frustumM(mProjectionMatrix3, 0, left, right, bottom, top, near, far);
Matrix.frustumM(mProjectionMatrix4, 0, left, right, bottom, top, near, far);
To clarify, the object that I am referring to uses mViewMatrix and mProjectionMatrix, not the other view matrices and projection matrices. If there isn't something wrong with this code, I can post more showing the places where I manipulated these matrices.
EDIT2: I simply do not understand why, but manually flipping coordinates (for instance, flipping the z-coordinate) either by changing the vertex data or by applying a scale matrix to the modelview, does not fix my chirality problem. I am absolutely stumped as to how to fix this.
Finally figured out my problem (after 16 hours of trying). Turns out I was culling the wrong side. Switching from GL_BACK to GL_FRONT did the trick for me.

Box2d jitter when camera follows

I am developing a box2d game on android and when the opengl camera follows the player the player jitters quite badly. When the camera is stationary, it appears to be fine. I tried box2d interpolation and that seemed to help slightly. Any suggestions?
public static void setCamera() {
// Position the eye behind the origin.
float eyeX = cameraX;
float eyeY = cameraY;
float eyeZ = cameraZoom;
// We are looking toward the distance
float lookX = cameraX;
float lookY = cameraY;
float lookZ = -5.0f;
// Set our up vector. This is where our head would be pointing were we
// holding the camera.
float upX = 0.0f;
float upY = 1.0f;
float upZ = 0.0f;
// Set the view matrix. This matrix can be said to represent the camera
// position.
// NOTE: In OpenGL 1, a ModelView matrix is used, which is a combination
// of a model and
// view matrix. In OpenGL 2, we can keep track of these matrices
// separately if we choose.
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY,
lookZ, upX, upY, upZ);
// Matrix.scaleM(mViewMatrix, 0, cameraZoom, cameraZoom, 0f);
// Matrix.orthoM(mProjectionMatrix, 0, left, right, top, bottom, near,
// far);
// Matrix.setLookAtM(mViewMatrix, 0, 1, 0, 1.0f, 1.0f, 0f, 0f, 0f, 1.0f,
// 0.0f);
}

OpenGL ES 2.0 cuts the screen in landscape mode

I'm starting to learn OpenGL, and are using the following site: http://www.learnopengles.com/android-lesson-one-getting-started/
But it seems that I got a problem at this part (works fine in portrait mode):
private float[] mViewMatrix = new float[16];
/** Store the projection matrix. This is used to project the scene onto a 2D viewport. */
private float[] mProjectionMatrix = new float[16];
/** Allocate storage for the final combined matrix. This will be passed into the shader program. */
private float[] mMVPMatrix = new float[16];
/** This will be used to pass in the transformation matrix. */
private int mMVPMatrixHandle;
/** This will be used to pass in model position information. */
private int mPositionHandle;
/** This will be used to pass in model color information. */
private int mColorHandle;
/** How many bytes per float. */
private final int mBytesPerFloat = 4;
/** How many elements per vertex. */
private final int mStrideBytes = 7 * mBytesPerFloat;
/** Size of the position data in elements. */
private final int mPositionDataSize = 3;
/** Offset of the color data. */
private final int mColorOffset = 3;
/** Size of the color data in elements. */
private final int mColorDataSize = 4;
public void onSurfaceChanged(GL10 gl, int width, int height)
{
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
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 = 10.0f;
System.out.println("Height: " + height);
System.out.println("Width: " + width);
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
public void onDrawFrame(GL10 gl)
{
final float eyeX = 0.0f;
final float eyeY = 0.0f;
final float eyeZ = 1.5f;
final float lookY = 0.0f; //Y direction of what user see
final float lookZ = -5.0f; //Z direction of what user see
// Set our up vector. This is where our head would be pointing were we holding the camera.
final float upX = 0.0f;
final float upY = 1.0f;
final float upZ = 0.0f;
GLES20.glClearColor(red, green, blue, clearcoloralpha);
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, xax, lookY, lookZ, upX, upY, upZ);
// Draw the triangle facing straight on.
for(int i = 0; i < Triangles.size(); i++)
{
Matrix.setIdentityM(Triangles.get(i).getModelMatrix(), 0);
if(Triangles.get(i).Rotate())
{
Triangles.get(i).rotation = (360.0f / 10000.0f) * ((int) Triangles.get(i).last);
Triangles.get(i).last+=20;
//Rotates the matrix by rotation degrees
Matrix.rotateM(Triangles.get(i).getModelMatrix(), 0, Triangles.get(i).rotation, 0.0f, 0.0f, 1.0f);
}
else
Matrix.rotateM(Triangles.get(i).getModelMatrix(), 0, Triangles.get(i).rotation, 0.0f, 0.0f, 1.0f);
drawTriangle(Triangles.get(i).getFloatBuffer(),Triangles.get(i));
}
}
private void drawTriangle(final FloatBuffer aTriangleBuffer, Triangle tri)
{
aTriangleBuffer.position(0);
GLES20.glVertexAttribPointer(mPositionHandle, tri.DataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mPositionHandle);
aTriangleBuffer.position(3);
GLES20.glVertexAttribPointer(mColorHandle, tri.ColorDataSize, GLES20.GL_FLOAT, false, mStrideBytes, aTriangleBuffer);
GLES20.glEnableVertexAttribArray(mColorHandle);
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, tri.getModelMatrix(), 0);
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
But when I try to move a triangle (to the left or right) in landscape mode the triangles get "cut off" (does not display the whole triangle) when moving them to far to one of the sides. It seems that they are been acted on as if they were outside the screen when they actually are not. As mentioned it seems to work fine in portrait mode.
Height is 752 and Width 1280 in landscape mode (Galaxy Tab 2).
Does this have something to do with the Project Matrix which is set here?
Thanks for any help!
You were right, the problem was you were moving you camera :D
xax should have stayed as 0.0f
Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, xax, lookY, lookZ, upX, upY, upZ);

Android OpenGL ES 2.0 screen coordinates to world coordinates

I'm building an Android application that uses OpenGL ES 2.0 and I've run into a wall. I'm trying to convert screen coordinates (where the user touches) to world coordinates. I've tried reading and playing around with GLU.gluUnProject but I'm either doing it wrong or just don't understand it.
This is my attempt....
public void getWorldFromScreen(float x, float y) {
int viewport[] = { 0, 0, width , height};
float startY = ((float) (height) - y);
float[] near = { 0.0f, 0.0f, 0.0f, 0.0f };
float[] far = { 0.0f, 0.0f, 0.0f, 0.0f };
float[] mv = new float[16];
Matrix.multiplyMM(mv, 0, mViewMatrix, 0, mModelMatrix, 0);
GLU.gluUnProject(x, startY, 0, mv, 0, mProjectionMatrix, 0, viewport, 0, near, 0);
GLU.gluUnProject(x, startY, 1, mv, 0, mProjectionMatrix, 0, viewport, 0, far, 0);
float nearX = near[0] / near[3];
float nearY = near[1] / near[3];
float nearZ = near[2] / near[3];
float farX = far[0] / far[3];
float farY = far[1] / far[3];
float farZ = far[2] / far[3];
}
The numbers I am getting don't seem right, is this the right way to utilize this method? Does it work for OpenGL ES 2.0? Should I make the Model Matrix an identity matrix before these calculations (Matrix.setIdentityM(mModelMatix, 0))?
As a follow up, if this is correct, how do I pick the output Z? Basically, I always know at what distance I want the world coordinates to be at, but the Z parameter in GLU.gluUnProject appears to be some kind of interpolation between the near and far plane. Is it just a linear interpolation?
Thanks in advance
/**
* Calculates the transform from screen coordinate
* system to world coordinate system coordinates
* for a specific point, given a camera position.
*
* #param touch Vec2 point of screen touch, the
actual position on physical screen (ej: 160, 240)
* #param cam camera object with x,y,z of the
camera and screenWidth and screenHeight of
the device.
* #return position in WCS.
*/
public Vec2 GetWorldCoords( Vec2 touch, Camera cam)
{
// Initialize auxiliary variables.
Vec2 worldPos = new Vec2();
// SCREEN height & width (ej: 320 x 480)
float screenW = cam.GetScreenWidth();
float screenH = cam.GetScreenHeight();
// Auxiliary matrix and vectors
// to deal with ogl.
float[] invertedMatrix, transformMatrix,
normalizedInPoint, outPoint;
invertedMatrix = new float[16];
transformMatrix = new float[16];
normalizedInPoint = new float[4];
outPoint = new float[4];
// Invert y coordinate, as android uses
// top-left, and ogl bottom-left.
int oglTouchY = (int) (screenH - touch.Y());
/* Transform the screen point to clip
space in ogl (-1,1) */
normalizedInPoint[0] =
(float) ((touch.X()) * 2.0f / screenW - 1.0);
normalizedInPoint[1] =
(float) ((oglTouchY) * 2.0f / screenH - 1.0);
normalizedInPoint[2] = - 1.0f;
normalizedInPoint[3] = 1.0f;
/* Obtain the transform matrix and
then the inverse. */
Print("Proj", getCurrentProjection(gl));
Print("Model", getCurrentModelView(gl));
Matrix.multiplyMM(
transformMatrix, 0,
getCurrentProjection(gl), 0,
getCurrentModelView(gl), 0);
Matrix.invertM(invertedMatrix, 0,
transformMatrix, 0);
/* Apply the inverse to the point
in clip space */
Matrix.multiplyMV(
outPoint, 0,
invertedMatrix, 0,
normalizedInPoint, 0);
if (outPoint[3] == 0.0)
{
// Avoid /0 error.
Log.e("World coords", "ERROR!");
return worldPos;
}
// Divide by the 3rd component to find
// out the real position.
worldPos.Set(
outPoint[0] / outPoint[3],
outPoint[1] / outPoint[3]);
return worldPos;
}
Algorithm is further explained here.
Hopefully my question (and answer) should help you out:
How to find absolute position of click while zoomed in
It has not only the code but also diagrams and diagrams and diagrams explaining it :) Took me ages to figure it out as well.
IMHO one doesn't need to re-implement this function...
I experimented with Erol's solution and it worked, so thanks a lot for it Erol.
Furthermore, I played with
Matrix.orthoM(mtrxProjection, 0, left, right, bottom, top, near, far);
and it works fine as well in my tiny noob example 2D OpenGL ES 2.0 project:
public void onSurfaceChanged(GL10 unused, int width, int height) {...

Categories

Resources