Presentation is loading. Please wait.

Presentation is loading. Please wait.

Cheap Realistic Skin Shading

Similar presentations

Presentation on theme: "Cheap Realistic Skin Shading"— Presentation transcript:

1 Cheap Realistic Skin Shading
Stephen Clement

2 Overview Popular Skin Models New Skin Model Ideas BRDF Layers
Back Scattering Blended Normals Shadows Extras Results Conclusion

3 Popular Skin Models

4 Popular Skin Models Red wrapped lighting Texture-space diffusion
Texture-space diffusion Texture-space diffusion (12-tap) Advanced RealTime Rendering Course).pptx Screen-space diffusion Blended Normals Offline “Fast-Skin Shaders”

5 Popular Skin Models (cont.)
The diffusion approximation techniques are the most popular when it comes to high-fidelity realism. Each model is in the extremes. Either extremely cheap/poor approximation or really good/expensive. Wrapped lighting can work in practice but fails in sharp lighting. Need a good alternative that’s somewhere in the middle. Has to be cheap but still look up-to-par.

6 New Skin Model

7 New Skin Model Trick is to improvise!
Perceptual rendering, not physical. Doesn’t have to be correct, just has to look good. Use core concepts of different techniques to approximate. Simulate multiple layers. Use a good (physically based) BRDF. Approximate common visual properties. Red bleeding on shadow edges. Soft appearance. Harsh falloff.

8 New Skin Model - Ideas Use concepts from other models.
Use Kelemen/Szirmay-Kalos BRDF. Looks great. Can be relatively cheap with proper optimizations. Simulate “Fast-Skin Shaders” Multiple layers. Each layer has it’s own texture (epidermal, subdermal). Epidermal layer is blurred lightly. Subdermal layer is blurred a lot. Diffuse is not blurred at all. Sum the layers at the end. Soften normal map using blended normals. Gives soft look without washing out lighting.

9 New Skin Model - BRDF Kelemen/Szirmay-Kalos BRDF Optimizations.
Save beckmann distribution to texture. Saves a crap-load of instructions. Save fresnel to texture. Math version may be cheaper depending on the system. Why use just 1 specular term? You can have 4 channels in your beckmann texture. Why not use them? Calculate the shader as usual but use a 4-value float instead. Weigh them at the end using a simple dot product. Additional cost isn’t very high and you get good varied specularities.  Use energy conservation if you think it’ll help.

10 New Skin Model – BRDF (Code)
Code modified from NVIDIA’s implementation. Don’t use these textures, compute them yourself for better precision. // Computes beckmann distribution // To bake to texture: texCoord.x = NdotH, texCoord.y = Exp float4 GetBeckmannDistribution( float NdotH, float Exp ) { // Some roughness weights float4 m = half4(1, 0.12, 0.023, 0.012) * (Exp * Exp); float alpha = acos( NdotH ); float ta = tan( alpha ); float4 val = 1.0 / (m * pow(NdotH, 4.0)) * exp(-(ta * ta) / m);    // Scale the value to fit within [0-1]       return 0.5 * pow(  val , 0.1 );   } // Computes fresnel reflectance (can be computed on the fly no problem) // To bake to texture: HdotV = texCoord.x, texCoord.y = F0 float GetFresnelKS( float3 HdotV, float F0 ) { float base = HdotV; float exponential = pow( base, 5.0 ); return exponential + F0 * ( exponential ); }

