Is it possible to test if a material is currently visible? I have a shader that places a red outline material around an object when part of it is hidden behind another object. If I can test if the material is currently rendered then i would know if the object is partially obstructed from view.
No built-in way.
First you need to deeply consider whether finding out if a material is rendered is the actual solution to your problem, maybe there’s some simpler alternative. If it is, then one way to do this is to make a fullscreen render pass that renders only the hidden part of your object (same thing your shader does).
The purpose of this is to get you an image that’s all black, but the hidden parts of the object are drawn in pure white. Once you have this image, all you need to do is determine whether there’s any white pixel on it. You can do this by downsampling the image to half its size, taking each group of 4 pixels and outputting a white pixel in the downsampled image if any of the 4 are white. Do this multiple times, halving the size of the image each time. Ultimately you’ll get a 1x1 image, either black or white. If it’s white, it means your object was partially (or completely) obstructed.
This method is quite similar to how you get an average luminance value for the entire screen for HDR tone mapping w/auto exposure, btw. It’s quite advanced stuff however, so there’s a chance everything I said sounds like chinese to you… if that’s the case, don’t fret! there’s lots of things to learn in graphics and it takes time.
Thanks for your time. I figured it wouldn’t be easy, just wanted to make sure there wasn’t a built in way to check that I was missing.
There is Renderer.isVisible, but that’s not going to work for your use-case. That also returns true if the object is rendered into a shadow map. Also, occlusion culling is conservative, so it may return false positives.
I would try something like this, similiar to what arkano said. For simplicity, let’s assume only certain types of objects can get this outline:
- Render scene as usual
- Render all the potentially obstructed objects into a render texture with a special shader if they’ve passed frustum culling test: The special pixel shader compares the current depth (SV_Depth or SV_Position.z) with the depth from the depth buffer (_CameraDepthTexture). If it is different, it returns 1, otherwise 0. Blend mode should be MAX. You can use a material override to do that (see CommandBuffer.DrawRenderer or CommandBuffer.DrawRendererList).
- Write a post-processing effect which uses the mask to create an outline
PS: You might even be able to use the stencil buffer for this. Set it up so that a stencil value of 1 gets written whenever a fragment fails the depth test.
Just to give you another option: Once you have a render texture that contains the pixels that determine the partially obstructed parts of your object, instead of the downsampling approach I initially suggested you could also use a compute shader to count the amount of “white” pixels in your texture: using atomic increments in group-shared memory. Again, this is quite advanced stuff but one route that’s worth exploring imho.