How to efficiently draw 2d with openGl es? - android

Originally I was using the canvas to draw my bitmaps in a 2d real time action type game, but for some reason my frame rate was terrible. I suspected it was the canvas so I switched to opengl. From surfing on the internet I learned to create a rectangle from 2 triangles and set a texture on it. I used glOrthof to set it up the 2d perspective and used the gltranslatef method to move my textures. I know the problem isn't the physics or anything because I tested moving a single texture at a constant velocity, (The x value moving at about 7 units per 33 milliseconds). It was still choppy. I set the fps to 30. This is my game loop:
public void onDrawFrame(GL10 gl) {
startTime = System.nanoTime();
gl.glClearColor(0f, .0f, .8f, 0.5f);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
g.updatePhysics();
onDraw(gl);
sleepTime = (int) (TICKS_INTERVAL - (System.nanoTime() - startTime)/1000000);
if(sleepTime > 0){
try{
Thread.sleep(sleepTime);
}catch(Exception e){}
}
}
and this is how they're being drawn:
public void onDraw(GL10 gl){
gl.glLoadIdentity();
if(g.state == g.STATE_GAME){
gl.glTranslatef(x, y, z);
rectangle.draw(gl);
gl.glLoadIdentity();
gl.glTranslatef(x, y, z);
rectangle2.draw()gl;
}
}
And this is the draw method within the rectangle:
public void draw(GL10 gl){
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertBuff);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuff);
gl.glDrawElements(GL10.GL_TRIANGLES, pIndex.length, GL10.GL_UNSIGNED_SHORT, pBuff);// Draw the vertices as triangle strip
//gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
Even when I set the frame rate to 60 there's still some stuttering, and it's frustrating because for the past month I've been just trying to get the frame rate smooth. I'm testing on a galaxy s2 so I know it isn't the hardware. If all this code is right, do you think maybe it could be something else in the activity? My GLSurfaceView is actually a custom view. Even getting a single texture to move smoothly at a constant velocity would be nice.

Related

Drawing 2D on a GLSurfaceView

