I have created 2 sphere's, and I am currently trying to texture them. However the texture coordinates seem to be a bit off.
The Texture (Just supposed to be a window or some kind of break):
The result of the texture being applied to both spheres (You can ignore the black lines not around the square, that's just the camera - yes it's an AR app):
Now I exported the Sphere using a perl script I found that converts obj files to a list of vertices and texture coords OBJ2OPENGL. And the obj file has been converted with 2160 Vertices.
When I render the sphere:
GLES20.glVertexAttribPointer(vertexHandle, 3, GLES20.GL_FLOAT,
false, 0, ufo_sphere.getVertices());
GLES20.glVertexAttribPointer(normalHandle, 3, GLES20.GL_FLOAT,
false, 0, ufo_sphere.getNormals());
GLES20.glVertexAttribPointer(textureCoordHandle, 3,
GLES20.GL_FLOAT, false, 0, ufo_sphere.getTexCoords());
GLES20.glEnableVertexAttribArray(vertexHandle);
GLES20.glEnableVertexAttribArray(normalHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
// activate texture 0, bind it, and pass to shader
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,
mTextures.get(textureIndex).mTextureID[0]);
GLES20.glUniform1i(texSampler2DHandle, 0);
// pass the model view matrix to the shader
GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false,
modelViewProjection, 0);
//GLES20.glDrawElements(GLES20.GL_TRIANGLES, sphere.getNumObjectVertex(), GLES20.GL_UNSIGNED_SHORT, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, sphere.getNumObjectVertex()); // I have tried TRIANGLES and TRIANGLE_FAN as well
// disable the enabled arrays
GLES20.glDisableVertexAttribArray(vertexHandle);
GLES20.glDisableVertexAttribArray(normalHandle);
GLES20.glDisableVertexAttribArray(textureCoordHandle);
I can see at least one thing which seems to be wrong...
GLES20.glVertexAttribPointer(textureCoordHandle, 3,
GLES20.GL_FLOAT, false, 0, ufo_sphere.getTexCoords());
Texture coordinates typically have a size of 2 (u, v). So you could try this instead:
GLES20.glVertexAttribPointer(textureCoordHandle, 2,
GLES20.GL_FLOAT, false, 0, ufo_sphere.getTexCoords());
Also, in the link you provided they use the GL_TRIANGLES format instead of GL_TRIANGLE_STRIP so you should switch back to that.
Related
I have a performance problem in my opengl 2.0 game. Framerate was good until I made a change in the game. Its some sort of outbreak game with 64 shapes (bricks). What I now want is when the ball hits a brick its not immediately removed - it changes status and that includes changing the texture or more correctly - the uv-coord of the atlas. I have a textureatlas and what I do is just to call GLES20.bindBuffer() for every texture in the loop, instead of calling the outside the loop. Earlier I had the same uv-coord for all shapes but now I change it depending on the bricks status and thats why I need to use binding inside the loop
private void drawShape() {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboDataListLevelSprites.get(iName).getBuff_id_vertices());
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, 0);
//used this snipped before when using the same image (uv-coords) for all bricks
/*GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboDataListLevelSprites.get(iName).getBuff_id_uvs());
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0);
*/
for (Iterator<BrickProperties> it = arrayListBricks.iterator(); it.hasNext(); ) {
BrickProperties bp = it.next();
//now bindbuffer inside loop just too switch uv-coords of the atlas when its time to use another image
int buffIndexVal = bp.get_status_diff();
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, BrickProperties.get_buff_id_uvs()[buffIndexVal]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, bp.getTranslateData()[0], bp.getTranslateData()[1], bp.getTranslateData()[2]);
if (bp.get_status() == 0) {
it.remove();
}
render();
}
}
private void render() {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
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);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}
I understand the reason to the performance drop is all the bindbuffer calls to the GPU but how could I possibly get around this problem?
It is one thing that you are binding a buffer for every object but then there is another thing you are using 2 buffers to draw a single object. You also have redundant call to unbind the buffer at the start of your render method, simply remove that.
In most cases (may be all cases) you want interleaved vertex data for increased performance. So use
{
position,
textureCoordinates
}
in a single buffer.
I see in your case you have 2 states of the same object where the second one will change vertex coordinates but not position coordinates. It might make sense to share the position data between the two if the buffer is relatively large (which I assume is not). Anyway for such sharing I would suggest you rather use your buffer structure as
{
position,
textureCoordinates,
secondaryTextureCoordinates
}
then use a separate buffer or even to put the secondary texture coordinates to another part of the same buffer.
So if the vertex buffers are relatively small then I suggest you to use "atlas" procedure. For your case that would mean creating twice the size of the buffer and put all the coordinates (having position duplicated) and put this vertex data so that there is one part after another.
I assume you can easily do that for your current drawing and effectively reduce the number of bound buffers to 0 per draw call (you only ned to bind it at some initialization). Now you will have the second part where you will set the attribute pointers for each of the drawn element just so that you may control which texture coordinates are used. This will again present redundant calls which may be avoided in your case:
Since the data structure is consistent in your buffer there is really no reason to set the pointers more the once. Simply set them once to the beginning when buffer is bound and then use the offset in draw call to control what part of the buffer is actually used GLES20.glDrawArrays(GLES20.GL_TRIANGLES, offset, 6).
If done properly your draw method should looks something like:
for (Iterator<BrickProperties> it = arrayListBricks.iterator(); it.hasNext(); ) {
BrickProperties bp = it.next();
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, bp.getTranslateData()[0], bp.getTranslateData()[1], bp.getTranslateData()[2]);
if (bp.get_status() == 0) {
it.remove();
}
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);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, bp.vertexOffset, 6);
}
This removes all the bindings and preserves only matrix operations and draw calls. If there are other drawings in the pipeline you need the buffer binding before the loop otherwise you may put it as a part of the initialization. In both cases the calls should be reduced significantly.
To add a note here it is a common practice to have another object that tracks the openGL states to avoid redundant calls. Instead of calling GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferID.. you would rather call something like contextObject.bindVertexBuffer(bufferID) which would check if the bufferID is the same as in previous call. And if it is then no actual binding would be done. If you create and use such system then it makes little difference on where you call the buffer binding and rest of the object setup since redundant calls will have no effect. Still this procedure alone will not make your situation optimal so you still need both.
You could bind buffer and draw all the objects with the same UV-s at once. Instead of iterating through each brick, iterate through all objects that use the same UV-s.
Also, try batching the objects so that you draw them all at once. Using Index Buffer Objects may help in this.
I am trying to do some video things on android with OpenglES,MediaCodec,SurfaceTexture,and a bunch of other things. First I decode frames from video as GL_TEXTURE_EXTERNAL_OES texture. Then I render this to framebuffer. Here is the code:
checkGlError("before renderTexture");
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, mCameraFbo.frameId());
checkGlError("renderTexture 1");
GLES20.glViewport(0, 0, mInputImageWidth, mInputImageHeight);
checkGlError("renderTexture 2");
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
checkGlError("renderTexture 3");
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
checkGlError("renderTexture 4");
GLES20.glUseProgram(mProgram);
if (texid != OpenGlUtils.NO_TEXTURE) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, texid);
GLES20.glUniform1i(GLES20.glGetUniformLocation(mProgram, "inputImageTexture"), 1);
}
mTriangleVertices.position(0);
GLES20.glEnableVertexAttribArray(maPositionHandle);
GLES20.glVertexAttribPointer(maPositionHandle, 2, GLES20.GL_FLOAT, false, 0, mTriangleVertices);
mGLTextureBuffer.position(0);
GLES20.glEnableVertexAttribArray(maTextureHandle);
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, 0, mGLTextureBuffer);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(maPositionHandle);
GLES20.glDisableVertexAttribArray(maTextureHandle);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glUseProgram(0);
It Crashes in My Nexus 5X and Nexus 6P, at this line "GLES20.glClear", with glError 1286. But It's just fine on other older devices,such as Nexus 5 and Xiaomi Note.
I've checked framebuffer state with "glCheckFramebufferStatus",I'm pretty sure it is fine.
Device info:
Nexus 5X, Android7.1.1
GPU info:
vendor : Qualcomm
renderer: Adreno (TM) 418
version : OpenGL ES 3.2 V#145.0 (GIT#If5818605d9)
Anybody have idea about this? Thanks in advance.
Figure out why...I create framebuffer with an EGL Context, use it with another,
I'm facing a big problem. I'm using a Transformer tf101 tab with Android 4.0.3 on it.
My app is using a custom OpenGL ES 2.0 surface. I'm rendering multiple planes with textures. this textures are changing approx. 20 times per second and are updated by passing byte arrays. However, in certain cases, the screen begins flickering and does not render the new textures. Additional UI Elements are still responsive and do their work as intended. It seems the OpenGL context ignores all commands and is unresponsive.
When this happens, a few lines show up in my logCat:
08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit: NvError_IoctlFailed with error code 1
followed by
08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit failed (err = 13, SyncPointValue = 879005, returning = 0)
and a few of them:
08-20 10:31:15.390: D/NvOsDebugPrintf(2898): NvRmChannelSubmit failed (err = 196623, SyncPointValue = 0)
Here is how i create my Textured Plane:
m_nTextureStorage[0] = 0;
GLES20.glGenTextures( 1, m_nTextureStorage, 0);
GLES20.glActiveTexture( GLES20.GL_TEXTURE0 );
GLES20.glBindTexture( GLES20.GL_TEXTURE_2D, m_nTextureStorage[ 0 ] );
// Set filtering
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST );
GLES20.glTexParameterf( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST );
GLES20.glTexParameteri( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
GLES20.glTexParameteri( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
and here is how i draw it:
GLES20.glEnable(GLES20.GL_TEXTURE_2D);
GLES20.glEnable(GLES20.GL_DEPTH_TEST);
GLES20.glActiveTexture( GLES20.GL_TEXTURE0 );
//GLES20.glUniformMatrix4fv(m_HMVPMatrixUniform, 1, false, mvpMatrix, 0);
GLES20.glUseProgram( m_nProgramHandle );
ByteBuffer oDataBuf = ByteBuffer.wrap( m_sTexture );
m_HTextureUniform = GLES20.glGetUniformLocation( m_nProgramHandle, "uTexture" );
m_HTextureCoordinate = GLES20.glGetAttribLocation( m_nProgramHandle, "TexCoordinate" );
GLES20.glUniform1iv( m_HTextureUniform, 2, m_nTextureStorage, 0 );
// get handle to the vertex shader's vPosition member
m_nPositionHandle = GLES20.glGetAttribLocation( m_nProgramHandle, "vPosition" );
// Prepare the triangle data
GLES20.glTexImage2D( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_LUMINANCE, 640, 480,
0, GLES20.GL_LUMINANCE, GLES20.GL_UNSIGNED_BYTE, oDataBuf );
// Prepare the triangle data
GLES20.glVertexAttribPointer( m_nPositionHandle, 3, GLES20.GL_FLOAT, false, 12, m_oVertexBuffer );
GLES20.glEnableVertexAttribArray( m_nPositionHandle );
GLES20.glVertexAttribPointer( m_HTextureCoordinate, 2, GLES20.GL_FLOAT, false, 12, m_oTextureBuffer);
GLES20.glEnableVertexAttribArray( m_HTextureCoordinate );
m_nMVPMatrixHandle = GLES20.glGetUniformLocation( m_nProgramHandle, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv( m_nMVPMatrixHandle, 1, false, mvpMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
The OpenGL Renderer simply calls the draw function of my TexturedPlane by passing the mvpMatrix. Im not deleting any textures since i've read that the android system will take care of that automatically.
I think it has something todo with the GPU going OOM, but im not sure since i haven't found anything related to the posted error messages.
Thanks it advance!
UPDATE:
The Rendermode was set to RENDER_WHEN_DIRTY . After Changing it to RENDERMODE_CONTINOUSLY the problem disappears.. Weird. Since this is just a workaround and no solution, I'm still asking for help ;)
Leaving the Rendermode at continuously is no option, since this consumes to much processor time and makes no sense, since rendering is only necessary when new textures a generated.
Finally found the solution.
When i call glFlush() after every rendering circle, it works fine. I no render every plane on a different texture channel, it works perfectly so far. Thanks for the help.
When you call ..:
GLES20.glUniform1iv( m_HTextureUniform, 2, m_nTextureStorage, 0 );
I think that binds a particular texture unit to the sampler uniform. But you're passing a texture name/object/handle/whatever (which is not a texture unit.) Maybe it's just coincidence, and you only ever pass in 0 (which is possibly the texture name in m_nTextureStorage,) which is coincidentally the correct/desired value?
Or maybe this results in the user-space driver crashing.
I have implemented the Bullet Physics engine into my android program with the NDK (I am using Vuforia's imagetarget example for android), and it is set up and working correctly, however I would like to render/draw my collision boxes/planes to see my rigid bodies (btRigidBody)/collision shapes (btCollisionShape), I'm positive this is possible but I can't find any tutorials on how to do it!
I have taken the hello world Bullet physics tutorial on their wiki page and modified it to apply the transformations from the falling physics body to a 3d object I have in opengl es 2.0 to view the collision bodies, here is the code I am using to render to object:
void drawRigidBody(btRigidBody* body,QCAR::Matrix44F modelViewMatrix, unsigned int textureID)
{
btTransform trans;
body->getMotionState()->getWorldTransform(trans);
LOG("sphere pos: (x %f , y %f, z %f)",trans.getOrigin().getX(),trans.getOrigin().getY(),trans.getOrigin().getZ());
float physicsMatrix[16];
trans.getOpenGLMatrix(physicsMatrix);
SampleUtils::scalePoseMatrix(kObjectScale, kObjectScale, kObjectScale,
&modelViewMatrix.data[0]);
QCAR::Matrix44F modelViewProjection, objectMatrix;
SampleUtils::multiplyMatrix(&modelViewMatrix.data[0], physicsMatrix, &objectMatrix.data[0]);
SampleUtils::multiplyMatrix(&projectionMatrix.data[0], &objectMatrix.data[0], &modelViewProjection.data[0]);
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signVerts[0]);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signNormals[0]);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*) &signTexCoords[0]);
glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE,
(GLfloat*)&modelViewProjection.data[0] );
glDrawArrays(GL_TRIANGLES, 0, signNumVerts);
}
EDIT: looking at the code for btBoxShape i noticed you can grab the box vertices and normals:
btVector3** vertices= wallShape->getVertices();
btVector3**normals = wallShape->getNormals();
but you can't grab a list of indices to draw the vertex points in a certain order!
If I recall correctly, this is not the proper way to draw debug shapes in Bullet. Did you read the user manual (PDF), page 16?
You are supposed to implement your own debug drawer class which implements btIDebugDraw, and in this class you implement the drawLine method.
You pass this debug drawer to bullet with setDebugDrawer, and then enable it with world->getDebugDrawer->setDebugMode(debugMode);
To draw the world, call world->debugDrawWorld();
This then calls drawLine on your custom function numerous times until a wireframe model of the physics world has been drawn.
I get the yuv data from camera , and send them to opengl, then I use fragment shader to convert the data to RGBA format and show it on the screen. Everything goes well but when I use glReadPixels to get the RGBA data from framebuffer to int array, I get wrong data.
// I use VBO to draw
glBindBuffer(GL_ARRAY_BUFFER, squareVerticesBufferID);
glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(gvPositionHandle);
glBindBuffer(GL_ARRAY_BUFFER, textureVerticesBuferID);
glVertexAttribPointer(gvTextureHandle, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(gvTextureHandle);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, squareVerticesIndexBufferID);
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, 0);
// Then I use glReadPixels to read the RGBA data
unsigned char *returnDataPointer = (unsigned char*) malloc(width * height * 4);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, returnDataPointer);
Unfortunately I get wrong data, the last thousands elements in the array are 0s,the same code works well on ios, did I miss something?
I work on Android 4.0.3 and use OpenGL ES 2 from the NDK.