11 New Skin Model – BRDF (Code)
float KelemenSzirmayTex( float3 N, float3 L, float3 V, float Exp, float F0 ) { // Pretty straightforward float NdotL = saturate(dot(N, L)); float h = L + V; float H = normalize(h); float HdotV = dot(H, V); // Get fresnel from texture; is a good value for F0 float fFresnel = tex2D(fresnelTex, float2(HdotV, F0)); // float fFresnel = GetFresnelKS(HdotV, F0 ); // Math version. // Get beckmann distributions from texture float4 fBeckmann = pow(2.0 * tex2D(beckmannSampler, float2(NdotH, Exp)), 10); float4 fSpec = max( (fBeckmann * fFresnel) / dot( h, h ), 0 ); // Weight results using dot product float result = saturate( NdotL ) * dot(fSpec, half4(1.0, 0.625, 0.075, 0.005)); return result; }

12 New Skin Model – BRDF (Result)
(Image intensified for clarity)

13 New Skin Model - Layers Simulating multiple layers.
Create new textures for each layer. Can be simulated using diffuse map with simple color operations in real-time. Use mip-map for subdermal map (should be blurrier than others). May actually be cheaper than using normal textures, depending on the resolution. Light each layer. Instead of blurring, just use lightly wrapped lighting for each layer. No wrapping for diffuse layer. ~0.8 – 0.9 for epidermal. ~0.7 – 0.8 for subdermal. Don’t wrap too much! You’ll get ugly ambient like the standard wrap method. Apply lighting to each texture and weigh accordingly. Make sure the result equals 1! Good values: Epidermal = 0.3, Subdermal = 0.2, Diffuse = 0.5

14 New Skin Model – Layers (Textures)
Diffuse Epidermal Subdermal Back Scattering Specular Normal

15 New Skin Model – Layers (Image)

16 New Skin Model – Back Scattering
Extremely simple. Just a few calculations with N·L. Mask by translucency texture. Store in subdermal map alpha channel. Alternatively, use vertex colors/alpha for mask. Use non-sharpened shadows. Soft shadows let the backscattering through more. Other techniques can be used instead. Translucent shadow maps. Issues: Might not properly be occluded in a shadowed area. Technique still needs work (incomplete).

17 New Skin Model – Back Scattering (Code)
float3 BackLighting(float3 lightColor, float NdotL, float shadowMap, float transTex) { // Calculate back scattering. float backLight = lerp(NdotL, 1.0, transTex) - lerp(NdotL, 1.0, 0.4); float3 result = saturate(backLight) * lightColor * shadowMap * backScatterStrength * backScatterColor; return result; }

18 New Skin Model – Back Scattering (Image)

19 New Skin Model – Blended Normals
Use blended normals to soften bump-mapping. Calculate N·L for vertex normals and bumped normals. Blend between them with different strengths for different color channels. Use “lerp(0.0, max, intensity)” for intensity of each channel Prevents perfectly smooth normals (we don’t want those). Good values for max: Red = 0.5 – 0.7 Green/Blue = 0.15 – 0.4 Intensity is contstant for all 0-1 Use new value for N·L for diffuse lighting.

20 New Skin Model – Blended Normals (Code)
float3 BlendNormals(float lightDiffusion, float vertexNdotL, float bumpNdotL, float3 lightPos) { // Tweak max values as you see fit. float redIntensity = lerp(0.0f, 0.6f, skinDiffusionAmount); float greenBlueIntensity = lerp(0.0f, 0.4f, skinDiffusionAmount); float red = lerp(vertexNdotL, bumpNdotL, redIntensity); float greenBlue = lerp(vertexNdotL, bumpNdotL, greenBlueIntensity); greenBlue = min(red, greenBlue); // remove unwanted green/blue // Put it all together. float3 result = float3(red, greenBlue.xx); return saturate(result); }

21 New Skin Model – Blended Normals (Image)

22 New Skin Model – Shadows
Need to compensate for not including shadows in diffusion process. 2 Options: Blur shadow map for each layer. Blurring shadow maps is expensive. Gets worse if done per-object. Cheat. Instead of blurring the shadow maps for each layer, sharpen them. 

23 New Skin Model - Shadows (cont.)
Sharpening shadows. Use pow() function to sharpen shadows. Subdermal shadow has no pow() applied. Epidermal has small pow() applied (~2-4). Diffuse has huge pow() applied (~8-16). Assumes soft shadows. Should be relatively soft/jittered/blurred. Don’t forget to compensate for the sharper shadow when applying shadows to specular! Otherwise you’ll get specularity bleeding into shadowed areas. Mileage may vary (depends on shadow map, scale of object, etc).

24 New Skin Model - Shadows (cont.)
Blended Shadows. Simply varying the sharpness of the shadows for each layer might not give enough bleeding color (artistic preference). Take idea from blended normals . Calculate 2 different powers for the shadow map. Blend between them for red and green/blue channels. This gives a nice red edge. Desaturate if the edge is too red. Make difference higher for subdermal layer (1 – 2). Make difference lower for epidermal layer (4 – 8). Make them both exactly the same for diffuse ( 16 – 16). Can be ignored if results were already good.

25 New Skin Model – Shadows (Code)
float3 BlendShadows(float2 shadowPow, float shadowMap) { // Calculate 2 different power factors. float shadowR = pow(shadowMap, shadowPow.x); float shadowGB = pow(shadowMap, shadowPow.y); // Blend shadows float red = lerp(shadowGB, shadowR, skinDiffusionAmount); float greenBlue = lerp(shadowGB, shadowR, skinDiffusionAmount * 0.5); float3 result = float3( red, greenBlue.xx ); // Result may be a bit too red, desaturate it a bit. result = lerp(result, dot(result, float3(0.33, 0.59, 0.11)), 0.75); return saturate(result); }

26 New Skin Model – Shadows (Image)
Pure diffuse layer Pure epidermal/subdermal layers

27 New Skin Model - Extras Rim Lighting Melanin “Oily” specular.
Calculate fresnel (N·V) Calculate rim term Rim = smoothstep(0.0, 0.5, fresnel) * rimStrength; Add to specular during lighting pass. spec += rim * lightColor * pow(N·H, rimPower) * N·L * shadowMap; Melanin Calculate luminance of diffuse texture. lum = dot(diffuse, float3(0.33, 0.59, 0.11)); Blend between 1 and diffuse*luminance. Multiply new result with original diffuse diffuse * lerp(1.0, diffuse*lum, melanin); “Oily” specular. Second independent specular term to give a bit of “oily” shine to the surface. Artists will probably thank you. 

28 New Skin Model – Notes Shadow sharpening doesn’t need to be done for every layer. Can simplify and apply single blended shadows beforehand. Can still provide good bleeding. Can do blended normals more than once. Create variety between bump strengths for each layer. Not limited to constant color for backscattering. Subdermal texture. Translucency ramp.

29 Results

30 Results

31 Results (cont.) Standard NdotL + Blinn-phong (physical model)
Skin Shading, no SSS Skin Shading, full SSS

32 Conclusion Use Kelemen/Szirmay-Kalos BRDF.
Bake beckmann distribution and fresnel into textures. Use 4 specular terms instead of 1. Approximate subsurface scattering with lightly wrapped texture layers. Epidermal, subdermal. Keep wrapping at a minimum to avoid washing out the lighting. Use blended normals to soften normal maps. Sharpen shadows for layers using pow() to create bleeding shadows. Faster than blurring. Use simple masked N·L calculations for backscattering. Really cheap and easy to do. Can add rim lighting or melanin for extra effect. Might prove more effective if mixed with more methods (diffusion maybe?)

33 Conclusion (cont.) The Good: New Skin Model is cheap and looks good.
Simulates various scattering effects (bleeding shadows, back lighting). Scales well with multiple characters. The Bad: Not as accurate as diffusion methods. Still early in it’s development (experimental). Wrapped lighting can start to show with very bright lights. However, lights that bright shouldn’t occur in the first place. Good shadow maps should help hide this.

34 Thanks for viewing!  References:
Screen-Space Perceptual Rendering of Human Skin, Jorge Jimenez, Veronica Sundstedt, Diego Gutierrez, 2009 Efficient Rendering of Human Skin, Eugene d'Eon, David Luebke, and Eric Enderton, Eurographics 2007 Real-Time Approximations to Subsurface Scattering, Simon Green, 2004 Uncharted 2: Character Lighting and Shading, John Hable, 2010 Crafting Physically Motivated Shading Models for Game Development, Naty Hoffman, 2010 Real-Time Realistic Skin Translucency, Jorge Jimenez, David Whelan, Veronica Sundstedt, Diego Gutierrez, 2010

35 Fin Head model available at Infinite-3D

Download ppt "Cheap Realistic Skin Shading"

Similar presentations

Ads by Google