I'm developing a game for android and this is my first experience with OpenGL.
When the application loads I create my vertices and texture buffers, I load images from drawable resources; using GLUtils.tex2Image2D to bind the image to a texture array.
I was wondering if glBindTexture() was the correct function to use when changing the texture to produce animation.
public void onDraw(GL10 gl){
sprite.animate();
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[sprite.frameNumber]);
sprite.draw(gl);
}
Code Explanation
sprite.animate() - changes the frame number depending on System.uptimeMillis()
sprite.draw() - does the actual drawing:
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
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);
//Disable the client state before leaving
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
The function does work, but I wanted to confirm it was the correct function to use, or if there is an alternative way to do this.
Binding a different texture to animate is one way to do what you want.
A more popular way of doing this is to have all your animations frames in a big texture (pack all the individual frames in a huge rectangle): to draw a different frame, just change the texture coordinates.
For example, pack four frames of animation in a big 2x2 square
1|2
3|4
Then you'll use for texture coordinates (0,0) (0.5,0) (0.5,0.5) (0,0.5) to display frame 1, and the rest should be obvious.
Related
I am in a situation where I need to render to a texture using FBO, and I need to remove some pixels from the buffer. That is, draw (0,0,0,0) color in a RGBA colored framebuffer. This will later allow me to later render this texture on top of another one and the 'zero pixels' will not be rendered since I use blending.
The problem is that I cannot draw such color on the screen because GL_BLEND is enabled while I am doing that and the zero pixels aren't rendered to the texture.
So I have tried disabling GL_BLEND just before rendering to the texture, and 1. It continued blending like nothing happened, 2.At some point it renders of all the graphics without blending although it clearly receives the glEnable(GL_BLEND) call.
Here is most of the code:
gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
gl.glDisable(GL11.GL_BLEND);
gl.glBindTexture(GL11.GL_TEXTURE_2D, 0);
gl.glFrontFace(GL11.GL_CW);
gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);
gl.glPushMatrix();
gl.glTranslatef(start_x+adv_x/2+adv_x*(float)col_idx, start_y+adv_y/2+adv_y*(float)j, -1.0f);
gl.glScalef(adv_x/2, adv_y/2, 1.0f);
gl.glColor4f(0,0,0,0);
gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertex.length / 3);
gl.glColor4f(1f, 1f, 1f, 1f);
gl.glPopMatrix();
gl.glEnable(GL11.GL_BLEND);
gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
This is code from an Android application, written in Java.
What can be the problem?
I have a scene in which I'd like to have some objects drawn using multi-texturing. I'd also like to draw some objects using only gl.glDrawArrays(GL10.GL_LINES...
However, whenever I add objects on-screen that have two textures applied, all objects that use GL_LINES or solid colors become faded.
I tried to put together a simple demo where all objects use the same draw method (hopefully I didn't create more confusion while trying to simplify).
I handle the multi-texturing in Model.java, with the relevant section here:
// Texture 1
gl.glClientActiveTexture(GL10.GL_TEXTURE0);
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture[0]);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_MODULATE);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexCoordBuffer1);
gl.glEnable(GL10.GL_TEXTURE_2D);
// Texture 2
gl.glClientActiveTexture(GL10.GL_TEXTURE1);
gl.glActiveTexture(GL10.GL_TEXTURE1);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexture[1]);
gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_DECAL);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexCoordBuffer2);
gl.glEnable(GL10.GL_TEXTURE_2D);
Any help would be greatly appreciated.
Note: Without the multi-textured object, outlines on triangles 1 and 4 are solid. This is how I'd like the outlines to show.
Note: With the multi-textured object (triangle 3), outlines on triangles 1 and 4 are faded.
Found a solution in this previous question that I had thought was unrelated.
I don't understand why, but I needed to call:
gl.glActiveTexture(GL10.GL_TEXTURE0);
after the Texture 2 block.
I am drawing objects in OpenGL in this order and z-order:
A background quad,
background objects = images with titles (textures)
a translucent black quad which darkens the background objects (colored quad with low alpha value),
and foreground objects = images with titles (textures, but the one in the center has a white quad behind it)
Currently, it looks like this:
This is not as it's supposed to be - the 5 objects around "Chikinki" (Timid Tiger, The Bishops,...) should be as bright as the "Chikinki" picture. Also, all titles (including Chikinki's) are darker than the textures really are. It seems to me as though the white quad behind the "Chikinki" image somehow forces OpenGL to draw the pic in front of it rightly. Without the translucent black quad (which is there to darken all objects except the one in the middle and 5 around it), everything is fine. So I suspect that this translucent quad somehow bleeds through, although the other objects are drawn after it and have a higher z-value.
As mentioned, the objects are drawn back-to-front, and also laid out back-to-front z-wise. Blending is always enabled. The white rectangle has blending function: gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA); and all images have function gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);. Depth-test is enabled.
Relevant texture-fill quad drawing code (too dim in the screenshot):
gl.glPushMatrix();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureName);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_REPEAT);
gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_REPEAT);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTexBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
mFVertexBuffer.position(0);
mTexBuffer.position(0);
mIndexBuffer.position(0);
gl.glDisable(GL10.GL_TEXTURE_2D);
gl.glDisable(GL10.GL_BLEND);
gl.glPopMatrix();
Relevant color-fill quad drawing code (shown OK in the screenshot):
gl.glPushMatrix();
gl.glEnable(GL10.GL_BLEND);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glColor4f(mRed, mGreen, mBlue, mAlpha);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 4);
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
gl.glPopMatrix();
gl.glDisable(GL10.GL_BLEND);
Have you got any clue what could be causing the darkening of these objects which should by all means be fully opaque, considering that they are drawn AFTER the translucent quad and have a HIGHER z-value?
SOLUTION
Tim pointed out in the comments that texture drawing is affected by the current color buffer (its alpha value). Calling gl.glColor4f(1,1,1,1); before drawing the images did the trick, reverting the earlier call to gl.glColor4f() with a lower-than-1 alpha value.
In my application I'm trying to create a mesh that is shaded by a single directional light. The problem I'm facing is that I can't seem to get the light to take my normals into account at all.
It works fine if I set the normals on a per-triangle-strip basis, but if I try to render a series of triangles with normals set using the glNormalPointer method the entire mesh is rendered using the same color (which is identical to the result I'm getting if I skip calling glNormalPointer all together).
My mesh render method looks like this:
public void render(GL10 gl) {
gl.glFrontFace(GL10.GL_CW);
gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indexBuffer.capacity(), GL10.GL_UNSIGNED_BYTE, indexBuffer);
}
You should call
glEnableClientState(GL_NORMAL_ARRAY);
I am writing a small app that at the moment generates a random map of textures.
I am drawing this map as a 10 x 15 group of "quads" which are infact all triangle strips. I use the "map" to grab an int which I then take as the location of the texture for this square in the textureAtlas. so for example 0 is the bottom left "tile". The atlas is 128 x 128 and split into 32 pixel tiles.
However I seem to be getting some odd artifacts where the texture from the one tile is creeping in to the next tile. I wondered if it was the image itself but as far as I can tell the pixels are exactly where they should be. I then looked at the texture coords I was specifying but they all look exact (0.0, 0.25, 0.5, 0.75, 1.0 - splitting it into the 4 rows and columns I would expect).
The odd thing is if I run it on the emulator I do not get any artifacts.
Is there a setting I am missing which would cause bleeding of 1 pixel? It seemed to only be vertical too - this could be related to on the phone I am "stretching" the image in that direction as the phone's screen is larger than normal in that direction.
I load the texture like so:
//Get a new ID
int id = newTextureID(gl);
//We will need to flip the texture vertically
Matrix flip = new Matrix();
flip.postScale(1f, -1f);
//Load up and flip the texture
Bitmap temp = BitmapFactory.decodeResource(context.getResources(), resource);
//Store the widths for the texturemap
int width = temp.getWidth();
int height = temp.getHeight();
Bitmap bmp = Bitmap.createBitmap(temp, 0, 0, width, height, flip, true);
temp.recycle();
//Bind
gl.glBindTexture(GL10.GL_TEXTURE_2D, id);
//Set params
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR);
//Push onto the GPU
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
TextureAtlas atlas = new TextureAtlas(id, width, height, tileSize);
return atlas;
I then render it like so:
gl.glBindTexture(GL10.GL_TEXTURE_2D, currentAtlas.textureID);
//Enable the vertices buffer for writing and to be used during our rendering
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
//Specify the location and data format of an array of vertex coordinates to use
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
//Enable the texture buffer
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, indices.length, GL10.GL_UNSIGNED_SHORT, indexBuffer);
I would take a picture, but I am unsure how to get a screen cap from the phone...
If anyone knows of how I can capture the current frame and perhaps put it out into a file I will do that if it helps explain what is going on!
Look forward to your response.
Edit: Here is a screencap - note I run the app in landscape but cap is in portrait. Also excuse the horrible textures :D they were merely a place holder / messing around.
ScreenCap
Well, after speaking to a friend I managed to solve this little problem.
It turns out that if you wish to have exact pixel perfect textures you have to specify the edge of the texture to be halfway into the pixel.
To do this I simply added half a pixel or subtracted half a pixel to the measurement for the texture coords.
Like so:
//Top Left
textureCoords[textPlace] = xAdjust*currentAtlas.texSpaceWidth + currentAtlas.halfPixelAdjust; textPlace++;
textureCoords[textPlace] = (yAdjust+1)*currentAtlas.texSpaceHeight - currentAtlas.halfPixelAdjust; textPlace++;
This was simply calculated when loading the texture atlas:
(float)(0.5 * ((1.0f / numberOfTilesInAtlasRow) / pixelsPerTile));
Although if the height was different to the width of each tile (which could happen) you would need to calculate them individually.
This has solved all the artifacts so I can continue on. Hope it helps someone else!