[Libgdx]Tilemap rendering issue

Hydro, how is that batching? At the very core you’re really just throwing some objects into a list without any rendering order. Doesn’t seem like that really solves the batching issue.

@sh10
Just use the depth buffer in conjunction with an orthographic camera for maximum black magic, but you don’t really need that.
Sorting manually and having multiple batches will sure be fine in your use-case, you do not use ten-thousands of sprites.

In case of rendering Sprites, just set the z value and render in whatever order you want:

You should probably also go have a look at the Sprite class and how it’s solving that problem.

I heard that depth buffer doesn’t work with transparent objects, Is that true ? Also I don’t know how to implement it with my code as I never used it, but it seems to be a good alternative to lower the draw calls.

Depth buffer can handle alpha mapped textures but only if it’s 1-bit alpha, which means a texel can either be fully transparent or fully opaque.
Semi transparent textures is where the depth buffer cannot help you and you need to sort back to front before rendering to get acceptable results.
Depth test can be enabled and disabled via opengl calls or by some handler method in LibGDX,
but you need to adapt your rendering to actually make it work (3D coordinates?).

BUT pls pls pls don’t hack together some dense stuff just to get 0.3ms instead of 0.5ms render time ::slight_smile:
You’re doing yourself a favor if you stick to the “slow” solution in your specific case.

I’d like to go for the easiest solution but it’s supposed to be a mobile game, I wouldn’t care otherwise if there are 50 more draw calls in my scene.
I was using Unity before and even though it’s not the most optimized engine you can get, I remember how crucial it is to lower draw calls if you want to target most android devices with a reasonable framerate.

Another sane option is to use a texture atlas, it’ll eliminate most of the texture switches,
LibGDX can do this automatically or you do it by hand, which might be favorable because you have more control.

I’ll try it yes.
Thank you everyone for your help and explanations :slight_smile:

[quote]Hydro, how is that batching? At the very core you’re really just throwing some objects into a list without any rendering order. Doesn’t seem like that really solves the batching issue.
[/quote]
There is no need for batching like that without translucency. This is handled in the shaders, and if you aren’t going to do it in the shaders, you could do it some order method. I prefer shaders. I don’t use blending using opengl. I just discard if it is completely translucent. On top of that, my texture support and indication byte, which lets me enable face culling in a neat method.

As for 2D, the way I order it is manually. 2D is only for GUIs. In OP’s specific case, he needs to load up just his Entities into the preexisting 2D batch. After, he needs to create another Entity which manages tile portions to draw. The static terrain portion is then rendered 9 times, or to liking, to cover the screen area in a proper manor. As far as texture go, you texture atlas.

So I tried to implement a sorting list on the Y axis, I also added a Z value but I can’t manage to sort things right… Let me explain :

http://image.noelshack.com/fichiers/2016/25/1466935336-grid.png

(note: white cells are tiles in the object layer, blue ones in the top layer)

Each cell contains a row index (from bottom to top), which is used as Y. If I sort entities & tiles with this Y value (descending order), the issue I had is fixed. When a player is at the row 4, it will be drawn after every blue tiles, which is exactly what I wanted.
Now imagine the blue cells as the top part of a tree and the player at row 5 (supposed to be behind the tree), it will be rendered behind the tiles at row 5 which is good, but the head of the character will be drawn in front of the rows 6 and 7 (as they have a higher Y value), which is problematic.
The Y value isn’t enough, so I added a Z member. Each drawable object (entities and tiles) sets their Z value as the index of the layer. 1 for object layer, 2 for top layer.
If I add this value to Y (getY() + getZ()) for the priority, it will not work.
Here’s a video showing what I’d like to achieve :

_Uu5qYXusek

Any idea ?

Check this: http://gamedev.stackexchange.com/a/8355
His “closer” function is what you need to use to sort for rendering,
but use only Y and Z in the nearness function.

function nearness(obj) {
    return obj.y + obj.z;
}

function closer(a, b) {
    if (nearness(a) > nearness(b)) {
        return "a";
    } else {
        return "b";
    }
}

You only need to take Y and Z (depth and height) into account, because your X-axis is parallel to the screen.

I hope the math is right, but you get the direction. ;D

Edit: this does only work for isometric games like shown in the article, so not in your case

