Files
UnrealEngine/Engine/Shaders/Private/PathTracing/Material/PathTracingTwoSidedFoliage.ush
2025-05-18 13:04:45 +08:00

92 lines
2.8 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================================
PathTracingTwoSidedFoliage.usf: Path tracing BRDF model for two-sided foliage material
===============================================================================================*/
#pragma once
#include "PathTracingDefaultLit.ush"
#include "PathTracingEnergyConservation.ush"
struct FTwoSidedFoliageData
{
float NoV;
FBxDFEnergyTermsRGB Spec;
float3 Back;
float ProbT;
};
FTwoSidedFoliageData PrepareTwoSidedFoliageData(FPathTracingPayload Payload, float3 V_World)
{
FTwoSidedFoliageData Data = (FTwoSidedFoliageData)0;
Data.NoV = saturate(dot(V_World, Payload.WorldNormal));
Data.Spec = ComputeGGXSpecEnergyTermsRGB(Payload.Roughness, Data.NoV, Payload.SpecularColor);
// pick back lobe proportionally to its contribution relative to front side
const float3 Diff = (1 - Data.Spec.E) * Payload.DiffuseColor;
Data.Back = (1 - Data.Spec.E) * Payload.SubsurfaceColor;
Data.ProbT = LobeSelectionProb(Data.Back, Diff + Data.Spec.E);
return Data;
}
FMaterialSample TwoSidedFoliage_SampleMaterial(
float3 V_World,
FPathTracingPayload Payload,
float3 RandSample
)
{
const FTwoSidedFoliageData Data = PrepareTwoSidedFoliageData(Payload, V_World);
if (RandSample.x < Data.ProbT)
{
RandSample.x = RescaleRandomNumber(RandSample.x, 0.0, Data.ProbT);
const float3 N = Payload.WorldNormal;
const float4 SampledValue = CosineSampleHemisphere(RandSample.yz);
return CreateMaterialSample(TangentToWorld(SampledValue.xyz, -N), Payload.BSDFOpacity * Data.Back / Data.ProbT, Data.ProbT * SampledValue.w, -1.0, 1.0, PATHTRACER_SCATTER_DIFFUSE);
}
else
{
RandSample.x = RescaleRandomNumber(RandSample.x, Data.ProbT, 1.0);
FMaterialSample Result = DefaultLit_SampleMaterial(V_World, Payload, RandSample);
Result.Weight /= 1.0 - Data.ProbT;
Result.Pdf *= 1.0 - Data.ProbT;
return Result;
}
}
FMaterialEval TwoSidedFoliage_EvalMaterial(
float3 V_World,
float3 L_World,
FPathTracingPayload Payload,
float2 DiffuseSpecularScale
)
{
const FTwoSidedFoliageData Data = PrepareTwoSidedFoliageData(Payload, V_World);
const float3 N = Payload.WorldNormal;
const float NoL = dot(N, L_World);
if (NoL < 0.0)
{
// Diffuse transmission (the implementation in TwoSidedBxDF does not appear to be a real BxDF)
if (Data.ProbT > 0)
{
float LambertPdf = -NoL / PI;
return CreateMaterialEval(Payload.BSDFOpacity * Data.Back / Data.ProbT * DiffuseSpecularScale.x, Data.ProbT * LambertPdf);
}
}
else if (Data.ProbT < 1)
{
FMaterialEval Result = DefaultLit_EvalMaterial(V_World, L_World, Payload, DiffuseSpecularScale);
Result.Weight /= 1.0 - Data.ProbT;
Result.Pdf *= 1.0 - Data.ProbT;
return Result;
}
return NullMaterialEval();
}