I have a one big Sprite on the Scene - for example 200x200 and in the app i have an array[200][200] in which i store 0 or 1 for each pixel in big sprite.
I want to draw one more textured sprite (for example 10x10) above existing one, but i want to calculate for eache pixel in new sprite if it needs to draw it on this scene depends on provided array (if in corresponding position of the pixel in new sprite in array is '1' - i need to draw this pixel, if '0' - i don't want to draw it (maybe set alpha = 0)).
I think i can use fragment shader for each of new sprites, but i can't understand how to provide array data to the shader to calculate color for each pixel.
I think also can use fragment shader for the whole scene (if render to texture).
I am quite new in opengl and can't figure out in what way to move.
When i create resources for the scene - i try to create my mask:
mask = new float[512*512*4];
for (int i = 0; i < mask.length; i++)
{
mask[i] = 2f;
}
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1029384756);
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 1, GLES20.GL_RGBA, 512, 512, 0, GLES20.GL_RGBA, GLES20.GL_FLOAT, FloatBuffer.wrap(mask));
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
Then when i draw new item on scene i use shader:
setShaderProgram(ShaderProgram.getInstance());
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glUniform1i(RadialBlurExample.RadialBlurShaderProgram.sUniformMask, GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1029384756);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
But i can't see new item on scene (maskVal is <0.5).
I try to find working way to pass array as a texture but i can't find it.
Upload your array as a second texture with the same dimensions as the sprite, and then when you draw the sprite, sample the second texture at the same texcoord.
If the second texture doesn't meet the mask criteria, discard the fragment
uniform sampler2d sprite;
uniform sampler2d mask;
in vec2 uv;
main() {
float maskVal = texture2D(mask, uv).r;
if(maskVal > 0.5) {
gl_FragColor = texture2D(sprite,uv);
} else {
discard;
}
}
Related
I am creating a simple traingle strip to cover the whole viewport with a single rectangle. Then I am applying a 100x100 texture to this surface which changes with every frame.
I set up viewPort and initialise my vertexBuffer etc. in the onSurfaceChanged method of my GLSurfaceView class, then call my rendering function from onDrawFrame.
This setup works as it should, but at random occasions only the right lower quarter of my rectangle gets rendered, the other 3/4th of the canvas is filled with background color! It doesn't happen every time, and the anomaly disappears after rotating the device back and forth (I guess because everything gets a reset in onSurfaceChanged)
I have tried to re-upload all vertices at every frame update with GLES20.glBufferData, which seems to get rid of this bug, although it might be that I just wasn't patient enough to observe it happening (as it is quite unpredictible). It's a very simple triangle strip, so I don't think that it consumes a lot of time, but it just feels bad practice to upload a data 60/sec which isn't changing at all!
//called from onSurfaceChanged
private fun initGL (side:Int) {
/*======== Defining and storing the geometry ===========*/
//vertices for TRIANGLE STRIP
val verticesData = floatArrayOf(
-1.0f,1.0f,//LU
-1.0f,-1.0f,//LL
1.0f,1.0f,//RU
1.0f,-1.0f//RL
)
//float : 32 bit -> 4 bytes
val vertexBuffer : FloatBuffer = ByteBuffer.allocateDirect(verticesData.size * 4)
.order(ByteOrder.nativeOrder()).asFloatBuffer()
vertexBuffer.put(verticesData).position(0)
val buffers = IntArray(1)
GLES20.glGenBuffers(1, buffers, 0)
vertexBufferId = buffers[0]
//upload vertices to GPU
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER,
vertexBuffer.capacity() * 4, // 4 = bytes per float
vertexBuffer,
GLES20.GL_STATIC_DRAW)
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
/*================ Shaders ====================*/
// Vertex shader source code
val vertCode =
"""
attribute vec4 aPosition;
void main(void) {
gl_Position = aPosition;
}
"""
val fragCode =
"""
precision mediump float;
varying vec2 vCoord;
uniform sampler2D u_tex;
void main(void) {
//1-Y, because we need to flip the Y-axis!!
vec4 color = texture2D(u_tex, vec2(gl_FragCoord.x/$side.0, 1.0-(gl_FragCoord.y/$side.0)));
gl_FragColor = color;
}
"""
// Create a shader program object to store
// the combined shader program
val shaderProgram = createProgram(vertCode, fragCode)
// Use the combined shader program object
GLES20.glUseProgram(shaderProgram)
val vertexCoordLocation = GLES20.glGetAttribLocation(shaderProgram, "aPosition")
GLES20.glVertexAttribPointer(vertexCoordLocation, 2, GLES20.GL_FLOAT, false, 0, vertexBuffer)
GLES20.glEnableVertexAttribArray(vertexCoordLocation)
//set ClearColor
GLES20.glClearColor(1f,0.5f,0.5f,0.9f)
//setup a texture buffer array
val texArray = IntArray(1)
GLES20.glGenTextures(1,texArray,0)
textureId = texArray[0]
if (texArray[0]==0) Log.e(TAG, "Error with Texture!")
else Log.e(TAG, "Texture id $textureId created!")
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
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)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST)
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST)
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT,1)
}
//called from onDrawFrame
private fun updateGLCanvas (matrix : ByteArray, side : Int) {
//create ByteBuffer from updated texture matrix
val textureImageBuffer : ByteBuffer = ByteBuffer.allocateDirect(matrix.size * 1)//Byte = 1 Byte
.order(ByteOrder.nativeOrder())//.asFloatBuffer()
textureImageBuffer.put(matrix).position(0)
//do I need to bind the texture in every frame?? I am desperate XD
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0,GLES20.GL_RGB, side, side, 0, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, textureImageBuffer)
//bind vertex buffer
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
// Clear the color buffer bit
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
//draw from vertex buffer
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP,0,4)
//unbind vertex buffer
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0)
}
There are no error messages and most of the time the code is behaving as it should ... which makes this a bit difficult to track ...
If you want to use a vertex buffer, then the buffer object has to be the currently bound to the target GLES20.GL_ARRAY_BUFFER, when the array of generic vertex attribute data is specified by glVertexAttribPointer. The vertex attribute specification refers to this buffer.
In this case the last parameter of glVertexAttribPointer is treated as a byte offset into the buffer object's data store.
In your case this means the last parameter has to be 0.
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBufferId)
GLES20.glVertexAttribPointer(vertexCoordLocation, 2, GLES20.GL_FLOAT, false, 0, 0)
Note, if no named buffer buffer object is bound (zero), then the last parameter is a pointer to the buffer memory. Every time when a draw call is performed, this buffer is read.
In your implementation, the data which was uploaded to the GPU is never used, because it isn't referenced by the vertex array specification.
See also Vertex Specification.
I'm trying to do some experiments with Open GL ES on Android.
I'm trying to write a shader that got two uniform variables pointing 2 textures.
One containing the current frame, and the other containing the texture drawn on frame before
They're created in java world like this:
texturenames = new int[2];
GLES20.glGenTextures(2, texturenames, 0);
// Bind texture to texturename
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[0]);
GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texturenames[1]);
Then are passed as parameters of the shader like this:
int location = GLES20.glGetUniformLocation (ShaderTools.program, "currentTexture" );
GLES20.glUniform1i ( location, 0 );
location = GLES20.glGetUniformLocation (ShaderTools.program, "prevFrameTexture" );
GLES20.glUniform1i ( location, 1 );
This is the content of the fragment shader:
precision mediump float;
varying vec2 v_TexCoordinate;
uniform sampler2D currentTexture;
uniform sampler2D prevFrameTexture;
main() {
gl_FragColor = (texture2D(currentTexture, v_TexCoordinate) +
texture2D(prevFrameTexture, v_TexCoordinate)) / 2;
}
What i want to achieve is create a sort of blurring effect that's the result of the average of current and previous frame.
Is it possibile to update prevFrameTexture directly into shader code? I didn't find any way to do this.
As alternative... how should i tackle this problem?
Should i copy the content of currentTexture into prevFrameTexture in java world?
I tried to draw alternatively the TEXTURE0 and TEXTURE1 into onDrawFrame but it doesn't work as glActiveTexture to swap from one to another, doesn't work inside that callback
Yes it is possible. Use Render To Texture (RTT)
We can make a FBO as a texture so you should make two FBOs.
An example of making a RTT below
glGenFramebuffers(1, &fbo[object_id]);
glBindFramebuffer(GL_FRAMEBUFFER, fbo[object_id]);
glGenRenderbuffers(1, &rboColor[object_id]);
glBindRenderbuffer(GL_RENDERBUFFER, rboColor[object_id]);
Right after, make a texture following code below
glGenTextures(1, &texture[texture_id].texture_id);
glBindTexture(GL_TEXTURE_2D, texture[texture_id].texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_width, texture_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture[texture_id].texture_id, 0);
Once you have RTT textures, you can update these by rendering each framebuffer
https://github.com/sunglab/StarEngine/blob/master/renderer/StarFBO.cpp
void StarFBO::createFBO(...)
https://github.com/sunglab/StarEngine/blob/master/renderer/StarTexture.cpp
void StarTexture::createTEXTURE_RTT(...)
I am currently rendering a camera preview using GL ES 2.0 on android to a SurfaceTexture, rendering it with opengl, then transferring it to a media codec's input surface to for recording. It is displayed to the user in a surface view and by setting that surface view's aspect ratio the camera preview is not distorted based on screen size.
The recording is in portrait, but at some point the incoming texture will start coming in landscape, at which point I'd like to zoom out and display it as a "movie" stretched wide to fit to the edge of the screen horizonatally with black bars on the top and bottom to maintain the aspect ratio of the texture.
The drawing code in onDrawFrame is pretty simple. The link has the rest of the setup code for shaders and the like but it's just setting up a triangle strip to draw.
private final float[] mTriangleVerticesData = {
// X, Y, Z, U, V
-1.f, -1.f, 0, 0.f, 0.f,
1.f, -1.f, 0, 1.f, 0.f,
-1.f, 1.f, 0, 0.f, 1.f,
1.f, 1.f, 0, 1.f, 1.f,
};
public static final String VERTEX_SHADER =
"uniform mat4 uMVPMatrix;\n" +
"uniform mat4 uSTMatrix;\n" +
"attribute vec4 aPosition;\n" +
"attribute vec4 aTextureCoord;\n" +
"varying vec2 vTextureCoord;\n" +
"void main() {\n" +
" gl_Position = uMVPMatrix * aPosition;\n" +
" vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
"}\n";
private float[] mMVPMatrix = new float[16];
private float[] mSTMatrix = new float[16];
public TextureManager() {
mTriangleVertices = ByteBuffer.allocateDirect(
mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTriangleVertices.put(mTriangleVerticesData).position(0);
mTriangleHalfVertices = ByteBuffer.allocateDirect(
mTriangleVerticesHalfData.length * FLOAT_SIZE_BYTES)
.order(ByteOrder.nativeOrder()).asFloatBuffer();
mTriangleHalfVertices.put(mTriangleVerticesHalfData).position(0);
Matrix.setIdentityM(mSTMatrix, 0);
}
onDrawFrame(){
mSurfaceTexture.getTransformMatrix(mSTMatrix);
GLES20.glUseProgram(mProgram);
checkGlError("glUseProgram");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID);
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maPosition");
GLES20.glEnableVertexAttribArray(maPositionHandle);
checkGlError("glEnableVertexAttribArray maPositionHandle");
mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false,
TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
checkGlError("glVertexAttribPointer maTextureHandle");
GLES20.glEnableVertexAttribArray(maTextureHandle);
checkGlError("glEnableVertexAttribArray maTextureHandle");
Matrix.setIdentityM(mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
checkGlError("glDrawArrays");
GLES20.glFinish();`
}
Things I've tried that haven't quite worked: Scaling mMVPMatrix or mSTMatrix to zoom in. I can zoom in, so I can get the "center slice" of the landscape video to display without distortion, but this cuts off a huge 40% portion of the video, so it isn't a great solution. Zooming out by scaling these matricies causes the texture to repeat the pixel on the edge because of the clamp to edge behavior.
Halving the x,y,z parts of mTriangleVerticesData gives some of the desired behavior as seen in the screenshot below, exact aspect ratio aside. The center part of the picture is halved and centered, as expected. However, the texture is repeated to the left, right, and bottom, and there is distortion to the top left. What I want is the center to be as it is, with black/nothing surrounding it.
I could scale out then translate mMVPMatrix or mSTMatrix and then change my shader to display black for anything outside (0,1) but eventually I want to overlay multiple textures on top of one another, like a full size background and partial size foreground texture. To do this I must eventually figure out how to only display a texture in a portion of the available space, not just manipulate the texture so it looks like that's what's happening.
Thanks for reading all that. Any help, suggestions, or wild guesses are appreciated.
The repeated image chunks look like GPU tiling artifacts, not texture repeating. Add a glClear() call to erase the background.
It would seem what you are looking for is a "fit" system to get the correct frame of your element. It would mean for instance you are having a 100x200 image and you want to display it in a frame of 50x50. The result should then be seeing the whole image in rectangle (25, 0, 25, 50). So the resulting frame must respect the image ratio (25/50 = 100/200) and original frame boundaries must be respected.
To achieve this generally you need to compare the image ratio and the target frame ratio: imageRatio = imageWidth/imageHeight and frameRatio = frameWidth/frameHeight. Then if image ratio is larger then the frame ratio it means you need black borders on top and bottom while if the frame ratio is larger then you will see black borders on left and right side.
So to compute the target frame:
imageRatio = imageWidth/imageHeight
frameRatio = frameWidth/frameHeight
if(imageRatio > frameRatio) {
targetFrame = {0, (frameHeight-frameWidth/imageRatio)*.5, frameWidth, frameWidth/imageRatio} // frame as: {x, y, width, height}
}
else {
targetFrame = {(frameWidth-frameHeight*imageRatio)*.5, 0, frameHeight*imageRatio, frameHeight} // frame as: {x, y, width, height}
}
In your case the image width and height are the ones received from the stream; frame width and height are from your target frame which seems to be a result from matrices but for full screen case that would simply be values from glOrtho if you use it. The target frame should then be used to construct the vertices positions so you get exactly correct vertex data to display the full texture.
I see you use matrices to do all the computation in your case and the same algorithm may be used to be converted to matrix but I discourage you to do so. You seem to be over-abusing matrices which makes your code completely unmaintainable. I suggest in your case you keep to "ortho" projection matrix, use frames to draw textures and only use matrix scale and translations where it makes sense to do so.
NOTE: I've updated this code now to the working form and provided everything I attempted in an answer. Hopefully it helps somebody else with the same problem.
My texture is being shown as black (that is, no texture). I've gone through several other questions here with the same problem, but could not find a solution. I'm sure I'm missing something quite simple (likely ordering), but can't figure it out.
I setup my texture like this (GLProgram.checkError checks for GL errors and logs them -- I get no errors anywhere):
/*Bitmap*/ bitmap = BitmapFactory.decodeResource( context.getResources(),
R.drawable.gears );
int textures[] = new int[1];
GLES20.glGenTextures( 1, textures, 0 );
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
GLProgram.checkError( "texImage2D" );
texture = textures[0];
To draw a square which should be textured I do this:
GLES20.glVertexAttribPointer(glProgram.hATex, 2, GLES20.GL_FLOAT, false,
2*SIZEOF_FLOAT, texBuffer.under);
GLProgram.checkError( "hATex" );
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 );
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture);
GLES20.glUniform1i(glProgram.hUTex, 0);
GLProgram.checkError( "Uniform" );
GLES20.glVertexAttribPointer( glProgram.hAttribPosition, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer.under );
GLProgram.checkError( "Vertex" );
GLES20.glDrawArrays( GLES20.GL_TRIANGLE_FAN, 0, vertexBuffer.size/COORDS_PER_VERTEX );
GLProgram.checkError( "draw" );
My vertex shader is:
precision mediump float;
attribute vec4 vPosition;
uniform mat4 mTransform;
attribute vec2 aTex;
varying mediump vec2 vTex;
void main() {
gl_Position = mTransform * vPosition;
vTex = aTex;
}
My fragment shader is:
precision mediump float;
uniform vec4 vColor;
uniform sampler2D uTex;
varying mediump vec2 vTex;
void main(void)
{
//gl_FragColor = vColor;
//testing vTex, and it is fine
//gl_FragColor = vec4( vTex[0], vTex[1], 0, 1.0 );
//so it must be uTex which is program
gl_FragColor = texture2D(uTex,vTex);
}
I left in the commented bits to show what I checked. My vTex parameter is correct, since that bit produces the expected red/green color sweep. So I assume it must be the texture itself.
Also, uTex, aTex are located via:
hATex = GLES20.glGetAttribLocation( hProgram, "aTex" );
checkError( "aTex" );
hUTex = GLES20.glGetUniformLocation( hProgram, "uTex" );
checkError( "uTex" );
My texture comes a JPG and is 64x64 in size. I checked just after loading and it has the correct size and does appear to have pixel colors (dumping a few at random were non-zero).
The code, as presented, now works. I modified it as I tried things and for the comments. I can't be sure at which step it actually started working, since it didn't work before. Here are some of the things I checked/double-checked in the process -- I presume it has to be a combination of these somehow:
Verify source image is square and a power of two in size
non-square works so long as power of 2 in both dimensions
non-power 2 works so long as TEXTURE_WRAP is set to CLAMP_TO_EDGE
Set Min/Mag to nearest
Call bindTexture during setup and in each draw
These are things I tried, and tried again now, and appear to make no different (that is, it works either way):
use bitmap options.inScaled = false (using default options works fine)
put texImage2d before/after the glTexParameter functions
add/remove mediump from vTex (mismatched works fine, probably because default)
not calling glEnableVertexAttribArray (this results in a white box, so it wasn't my problem)
changing order of vertices and texture coords (all orders work once other things are correct -- texture may be skewed, but it does appear)
changing resource format (JPG/PNG) (RGB/Grayscale)
changing object transform matrix
TEXTURE_WRAP settings (not needed in this case, works without)
In the case when it wasn't working the error was silent: calls to glGetError returned okay and glGetProgramInfoLog was empty.
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.