12
\$\begingroup\$

Note: I've already found an answer (which I will post after this question) - I was just wondering if I was doing it right, or if there is a better way.

I'm making a "2.5D" isometric game using OpenGL ES (JOGL). By "2.5D", I mean that the world is 3D, but it is rendered using 2D isometric tiles.

The original problem I had to solve was that my textures had to be rendered in order (from back to front), so that the tiles overlapped properly to create the proper effect. After some reading, I quickly realised that this is the "old hat" 2D approach. This became difficult to do efficiently, since the 3D world can be modified by the player (so stuff can appear anywhere in 3D space) - so it seemed logical that I take advantage of the depth buffer. This meant that I didn't have to worry about rendering stuff in the correct order.

However, I faced a problem. If you use GL_DEPTH_TEST and GL_BLEND together, it creates an effect where objects are blended with the background before they are "sorted" by z order (meaning that you get a weird kind of overlap where the transparency should be).

transparency overlap problem

Here's some pseudo code that should illustrate the problem (incidentally, I'm using libgdx for Android).

create() {
    // ...
    // some other code here
    // ...

    Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
    Gdx.gl.glEnable(GL10.GL_BLEND);
}

render() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

    // ...
    // bind texture and create vertices
    // ...
}

So the question is: How do I solve the transparency overlap problem?

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Just a comment to tell you that I have gone exactly the same way as you for my 2D engine: first trying to be clever and Z-sort tiles myself, then realising there was no reason the scene should be flat, thus giving my tiles a Z coordinate and activating alpha test. Not sure whether you’re right, but you’re not alone :-) \$\endgroup\$ Commented Mar 11, 2011 at 0:51

2 Answers 2

7
\$\begingroup\$

OK, so here's my solution (please comment if it can be done better)...

Turns out that I should in fact be using alpha testing (though, I discovered this by accident, so I'm not entirely sure why it works).

create() {
    // ...
    // some other code here
    // ...

    Gdx.gl.glEnable(GL10.GL_DEPTH_TEST);
    Gdx.gl.glEnable(GL10.GL_ALPHA_TEST);
}

render() {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    Gdx.gl10.glAlphaFunc(GL10.GL_GREATER, 0);

    // ...
    // bind texture and create vertices
    // ...
}

Note the use of GL_ALPHA_TEST, and glAlphaFunc.

\$\endgroup\$
1
  • \$\begingroup\$ It solved my problem too. Thanks for sharing. You are great \$\endgroup\$
    – Mathlover
    Commented Jan 12, 2014 at 21:37
2
\$\begingroup\$

Alpha testing is used to stop the renderer drawing pixels to any buffer, including the z buffer. Alpha blending is just a visual thing - values are still written to the zbuffer, which can result in problems like this - invisible pixels are infront of subsequently rendered pixels which means they'll fail the ztest when you draw the new pixels. This is what you can see in the image you gave, a ztest fail.

Switching off z writing will also achieve the same ends but you have to ensure you draw everything int back to front order. This should be easy enough to do in your isometric game.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I think that drawing stuff from back to front is easy in a 2D iso game only when you have a fixed Y plane, and the designer is in full control of the world. However, when stuff can exist anywhere in 3D space, and you allow the user to change stuff, it becomes more complicated. I think using the depth buffer will make my life a lot easier. \$\endgroup\$ Commented Mar 10, 2011 at 16:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .