2
$\begingroup$

I need something to be cleared up for me, and I hope this is the right place to ask my question:

I intend to attempt stochastic transparency, where I will draw glass panes and smoke particles onto the g-buffer for deferred shading. For every 2x2 cell of pixels, I will allow up to 3 of the 4 pixels to be used for glass or smoke. The last pixel is always the opaque background. But say we have this situation:

  • Camera
  • (Near clip plane)
  • Smoke particle
  • Glass pane
  • Solid wall
  • (Far clip plane)

The smoke particle is in front of the glass pane, and would occupy all 3 pixels. This I do not want, and therefore I will need to check whether neighbouring pixels in that 2x2 cell already have 'smoke' or 'glass' written to them, rather than just the simple Z-check.

I therefore wish to sample neighbouring pixels from the same g-buffer that I'm currently writing to, but this seems not possible, am I right? And why do the depth & stencil buffers seem to be exceptions to this, or does this have something to do with only reading the exact pixel you are about to write to?

I hope the way I formulated the question(s) make sense, and is sufficiently detailed.

$\endgroup$

1 Answer 1

3
$\begingroup$

In general you can't safely read from neighboring pixels in the render target you're currently writing to. You can sample from them, but there's no guarantees about how other pixels are scheduled on the GPU, so it's a race condition—you might get the neighboring pixel value either before or after modification, and it might change frame to frame due to unpredictable scheduling differences.

You can read from the same pixel you're about to write to, but only if your geometry is set up to ensure that nothing is overlapping in screen space (e.g. a full-screen pass). If other triangles in the same render pass are overlapping the same area on screen, then you have a race condition again, similar to the neighboring-pixels case. (You can use fragment_shader_interlock or equivalent functionality to address this case, but it is not universally supported across all GPU vendors, and it can also be slow.)

The depth and stencil buffers, as well as fixed-function blending (additive, alpha, etc) can get around this because they have special-purpose hardware that sorts the fragments in submission order in order to apply those simple fixed operations.

I believe the way stochastic transparency usually works is to randomize the set of pixels output and use spatial/temporal filtering to clean up the noise afterward. So you wouldn't have such fine-grained control like "within each 2x2 block, there will be N pixels of this, and M pixels of that". It would be more probablistic, like "on average, X% of the pixels will be this, and Y% of the pixels will be that", with the exact outputs being randomly chosen each frame.

$\endgroup$
1
  • 1
    $\begingroup$ Thank you for your answer. I guess I do not need any more than the details you have provided. And regarding using noise for the stochastic transparency: Yes that is correct, however I have not managed to create a filter that can tidy up the image sufficiently, so I hoped I might get around that by coming up with something like the 2x2 block thing that could work. (I will now move on to plan B: using some kind of spatial hashing function for the noise so that the sample distribution becomes more favorable for the filtering process.) $\endgroup$
    – MrDropC
    Mar 14, 2021 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.