I was able to write the following working code to draw any number of "sprites" (defined as 2 tringles, 6 vertices)
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, getCamera().mViewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mShader.getMVMatrixHandle(), 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, getCamera().projMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mShader.getMVPMatrixHandle(), 1, false, mMVPMatrix, 0);
mPositions.position(0);
mColors.position(0);
mNormals.position(0);
mTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mShader.getPositionHandle(), mPositionDataSize, GLES20.GL_FLOAT, false, 0, mPositions);
GLES20.glVertexAttribPointer(mShader.getColorHandle(), mColorDataSize, GLES20.GL_FLOAT, false, 0, mColors);
GLES20.glVertexAttribPointer(mShader.getNormalHandle(), mNormalDataSize, GLES20.GL_FLOAT, false, 0, mNormals);
GLES20.glVertexAttribPointer(mShader.getTextureCoordinateHandle(), mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mTextureCoordinates);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6*numSprites);
Using a sprite atlas this code displays many different sprite textures in one fell swoop, which is very fast.
However, I would also like to draw multiple copies of a 3D .obj
file. Now I've loaded in the necessary FloatBuffers
of positions, normals, texture coordinates, etc., so I can easily add these buffers to the mPositions
, mTextureCoordinates
buffers above, etc., no problem.
But these instances of the .obj
model I'm trying to display need to be in different x/y locations.
Is there an efficient way this can be achieved in OpenGL? Maybe one of the following:
I could displace the .obj
files _positions
buffer before adding to the global mPositions
buffer to draw, but this seems rather inefficient.
One solution is to run a separate instance of the above code for each .obj
3D object, including an OpenGL translation for each instance. But I've heard this is costly if you have many 3D objects. (This is the reason I use a sprite atlas for 2D sprites in the above code)
"Another" approach that seems to work is to add the following example code, where _positions
etc are the buffers for the `.obj. file, and I draw 5 of the same object file in a row using a translation. It's very similar to (2) but without having to repeat the OpenGL initialisation code every time.
for (int c1 = 0; c1 < 5; c1++) {
_positions.position(0);
_normals.position(0);
_textureCoordinates.position(0);
Matrix.setIdentityM(mModelMatrix, 0);
Matrix.translateM(mModelMatrix, 0, cx + dx * c1 * 4, cy, 0);
Matrix.scaleM(mModelMatrix, 0, 0.1f, 0.1f, 0.03f);
Matrix.rotateM(mModelMatrix, 0, -90, 1, 0, 0);
Matrix.multiplyMM(mMVPMatrix, 0, getCamera().mViewMatrix, 0, mModelMatrix, 0);
GLES20.glUniformMatrix4fv(mShader.getMVMatrixHandle(), 1, false, mMVPMatrix, 0);
Matrix.multiplyMM(mMVPMatrix, 0, getCamera().projMatrix, 0, mMVPMatrix, 0);
GLES20.glUniformMatrix4fv(mShader.getMVPMatrixHandle(), 1, false, mMVPMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, numFaces);
}
But I'm not sure if this isn't just as inefficient as the (2) ?
- Maybe there's no way round it? Perhaps (2)/(3) is the only way and I'm just being over cautious because of my "bad" experience without using a sprite atlas for 2D sprites? After all, I was originally drawing 1000's of 2D sprites using method (1) originally, but I will only be drawing around 10-20 3D objects. In the 2D case, switching to a sprite atlas greatly speeded things up !