92 lines
2.8 KiB
HLSL
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();
|
|
} |