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:

1. I could displace the `.obj` files `_positions` buffer before adding to the  global `mPositions` buffer to draw, but this seems rather inefficient.

2. 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)

3. "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) ?

4. 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 !