Hey everyone, I have this simple transparency shader and I was wondering if it is possible for a shader to draw itself as opaque if there are 3 or more objects in front of it.
In the image, the area where all three orange blocks overlap isn’t completely opaque but it might as well be. I’m hoping I can save a little on performance if I can prevent rendering anything that is behind 3 levels deep of transparency.
It’s not a very easy thing to achieve. You can look into order-independent transparency, but I don’t think it’s a thing for people very new to shaders
When you’re rendering something, the shader has no information of what’s behind or in the front of the pixel being rendered.
One thing to understand is transparent objects render back to front. That is the objects further away render first. This is to ensure the correct draw order of transparent objects. Think of it like putting down stickers on a piece of paper; you have to put down the ones in the “back” first because you can’t put stickers behind them afterwards with out ripping them off and damaging the paper or the sticker. So you can’t make the transparent object in the back opaque based on stuff that’s in front since what’s in front hasn’t been rendered yet.
Now it is possible to render front to back transparency and to use stencils to cull drawing after enough layers have rendered. But to do that requires rendering all transparencies to an off screen buffer and using destination alpha and the scene depth buffer to composite. Then using an incrementing stencil to skip rendering after some threshold. Then composite that buffer back into the main frame buffer. This is a technique I believe the RedLynx Trials games used on their early titles, but I don’t believe they use anymore.
If the above paragraph sounds like gibberish to you, it is not something I would recommend you get into yet.
Thanks for the explanations. The first part was familiar, things I’ve forgotten.
Front to back rendering sounds like a fun thing to try but perhaps an experiment for another time. The effort involved to avoid overdraw sounds like it won’t be practical to venture into and may not even save the performance I’m looking for.
In the left configuration, the red glass doesn’t look transparent at all. Why is that so? The render order of the objects is red then green then blue. When red is rendered, the Z-values in the depth buffer are set and no fragment from another triangle with a farther away Z-value will be rendered at all. So there is no chance to blend green and blue because their fragments are discarded before blending.
In the center configuration, depth testing has been artificially turned off. First red is rendered with nothing to blend it with since it is the first thing rendered. Then green is rendered and blended and blue is rendered and blended. Each time the new object will take 50% of itself and 50% from the already rendered objects, so at the time blue is rendered, only 25% of red will be left.
Nice visual representation Seyed, it looks like Front to Back as presented wouldn’t be desirable in my case either. Which brings even more clarity to me about the technique bgolus was referring to.
I also looked at order-independent transparency but that didn’t quite look like what I would need.
If only I could know how many things there are waiting to be rendered over the same pixel and how many have already been to save on performance when I have 10 transparent objects overlapping each other so all 10 wouldn’t have to blend.
Actually, the advanced technique I was describing would look exactly like back to front sorting, but use front to back. Unfortunately the presentation I remember it being detailed in was difficult to find last time I looked a few years ago, and has now completely disappeared from the web as far as I can tell. I had a copy of it on my old work computer at my last job, but I forgot to grab it before I left.
However, I did find this post which describes a similar base technique:
Augment that technique with using the stencil buffer like this:
Stencil {
Ref 255
Comp NotEqual
Pass IncrSat
}
Change 255 to any value between 1 and 255 to set the number of layers to render before skipping.
Cool, that’s what I thought. What I was trying to say was normal front-to-back wouldn’t be right but that plus stencils might. (I also thought stencil was a metaphor )
That stencil thing is pretty sweet. Even with testing normal back to front I can see how it prevents rendering and blending of additional surfaces.
Yeah, it’s an interesting technique. But it comes at the cost of needing a second framebuffer with a full fat depth buffer since only 24 bit depth buffers have a stencil, and you can’t use the stencil buffer for anything else.
Usually it’s easier and more efficient to just avoid that much overdraw manually or possibly use some kind of two pass technique. For the case you presented of solid color polygons you’ll need a lot of overdraw before it’s really an issue.
Unfortunately for me, my game is pretty much nothing but overdraw. It runs pretty well for the most part thanks to simple geometry but there are some instances were it chugs.
Perhaps I can save on performance by using a solid material for objects that are far away from the player and then switching the material when the player gets close enough. Hopefully I can avoid it looking weird if I also apply the transparency over time instead of just hot swapping it out.
You could look into rendering to a buffer that’s smaller, this should save you a ton of performance at cost of being lower resolution. Primitive, but always works well. Jason Booth has an asset on asset store for this for free.