// 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 }