I’m building a particle system in WebGL and rendering them as gl.POINTS.
In that picture above, I’m rendering those two cubes first then rendering my particles. I have depth testing enabled, so there are some particles completely blocked by the cubes, but there are some particles that are only partially blocked by the cubes. This makes sense, as when rendering with gl.POINTS, every fragment for a point gets the same z value.
But this is undesirable, I would rather have the particle be completely rendered or not rendered at all. A logical rule to be followed would be: If the center pixel is visible, render the whole particle. If not, render none of it.
Is it possible to accomplish this in a simple and fast way?
Is manual clipping followed by Z-buffer-less drawing an option?
I mean, after you`ve rendered the scene using Z-buffer, can you clear Z and determine what points are visible and draw the visible part of your particle system above everything?
If not, you still can draw Z-buffer to a texture while rendering the scene, then clear it (leaving the texture filled with the actual Z) and then pass this texture to particles` vertex shader. There you will be able to compare depths and send the point off the frustum if it is does not pass this manual per-vertex depth test.
You need to implement an occlusion query in some form to suppress rendering of sprites for particles which are not visible. Basically, test the depth buffer at the location of the particle first, and then only render the sprite if that position is unoccluded.
There are at least 3 ways to do this (in order of decreasing performance):
Depth buffer readback in sprite shader using adjusted fragment location
Occlusion queries + conditional rendering
Occlusion queries + manual CPU-side readback and selective sprite drawing
What you are asking for will result in popping, which is probably not desirable either - just so you are aware.
But, if you are certain that is what you want, a solution could be manually sampling the depthbuffer from at the center of the particle. If the point is occluded, do not render the particle. There are a number of ways you can do this: use discard in the fragment shader, collapse the vertices from the vertex-shader, or do the depthsampling in the geometry shader and not emit any primitives if the particle is occluded.
Yes, unless you sample some finite area with > 1 sample. Two options (which can be used together):
look at the multiple depth samples within a pixel (if using MSAA) at the center of the particle, and/or
look at the depth samples across a small region of pixels around the center of the particle.
Average the occlusion test results (“not” the depth values; the results of the depth comparison), and use that to set an alpha value (which can be used to drive blend alpha, multisample alpha, or some other form of transparency).