That won’t work. If I add the Z value to Y the same problem will happen if a tree contains several rows in the top layer, the head will never be rendered behind the second or third row.

I sketched it, yes, seems like it’s only working for an isometric game.
Have you tried just sorting like this:

Tile getCloser(Tile a, Tile b) {
    if (a.y < b.y) {
        return a;
    } else if (b.y < a.y){
        return b;
    } else if(a.z > b.z) {
        return a;
    } else {
        return b;
    }
}

bigger y => farther away from camera, bigger z => higher layer

if getCloser(a,b) returns a, that means you should render a after b, because a is “closer” to the camera.

Sort rows by depth, items within each row by height.

Tiles need to be equal size and height for this to work!

It doesn’t work when the player needs to be drawn in front of the tree:

http://image.noelshack.com/fichiers/2016/25/1466962265-in-front.png

But it works when the player is behind :

http://image.noelshack.com/fichiers/2016/25/1466962272-behind.png

The solution from above will work correctly, the player has a lower y value (y=2) than any part of the tree (y=3,4,5,…,8).
That means he’ll be rendered in front of the tree in the first picture and behind it in the second (if you use the sorting formula i posted last).

Did you actually implement the sorting :cranky:
Edit: Also keep in mind that you need to sort everything together, it won’t work otherwise.

Sorry, actually I misread your post and I thought A had to be drawn before B when A is returned. Thanks :slight_smile:

Hello, it’s me again ;D

Here’s my edited code :

MapDrawable is a shared interface between Tiles and Entities

public interface MapDrawable {
    float getX();
    float getY();
    float getWidth();
    float getHeight();
    int getLayer();
    TileMap getTileMap();
    void setTileMap(TileMap tileMap);
    void draw(Batch batch);
}

in my TileMap class I created a comparator :


static final Comparator<MapDrawable> closerComparator = new Comparator<MapDrawable>() {
    @Override
    public int compare(MapDrawable a, MapDrawable b) {
        if(a.getY() != b.getY())
            return (a.getY() < b.getY()) ? 1 : -1;
        if(a.getLayer() != b.getLayer())
            return (a.getLayer() < b.getLayer()) ? -1 : 1;
        return 0;
    }
};

The rendering part :


renderQueue.clear();

// add tiles in render queue
enqueueLayer(LOWER_LAYER, getLayer(LOWER_LAYER));
enqueueLayer(UPPER_LAYER, getLayer(UPPER_LAYER));

// add other drawables (entities)
renderQueue.addAll(drawables);

// sort drawables
renderQueue.sort(closerComparator);

batch.begin();
// draw terrain layer first, not affected by rendering order with entities
drawStaticLayer(batch, getLayer(TERRAIN_LAYER));
for(MapDrawable drawable : renderQueue) {
    drawable.draw(batch);
}
batch.end();

But I don’t get this part :

Everything is sorted by rows then by depth, what’s this height ? The height of tiles&entities ?
It’s still not working so I guess I’m missing something.

height = layer index
depth = row index

The compare function seems right, have you tried inverting the 1 and -1 in both return calls?

static final Comparator<MapDrawable> closerComparator = new Comparator<MapDrawable>() {
    @Override
    public int compare(MapDrawable a, MapDrawable b) {
        if(a.getY() != b.getY())
            return (a.getY() < b.getY()) ? -1 : 1;
        if(a.getLayer() != b.getLayer())
            return (a.getLayer() < b.getLayer()) ? 1 : -1;
        return 0;
    }
};

That’s the result I get with the current code :

http://image.noelshack.com/fichiers/2016/26/1467127593-in-front.png

http://image.noelshack.com/fichiers/2016/26/1467127599-behind.png

I created a pastebin with the whole code if you want to try it :
http://pastebin.com/8qM3daNk

I’m done here ;D
The sorting algorithm sorts in world space (google it), that means the top and the bottom of the tree need to have the same y-coordinate for correct sorting.

But that wouldn’t display right, so you need to shift the layer up along y by adding the layer id to the y coordinate (if layer 0 is ground).
This means shifting the tree-top up along the y-axis is done after sorting and before/while rendering.

[OR you shift in the sorting function, but that’s kinda ugly and backwards]

Another thing, is your player made up of 4x2 sprites? that means you need at least 4 layers for correct display ::slight_smile: