问题
Hej,
I'm creating simple game for Android in OpenGL ES 2.0. The game will contain few types of different sprites, but these will occur more than once.
For now let's say I have 1 object (sprite). So far I've implemented VBO and Index buffering, so an object as whole is stored on GPU, as I understand.
What I would like to do now is to draw this object multiple times, only thing differing it's position. As for now, this is implemented as follows:
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.getBufferId());
for(int i=0; i<1000; i++){
multiplyMM(MVP, 0, viewMatrix, 0, tempGetRandomMVPMatrix(), 0);
glUniformMatrix4fv(uMatrixLocation, 1, false, MVP, 0);//TODO
if(androidVersion > Build.VERSION_CODES.FROYO)
glDrawElements(GL_TRIANGLES, indexArray.length, GL_UNSIGNED_SHORT, 0);
else{
if(repairedGL20 == null){
repairedGL20 = new AndroidGL20();
}
repairedGL20.glDrawElements(GL_TRIANGLES, indexArray.length, GL_UNSIGNED_SHORT, 0);
}
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
If I understand correctly the main problem is call glDrawElements which is called every time I change MVP matrix. Is there any way of sending all MVP matrices to GPU and draw one element multiple times there with only 1 call to glDrawElements?
Some more info about object. It has around 24 vertices and texture 64x64. Currently with 1k objects I have 35FPS, I would like to get higher fps since I will be drawing some more sprites.
Here are my shaders: Vertex:
uniform mat4 u_Matrix;
attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;
varying vec2 v_TextureCoordinates;
void main(){
v_TextureCoordinates = a_TextureCoordinates;
gl_Position = u_Matrix * a_Position;
}
Fragment:
precision mediump float;
uniform sampler2D u_TextureUnit;//actual texture data
varying vec2 v_TextureCoordinates;
void main(){
gl_FragColor = texture2D(u_TextureUnit, v_TextureCoordinates);
}
One more thing I don't quite understand about textures. If I create texture something like this:
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);//binds texture to texture object
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//minimization filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);//send texture data to OpenGL to the CURRENTLY BOUND object
When I'll be drawing objects with this texture, where is texture saved, on CPU's memory or on GPU? Furthermore in example above where I'm drawing same sprite, is texture being sent to GPU each draw call? If this is so, is there any way to optimize this (something similar to VBO)?
回答1:
For example lets say I have 1 object with 2 vertices that I want to translate to 2 places with MVP. How can I make "gl_Position" to be drawn in 2 separate places at the same time?
That can never be done. What I was referring to in my initial comment is something like a vertex buffer full of N-many (probably 4) vertices per-sprite... if in addition to the position in your vertex buffer you include an additional field, you can transform the vertices using different matrices in your shader. You will always have to define N vertices per-object, but you can use a static vertex buffer to do this as I will explain below.
Say you had a sprite defined by the points (before transformation):
Position
<0.0,0.0>
<1.0,0.0>
<1.0,1.0>
<0.0,1.0>
If your modelview matrix includes scaling information, you can use the same set of points over and over, by the way.
Now, if you want to extend this to draw 3 sprites in a single call, you could do this:
Position Idx
<0.0,0.0> [0]
<1.0,0.0> [0]
<1.0,1.0> [0]
<0.0,1.0> [0]
<0.0,0.0> [1]
<1.0,0.0> [1]
<1.0,1.0> [1]
<0.0,1.0> [1]
<0.0,0.0> [2]
<1.0,0.0> [2]
<1.0,1.0> [2]
<0.0,1.0> [2]
Basically I added a new field to the vertex buffer, which identifies the sprite each set of 4 points belongs to; use a GLubyte
for best performance. You will notice that the same set of points repeats over and over. Implementing instancing this way effectively increases the storage requirements to O (N*V + 4N)
, where V is the size of the original vertex data structure for 4 points and N is the number of sprites.
You can go as far as to define a vertex buffer that contains enough points for 16 sprites, and then when you want to draw multiple sprites in a single call you will always use the same vertex buffer and use a subset of the total number of points. To draw 4 sprites using this vertex buffer, simply draw the first 16 out of the 64 points it contains total.
Now, this is only half of the process. You also need to setup your vertex shader to take an array of modelview matrix uniforms that define the transformation per-sprite.
Here is an example vertex shader that could be used to do this:
#version 100
uniform mat4 proj_mat;
uniform mat4 instanced_mv [16];
attribute vec4 vtx_pos;
attribute vec2 vtx_st;
attribute float vtx_sprite_idx; // This would be a uint in desktop GLSL
varying vec2 tex_st;
void main (void) {
gl_Position = proj_mat * instanced_mv [(int)vtx_sprite_idx] * vtx_pos;
tex_st = vtx_st;
}
There are a few of things to note here:
- GLES 2.0 does not support integer vertex attributes, so the index must be floating-point
- Indexing uniform arrays must be done using integer expressions in vertex shaders, so a cast is necessary.
- Indexing uniform arrays must be done using integer expressions in vertex shaders, so a cast is necessary.
- The number of modelview uniforms is really the limiting factor to how many sprites you can instance at once
- Vertex shaders are only required to support 128 4-component uniform variables (a
mat4
counts as 4 4-component uniforms), so this means if your vertex shader had only modelview uniforms you could support a maximum array of 32 (128/4).
- Vertex shaders are only required to support 128 4-component uniform variables (a
- Store the sprite index as a
GLubyte
in your vertex buffer, but make sure you do not enable floating-point normalization when you set up your Vertex Attrib. Pointer.
Last, this shader has not been tested. If you have trouble understanding anything here or run into issues implementing this, feel free to leave a comment.
来源:https://stackoverflow.com/questions/19483586/android-opengl-2-0-sprite-optimization