A lot of progress has been made in the area of complex, multilayered materials rendering (e.g. patina, laquered wood, car paint).
From what I understand, GPUs nowadays have enough compute power to handle multilayered BRDF in real time, which should technically allow accurate physically based layer simulation (by technically accurate I mean accurate light attenuation per layer, energy conservation for the whole material, ...) in real time.
So far, I've tried to built my own material layering system (offline shader generation, supports 4 layers, ...).
It works ok but it's nowhere close to be physically realistic, since my blending function between layers (based on The Order 1886 paper http://www.gdcvault.com/play/1020162/Crafting-a-Next-Gen-Material page 81) is a naive linear interpolation for each input:
void BlendLayers( inout MaterialLayer baseLayer, in MaterialLayer topLayer )
{
baseLayer.BaseColor = lerp( baseLayer.BaseColor, topLayer.BaseColor * topLayer.DiffuseContribution, topLayer.BlendMask );
baseLayer.BaseColor = saturate( baseLayer.BaseColor );
baseLayer.Reflectance = lerp( baseLayer.Reflectance, topLayer.Reflectance * topLayer.SpecularContribution, topLayer.BlendMask );
baseLayer.Reflectance = saturate( baseLayer.Reflectance );
baseLayer.Normal = BlendNormals( baseLayer.Normal, topLayer.Normal * topLayer.NormalMapContribution );
baseLayer.Roughness = lerp( baseLayer.Roughness, topLayer.Roughness * topLayer.SpecularContribution, topLayer.BlendMask );
baseLayer.Roughness = clamp( baseLayer.Roughness, 1e-3f, 1.0f );
baseLayer.Metalness = lerp( baseLayer.Metalness, topLayer.Metalness * topLayer.SpecularContribution, topLayer.BlendMask );
baseLayer.Metalness = clamp( baseLayer.Metalness, 1e-3f, 1.0f );
baseLayer.AmbientOcclusion = lerp( baseLayer.AmbientOcclusion, topLayer.AmbientOcclusion, topLayer.BlendMask );
baseLayer.AmbientOcclusion = saturate( baseLayer.AmbientOcclusion );
baseLayer.Emissivity = lerp( baseLayer.Emissivity, topLayer.Emissivity, topLayer.BlendMask );
}
float4 EntryPointPS( psData_t VertexStage ) : SV_TARGET
{
float3 N = normalize( VertexStage.normal );
MaterialLayer BaseLayer;
float4 LightContribution = float4( 0, 0, 0, 1 );
MaterialLayer TestLayer1 = GetTestLayer1Layer( VertexStage, N );
BaseLayer = TestLayer1;
MaterialLayer TestLayer2 = GetTestLayer2Layer( VertexStage, N );
BlendLayers( BaseLayer, TestLayer2 );
LightContribution += ComputeLighting( VertexStage.positionWS.xyz, VertexStage.position.xyz, VertexStage.depth, SHADING_MODEL_LIT, BaseLayer );
return LightContribution;
}
I'm looking to build a car paint material based on this system, split in 3 layers (primer coat, metal flakes and clear coat, as described during Forza Motorsport 5 session at GDC https://www.gdcvault.com/play/1020556/Lighting-and-Materials-in-Forza). With my current system, the whole thing looks... lame (and too plastic-ish to be believable).
I had a look at COD:IW paper ( https://www.activision.com/cdn/research/s2017_pbs_multilayered_slides_final.pdf ) but their approach seems quite complicated (in details at page 29). UE4 handle multi-layering easily so I guess there is a way to simulate layers in a cheap way without ending with NaN and artifacts all over the place.
↧