Reputation: 1165
I would like to know how to access and manipulate each sprite individaully when the vertices of those sprites are stored in one and the same VBO. For performance reason I use a textureatlas for my sprites and then maps those to the vertexarray. I made a try to split up the sprites in separate vertex-arrays and put those in separate VBO's. But this hits perfomance if I draw let say 100 sprites since a lot of separate draws has to be made each call. Instead I want to use one and the same VBO and from that translate each sprite separately. Is this possible?
sourcecode
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
vertexBuffer = GLData.createVertices(nSprites, vertices);
GLData.createUvsData(nSprites, alienUvs, uvBufferAlien);
//drawListBuffer = GLData.createIndices(indices, nSprites);
GLData.createVertexBufferObject(vertexBuffer,nSprites, uvBufferAlien, bufferId.length, bufferId);
createCamera();
GLES20.glEnable(GLES20.GL_CULL_FACE);
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
// get shadersource
final String vertexShader = getVertexShader();
final String fragmentShader = getFragmentShader();
final int vertexShaderHandle = ShaderHelper.compileShader(GLES20.GL_VERTEX_SHADER, vertexShader);
final int fragmentShaderHandle = ShaderHelper.compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentShader);
mProgramHandle = ShaderHelper.createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
new String[] {"a_Position", "a_Color", "a_Normal", "a_TexCoordinate"});
//create texture
textureHandle = TextureHelper.loadTexture(context);
GLES20.glUseProgram(mProgramHandle);
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVPMatrix");
mMVMatrixHandle = GLES20.glGetUniformLocation(mProgramHandle, "u_MVMatrix");
//mColorHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Color");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_TexCoordinate");
mPositionHandle = GLES20.glGetAttribLocation(mProgramHandle, "a_Position");
}
@Override
public void onSurfaceChanged(GL10 unused, int width, int height) {
game_width = width;
game_height = height;
GLES20.glViewport(0, 0, width, height);
// Create a new perspective projection matrix. The height will stay the same
// while the width will vary as per aspect ratio.
final float ratio = (float) width / height;
final float left = -ratio;
final float right = ratio;
final float bottom = -1.0f;
final float top = 1.0f;
final float near = 1f;
final float far = 20.0f;
Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
}
@Override
public void onDrawFrame(GL10 unused) {
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, 2, 0f, -7f);
draw();
}
private void draw() {
//uvs
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[0]);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, 0);
//vertices
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, bufferId[1]);
GLES20.glEnableVertexAttribArray(mPositionHandle);
GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, 0, 0);
// Clear the currently bound buffer (so future OpenGL calls do not use this buffer).
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
/* MATRIX */
// This multiplies the view matrix by the model matrix, and stores the result in the MVP matrix
// (which currently contains model * view).
Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
// Pass in the modelview matrix.
GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
// This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
// (which now contains model * view * projection).
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
// Pass in the combined matrix.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
// Draw the sprites
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6 * nSprites);
}
vertex-shader
attribute vec4 a_Position;
uniform mat4 u_MVMatrix;
uniform mat4 u_MVPMatrix;
void main() {
gl_Position = u_MVPMatrix * a_Position;
}
Upvotes: 0
Views: 118
Reputation: 12159
You can upload a uniform matrix array, and an index into that as a per-vertex attribute for each sprite to give you a unique matrix for each sprite (technique used for skinning skeletal animation models, but works here too).
However, for simple sprites the cost of uploading the matrices is going to be almost as expensive as updating a position array, and there are limits on the size of the uniform array you'll need to worry about. You may be better off just animating them in software and uploading a new position for each vertex in the batch every frame. Split position into a separate buffer from, e.g. your texture coordinates, to minimize the bandwidth you are uploading each frame.
Upvotes: 2