I am attempting to draw a 2D square on a GLSurfaceView in 2D mode. I can draw the object in 3D mode and have tested that the square is out in 3D space. I then try to configure the matrix for 2d drawing and when I attempt to draw my object nothing appears.
My GLSurfaceView instance implements GLSurfaceView.Renderer.
I've broken the setup into two functions:
private void prepare3Ddrawing(GL10 gl)
{
gl.glLoadIdentity();
gl.glViewport(0, 0, getWidth(), getHeight());
gl.glDisable(GL10.GL_DITHER);
gl.glEnable(GL10.GL_DEPTH_TEST);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluPerspective(gl, 45.0f, (float)getWidth()/(float)getHeight(),0.1f,100.0f);
}
private void prepare2Ddrawing(GL10 gl)
{
gl.glDisable(GL10.GL_CULL_FACE);
gl.glDisable(GL10.GL_DEPTH_TEST);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl,0,getWidth(), 0, getHeight());
gl.glScalef(1, -1, 1);
gl.glTranslatef(0, -getHeight(), 0);
gl.glMatrixMode(GL10.GL_MODELVIEW);
}
And here is my draw method...
public void onDrawFrame(GL10 gl)
{
gl.glClear(GL10.GL_DEPTH_BUFFER_BIT|GL10.GL_COLOR_BUFFER_BIT);
prepare3Ddrawing(gl);
camera.draw(gl);
go2d.draw(gl);
prepare2Ddrawing(gl);
go2d.draw(gl);
}
and finally, my go2d object is an instance of an object I created called GameObject2d. It's draw method looks like this...
#Override
public void draw(GL10 gl)
{
super.draw(gl);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glEnable(GL10.GL_ALPHA_TEST);
gl.glAlphaFunc(GL10.GL_GREATER, 0.0f);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL10.GL_BLEND);
gl.glFrontFace(GL10.GL_CW);
//gl.glEnable(GL10.GL_CULL_FACE);
gl.glCullFace(GL10.GL_BACK);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, indexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL10.GL_CULL_FACE);
gl.glDisable(GL10.GL_ALPHA_TEST);
gl.glDisable(GL10.GL_TEXTURE_2D);
}
Does anyone have any ideas? Again, I am still able to see the 3D rendered version of the go2D object, but I do not see the 2D version.
Thanks.
As you don't include any data, I can only propose two methods to debug the issue.
Step 1: try to force your 2d - perspective matrix and modelview matrix to be Identity Matrices. Then if you force your Square data vertices inside the clip space (e.g.
x,y = +-1 or x,y= +-0.75, z=0, you should see a square appearing in the screen.
Step 2: now that the data model is correct, check what your model view and perspective matrices do: multiply each of your square vertices (x,y,z, w=1) with ModelView Matrix * CameraMatrix * PerspectiveMatrix. What do you get? Are the x,y,z much outside |w| ?

How to set on texture on top of another texture in android using OPEN GL

I have been searching for this for the pass two days .I am developing an android game using Open GL in which there is a situation where i have to display two images at the same time, one should be the background image and second one is displayed depending on a condition.
I have displayed the background imgae using Open GL Texture property.But when i tried to display the second image by using texture first one is not displaying.Since i am dealing with multiple texture i have used a GLTexture class to manipulate the texture (http://tkcodesharing.blogspot.in/2008/05/working-with-textures-in-androids.html).Even then i am not able to display two images at the same time.
Here is some code :
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
glTextures= new GLTextures(gl,this.context);//class to manipulate textures
//adding image resources
this.glTextures.add(R.drawable.back);
this.glTextures.add(R.drawable.hand);
//loading texture
this.glTextures.loadTextures();
gl.glEnable(GL10.GL_TEXTURE_2D);
...
}
In onDrawFrame
gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -3.5f);
glTextures.setTexture(R.drawable.back);//it will bind this particular texture for drawing
draw(gl);
if(condition == 1){
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 1.0f, -7.0f);
glTextures.setTexture(R.drawable.hand);
drawSecond(gl);
}
////////////////////////////////////////////////////////
In draw code
public void draw(GL10 gl){
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
public void drawSecond(GL10 gl){
gl.glActiveTexture(GL10.GL_TEXTURE1);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
//GLES20.glUniform1i(isShaked, 1);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, vertices.length/3);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
}
remove "gl.glActiveTexture(GL10.GL_TEXTURE0);" and gl.glActiveTexture(GL10.GL_TEXTURE1);
lines from the rendering code.
you use multiple texture units only if you need multi-texturing,
which is using multiple textures in one draw call.
just bind the first texture to the active texture unit (default to GL_TEXTURE0) and draw the first triangle strip, than bind the second texture (without changing the active texture unit GL_TEXTURE0) and draw the second triangle strip.

Low FPS with OpenGL on Android

I contact because, I try to use openGL with android, in order to make a 2D game :)
Here is my way of working:
I have a class GlRender
public class GlRenderer implements Renderer
In this class, on onDrawFrame I do
GameRender() and GameDisplay()
And on gameDisplay() I have:
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Reset the Modelview Matrix
gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Modelview Matrix
gl.glLoadIdentity(); //Reset The Modelview Matrix
// Point to our buffers
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// Set the face rotation
gl.glFrontFace(GL10.GL_CW);
for(Sprites...)
{
sprite.draw(gl, att.getX(), att.getY());
}
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
And in the draw method of sprite I have:
_vertices[0] = x;
_vertices[1] = y;
_vertices[3] = x;
_vertices[4] = y + height;
_vertices[6] = x + width;
_vertices[7] = y;
_vertices[9] = x + width;
_vertices[10] = y + height;
if(vertexBuffer != null)
{
vertexBuffer.clear();
}
// fill the vertexBuffer with the vertices
vertexBuffer.put(_vertices);
// set the cursor position to the beginning of the buffer
vertexBuffer.position(0);
// bind the previously generated texture
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
// Point to our vertex buffer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer.mByteBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer.mByteBuffer);
// Draw the vertices as triangle strip
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, _vertices.length / 3);
My problem is that I have a low frame rate, even at 30 FPS I loose some frame sometimes with only 1 sprite (but it is the same with 50)
Am I doing something wrong? How can I improve FPS?
In general, you should not be changing your vertex buffer for every sprite drawn. And by "in general", I pretty much mean "never," unless you're making a particle system. And even then, you would use proper streaming techniques, not write a quad at a time.
For each sprite, you have a pre-built quad. To render it, you use shader uniforms to transform the sprite from a neutral position to the actual position you want to see it on screen.

OpenGL ES 1.1 strange lighting problems

