Slide 1

advertisement
Cheap Realistic Skin Shading
Overview
• Popular Skin Models
• New Skin Model
– Ideas
– BRDF
– Layers
– Back Scattering
– Blended Normals
– Shadows
– Extras
• Results
• Conclusion
Popular Skin Models
Popular Skin Models
• Red wrapped lighting
–
http://http.developer.nvidia.com/GPUGems/gpugems_ch16.html
• Texture-space diffusion
–
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html
• Texture-space diffusion (12-tap)
–
http://advances.realtimerendering.com/s2010/Hable-Uncharted2(SIGGRAPH 2010 Advanced RealTime Rendering
Course).pptx
• Screen-space diffusion
–
http://giga.cps.unizar.es/~diegog/ficheros/pdf_papers/TAP_Jimenez_LR.pdf
• Blended Normals
–
http://advances.realtimerendering.com/s2010/Hable-Uncharted2(SIGGRAPH 2010 Advanced RealTime Rendering
Course).pptx
• Offline “Fast-Skin Shaders”
–
http://www.google.ca/#hl=en&source=hp&biw=1920&bih=965&q=fast+skin+shader&aq=f&aqi=gm5&aql=&oq=&gs_rfai=&fp=bc38547320fe36d4
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.
New Skin Model
New Skin Model
• Trick is to improvise!
• Perceptual rendering, not physical.
– Doesn’t have to be correct, just has to
• 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.
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.
New Skin Model - BRDF
• Kelemen/Szirmay-Kalos BRDF Optimizations.
– 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.
• Use energy conservation if you think it’ll help.
New Skin Model – BRDF (Code)
Code modified from NVIDIA’s implementation.
// 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 = 1.0 - HdotV;
float exponential = pow( base, 5.0 );
return exponential + F0 * ( 1.0 - exponential );
}
Don’t use these textures, compute
them yourself for better precision.
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; 0.028 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;
}
New Skin Model – BRDF (Result)
(Image intensified for clarity)
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.
– 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.
– You’ll get ugly ambient like the standard wrap method.
– Apply lighting to each texture and weigh accordingly.
Epidermal = 0.3, Subdermal = 0.2, Diffuse = 0.5
New Skin Model – Layers (Textures)
Diffuse
Epidermal
Subdermal
Back Scattering
Specular
Normal
New Skin Model – Layers (Image)
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.
– Translucent shadow maps.
– Might not properly be occluded in a shadowed area.
• Technique still needs work (incomplete).
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;
}
New Skin Model – Back Scattering (Image)
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.
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);
}
New Skin Model – Blended Normals (Image)
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.
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).
• Should be relatively soft/jittered/blurred.
• Otherwise you’ll get specularity bleeding into shadowed areas.
• Mileage may vary (depends on shadow map, scale of object,
etc).
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).
• 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 ( – ).
• Make difference lower for epidermal layer ( – ).
• Make them both exactly the same for diffuse ( –
• Can be ignored if results were already good.
).
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);
}
New Skin Model – Shadows (Image)
Pure diffuse layer
Pure epidermal/subdermal layers
New Skin Model - Extras
• Rim Lighting
– 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.
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.
Results
Results
Results (cont.)
Standard NdotL + Blinn-phong (physical model)
Skin Shading, no SSS
Skin Shading, full SSS
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?)
Conclusion (cont.)
• New Skin Model is cheap and looks good.
• Simulates various scattering effects (bleeding shadows,
back lighting).
• Scales well with multiple characters.
• 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.
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
–
•
http://advances.realtimerendering.com/s2010/HableUncharted2(SIGGRAPH%202010%20Advanced%20RealTime%20Rendering%20Course).pptx
Crafting Physically Motivated Shading Models for Game Development, Naty Hoffman, 2010
–
•
http://http.developer.nvidia.com/GPUGems/gpugems_ch16.html
Uncharted 2: Character Lighting and Shading, John Hable, 2010
•
•
http://http.developer.nvidia.com/GPUGems3/gpugems3_ch14.html
Real-Time Approximations to Subsurface Scattering, Simon Green, 2004
–
•
http://giga.cps.unizar.es/~diegog/ficheros/pdf_papers/TAP_Jimenez_LR.pdf
http://renderwonk.com/publications/s2010-shadingcourse/hoffman/s2010_physically_based_shading_hoffman_b.pdf
Real-Time Realistic Skin Translucency, Jorge Jimenez, David Whelan, Veronica Sundstedt,
Diego Gutierrez, 2010
•
http://giga.cps.unizar.es/~diegog/projects/IEEE/ieee.html
Fin
Head model available at Infinite-3D
Download