I recently gave a 15 minute presentation about Real-Time Skin Rendering for my Advanced Graphics Course and I thought maybe I would write up some of the significant bits here. First and foremost this talk was based off of information from 2 sources: Eugene d'Eon and David Luebke's article in GPU Gems 3 about their work on the Human Head Demo, and John Hable's course notes from his presentation on Character Lighting and Shading at Siggraph 2010. Note that all the images in this post are from Hable's presentation.
Skin rendering is notable primarily for the challenges of replicating the subsurface scattering found in human skin. This subsurface scattering creates a vibrant glow of sorts in the diffuse component of the skin, and without it the skin can appear dry and unnatural.
Here's a shot from Hable's presentation of skin rendered with standard Blinn-Phong shading model:
An important comment that Hable makes in his presentation is that the input mesh is very high detail with high detail diffuse color and bump textures, and although the skin appears too rough in the Blinn-Phong model, blurring those is a hack and not a good solution. Rather, modeling subsurface will smooth a lot of the rough feeling in a much more vibrant manner.
NVIDIA calculates subsurface scattering by blurring the irradiance texture that has the diffuse component for the skin. The irradiance texture is split into multiple Gaussians, and then these are blended together to create the final irradiance result.
Here's a shot of the same model and lighting conditions using NVIDIA's approach:
Definitely a huge improvement here. But it comes with the price of a lot of texture reads and writes. In a game that can be a lot for skin rendering on multiple characters. Hable presents the alternatives that Naughty Dog examined to try to find a good middle ground between cost and performance. A single 12-tap blur is used in place of the sum of gaussians for cut scenes in Uncharted 2. Here's what it looks like (the differences are subtle):
I'm not going to go into much detail about the approach that Naughty Dog used during gameplay for Uncharted 2, because it ditches the blurs altogether and uses an approximation created by pretending that the normals for each color channel are bent. It's better than the straight diffuse, and as Hable points out, good enough for a game where most of the time the player only sees the skin on the back of Drake's neck if they're not in a cut scene. Here's a shot of the Blended Normals approach:
This post definitely only skims the surface of real-time skin rendering, and I definitely recommend checking out the NVIDIA article and Hable's presentation if you are thinking of implementing specialized skin shaders. Hopefully sometime in the future I'll be able to find the time to try my own hand at it.