3

From one angle my shrubs look like this:

From the other, they look like this:

My theory is that when looking at the shrubs from the first angle, all the blocks behind the shrub have already been drawn, so when it comes to draw the shrub, it just draws them overtop.

From the other angle, however, it's basically trying to draw the shrub first, and then when it goes to draw the block behind the shrub, it checks the depth buffer and sees that there's something already blocking the view of the block, so it doesn't render it, causing the navy blue squares (my clear color).

I really have no idea how to fix this issue though. Disabling the depth test causes all kinds of other errors. Is there some way to flag the vertex or polygon as having transparency so that it knows it still needs to render what's behind?


Found this. Is this the only solution? To separate my transparent and opaque blocks, and then manually sort them on the CPU pretty much every single frame because the player can move around? There has to be a way to delegate this to the GPU...

Community
  • 1
  • 1
mpen
  • 272,448
  • 266
  • 850
  • 1,236

3 Answers3

10

That link (and sorting on CPU) is for alpha blending. If you need only Alpha Testing (not Blending), then you don't need to sort anything. Just enable alpha test, keeping depth test enabled, and everything will be rendered fine.

See here: http://www.opengl.org/wiki/Transparency_Sorting You need "Alpha test" that requires alpha testing, not "Standard translucent" that requires sorting.

Mārtiņš Možeiko
  • 12,733
  • 2
  • 45
  • 45
  • Enabling alpha testing will cause it to use `glAlphaFunc`, right? What function should I be using then? The default doesn't seem to work. "not equal" almost works, except when looking directly from the side: http://i.imgur.com/HMhSu.png – mpen Feb 19 '12 at 21:35
  • @Martins: Nvm. Your article explains it pretty well. I'll have to deal with translucency later, but I guess I'll cross that bridge in a bit. – mpen Feb 19 '12 at 21:58
  • 1
    Man, you are my savior!!! I've been battling this issue for 48 hours straight, and in the end it was just two line of code to solve it... Thank you, I would give you money if I could lol. Thank you. – user2758776 Jul 05 '19 at 22:02
3

If you're in WebGL or OpenGL ES 2.0 (iPhone/Android) there is no alpha testing. Instead you need to not draw transparent pixels. That way they won't affect the depth buffer since no pixel was written. To do that you need to discard pixels that are transparent in your fragment shader. You could hard code it

...
void main() {
   vec4 color = texture2D(u_someSampler, v_someUVs);
   if (color.a == 0.0) {
     discard;
   }
   gl_FragColor = color;
}

or you could simulate the old style alpha testing where you can set the alpha value

...
uniform float u_alphaTest;
void main() {
   vec4 color = texture2D(u_someSampler, v_someUVs);
   if (color.a < u_alphaTest) {
     discard;
   }
   gl_FragColor = color;
}
gman
  • 100,619
  • 31
  • 269
  • 393
3

Solution #1:

  1. Render all non-transparent objects first in any order, depth buffer enabled. That includes all objects that use alpha testing without alpha blending.
  2. For glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) objects (smoke/glass/grass): Render transparent scene from furthest polygon to nearest polygon with depth buffer write disabled (glDepthMask(GL_FALSE)). If all transparent objects are convex and do not intersect, you can sort objects instead of polygons.
  3. For glBlendFunc(GL_SRC_ALPHA, GL_ONE) and glBlend(GL_ONE, GL_ONE) (fire, "magic" particle systems, glow): Render transparent scene in any order with depth buffer write (glDepthMask(GL_FALSE)) disabled.
  4. Do not render any depth-buffer enabled objects after step #3.

Solution #2:
Use depth-peeling (google it). Especially if transparent objects intersect each other. Not suitable for particle systems and grass, which require Solution #1.


and then manually sort them on the CPU pretty much every single frame

Insertion sort works great for already sorted or partially sorted data.

There has to be a way to delegate this to the GPU...

I think you can generate grass polygons (in correct order) in geometry shader using texture that has a channel (say, alpha), that marks areas with and without grass. Requires OpenGL 4, and you probably will have to perform some kind of higher-level sorting for polygons you'll feed to shader to generate grass patches.

Individual shrubs can be rotated in vertex shader (by +- 90/180/270 degrees) to maintain correct polygon ordering if they're perfectly symmetrical in all directions.

And there's merge sort algorithm that parallelizes well and can be performed on GPU, using either GDGPU approach or OpenCL/CUDA.

However, using something like that to render 5 shrubs of grass is roughly equivalent to trying to kill a cockroach with grenade launcher - fun thing to do, but not exactly efficient.

I suggest to forget about "offloading it to GPU" until you actually run into performance problem. Use profilers and always measure before optimizing, otherwise you'll waste large amount of development time doing unnecessary optimizations.

SigTerm
  • 26,089
  • 6
  • 66
  • 115
  • Hah! I remember learning about sorting algorithms and thinking "when am I ever going to know beforehand that my data is already *mostly sorted*? Finally, a use-case. I'm going to dig into this deeper. Thanks for the step-by-step, very helpful. – mpen Feb 19 '12 at 22:27
  • The shrubs aren't really an issue, especially since I can render them with alpha testing, but it's big bodies of water that concern me. Those have translucency, so I'll have to sort them. Fortunately, I guess it's just the surface polygons that need sorting. I'll try it out and see how well it works. By "delegate to the GPU" I was thinking more along the lines of doing a single render pass first, and then collecting data back about their distances, similar to what this guy does: http://rastergrid.com/blog/2010/02/instance-culling-using-geometry-shaders/ – mpen Feb 19 '12 at 22:42
  • @Mark: Unless you have VERY big waves, you don't need to sort water, because it is flat, so you can render it all in one go. For non-flat water, you still normally don't need to sort it, just render it after everything that is non-transparent. Of course, if you're making walls out of it, there's a problem and it will need sorting. – SigTerm Feb 19 '12 at 23:28
  • Every play Minecraft? That's exactly what people do with water >. – mpen Feb 20 '12 at 00:12
  • 1
    @Mark: "Every play Minecraft?" No. You might want to check out [sauerbraten](http://sauerbraten.org/), though (comes with source code). – SigTerm Feb 20 '12 at 04:25
  • Could you please explain why do we need to disable depth buffer write if we draw polygons from furthest to nearest anyway? – parean Aug 26 '22 at 18:47
  • @Oroffe This answer is 10 years old. Because transparent objects can still intersect each other. When you have multiple particle systems, normally you do not sort all particles in the world at the same time, because normally you CAN'T draw them all in a single pass. That means if you have a fog particle system and draw it sorted with depth write enabled, it will look fine. When you add a fire particle system in the same area, however, it will no longer look fine and will be clipped by depth information left by fog particles. So, as a rule of the thumb, no depth write for transparency – SigTerm Sep 05 '22 at 05:58