Updated MultilayerPBR

This commit is contained in:
antonmic
2021-04-17 10:28:27 -07:00
parent aa06908024
commit d0760009b0
3 changed files with 118 additions and 77 deletions
@@ -99,7 +99,6 @@ struct VSOutput
float3 m_blendMask : UV7;
};
#include <Atom/Features/PBR/LightingModel.azsli>
#include <Atom/Features/Vertex/VertexHelper.azsli>
VSOutput ForwardPassVS(VSInput IN)
@@ -162,14 +161,14 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
if(o_debugDrawMode == DebugDrawMode::BlendMaskValues)
{
float3 blendMaskValues = GetBlendMaskValues(IN.m_uv[MaterialSrg::m_blendMaskUvIndex], IN.m_blendMask);
return MakeDebugOutput(IN, blendMaskValues);
return DebugOutput(blendMaskValues);
}
if(o_debugDrawMode == DebugDrawMode::DepthMaps)
{
GetDepth_Setup(IN.m_blendMask);
float depth = GetDepth(IN.m_uv[MaterialSrg::m_parallaxUvIndex], float2(0,0), float2(0,0));
return MakeDebugOutput(IN, float3(depth,depth,depth));
return DebugOutput(float3(depth,depth,depth));
}
// ------- Parallax -------
@@ -197,6 +196,9 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
}
}
Surface surface;
surface.position = IN.m_worldPosition;
// ------- Setup the per-layer UV transforms -------
float2 uvLayer1[UvSetCount];
@@ -240,7 +242,7 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float3 normalTS = ReorientTangentSpaceNormal(layer1_normalTS, layer2_normalTS);
normalTS = ReorientTangentSpaceNormal(normalTS, layer3_normalTS);
// [GFX TODO][ATOM-14591]: This will only work if the normal maps all use the same UV stream. We would need to add support for having them in different UV streams.
float3 normalWS = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
surface.normal = normalize(TangentSpaceToWorld(normalTS, IN.m_normal, tangents[MaterialSrg::m_parallaxUvIndex], bitangents[MaterialSrg::m_parallaxUvIndex]));
// ------- Base Color -------
@@ -262,34 +264,24 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float layer3_metallic = GetMetallicInput(MaterialSrg::m_layer3_m_metallicMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_metallicMapUvIndex], MaterialSrg::m_layer3_m_metallicFactor, o_layer3_o_metallic_useTexture);
metallic = BlendLayers(layer1_metallic, layer2_metallic, layer3_metallic, blendMaskValues);
}
// ------- Specular -------
float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
float specularF0 = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
surface.SetAlbedoAndSpecularF0(baseColor, specularF0, metallic);
// ------- Roughness -------
float layer1_roughness = GetRoughnessInput(MaterialSrg::m_layer1_m_roughnessMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_roughnessMapUvIndex], MaterialSrg::m_layer1_m_roughnessFactor, MaterialSrg::m_layer1_m_roughnessLowerBound, MaterialSrg::m_layer1_m_roughnessUpperBound, o_layer1_o_roughness_useTexture);
float layer2_roughness = GetRoughnessInput(MaterialSrg::m_layer2_m_roughnessMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_roughnessMapUvIndex], MaterialSrg::m_layer2_m_roughnessFactor, MaterialSrg::m_layer2_m_roughnessLowerBound, MaterialSrg::m_layer2_m_roughnessUpperBound, o_layer2_o_roughness_useTexture);
float layer3_roughness = GetRoughnessInput(MaterialSrg::m_layer3_m_roughnessMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_roughnessMapUvIndex], MaterialSrg::m_layer3_m_roughnessFactor, MaterialSrg::m_layer3_m_roughnessLowerBound, MaterialSrg::m_layer3_m_roughnessUpperBound, o_layer3_o_roughness_useTexture);
float roughness = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
surface.roughnessLinear = BlendLayers(layer1_roughness, layer2_roughness, layer3_roughness, blendMaskValues);
// ------- Specular -------
float layer1_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer1_m_specularF0Map, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_specularF0MapUvIndex], MaterialSrg::m_layer1_m_specularF0Factor, o_layer1_o_specularF0_useTexture);
float layer2_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer2_m_specularF0Map, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_specularF0MapUvIndex], MaterialSrg::m_layer2_m_specularF0Factor, o_layer2_o_specularF0_useTexture);
float layer3_specularF0Factor = GetSpecularInput(MaterialSrg::m_layer3_m_specularF0Map, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_specularF0MapUvIndex], MaterialSrg::m_layer3_m_specularF0Factor, o_layer3_o_specularF0_useTexture);
float specularF0Factor = BlendLayers(layer1_specularF0Factor, layer2_specularF0Factor, layer3_specularF0Factor, blendMaskValues);
// ------- Emissive -------
float3 layer1_emissive = GetEmissiveInput(MaterialSrg::m_layer1_m_emissiveMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_emissiveMapUvIndex], MaterialSrg::m_layer1_m_emissiveIntensity, MaterialSrg::m_layer1_m_emissiveColor.rgb, o_layer1_o_emissiveEnabled, o_layer1_o_emissive_useTexture);
float3 layer2_emissive = GetEmissiveInput(MaterialSrg::m_layer2_m_emissiveMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_emissiveMapUvIndex], MaterialSrg::m_layer2_m_emissiveIntensity, MaterialSrg::m_layer2_m_emissiveColor.rgb, o_layer2_o_emissiveEnabled, o_layer2_o_emissive_useTexture);
float3 layer3_emissive = GetEmissiveInput(MaterialSrg::m_layer3_m_emissiveMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_emissiveMapUvIndex], MaterialSrg::m_layer3_m_emissiveIntensity, MaterialSrg::m_layer3_m_emissiveColor.rgb, o_layer3_o_emissiveEnabled, o_layer3_o_emissive_useTexture);
float3 emissive = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
// ------- Occlusion -------
float layer1_occlusion = GetOcclusionInput(MaterialSrg::m_layer1_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer1_m_ambientOcclusionFactor, o_layer1_o_ambientOcclusion_useTexture);
float layer2_occlusion = GetOcclusionInput(MaterialSrg::m_layer2_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer2_m_ambientOcclusionFactor, o_layer2_o_ambientOcclusion_useTexture);
float layer3_occlusion = GetOcclusionInput(MaterialSrg::m_layer3_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer3_m_ambientOcclusionFactor, o_layer3_o_ambientOcclusion_useTexture);
float occlusion = BlendLayers(layer1_occlusion, layer2_occlusion, layer3_occlusion, blendMaskValues);
surface.CalculateRoughnessA();
// ------- Subsurface -------
@@ -300,14 +292,50 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
float2 transmissionUv = IN.m_uv[MaterialSrg::m_transmissionThicknessMapUvIndex];
float4 transmissionTintThickness = GeTransmissionInput(MaterialSrg::m_transmissionThicknessMap, MaterialSrg::m_sampler, transmissionUv, MaterialSrg::m_transmissionTintThickness);
surface.transmission.tint = transmissionTintThickness.rgb;
surface.transmission.thickness = transmissionTintThickness.w;
surface.transmission.transmissionParams = MaterialSrg::m_transmissionParams;
// ------- Anisotropy -------
if (o_enableAnisotropy)
{
const float anisotropyAngle = 0.0f;
const float anisotropyFactor = 0.0f;
surface.anisotropy.Init(surface.normal, tangents[0], bitangents[0], anisotropyAngle, anisotropyFactor, surface.roughnessA);
}
// ------- Lighting Data -------
LightingData lightingData;
// Light iterator
lightingData.tileIterator.Init(IN.m_position, PassSrg::m_lightListRemapped, PassSrg::m_tileLightData);
lightingData.Init(surface.position, surface.normal, surface.roughnessLinear);
// Directional light shadow coordinates
lightingData.shadowCoords = IN.m_shadowCoords;
// ------- Emissive -------
float3 layer1_emissive = GetEmissiveInput(MaterialSrg::m_layer1_m_emissiveMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_emissiveMapUvIndex], MaterialSrg::m_layer1_m_emissiveIntensity, MaterialSrg::m_layer1_m_emissiveColor.rgb, o_layer1_o_emissiveEnabled, o_layer1_o_emissive_useTexture);
float3 layer2_emissive = GetEmissiveInput(MaterialSrg::m_layer2_m_emissiveMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_emissiveMapUvIndex], MaterialSrg::m_layer2_m_emissiveIntensity, MaterialSrg::m_layer2_m_emissiveColor.rgb, o_layer2_o_emissiveEnabled, o_layer2_o_emissive_useTexture);
float3 layer3_emissive = GetEmissiveInput(MaterialSrg::m_layer3_m_emissiveMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_emissiveMapUvIndex], MaterialSrg::m_layer3_m_emissiveIntensity, MaterialSrg::m_layer3_m_emissiveColor.rgb, o_layer3_o_emissiveEnabled, o_layer3_o_emissive_useTexture);
lightingData.emissiveLighting = BlendLayers(layer1_emissive, layer2_emissive, layer3_emissive, blendMaskValues);
// ------- Occlusion -------
float layer1_occlusion = GetOcclusionInput(MaterialSrg::m_layer1_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer1[MaterialSrg::m_layer1_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer1_m_ambientOcclusionFactor, o_layer1_o_ambientOcclusion_useTexture);
float layer2_occlusion = GetOcclusionInput(MaterialSrg::m_layer2_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer2[MaterialSrg::m_layer2_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer2_m_ambientOcclusionFactor, o_layer2_o_ambientOcclusion_useTexture);
float layer3_occlusion = GetOcclusionInput(MaterialSrg::m_layer3_m_ambientOcclusionMap, MaterialSrg::m_sampler, uvLayer3[MaterialSrg::m_layer3_m_ambientOcclusionMapUvIndex], MaterialSrg::m_layer3_m_ambientOcclusionFactor, o_layer3_o_ambientOcclusion_useTexture);
lightingData.occlusion = BlendLayers(layer1_occlusion, layer2_occlusion, layer3_occlusion, blendMaskValues);
// ------- Clearcoat -------
float clearCoatFactor = 0.0f;
float clearCoatRoughness = 0.0f;
float3 clearCoatNormal = float3(0.0, 0.0, 0.0);
if(o_clearCoat_feature_enabled)
{
// --- Layer 1 ---
float layer1_clearCoatFactor = 0.0f;
float layer1_clearCoatRoughness = 0.0f;
float3 layer1_clearCoatNormal = float3(0.0, 0.0, 0.0);
@@ -323,6 +351,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer1_clearCoatFactor, layer1_clearCoatRoughness, layer1_clearCoatNormal);
}
// --- Layer 2 ---
float layer2_clearCoatFactor = 0.0f;
float layer2_clearCoatRoughness = 0.0f;
float3 layer2_clearCoatNormal = float3(0.0, 0.0, 0.0);
@@ -338,6 +368,8 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer2_clearCoatFactor, layer2_clearCoatRoughness, layer2_clearCoatNormal);
}
// --- Layer 3 ---
float layer3_clearCoatFactor = 0.0f;
float layer3_clearCoatRoughness = 0.0f;
float3 layer3_clearCoatNormal = float3(0.0, 0.0, 0.0);
@@ -353,22 +385,58 @@ PbrLightingOutput ForwardPassPS_Common(VSOutput IN, bool isFrontFace, out float
layer3_clearCoatFactor, layer3_clearCoatRoughness, layer3_clearCoatNormal);
}
clearCoatFactor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
clearCoatRoughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
// --- Blend Layers ---
surface.clearCoat.factor = BlendLayers(layer1_clearCoatFactor, layer2_clearCoatFactor, layer3_clearCoatFactor, blendMaskValues);
surface.clearCoat.roughness = BlendLayers(layer1_clearCoatRoughness, layer2_clearCoatRoughness, layer3_clearCoatRoughness, blendMaskValues);
// [GFX TODO][ATOM-14592] This is not the right way to blend the normals. We need to use ReorientTangentSpaceNormal(), and that requires GetClearCoatInputs() to return the normal in TS instead of WS.
clearCoatNormal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
clearCoatNormal = normalize(clearCoatNormal);
surface.clearCoat.normal = BlendLayers(layer1_clearCoatNormal, layer2_clearCoatNormal, layer3_clearCoatNormal, blendMaskValues);
surface.clearCoat.normal = normalize(surface.clearCoat.normal);
// manipulate base layer f0 if clear coat is enabled
// modify base layer's normal incidence reflectance
// for the derivation of the following equation please refer to:
// https://google.github.io/filament/Filament.md.html#materialsystem/clearcoatmodel/baselayermodification
float3 f0 = (1.0 - 5.0 * sqrt(surface.specularF0)) / (5.0 - sqrt(surface.specularF0));
surface.specularF0 = lerp(surface.specularF0, f0 * f0, surface.clearCoat.factor);
}
// Diffuse and Specular response (used in IBL calculations)
lightingData.specularResponse = FresnelSchlickWithRoughness(lightingData.NdotV, surface.specularF0, surface.roughnessLinear);
lightingData.diffuseResponse = 1.0 - lightingData.specularResponse;
if(o_clearCoat_feature_enabled)
{
// Clear coat layer has fixed IOR = 1.5 and transparent => F0 = (1.5 - 1)^2 / (1.5 + 1)^2 = 0.04
lightingData.diffuseResponse *= 1.0 - (FresnelSchlickWithRoughness(lightingData.NdotV, float3(0.04, 0.04, 0.04), surface.clearCoat.roughness) * surface.clearCoat.factor);
}
// ------- Multiscatter -------
lightingData.CalculateMultiscatterCompensation(surface.specularF0, o_specularF0_enableMultiScatterCompensation);
// ------- Lighting Calculation -------
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
// Apply Decals
ApplyDecals(lightingData.tileIterator, surface);
PbrLightingOutput lightingOutput = PbrLighting(IN,
baseColor, metallic, roughness, specularF0Factor,
normalWS, tangents[0], bitangents[0], anisotropy,
emissive, occlusion, transmissionTintThickness, MaterialSrg::m_transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, o_opacity_mode);
// Apply Direct Lighting
ApplyDirectLighting(surface, lightingData);
// Apply Image Based Lighting (IBL)
ApplyIBL(surface, lightingData);
// Finalize Lighting
lightingData.FinalizeLighting(surface.transmission.tint);
if (o_opacity_mode == OpacityMode::Blended || o_opacity_mode == OpacityMode::TintedTransparent)
{
alpha = FresnelSchlickWithRoughness(lightingData.NdotV, alpha, surface.roughnessLinear).x; // Increase opacity at grazing angles.
}
PbrLightingOutput lightingOutput = GetPbrLightingOutput(surface, lightingData, alpha);
// ------- Opacity -------
@@ -117,3 +117,16 @@ PbrLightingOutput GetPbrLightingOutput(Surface surface, LightingData lightingDat
return lightingOutput;
}
PbrLightingOutput DebugOutput(float3 color)
{
PbrLightingOutput output = (PbrLightingOutput)0;
float defaultNormal = float3(0.0f, 0.0f, 1.0f);
output.m_diffuseColor = float4(color.rgb, 1.0f);
output.m_normal.rgb = EncodeNormalSignedOctahedron(defaultNormal);
output.m_clearCoatNormal = float4(EncodeNormalSphereMap(defaultNormal), 0.0f, 1.0f);
return output;
}
@@ -137,43 +137,3 @@ PbrLightingOutput PbrLighting( VSOutput IN,
return lightingOutput;
}
//! Populates a PbrLightingOutput struct with values that can be used to render a simple debug color in the PBR pipeline.
//! Note that this will not give you a the exact color screen pixels since it is used in the PBR pipeline, it may
//! still have lighting or other affects applied on top of it. But this is still a convenient way to quickly get some
//! colors on screen.
//! @param IN the pixel shader input structure
//! @param debugColor the color to be drawn
//! @param normalWS world space normal vector
//! @return a PbrLightingOutput as returned by the main PbrLighting() function
PbrLightingOutput MakeDebugOutput(VSOutput IN, float3 debugColor, float3 normalWS)
{
// We happen to set this up initially using baseColor, but we could consider adding an option to use
// emissive instead to avoid depending on scene lighting.
const float3 baseColor = debugColor;
const float metallic = 0;
const float roughness = 1;
const float specularF0Factor = 0.5;
const float3 normal = normalWS;
const float3 emissive = {0,0,0};
const float occlusion = 1;
const float clearCoatFactor = 0.0f;
const float clearCoatRoughness = 0.0f;
const float3 clearCoatNormal = {0,0,0};
const float4 transmissionTintThickness = {0,0,0,0};
const float4 transmissionParams = {0,0,0,0};
const float2 anisotropy = 0.0; // Does not affect calculations unless 'o_enableAnisotropy' is enabled
const float alpha = 1.0;
PbrLightingOutput lightingOutput = PbrLighting(IN, baseColor, metallic, roughness, specularF0Factor,
normal, IN.m_tangent, IN.m_bitangent, anisotropy,
emissive, occlusion, transmissionTintThickness, transmissionParams, clearCoatFactor, clearCoatRoughness, clearCoatNormal, alpha, OpacityMode::Opaque);
return lightingOutput;
}
//! Same as above, using the vertex normal
PbrLightingOutput MakeDebugOutput(VSOutput IN, float3 debugColor)
{
return MakeDebugOutput(IN, debugColor, normalize(IN.m_normal));
}