Draworder OpenGL - большие объекты над меньшими

В моей игре OpenGL ES для Android я пытаюсь рисовать фигуры в последовательном порядке в соответствии с их z-значением (то есть положением в z-плоскости). Это значит сначала нарисовать самые маленькие фигуры (текстуры), а затем нарисовать больше. Я сохранил свойства фигур в массиве, и при рисовании и обновлении я использую итератор. Допустим, это массив List с его z-значениями (просто пример)

ArrayList arraylistBricks

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

Я сортирую этот arrayList, используя Collections.sort(..) для каждого кадра, и после сортировки список выглядит следующим образом

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

То есть самые маленькие фигуры находятся первыми в списке и должны быть нарисованы первыми. Я вижу, что массив действительно отсортирован, но почему-то ничего не происходит. Я хочу, чтобы меньшие фигуры были позади больших. Есть ли у GPU какой-то алгоритм порядка рисования? Я только что мигрировал из skia в opengl и был удивлен этим.

Что мне здесь не хватает? Как я мог решить проблему?

 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();
            }
        }
    }

}

метод рендеринга

   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);
}

обновление (фрагмент)

   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 ответа

OpenGL ES 2 имеет встроенное тестирование глубины. Вы можете включить его, используя glEnable(GL_DEPTH_TEST),

Не забывайте очищать буфер каждый кадр (или проверять буфер кадров, если вы используете OpenGL ES 3).

Это значит сначала нарисовать самые маленькие фигуры (текстуры), а затем нарисовать больше.

Не делайте этого так - вы потеряете все преимущества раннего теста для уничтожения окклюдированных фрагментов до того, как они будут затенены.

Визуализируйте непрозрачные фрагменты в порядке рендеринга спереди к спине (тест глубины включен, запись глубины включена), затем просвечивайте прозрачность поверх в порядке рендеринга спереди назад (тест глубины включен, запись глубины отключена).

Другие вопросы по тегам