I am examining an interesting problem I'm facing with OpenGL lighting on Android. I'm working on a 3D Viewer where you can add and manipulate 3D objects. You can also set a light with different attributes. The problem I was facing with my Viewer was that the highlight on the 3D objects from the light (it is a point light) behaved strangely. If the light source was in the exact same point as the camera, the highlight would move in the opposite direction you would expect. (So if you move the object to the left, the highlight moves to the leftedge of the object as well, instead of the right, which is what I was expecting.)
So to further narrow the problem down I've created a small sample application that only renders a square and then I rotate that square around the camera position (the origin), which is also where the light is placed. This should result in all squares facing the camera directly, so that they would be completely highlighted. The result though looked like that:
Can it be that these artifacts appear because of the distortion you get on the border due to the projection?
In the first image the distance between the sphere and the camera is about 20 units and the size of the sphere is about 2. If I move the light closer to the object the highlight looks a lot better, in the way I'm expecting it.
In the second image the radius in which the squares are located is 25 units.
I'm using OpenGL ES 1.1 (since I was struggling to get it to work with shaders in ES 2.0) on Android 3.1
Here is some of the code I'm using:
public void onDrawFrame(GL10 gl) {
// Setting the camera
GLU.gluLookAt(gl, 0, 0, 0, 0f, 0f, -1f, 0f, 1.0f, 0.0f);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
for (int i = 0; i < 72; i++) {
gl.glPushMatrix();
gl.glRotatef(5f * i, 0, 1, 0);
gl.glTranslatef(0, 0, -25);
draw(gl);
gl.glPopMatrix();
}
}
public void draw(GL10 gl) {
setMaterial(gl);
gl.glEnable(GL10.GL_NORMALIZE);
gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glFrontFace(GL10.GL_CCW);
// Enable the vertex and normal state
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
gl.glNormalPointer(GL10.GL_FLOAT, 0, mNormalBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, mIndexBuffer.capacity(), GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
}
// Setting the light
private void drawLights(GL10 gl) {
// Point Light
float[] position = { 0, 0, 0, 1 };
float[] diffuse = { .6f, .6f, .6f, 1f };
float[] specular = { 1, 1, 1, 1 };
float[] ambient = { .2f, .2f, .2f, 1 };
gl.glEnable(GL10.GL_LIGHTING);
gl.glEnable(GL10.GL_LIGHT0);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glLightfv(GL10.GL_LIGHT0, GL_POSITION, position, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_DIFFUSE, diffuse, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_AMBIENT, ambient, 0);
gl.glLightfv(GL10.GL_LIGHT0, GL_SPECULAR, specular, 0);
}
private void setMaterial(GL10 gl) {
float shininess = 30;
float[] ambient = { 0, 0, .3f, 1 };
float[] diffuse = { 0, 0, .7f, 1 };
float[] specular = { 1, 1, 1, 1 };
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse, 0);
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient, 0);
gl.glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular, 0);
gl.glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
}
I'm setting the light in the beginning, when the activity is started (in onSurfaceCreated) and the material everytime I draw a square.
The effect in your second example (with the squares) is rather due to the default non-local viewer that OpenGL uses. By default the eye-space view vector (the vector from vertex to camera, used for the specular highlight computation) is just taken to be the (0, 0, 1)-vector, instead of the normalized vertex position. This approximation is only correct if the vertex is in the middle of the screen, but gets more and more incorrect the farther you move to the boundary of the srceen.
To change this and let OpenGL use the real vector from the vertex to the camera, just use the glLightModel function, especially
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
I'm not sure if this is also the cause for your first problem (with the sphere), but maybe, just try it.
EDIT: It seems you cannot use GL_LIGHT_MODEL_LOCAL_VIEWER in OpenGL ES. In this case there is no way around this problem, except switching to OpenGL ES 2.0 and doing all lighting computations yourself, of course.
Your light is probably moving when you're moving your object.
Take a look at this answer http://www.opengl.org/resources/faq/technical/lights.htm#ligh0050

How to flip an Image in OpenGL?

I hate to ask such a dumb question but I just can't firgure out how to flip an image using Android OpenGL.
I try using gl.glScalef(-1,y,z) android gl.glRotatef(180,0,1,0) but when I do this the image flip but it also change the positions which I do not want. I'm sure there a easy way to do this I'm just not getting.
Here is my draw code:
public void draw(GL10 gl){
gl.glLoadIdentity();
gl.glTranslatef(position.x, position.y, 0);
gl.glRotatef(angle, rotX, rotY, rotZ);
gl.glScalef(scaleX, scaleY, scaleZ);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textureId[0]);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glEnable(GL10.GL_BLEND);
gl.glVertexPointer(2, GL10.GL_FLOAT, 0, vertexsBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL10.GL_BLEND);
if(animation == true){
PlayAnimations();
}
}
center the object (remember the translation)
perform the flipping by scaling to -1 with respect to the desired axis.
then "reverse translate" the object.
For more information, please grab yourself a copy of Computer Graphics by James D. Foley.
http://www.amazon.com/Computer-Graphics-Principles-Practice-2nd/dp/0201848406
You could use a different set of texture coordinates or use a texture matrix.

Categories

Resources