1

Using libgdx, I want to discard occluded sprites using a depth buffer. To do so I use the provided Decal and DecalBatch with an OrthographicCamera and I set the z position manually.

Depending my sprite position on the x and y axes, the depth buffer works or not as expected.

red square z = 98 green square z = 10

Square comparaison

The square are 50% transparent so I can see if the depth test occurred as expected.

Here the test code:

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g3d.decals.CameraGroupStrategy;
import com.badlogic.gdx.graphics.g3d.decals.Decal;
import com.badlogic.gdx.graphics.g3d.decals.DecalBatch;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.Array;
import fr.t4c.ui.GdxTest;

public class DecalTest extends GdxTest {
    DecalBatch batch;
    Array<Decal> decals = new Array<Decal>();
    OrthographicCamera camera;
    OrthoCamController controller;
    FPSLogger logger = new FPSLogger();

    Decal redDecal;
    Decal greenDecal;

    public void create() {

        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        //camera.near = 1;
        camera.position.set(600, 600, 100);
        camera.near = 1;
        camera.far = 100;

        controller = new OrthoCamController(camera);

        Gdx.input.setInputProcessor(controller);
        batch = new DecalBatch(new CameraGroupStrategy(camera));

        TextureRegion[] textures = {
                new TextureRegion(new Texture(Gdx.files.internal("src/test/resources/redsquare.png"))),
                new TextureRegion(new Texture(Gdx.files.internal("src/test/resources/greensquare.png")
                ))};

        redDecal = Decal.newDecal(textures[0], true);
        redDecal.setPosition(600, 600, 98f);
        decals.add(redDecal);

        greenDecal = Decal.newDecal(textures[1], true);
        greenDecal.setPosition(630, 632f, 10f);
        decals.add(greenDecal);

        Decal decal = Decal.newDecal(textures[0], true);
        decal.setPosition(400, 500, 98f);
        decals.add(decal);

        decal = Decal.newDecal(textures[1], true);
        decal.setPosition(430f, 532f, 10f);
        decals.add(decal);
    }

    public void render() {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
        Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
        Gdx.gl.glDepthFunc(GL20.GL_LEQUAL);

        camera.update();
        for (int i = 0; i < decals.size; i++) {
            Decal decal = decals.get(i);
            batch.add(decal);
        }
        batch.flush();
    }

    @Override
    public void dispose() {
        batch.dispose();
    }

    public static void main(String[] args) {
        LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
        cfg.useGL30 = false;
        cfg.width = 640;
        cfg.height = 480;
        cfg.resizable = false;
        cfg.foregroundFPS = 0; // Setting to 0 disables foreground fps
        // throttling
        cfg.backgroundFPS = 0; // Setting to 0 disables background fps
        new LwjglApplication(new DecalTest(), cfg);
    }
}

It is a depth buffer precision problem, the orientation of the camera that messed up the calcul or something else?

Edit: I expect the sprites being occluded if they are behind another. So in my example the red square should occlude the green part he is in front of. The left bottom squares have the right behaviour but the upper right squares does not. The things is red squares have the same Z value and green squares have the same Z value too(different than the red squares Z of course). So the only things that made the square couples different is their x and y position, which should not impact the depth test.

So, what I want is a consistent depth test behaviour that occluded hided texture as we see whith the bottom left squares no matter their x and y position. According to the comment, I added information about what I expect.

QuentinR
  • 115
  • 1
  • 11
  • Not clear what a problem is? Write more information, what do you want to get – Stanislav Batura Dec 12 '18 at 09:37
  • I added some explanations in the edit part. – QuentinR Dec 12 '18 at 09:58
  • You say "The square are 50% transparent so I can see if the depth test occurred as expected." and then "I expect the sprites being occluded if they are behind another.". Are they transparent or not? To me it looks like the red square is in front of the green square in both examples but one of them is transparent and not the other. What happens if you only have one red and one green square and move them around? – Johan Dec 13 '18 at 07:41
  • All sprites are transparent at 50%. So if they are blended like in the top right squares couple, it means the depth test didn't work properly because the green pixels behind the red square are displayed. If the depth test work as i expect, it does like the bottom left squares(they don't blend despite they are transparent because the green pixels are discarded). Is this explanation clear? – QuentinR Dec 13 '18 at 10:45
  • This is not a depth buffer issue, but an order issue. All opaque meshes should be drawn front-to-back first and after that all transparent meshes should be drawn back-to-front. In your case the transparent front object is likely drawn *before* the object behind it. – Xoppa Dec 17 '18 at 23:05

1 Answers1

0

Decal and DecalBatch rely on GroupStrategy for depth sorting, NOT the camera. Additionally, these strategies sort depth EITHER by the distance from the camera OR by only the Z axis, which would required for a perspective camera i.e. a decal that is closer and should occlude as measured by Z, might be further as measured by distance from camera.

i.e. (x,y,z) Camera 0,0,1.

Decal A 1,1,0 (Z distance 1, vector distance 1.73)

Decal B 0,0,-0.1 (Z distance 1.1, vector distance 1.1)

The depth strategy you chose for the above decals could either consider A or B first.

The most common recommended GroupStrategy is CameraGroupStrategy, but this does not sort by Z, but uses camera distance. If you intialise DecalBatch instead with SimpleOrthoGroupStrategy then depth will be sorted purely by Z, here is depth sort for it, you can look at the other group strategies and see its purely absolute distance.

    class Comparator implements java.util.Comparator<Decal> {
        @Override
        public int compare (Decal a, Decal b) {
            if (a.getZ() == b.getZ()) return 0;
            return a.getZ() - b.getZ() < 0 ? -1 : 1;
        }
    }
londonBadger
  • 611
  • 2
  • 5
  • 5