Hi there and welcome to a new development update. This time I want to talk about skin shading or more generally speaking: sub surface scattering (SSS).
I had already implemented a solution for SSS on a per object basis for quite some time but it required the objects to be rendered in a forward rendering pass while the game now primarily uses deferred rendering. I can’t simply convert the shader to deferred rendering as in this mode the required light information is not available for object shader. As mixing deferred and forward rendering for half transparent objects is already annoying enough I eventually fully switched to deferred rendering for all opaque objects. But this forced me to find a new solution for rendering SSS. From all currently known solutions I chose to use a screen based approach. For now without any depth analysis.
There is one restriction though: it should be possible to mask the SSS effect not only per (sub-) mesh but also per texture. I wanted to be able to avoid splitting models into multiple submeshes just to realise different SSS parameter on a single object. Therefore, before applying the SS-SSS effect, I had to mask not only the required objects but also the affected texels.
But – of course – it didn’t turned out to be that easy. In Unity the usual approach in this case would be to render the scene using a replacement shader to a black and white mask. But this approach would have forced me to create replacements for all possible shader in the game. You can read more about replacement shader in Unity here. In my case it turned out I would have to write additional replacements for all shader doing vertex deformation (e.g. the tessellation shader). Beside their primary task of masking the required objects with a specific colour these replacements have to provide the exact same vertex deformation as the original shader. That would have cost me quite some effort.
Another approach uses the stencil buffer for masking but it can only mask per object/material not per texel. And for deferred rendering it turns out to be nearly useless as the stencil buffer is also used by the deferred renderer itself. Check this out for more in depth info.
To reach my goal I came up with a method to combine both techniques:
First, for each affected screen pixel, the SSS enabled material writes one bit (the only available in deferred mode) to the stencil buffer.
This bit is then read by the SS-SSS full screen shader which discard any pixel where it is not set.
Then I render a 2nd camera (from the same perspective) using shader replacement. By using a ‘replacementTag’ I can make sure to render only objects containing a SSS enabled material.
The replacement shader I use is very simple and just outputs the colour of the object’s SSS-mask texture.
Finally I combine both images to get the required screen space mask for the SS-SSS effect.
One issue still remains with half transparent pixel: They can’t receive a proper stencil buffer flag as they are half-visible but the stencil buffer only knows ‘completely visible’ and ‘completely invisible’. But as mentioned earlier I rarely use them anyway. In the few remaining cases it doesn’t look too wrong as you can hardly tell if the amount of SSS you see through half transparent pixel is ‘too much’ or not.
Thanks for reading and see you soon.
If you know of some new developments let me know!