How do I make a z-test shader like this one?

I don’t know much about shaders and not sure what to call the effect but I essentially want to ztest and check if there’s something blocking the view of an object. If so I want to display a flat silhouette of the object with a transparency option. I’ve seen a few examples that render an opaque colour but it’s not quite what I want.

An example can be seen in the Mario + Rabbids game. I don’t know if you can tell in this screenshot.

I’m not sure if i understood what you want, but i guess it’s something like this:

Here’s the shader (I added it to pastebin as well so you can instant view it)

I just created a new standard surface shader and basically copied the CG code to make shaderlab create a seperate pass. As you can see i just set the rendertype and queue to Transparent, removed the shadow tag from the pragma and added the “alpha:blend” tag and added those lines before the “second pass”:

ZTest Greater
Blend SrcAlpha OneMinusSrcAlpha 
ZWrite Off

It will only render the object if the ztest would actually fail. It uses ordinary source alpha blending and disables zwriting (since we only draw on top of existing geometry).

I’ve added another Color property called “_Silhouette” which i used in the second pass as color, The whole surface function for the second pass just consists of

o.Albedo = _Silhouette.rgb;
o.Alpha = _Silhouette.a;

That’s all.

edit
Ok since several overlapping object (or complex objects with overlap) will of course “stack”, we can use the stencil buffer to get a uniform color, even when mutliple objects overlap. However for this we need basically 3 parts:

  • The shader for the actual objects need to write to the stencil buffer in case their ztest fails.
  • Another shader that will only render our silhouette color in the regions the stencil buffer has been set to a certain value
  • We need a script (or any other solution) that renders a full screen quad with the shader from point 2 after the camera has finished rendering.

The result looks like this:

However this approach has other problems if you have self intersecting / overlapping meshes since they can’t be sorted from far to near by unity. This would result in some areas on the character being “shaded” which are not covered by other objects but just by itself. This can’t be prevented with this approach. To fix this you would need to use 3 different shaders. One for occluders and one for the objects that you want to see through the occluders and the fullscreen quad. The drawing order has to be:

  • Objects which should be seen through the occluders
  • Occluders
  • fullscreen quad

The objects would write a value of 1 into the stencil buffer. The occluder shader would have a second pass which only renders if the stencil value is 1 and in that case increment the stencil value. The fullscreen quad would then only shade the areas with a value of 2.

Though this approach heavily limits your flexiblity since you need to enforce a particular rendering order and you have to specifically have a special shader on all occluders. So it would heavily affect the level design.

Thanks. Any idea how I can flatten the geometry into a silhouette?

When you put it on a more complex object than a cube you can see all the geometry overlapping itself. e.g:

Here’s how I’d like it to look: