vendredi 6 juillet 2012

Graphics - SSS gone cheap

Subsurface scattering is one of those nice effects that usually are rather expensive.

In  "Approximating Translucency for a Fast, Cheap and Convicing Subsurface Scattering look" , Colin Barré-Brisebois presents a great "trick" to obtain a nice effect at very low cost.
Here, "very low cost" means "approx. 13 ALU" according to him.

I was really fond of the result so I took a couple hours, and implemented it.

See the light scattering through the matter ? (I removed SSAO & shadows for the screenies)

It's forward rendering, but you can also integrate it properly in a deferred rendering pipeline - see the presentation.

So basically, how does it work ?

The scattering part is computed with :

float3 vLTLight =  Ln + Nn * fLTDistortion;
float fLTDot = pow( saturate( dot( Vn, -vLTLight )), iLTPower ) * fLTScale;
float3 fLT = fLightAttenuation * ( fLTDot + fLTAmbient ) * fLTThickness;
result.rgb += diffuseColor * LampColor * fLT;

Most terms are self-explanatory, but notice the fLTThickness parameter : you get it by sampling a "thickness map".

This thickness map is obviously a per object feature, which can be generated at preprocessing stage, either by xNormal (though I haven't tried it yet), or simply by inverting the normals of your mesh and generating the ambient occlusion map (and then negating the resulting map) with your favorite DCC.

Here is a sample for FXComposer, with some hard wired values within the fragment shader (!).