Skip to main content
added 47 characters in body
Source Link
user9851
user9851

(I'm interested in OpenGL ES 2.0 primarily)

(I'm interested in OpenGL ES 2.0 primarily)

Source Link
user9851
user9851

Efficiently drawing multiple instances of 3D objects

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) ?

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