685 lines
26 KiB
HLSL
685 lines
26 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================================
|
|
PathTracingMaterialSampling.usf: Material sampling functions
|
|
===============================================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "PathTracingMaterialCommon.ush"
|
|
#include "PathTracingFresnel.ush"
|
|
#include "PathTracingLambert.ush"
|
|
#if !SIMPLIFIED_MATERIAL_SHADER
|
|
#include "PathTracingGlossy.ush"
|
|
#if SUBSTRATE_ENABLED
|
|
#include "PathTracingSubstrate.ush"
|
|
#include "PathTracingSubstrateFoliage.ush"
|
|
#include "PathTracingSubstrateSolidGlass.ush"
|
|
#include "PathTracingSubstrateThinGlass.ush"
|
|
#else
|
|
#include "PathTracingSolidGlass.ush"
|
|
#include "PathTracingThinGlass.ush"
|
|
#include "PathTracingDefaultLit.ush"
|
|
#include "PathTracingClearCoat.ush"
|
|
#include "PathTracingTwoSidedFoliage.ush"
|
|
#include "PathTracingCloth.ush"
|
|
#include "PathTracingSubsurfaceProfile.ush"
|
|
#endif // SUBSTRATE_ENABLED
|
|
#include "PathTracingEye.ush"
|
|
#include "PathTracingHair.ush"
|
|
#include "PathTracingMedium.ush"
|
|
#endif // !SIMPLIFIED_MATERIAL_SHADER
|
|
|
|
float3 EstimateMaterialAlbedo(FPathTracingPayload Payload)
|
|
{
|
|
// TODO: make this more accurate by estimating the directional albedo?
|
|
float3 Albedo = 0;
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
#if SIMPLIFIED_MATERIAL_SHADER
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
Albedo = Payload.BaseColor + Payload.SubsurfaceColor;
|
|
break;
|
|
#elif PATHTRACING_SUBSTRATE_PAYLOAD
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
{
|
|
Albedo = Payload.DiffuseColor + Payload.SubsurfaceColor + Payload.SpecularColor + Payload.FuzzAmount * Payload.FuzzColor;
|
|
Albedo *= Payload.GetMaxLobeWeight();
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
{
|
|
Albedo = 1.0 + Payload.FuzzAmount * Payload.FuzzColor;
|
|
Albedo *= Payload.GetMaxLobeWeight();
|
|
break;
|
|
}
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
{
|
|
Albedo = Payload.DiffuseColor + Payload.GetFoliageTransmissionColor() + Payload.SpecularColor + Payload.FuzzAmount * Payload.FuzzColor;
|
|
Albedo *= Payload.GetMaxLobeWeight();
|
|
break;
|
|
}
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
{
|
|
const float F0 = F0RGBToF0(Payload.SpecularColor);
|
|
Albedo = Payload.HasRefraction() ? lerp(Payload.GetTransmittanceColor(), 1.0, F0) : F0;
|
|
Albedo += Payload.DiffuseColor + Payload.FuzzAmount * Payload.FuzzColor;
|
|
Albedo *= Payload.GetMaxLobeWeight();
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
{
|
|
Albedo = Payload.DiffuseColor + Payload.SubsurfaceColor + Payload.SpecularColor + Payload.RoughnessData.z * CLEAR_COAT_F0 + Payload.FuzzAmount * Payload.FuzzColor;
|
|
Albedo *= Payload.GetMaxLobeWeight();
|
|
break;
|
|
}
|
|
case SHADINGMODELID_EYE:
|
|
Albedo = Payload.DiffuseColor + Payload.SubsurfaceColor + Payload.SpecularColor;
|
|
break;
|
|
case SHADINGMODELID_HAIR:
|
|
// SUBSTRATE_TODO: Add more cases here?
|
|
#else
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
case SHADINGMODELID_SUBSURFACE:
|
|
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
case SHADINGMODELID_EYE:
|
|
Albedo = Payload.DiffuseColor + Payload.SpecularColor + Payload.SubsurfaceColor;
|
|
break;
|
|
case SHADINGMODELID_DEFAULT_LIT:
|
|
Albedo = Payload.DiffuseColor + Payload.SpecularColor;
|
|
break;
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
Albedo = Payload.DiffuseColor + Payload.SpecularColor + Payload.GetClearCoat() * CLEAR_COAT_F0;
|
|
break;
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
{
|
|
// glass portion is a mixture of pure specular and tinted transmission (when refracting)
|
|
// or glass portion is just the specular highlight with transmission accounted for by transparency
|
|
const float F0 = F0RGBToF0(Payload.SpecularColor);
|
|
Albedo = Payload.HasRefraction() ? lerp(Payload.GetTransmittanceColor(), 1.0, F0) : F0;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
{
|
|
Albedo = 1.0; // all energy is either reflected or transmitted
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLOTH:
|
|
Albedo = (Payload.DiffuseColor + lerp(Payload.SpecularColor, Payload.GetClothColor(), Payload.GetClothAmount()));
|
|
break;
|
|
case SHADINGMODELID_HAIR:
|
|
#endif
|
|
default:
|
|
Albedo = Payload.GetBaseColor();
|
|
break;
|
|
}
|
|
Albedo *= Payload.BSDFOpacity;
|
|
|
|
return Albedo;
|
|
}
|
|
|
|
#if !SIMPLIFIED_MATERIAL_SHADER
|
|
|
|
#define ROUGHNESS_WEIGHT(r) DenoiserRoughnessWeight(r, PathRoughness)
|
|
|
|
void AccumulateAlbedoNormal(inout FPathTracingPayload Payload, float3 PathThroughput, float PathRoughness, inout float3 Albedo, inout float3 Normal)
|
|
{
|
|
float AOVWeight = DenoiserAOVWeight(PathRoughness);
|
|
if (AOVWeight == 0)
|
|
{
|
|
// no contribution
|
|
return;
|
|
}
|
|
PathThroughput *= AOVWeight;
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
PathThroughput *= Payload.WeightV * Payload.BSDFOpacity * lerp(1.0, Payload.TransmittanceN, Payload.CoverageAboveAlongN);
|
|
#endif
|
|
float NormThroughput = Luminance(PathThroughput);
|
|
// figure out how much the specular lobes should contribute to the total (relative to the current PathRoughness)
|
|
// if we are above the MinRoughness, use the PathRoughness as are lower bound instead so that multiple bounces don't accumulate too much albedo
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
{
|
|
const float Roughness0 = Payload.RoughnessData.x;
|
|
const float Roughness1 = Payload.RoughnessData.y;
|
|
const float SpecBlend = Payload.RoughnessData.z;
|
|
const float RoughnessWeight = lerp(ROUGHNESS_WEIGHT(Roughness0), ROUGHNESS_WEIGHT(Roughness1), SpecBlend);
|
|
Albedo += PathThroughput * (Payload.DiffuseColor + Payload.SubsurfaceColor + Payload.SpecularColor * RoughnessWeight + Payload.FuzzAmount * Payload.FuzzColor);
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
{
|
|
const float Roughness0 = Payload.RoughnessData.x;
|
|
const float Roughness1 = Payload.RoughnessData.y;
|
|
const float SpecBlend = Payload.RoughnessData.z;
|
|
const float RoughnessWeight = lerp(ROUGHNESS_WEIGHT(Roughness0), ROUGHNESS_WEIGHT(Roughness1), SpecBlend);
|
|
float GlassAlbedo = 1.0;
|
|
Albedo += PathThroughput * (GlassAlbedo * RoughnessWeight + Payload.FuzzAmount * Payload.FuzzColor);
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
{
|
|
const float Roughness0 = Payload.RoughnessData.x;
|
|
const float Roughness1 = Payload.RoughnessData.y;
|
|
const float SpecBlend = Payload.RoughnessData.z;
|
|
const float RoughnessWeight = lerp(ROUGHNESS_WEIGHT(Roughness0), ROUGHNESS_WEIGHT(Roughness1), SpecBlend);
|
|
Albedo += PathThroughput * (Payload.DiffuseColor + Payload.GetFoliageTransmissionColor() + Payload.SpecularColor * RoughnessWeight + Payload.FuzzAmount * Payload.FuzzColor);
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
{
|
|
const float F0 = F0RGBToF0(Payload.SpecularColor);
|
|
const float3 GlassAlbedo = Payload.HasRefraction() ? lerp(Payload.GetTransmittanceColor(), 1.0, F0) : F0;
|
|
const float Roughness0 = Payload.RoughnessData.x;
|
|
const float Roughness1 = Payload.RoughnessData.y;
|
|
const float SpecBlend = Payload.RoughnessData.z;
|
|
const float RoughnessWeight = lerp(ROUGHNESS_WEIGHT(Roughness0), ROUGHNESS_WEIGHT(Roughness1), SpecBlend);
|
|
Albedo += PathThroughput * (RoughnessWeight * GlassAlbedo + Payload.DiffuseColor + Payload.FuzzAmount * Payload.FuzzColor);
|
|
Normal += NormThroughput * RoughnessWeight * Payload.WorldNormal;
|
|
|
|
}
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
{
|
|
const float Roughness0 = Payload.RoughnessData.x;
|
|
const float Roughness1 = Payload.RoughnessData.y;
|
|
const float SpecBlend = Payload.RoughnessData.z;
|
|
const float Roughness0Weight = ROUGHNESS_WEIGHT(Roughness0);
|
|
const float Roughness1Weight = SpecBlend * ROUGHNESS_WEIGHT(Roughness1);
|
|
Albedo += PathThroughput * (Payload.DiffuseColor + Roughness0Weight * Payload.SpecularColor + Roughness1Weight * CLEAR_COAT_F0 + Payload.FuzzAmount * Payload.FuzzColor);
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_EYE:
|
|
{
|
|
const float RoughnessWeight = ROUGHNESS_WEIGHT(Payload.GetEyeRoughness());
|
|
Albedo += PathThroughput * (Payload.DiffuseColor + RoughnessWeight * Payload.SpecularColor + Payload.SubsurfaceColor);
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
Albedo += PathThroughput * Payload.GetBaseColor();
|
|
Normal += NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
|
|
const float RoughnessWeight = ROUGHNESS_WEIGHT(Payload.Roughness);
|
|
const float BrdfWeight = Payload.BSDFOpacity;
|
|
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
case SHADINGMODELID_SUBSURFACE:
|
|
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
case SHADINGMODELID_EYE:
|
|
Albedo += BrdfWeight * PathThroughput * (Payload.DiffuseColor + RoughnessWeight * Payload.SpecularColor + Payload.SubsurfaceColor);
|
|
Normal += BrdfWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
case SHADINGMODELID_DEFAULT_LIT:
|
|
case SHADINGMODELID_CLEAR_COAT: // TODO: can we be more precise with clearcoat?
|
|
Albedo += BrdfWeight * PathThroughput * (Payload.DiffuseColor + RoughnessWeight * Payload.SpecularColor);
|
|
Normal += BrdfWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
case SHADINGMODELID_CLOTH:
|
|
Albedo += BrdfWeight * PathThroughput * (Payload.DiffuseColor + lerp(RoughnessWeight * Payload.SpecularColor, Payload.GetClothColor(), Payload.GetClothAmount()));
|
|
Normal += BrdfWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
{
|
|
const float F0 = F0RGBToF0(Payload.SpecularColor);
|
|
const float3 GlassAlbedo = Payload.HasRefraction() ? lerp(Payload.GetTransmittanceColor(), 1.0, F0) : F0;
|
|
Albedo += BrdfWeight * RoughnessWeight * PathThroughput * GlassAlbedo;
|
|
Normal += BrdfWeight * RoughnessWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
{
|
|
const float GlassAlbedo = 1.0; // solid glass has unit albedo
|
|
Albedo += BrdfWeight * RoughnessWeight * PathThroughput * GlassAlbedo;
|
|
Normal += BrdfWeight * RoughnessWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
default:
|
|
Albedo += BrdfWeight * PathThroughput * Payload.BaseColor;
|
|
Normal += BrdfWeight * NormThroughput * Payload.WorldNormal;
|
|
break;
|
|
}
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
}
|
|
#undef ROUGHNESS_WEIGHT
|
|
|
|
void AccumulateAlbedo(float3 SigmaS, float3 PathThroughput, float PathRoughness, inout float3 Albedo)
|
|
{
|
|
PathThroughput *= DenoiserAOVWeight(PathRoughness);
|
|
// Volume acts as diffuse scattering, so make it contribute fully (like DiffuseColor above)
|
|
Albedo += SigmaS * PathThroughput;
|
|
}
|
|
|
|
#endif // SIMPLIFIED_MATERIAL_SHADER
|
|
|
|
// returns an average roughness for the whole material (for the path roughness of shadow rays from this material)
|
|
float GetAverageRoughness(FPathTracingPayload Payload)
|
|
{
|
|
#if SIMPLIFIED_MATERIAL_SHADER
|
|
return 1.0;
|
|
#elif PATHTRACING_SUBSTRATE_PAYLOAD
|
|
float AvgRoughness = Payload.RoughnessData.x;
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
{
|
|
AvgRoughness = max(AvgRoughness, Payload.RoughnessData.y);
|
|
// Only non-glass slabs contain diffuse
|
|
float DiffuseFraction = Payload.HasRefraction() ? 1.0 : F0RGBToMetallic(Payload.SpecularColor);
|
|
AvgRoughness = lerp(1.0, AvgRoughness, DiffuseFraction);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
{
|
|
// NOTE: this case does not contain a diffuse lobe yet
|
|
AvgRoughness = max(AvgRoughness, Payload.RoughnessData.y);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
{
|
|
AvgRoughness = max(AvgRoughness, Payload.RoughnessData.y);
|
|
float DiffuseFraction = LobeSelectionProb(Payload.DiffuseColor + Payload.FuzzAmount * Payload.FuzzColor, Payload.SpecularColor);
|
|
AvgRoughness = lerp(1.0, AvgRoughness, DiffuseFraction);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
{
|
|
AvgRoughness = max(AvgRoughness, Payload.RoughnessData.y);
|
|
float DiffuseFraction = F0RGBToMetallic(Payload.SpecularColor + Payload.RoughnessData.z * CLEAR_COAT_F0);
|
|
AvgRoughness = lerp(1.0, AvgRoughness, DiffuseFraction);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_EYE:
|
|
{
|
|
float DiffuseFraction = F0RGBToMetallic(Payload.SpecularColor);
|
|
AvgRoughness = lerp(1.0, AvgRoughness, DiffuseFraction);
|
|
break;
|
|
}
|
|
// SUBSTRATE_TODO: do we need special cases for the other slab types?
|
|
}
|
|
return AvgRoughness;
|
|
#else
|
|
float Roughness = Payload.Roughness;
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
Roughness = max(Roughness, Payload.GetClearCoatRoughness());
|
|
break;
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
{
|
|
float3 DualRoughnessData = Payload.GetDualRoughnessSpecular();
|
|
Roughness = max(DualRoughnessData.x, DualRoughnessData.y);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
return Roughness; // both cases are purely specular, no diffuse
|
|
}
|
|
float AvgRoughness = lerp(1.0 /* diffuse lobe */, Roughness, Payload.Metallic);
|
|
return AvgRoughness;
|
|
#endif
|
|
}
|
|
|
|
void AdjustDiffuseSSSContribution(inout float3 DiffColor, inout float3 SSSColor, inout float3 Radius)
|
|
{
|
|
// Below this radius, lerp to diffuse so we can avoid numerical issues in the random walk itself which lead to darkening
|
|
const float MinRadius = 0.02;
|
|
float3 Blend = saturate(Radius / MinRadius);
|
|
DiffColor += SSSColor * (1 - Blend);
|
|
SSSColor *= Blend;
|
|
Radius = max(Radius, MinRadius);
|
|
}
|
|
|
|
#if !SIMPLIFIED_MATERIAL_SHADER
|
|
void AdjustPayloadAfterUnpack(inout FPathTracingPayload HitPayload, bool bApplyOverrides)
|
|
{
|
|
// This function can also do a bit of per-material post-processing to simplify the rest of the code
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.DiffuseColor = HitPayload.DiffuseColor * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
|
|
HitPayload.SpecularColor = HitPayload.SpecularColor * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.xyz;
|
|
}
|
|
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
switch (HitPayload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
{
|
|
// NOTE: if radius is 0 the sss color will get flipped back into diffuse
|
|
HitPayload.SubsurfaceColor = HitPayload.DiffuseColor;
|
|
HitPayload.DiffuseColor = 0;
|
|
AdjustDiffuseSSSContribution(HitPayload.DiffuseColor, HitPayload.SubsurfaceColor, HitPayload.MeanFreePath);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.SetFoliageTransmissionColor(HitPayload.GetFoliageTransmissionColor() * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz);
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.RoughnessData.z = HitPayload.RoughnessData.z * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.x;
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_EYE:
|
|
{
|
|
// eye still needs a diffuse component for the iris center
|
|
float IrisMask = HitPayload.GetEyeIrisMask();
|
|
HitPayload.SubsurfaceColor = HitPayload.DiffuseColor - IrisMask * HitPayload.DiffuseColor;
|
|
HitPayload.DiffuseColor *= IrisMask;
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
switch (HitPayload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_UNLIT:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.BaseColor = HitPayload.BaseColor * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SUBSURFACE:
|
|
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
|
{
|
|
HitPayload.SubsurfaceRadius = HitPayload.GetSubsurfaceRadius();
|
|
// fallthrough to case below to avoid over-bright SSS
|
|
}
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
{
|
|
HitPayload.SubsurfaceColor = HitPayload.GetSubsurfaceColor();
|
|
float3 Front = HitPayload.DiffuseColor;
|
|
float3 Back = HitPayload.SubsurfaceColor;
|
|
float3 Sum = Front + Back;
|
|
float S = max(Sum.x, max(Sum.y, Sum.z));
|
|
if (S > 1)
|
|
{
|
|
// nudge the material back to something physically plausible
|
|
// NOTE: we ignore spec here since it should be accounted for by the brdf model itself
|
|
HitPayload.DiffuseColor = Front / S;
|
|
HitPayload.SubsurfaceColor = Back / S;
|
|
}
|
|
if (HitPayload.ShadingModelID != SHADINGMODELID_TWOSIDED_FOLIAGE)
|
|
{
|
|
AdjustDiffuseSSSContribution(HitPayload.DiffuseColor, HitPayload.SubsurfaceColor, HitPayload.SubsurfaceRadius);
|
|
}
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.SubsurfaceColor = HitPayload.SubsurfaceColor * View.DiffuseOverrideParameter.w + View.DiffuseOverrideParameter.xyz;
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
{
|
|
HitPayload.SubsurfaceRadius = HitPayload.GetSubsurfaceRadius();
|
|
// NOTE: if radius is 0 the sss color will get flipped back into diffuse
|
|
HitPayload.SubsurfaceColor = HitPayload.DiffuseColor;
|
|
HitPayload.DiffuseColor = 0;
|
|
AdjustDiffuseSSSContribution(HitPayload.DiffuseColor, HitPayload.SubsurfaceColor, HitPayload.SubsurfaceRadius);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_EYE:
|
|
{
|
|
HitPayload.SubsurfaceRadius = HitPayload.GetSubsurfaceRadius();
|
|
// eye still needs a diffuse component for the iris center
|
|
float IrisMask = HitPayload.GetEyeIrisMask();
|
|
HitPayload.SubsurfaceColor = HitPayload.DiffuseColor - IrisMask * HitPayload.DiffuseColor;
|
|
HitPayload.DiffuseColor *= IrisMask;
|
|
AdjustDiffuseSSSContribution(HitPayload.DiffuseColor, HitPayload.SubsurfaceColor, HitPayload.SubsurfaceRadius);
|
|
break;
|
|
}
|
|
case SHADINGMODELID_HAIR:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.BaseColor = HitPayload.BaseColor * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.xyz;
|
|
HitPayload.Specular = HitPayload.Specular * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.x;
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.SetClearCoat(HitPayload.GetClearCoat() * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.x);
|
|
}
|
|
break;
|
|
}
|
|
case SHADINGMODELID_CLOTH:
|
|
{
|
|
if (bApplyOverrides)
|
|
{
|
|
HitPayload.SetClothColor(HitPayload.GetClothColor() * View.SpecularOverrideParameter.w + View.SpecularOverrideParameter.xyz);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
}
|
|
|
|
struct FSSSRandomWalkInfo
|
|
{
|
|
float3 Color;
|
|
float3 Radius;
|
|
float3 Weight; // multiplier for the path throughput to take into account energy conservation from specular above the SSS
|
|
float Prob; // probability of choosing to perform the random walk
|
|
float G;
|
|
};
|
|
|
|
|
|
FSSSRandomWalkInfo GetMaterialSSSInfo(FPathTracingPayload Payload, float3 V_World)
|
|
{
|
|
FSSSRandomWalkInfo Result = (FSSSRandomWalkInfo)0;
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
if (any(Payload.MeanFreePath > 0.0))
|
|
{
|
|
Result.Color = Payload.SubsurfaceColor;
|
|
Result.Radius = Payload.MeanFreePath;
|
|
Result.G = Payload.PhaseG;
|
|
if (Payload.ShadingModelID == SHADINGMODELID_SUBSTRATE)
|
|
{
|
|
FSubstrateSingleSlabData Data = (FSubstrateSingleSlabData)0;
|
|
Data.PrepareBSDF(V_World, Payload, true);
|
|
Result.Weight = Payload.WeightV * Payload.BSDFOpacity * Data.DiffuseWeight;
|
|
Result.Prob = Data.LobePdf.x;
|
|
}
|
|
else if (Payload.ShadingModelID == SHADINGMODELID_CLEAR_COAT)
|
|
{
|
|
FSubstrateClearCoatData Data = (FSubstrateClearCoatData)0;
|
|
Data.PrepareBSDF(V_World, Payload, true);
|
|
Result.Weight = Payload.WeightV * Payload.BSDFOpacity * Data.DiffuseWeight;
|
|
Result.Prob = Data.LobePdf.x;
|
|
}
|
|
else if (Payload.ShadingModelID == SHADINGMODELID_EYE)
|
|
{
|
|
const float NoV = saturate(dot(Payload.WorldNormal, V_World));
|
|
const float3 SpecE = ComputeGGXSpecEnergyTermsRGB(Payload.GetEyeRoughness(), NoV, Payload.SpecularColor).E;
|
|
const float DiffWeight = (1 - Luminance(SpecE));
|
|
const float3 SSSAlbedo = DiffWeight * Payload.SubsurfaceColor;
|
|
const float3 DiffAlbedo = DiffWeight * Payload.DiffuseColor;
|
|
const float3 SpecAlbedo = SpecE;
|
|
Result.Prob = LobeSelectionProb(SSSAlbedo, DiffAlbedo + SpecAlbedo);
|
|
Result.Weight = Payload.BSDFOpacity * DiffWeight;
|
|
}
|
|
}
|
|
#else
|
|
Result.Color = Payload.SubsurfaceColor;
|
|
Result.Radius = Payload.SubsurfaceRadius;
|
|
Result.Weight = 0;
|
|
Result.Prob = 0;
|
|
Result.G = Payload.GetSubsurfacePhaseFunction();
|
|
if (Payload.IsSubsurfaceMaterial())
|
|
{
|
|
const float NoV = saturate(dot(Payload.WorldNormal, V_World));
|
|
float3 SpecE = 0;
|
|
if (Payload.ShadingModelID == SHADINGMODELID_SUBSURFACE_PROFILE)
|
|
{
|
|
// dual spec
|
|
const float3 DualRoughnessData = Payload.GetDualRoughnessSpecular();
|
|
const float3 SpecE0 = ComputeGGXSpecEnergyTermsRGB(DualRoughnessData.x, NoV, Payload.SpecularColor).E;
|
|
const float3 SpecE1 = ComputeGGXSpecEnergyTermsRGB(DualRoughnessData.y, NoV, Payload.SpecularColor).E;
|
|
SpecE = lerp(SpecE0, SpecE1, DualRoughnessData.z);
|
|
}
|
|
else
|
|
{
|
|
// single spec
|
|
SpecE = ComputeGGXSpecEnergyTermsRGB(Payload.Roughness, NoV, Payload.SpecularColor).E;
|
|
}
|
|
|
|
const float3 SSSLobeAlbedo = (1 - SpecE) * Payload.SubsurfaceColor;
|
|
const float3 DiffLobeAlbedo = (1 - SpecE) * Payload.DiffuseColor;
|
|
const float3 SpecLobeAlbedo = SpecE;
|
|
Result.Prob = LobeSelectionProb(SSSLobeAlbedo, DiffLobeAlbedo + SpecLobeAlbedo);
|
|
Result.Weight = Payload.BSDFOpacity * (1 - SpecE);
|
|
}
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
return Result;
|
|
}
|
|
|
|
void RemoveMaterialSSS(inout FPathTracingPayload Payload)
|
|
{
|
|
// Tweak the payload to remove subsurface scattering without chaning the overall color
|
|
// This function is free to assume this material contains SSS
|
|
Payload.DiffuseColor += Payload.SubsurfaceColor;
|
|
Payload.DiffuseColor = saturate(Payload.DiffuseColor);
|
|
Payload.SubsurfaceColor = 0.0;
|
|
}
|
|
|
|
#endif // SIMPLIFIED_MATERIAL_SHADER
|
|
|
|
|
|
FMaterialSample SampleMaterial(
|
|
float3 V_World,
|
|
FPathTracingPayload Payload,
|
|
float3 RandSample
|
|
)
|
|
{
|
|
#if SIMPLIFIED_MATERIAL_SHADER
|
|
return Simplified_SampleMaterial(Payload, RandSample);
|
|
//return Lambert_SampleMaterial(Payload, RandSample);
|
|
#else
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_UNLIT:
|
|
return Volumetric_SampleMaterial(V_World, Payload, RandSample);
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
return Substrate_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
return SubstrateSolidGlass_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
return SubstrateFoliage_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
return SubstrateThinGlass_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
return SubstrateClearCoat_SampleMaterial(V_World, Payload, RandSample);
|
|
#else
|
|
case SHADINGMODELID_DEFAULT_LIT:
|
|
case SHADINGMODELID_SUBSURFACE:
|
|
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
|
return DefaultLit_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
return RoughThinGlass_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
return RoughGlass_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
return SubsurfaceProfile_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_CLOTH:
|
|
return Cloth_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
return ClearCoat_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
return TwoSidedFoliage_SampleMaterial(V_World, Payload, RandSample);
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
case SHADINGMODELID_EYE:
|
|
return Eye_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_HAIR:
|
|
return Hair_SampleMaterial(V_World, Payload, RandSample);
|
|
case SHADINGMODELID_MEDIUM:
|
|
return Medium_SampleMaterial(V_World, Payload, RandSample);
|
|
default:
|
|
return Lambert_SampleMaterial(Payload, RandSample);
|
|
}
|
|
return NullMaterialSample();
|
|
#endif // SIMPLIFIED_MATERIAL_SHADER
|
|
}
|
|
|
|
FMaterialEval EvalMaterial(
|
|
float3 V_World,
|
|
float3 L_World,
|
|
FPathTracingPayload Payload,
|
|
float2 DiffuseSpecularScale
|
|
)
|
|
{
|
|
#if SIMPLIFIED_MATERIAL_SHADER
|
|
return Simplified_EvalMaterial(L_World, Payload);
|
|
//return Lambert_EvalMaterial(L_World, Payload);
|
|
#else
|
|
switch (Payload.ShadingModelID)
|
|
{
|
|
case SHADINGMODELID_UNLIT:
|
|
return Volumetric_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
#if PATHTRACING_SUBSTRATE_PAYLOAD
|
|
case SHADINGMODELID_SUBSTRATE:
|
|
return Substrate_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
return SubstrateSolidGlass_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
return SubstrateFoliage_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
return SubstrateThinGlass_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
return SubstrateClearCoat_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
#else
|
|
case SHADINGMODELID_DEFAULT_LIT:
|
|
case SHADINGMODELID_SUBSURFACE:
|
|
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
|
return DefaultLit_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_THIN_TRANSLUCENT:
|
|
return RoughThinGlass_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_SOLID_GLASS:
|
|
return RoughGlass_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
|
return SubsurfaceProfile_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_CLOTH:
|
|
return Cloth_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_CLEAR_COAT:
|
|
return ClearCoat_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
|
return TwoSidedFoliage_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
#endif // PATHTRACING_SUBSTRATE_PAYLOAD
|
|
case SHADINGMODELID_EYE:
|
|
return Eye_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_HAIR:
|
|
return Hair_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
case SHADINGMODELID_MEDIUM:
|
|
return Medium_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
|
|
default:
|
|
return Lambert_EvalMaterial(L_World, Payload, DiffuseSpecularScale);
|
|
}
|
|
return NullMaterialEval();
|
|
#endif // SIMPLIFIED_MATERIAL_SHADER
|
|
}
|