Reputation: 7486
I'd like to draw semi-transparent primitives with GLKit. I already disabled depth testing via glDisable(GL_DEPTH_TEST)
and enabled blending via
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Now for large alpha values (e.g. 0.9), I need to draw the farthest triangles first so they don't appear above nearer triangles. This is also stated in the documentation for glBlendFunc:
Transparency is best implemented using blend function (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) with primitives sorted from farthest to nearest. Note that this transparency calculation does not require the presence of alpha bitplanes in the frame buffer
And in the OpenGL transparency FAQ:
When using depth buffering in an application, you need to be careful about the order in which you render primitives. Fully opaque primitives need to be rendered first, followed by partially opaque primitives in back-to-front order. If you don't render primitives in this order, the primitives, which would otherwise be visible through a partially opaque primitive, might lose the depth test entirely.
But as the viewing angle can change (when I change the render effect's modelViewMatrix
), the farthest-to-nearest order depends on the current viewing angle.
Is there a way to have OpenGL automatically render my primitives in the right order, and if not, what would be the best way to proceed? I think that calculating the z-position of (depending on the current viewing angle) and ordering a few thousand triangles for each frame (or, more precisely, each time the viewing angle changes, which can be each frame) would be too cost intensive, especially as I'd need to push this order to the GPU for each frame.
Note that I'm not concerned with using textures (just colored vertices).
Upvotes: 1
Views: 801
Reputation: 100632
There's no automatic solution because there's no robust real-time solution due to the problem of mutual overlap. If you'll forgive the ASCII art, consider four quads arranged as:
+--+ +--+
| | | |
+---------------------| |------+
| | | |
+---------------------| |------+
| | | |
| | | |
| | | |
+----| |-----------------------+
| | | |
+----| |-----------------------+
| | | |
+--+ +--+
There is no correct ordering. You'd need to split at least one of the quads into two — which is what an ahead-of-time scheme like building a BSP tree would do. That's why depth buffering exists; to solve this problem per-pixel on the basis that most geometry is opaque.
So the best ways to proceed are:
Upvotes: 5
Reputation: 17278
First of all, no, there is no way to have OpenGL do this for you. You'll have to manually sort your transparent geometry, based on the current camera and model position (i.e. the modelview matrix).
To implement this, in real-time implementations you don't usually sort individual triangles, but logical subsets thereof (meshes, submeshes). Problem cases then become:
Performance-wise it is important that, while constructing your scene, you split up your elements in (partially) transparent v.s. non-transparent. This way you avoid large sort operations, as you only need to sort the transparent geometry.
Advanced techniques
For a completely different approach, look up depth peeling and similar techniques. When done right, those techniques have a lot to offer. However, I don't know of any OpenGL ES titles actually implementing them. That doesn't mean it's not an option though.
However...
If you are not very familiar with 3D programming in general yet, I'd strongly advise to stick with the manual sort and try to reduce the artifacts to a minimum. This way you can make an informed decision whether such an implementation is sufficient or not for your particular case.
If nothing else, implementing this stuff will automatically grant you the superhuman ability to immediately spot (and be hugely distracted by) transparency-related rendering issues in every videogame you´ll ever play from now on. A marvelous skill to have.
Upvotes: 4