There are a couple of common development challenges which affect all games that make use of third person cameras :-
Most games solve these by using dynamic camera systems which actively avoids clipping by pushing or rotating away from environmental geometry, keeping the player character in view at all times.
For our game Recompile, it was an important goal for us to not go down this route of using automatic camera forces. We wanted to solve the problems above without ever taking control of the camera away from the player.
Firstly, the player character is rendered normally. Then, we render it again, using a different shader that makes use of ShaderLab's Depth Testing. Here, we use the ZTest Greater syntax to specify that this material should only be drawn if it is occluded by other geometry.
The SubShader's queue tag must be one less than what the character is normally rendered at, so that we don't run into any self-occlusion issues (if the character's geometry occludes itself). In our case, our character is normally rendered in the Transparent queue, so for this shader we will use the Transparent-1 queue.
To differentiate it from the non-occluded character, the occluded portions are rendered in a slightly darker color with minimal bloom.
A more traditional occluded style could be used instead, such as an outline shader - the ZTest remains the same regardless of the visual output.
We still have the problem of environmental geometry covering the screen, or worse, intersecting with the camera resulting in a mess of clipped polygons.
The solution is to smoothly and seamlessly fade out any geometry that is too close to the camera. Instead of semi-transparency, we prefer to use a dithered alpha cutout which is great for performance as it saves on overdraw and better fits the art style of our game.
In the shader's vertex function, we calculate the amount of dithering applied to the object using its world space distance from the camera.
So then we can smoothly fade out the dithering the closer the camera approaches the occluding object.
In this case, the dithering starts at 2 units and fades out completely at 0.1 units.
In the shader's fragment/surface function, we use a screen space texture to apply the alpha cutout, using our previous dither value from the vertex function as our threshold. The built-in clip() function is the best way to accomplish this, as it completely disables rendering of that fragment.
See Unity's Surface Shader Examples for more info on screen space textures and cutouts.
For a traditional dithered look, you could use a Bayer Matrix texture to control the alpha cutout.
However, we prefer this blue noise texture instead as it is more natural looking and doesn't suffer from obvious repetition.
The result is a more gradual, dithered clipping effect, smoothly fading out as the camera passes through the object.
Combining the two techniques results in a character that is always visible, and camera clipped geometry that smoothly fades out, never obscuring your view. All whilst retaining complete manual camera control for the player.
Recompile is an atmospheric action exploration game, combining 3D precision platforming, intense combat and environmental hacking mechanics.
Found out more about the game's development on Twitter. Thank you for reading!