Sorry for the non-descriptive title to this post, but I just couldn't phrase it (please suggest a better title if you think of one).
A part of my current engine calls a quad to be rendered over and over for dynamic lights... and it seemed to be working fine, but for some weird reason after a few lights are created then destroyed the game remains as slow as it would be if they were still being drawn... I'm wondering if my drawSprite function is leaving something in memory...
Here is the function with a slimmed down version of the function that calls it:
public void lightBlock(GL10 gl, int _x, int _y, float shade)
{
if (map[_x][_y].Type()==1)
{
gl.glPushMatrix();
gl.glTranslatef(_x*2,getFH(_x,_y)+.01f,_y*2);
gl.glRotatef(90,1, 0, 0);
gl.glScalef(2, 2, 0);
gl.glColor4f(shade,shade,shade, 1f);
drawSprite(gl,0);
gl.glPopMatrix();
gl.glPushMatrix();
gl.glTranslatef(_x*2,getRH(_x,_y)-.01f,_y*2);
gl.glRotatef(-90,1, 0, 0);
gl.glScalef(2, 2, 0);
gl.glColor4f(shade,shade,shade, 1f);
//Draw the vertices
drawSprite(gl,0);
gl.glPopMatrix();
}
}
public void drawSprite(GL10 gl, int tex)
{
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, tex);
//defines the vertices we want to draw
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, SvertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, StexBuffer);
//Draw the vertices
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT, SindexBuffer);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
If the lights are not in use, these functions are not called... but oddly enough once they have been called many times, the game runs as slow as it would be if they were all running at once... And it runs normally as soon as I comment out the "drawSprite()" calls...
The lights are called inside the "onDrawFrame" function.
Any help would be great...
Have you checked you aren't making too many of the objects?
I had a problem where it got progressively slower, turned out I wasn't clearing my "addToScene" list. This mean every frame I was adding annother set of all the entities in my game.
If you are doing that with sprites, you won't notice the slowdown if you comment out the thing that takes time - ie the drawing.
Related
I am very new to OpenGL, and I am trying to create a 2 pass shader. Basically, it has two frame buffers and two shader programs. It runs the first pass as usual, and then I need to take the resulting texture and pass it as an input to the second shader. How is this done? I cannot seem to see how you take a resulting texture and use it as an input to the next texture?
Here is some code: This code assumes I have setup the second filter program, and some attributes and uniforms in the program correctly
#Override
public void onDraw(final int textureId, final FloatBuffer cubeBuffer,final FloatBuffer textureBuffer){
//this draws the first pass (this is tested and working)
super.onDraw(textureId, cubeBuffer, textureBuffer);
//change the program
GLES20.glUseProgram(secondFilterProgram);
//clear the old colors
GLES20.glClearColor(0, 0, 0, 1);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glActiveTexture(GLES20.GL_TEXTURE3); //change the texture
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, secondFilterOutputTexture[0]);
GLES20.glUniform1i(secondFilterInputTextureUniform, 3);
cubeBuffer.position(0);
GLES20.glVertexAttribPointer(secondFilterPositionAttribute, 2, GLES20.GL_FLOAT, false, 0, cubeBuffer);
GLES20.glEnableVertexAttribArray(secondFilterPositionAttribute);
textureBuffer.position(0);
GLES20.glVertexAttribPointer(secondFilterTextureCoordinateAttribute, 2, GLES20.GL_FLOAT, false, 0, textureBuffer);
GLES20.glEnableVertexAttribArray(secondFilterTextureCoordinateAttribute); //same as line from init
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(secondFilterPositionAttribute);
GLES20.glDisableVertexAttribArray(secondFilterTextureCoordinateAttribute);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
}
I feel like I am missing a piece of the puzzle here. Again, I am very new to OpenGL, so any help, even conceptually is appreciated
What you want to achieve is called Render to Texture
A small tutorial how to do this with android can be found here:
http://blog.shayanjaved.com/2011/05/13/android-opengl-es-2-0-render-to-texture/
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.
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
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.
Does anyone know how to point out a given section of the texture buffer array stored in a HW buffer? I'm drawing a triangle strip and filling it with a square image. In my texture I have two square images next to each other, so the texture coordinate buffer points out them out with a total of 16 floats.
With software buffers I'm doing this to access the second image in the texture:
textureCoordinateBuffer.position(8);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureCoordinateBuffer);
With hardware buffers I assumed I do something like this:
// setup HW buffers
// ...
// select HW buffers
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER,vertexCoordinateBufferIndex);
gl11.glVertexPointer(3, GL10.GL_FLOAT, 0, 0);
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, textureCoordinateBufferIndex);
// Point out the first image in the texture coordinate buffer
gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 0);
// Draw
// ...
Which works nicely if you want to point out the first image in the texture.
But I would like to access the second image - so I assumed I do this in the last line:
// Point out the second image in the texture coordinate buffer - doesn't work!
gl11.glTexCoordPointer(2, GL11.GL_FLOAT, 0, 8);
But this renders a scewed and discolored image.
Anyone who knows how to to this correctly?
You might want to take a look at the NeHe Android Tutorials. They go into this in detail and show you what you need to do.
Specifically, the lesson you are looking for is here:
http://insanitydesign.com/wp/projects/nehe-android-ports/
Lesson 6
You might not be binding and enabling the buffers, here's a snippet from the tutorial:
public void draw(GL10 gl) {
//Bind our only previously generated texture in this case
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
//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_CCW);
//Enable the vertex and texture state
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
//Draw the vertices as triangles, based on the Index Buffer information
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_BYTE, indexBuffer);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}
Credit: Insanity Design - http://insanitydesign.com/
Edit:
I see what you're asking. Here's more code that should be able to help you then. If you look into the SpriteMethodTest app for android:
http://apps-for-android.googlecode.com/svn/trunk/SpriteMethodTest
You'll notice that Chris Pruett (The developer of this app) shows you the multitude of ways to draw textures to the screen. Below is the code (I believe) you're looking for.
Grid.java
public void beginDrawingStrips(GL10 gl, boolean useTexture) {
beginDrawing(gl, useTexture);
if (!mUseHardwareBuffers) {
gl.glVertexPointer(3, mCoordinateType, 0, mVertexBuffer);
if (useTexture) {
gl.glTexCoordPointer(2, mCoordinateType, 0, mTexCoordBuffer);
}
} else {
GL11 gl11 = (GL11)gl;
// draw using hardware buffers
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mVertBufferIndex);
gl11.glVertexPointer(3, mCoordinateType, 0, 0);
gl11.glBindBuffer(GL11.GL_ARRAY_BUFFER, mTextureCoordBufferIndex);
gl11.glTexCoordPointer(2, mCoordinateType, 0, 0);
gl11.glBindBuffer(GL11.GL_ELEMENT_ARRAY_BUFFER, mIndexBufferIndex);
}
}
// Assumes beginDrawingStrips() has been called before this.
public void drawStrip(GL10 gl, boolean useTexture, int startIndex, int indexCount) {
int count = indexCount;
if (startIndex + indexCount >= mIndexCount) {
count = mIndexCount - startIndex;
}
if (!mUseHardwareBuffers) {
gl.glDrawElements(GL10.GL_TRIANGLES, count,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer.position(startIndex));
} else {
GL11 gl11 = (GL11)gl;
gl11.glDrawElements(GL11.GL_TRIANGLES, count,
GL11.GL_UNSIGNED_SHORT, startIndex * CHAR_SIZE);
}
}
Specifically, you'll want to look at the code where it takes the false branch of !mUseHardwareBuffers. I suggest you look at the full Grid.java file for a better representation of how to do it because he also sets up the texture pointers and enables OpenGL to start drawing.
On a Side Note: I suggest reading this from Chris also:
http://www.scribd.com/doc/16917369/Writing-Real-Time-Games-for-Android
He goes into what this app does and what he found the most effective way of drawing textures was.