Draworder OpenGL - larger objects over smaller

86 views Asked by At

In my OpenGL ES Android game I am trying draw shapes in succesive order in accordance with their z-value (that is position in the z-plane). This means to draw the smallest most distant shapes (textures) first and then draw the larger. I have stored the shapes properties in an arraylist and when drawing and updating I am using an Iterator. Let say the this is the arrayList with its z-values (just an example)

ArrayList arraylistBricks

obj (0) ... z = -20 
obj (1) ... z = -37
obj (2) ... z = -31
obj (3) -...z = -20

I sort this arrayList using Collections.sort(..) for every frame and after the sorting the list look like this

obj (0) ... z = -37 
obj (1) ... z = -31
obj (2) ... z = -20
obj (3) -...z = -20

That is - the smallest shapes are first in the list and are first to be drawn. I can see that the arraylist is really sorted but somehow nothing happends.What I want is that the smaller shapes should be behind the larger ones. Does the GPU have some sort of algortitm of drawingorder? I just migrated from skia to opengl and was surprised over this.

What do I miss here? How could I solve the problem?

 private void drawShape() {

    GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vboDataListLevelSprites.get(iName).getBuff_id_vertices());
    GLES20.glEnableVertexAttribArray(mPositionHandle);
    GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, 0);
    for (int i = 0; i < BrickProperties.get_buff_id_uvs().length; i++) {
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, BrickProperties.get_buff_id_uvs()[i]);
        GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
        GLES20.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

        for (Iterator<BrickProperties> shapeIterator = arrayListBricks.iterator(); shapeIterator.hasNext(); ) {

            BrickProperties bp = shapeIterator.next();
            int buffIndexVal = bp.get_status_diff();

            if (buffIndexVal == i) {
                Matrix.setIdentityM(mModelMatrix, 0);
                Matrix.translateM(mModelMatrix, 0, bp.getTranslateData()[0], bp.getTranslateData()[1], bp.getTranslateData()[2]);

                if (bp.get_status() == 0) {
                    Matrix.rotateM(mModelMatrix, 0, bp.getAngleInDegrees(), 0, 1, 0);
                }

                render();
            }
        }
    }

}

the render-method

   private void render() {

    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mMVPMatrix, 0);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
}

update (snippet)

   public void update() {

    Collections.sort(arrayListBricks, new Comparator<BrickProperties>() {
        @Override
        public int compare(BrickProperties bp2, BrickProperties bp1)
        {
            int result = Float.compare(bp1.getTranslateData()[2], bp2.getTranslateData()[2]);
            return result;

        }
    });
    Collections.reverse(arrayListBricks);

....
2

There are 2 answers

3
Reaper On

OpenGL ES 2 has an in-built depth testing. You could enable it by using glEnable(GL_DEPTH_TEST).

Don't forget to clear the buffer each frame (or ivalidate the framebuffer if you use OpenGL ES 3).

2
solidpixel On

This means to draw the smallest most distant shapes (textures) first and then draw the larger.

Don't do it this way - you lose all of the benefits of the early-zs test for killing occluded fragments before they are shaded.

Render your opaque fragments in front-to-back render order (depth test enabled, depth write enabled), then render transparents over the top in back-to-front render order (depth test enabled, depth write disabled).