You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
Note that the new code accepts a pair of random numbers in the unit square instead of on the unit disk. This required updating all callers (which all passed in the result of UniformSampleDisk anyway). Also, call the aniso variant which saves a useless square followed by sqrt. The old non-aniso method is removed as there is no real savings to be had from the non-anisotropic case anymore. #rb Sebastien.Hillaire [CL 26031587 by chris kulla in ue5-main branch]
170 lines
5.0 KiB
Plaintext
170 lines
5.0 KiB
Plaintext
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================================
|
|
PathTracingEye.usf: Path tracing BRDF model for the eye material
|
|
===============================================================================================*/
|
|
|
|
#pragma once
|
|
|
|
#include "PathTracingMaterialCommon.ush"
|
|
#include "PathTracingFresnel.ush"
|
|
#include "PathTracingEnergyConservation.ush"
|
|
|
|
struct FEyeData
|
|
{
|
|
float3x3 Basis;
|
|
float2 Alpha;
|
|
float3 V;
|
|
|
|
FBxDFEnergyTermsRGB Spec;
|
|
float3 DiffWeight;
|
|
float LobeProb;
|
|
};
|
|
|
|
FEyeData PrepareEyeData(FPathTracingPayload Payload, float3 V_World)
|
|
{
|
|
FEyeData Data = (FEyeData)0;
|
|
|
|
Data.Basis = GetTangentBasis(Payload.WorldNormal);
|
|
Data.Alpha = GetGGXAlpha(Payload.GetEyeRoughness());
|
|
Data.V = mul(Data.Basis, V_World);
|
|
|
|
const float NoV = saturate(Data.V.z);
|
|
Data.Spec = ComputeGGXSpecEnergyTermsRGB(Payload.GetEyeRoughness(), NoV, Payload.SpecularColor);
|
|
|
|
Data.DiffWeight = (1 - Luminance(Data.Spec.E)) * Payload.DiffuseColor;
|
|
|
|
// Probability of picking diffuse lobe vs. specular lobe
|
|
Data.LobeProb = LobeSelectionProb(Data.DiffWeight, Data.Spec.E);
|
|
|
|
return Data;
|
|
}
|
|
|
|
FMaterialEval Eye_EvalMaterial(
|
|
float3 V_World,
|
|
float3 L_World,
|
|
FPathTracingPayload Payload,
|
|
float2 DiffuseSpecularScale
|
|
)
|
|
{
|
|
const FEyeData Data = PrepareEyeData(Payload, V_World);
|
|
|
|
// move vectors into right shading frame
|
|
const float3 V = Data.V;
|
|
const float3 L = mul(Data.Basis, L_World);
|
|
const float3 H = normalize(V + L);
|
|
|
|
const float NoV = saturate(V.z);
|
|
const float NoL = saturate(L.z);
|
|
const float VoH = saturate(dot(V, H));
|
|
|
|
|
|
FMaterialEval Result = NullMaterialEval();
|
|
|
|
const float IrisMask = Payload.GetEyeIrisMask();
|
|
const float3 IrisNormal = Payload.GetEyeIrisNormal();
|
|
const float3 CausticNormal = Payload.GetEyeCausticNormal();
|
|
const float IrisNoL = saturate(dot(IrisNormal, L_World));
|
|
const float Power = lerp(12, 1, IrisNoL);
|
|
const float Caustic = 0.8 + 0.2 * (Power + 1) * pow(saturate(dot(CausticNormal, L_World)), Power);
|
|
const float Iris = IrisNoL * Caustic;
|
|
const float Sclera = NoL;
|
|
const float EyeDiffuseTweak = 2 * lerp(Sclera, Iris, IrisMask);
|
|
const float DiffPdf = 1 / (2 * PI);
|
|
|
|
// Diffuse Lobe
|
|
Result.AddLobeWithMIS(Data.DiffWeight * EyeDiffuseTweak * DiffuseSpecularScale.x, DiffPdf, Data.LobeProb);
|
|
|
|
// Specular lobe
|
|
const float2 GGXResult = GGXEvalReflection(L, V, H, Data.Alpha);
|
|
const float3 F = F_Schlick(Payload.SpecularColor, VoH);
|
|
const float3 SpecWeight = F * GGXResult.x * Data.Spec.W;
|
|
const float SpecPdf = GGXResult.y;
|
|
|
|
Result.AddLobeWithMIS(SpecWeight * DiffuseSpecularScale.y, SpecPdf, 1.0 - Data.LobeProb);
|
|
|
|
Result.Weight *= Payload.BSDFOpacity;
|
|
|
|
return Result;
|
|
}
|
|
|
|
FMaterialSample Eye_SampleMaterial(
|
|
float3 V_World,
|
|
FPathTracingPayload Payload,
|
|
float3 RandSample
|
|
)
|
|
{
|
|
const FEyeData Data = PrepareEyeData(Payload, V_World);
|
|
|
|
const float3 V = Data.V;
|
|
const float NoV = saturate(V.z);
|
|
|
|
// Randomly choose to sample diffuse or specular
|
|
float3 L = 0, H = 0;
|
|
const bool bSampledDiffuse = RandSample.x < Data.LobeProb;
|
|
if (bSampledDiffuse)
|
|
{
|
|
RandSample.x = RescaleRandomNumber(RandSample.x, 0.0, Data.LobeProb);
|
|
|
|
L = UniformSampleHemisphere(RandSample.xy).xyz;
|
|
H = normalize(L + V);
|
|
}
|
|
else
|
|
{
|
|
RandSample.x = RescaleRandomNumber(RandSample.x, Data.LobeProb, 1.0);
|
|
|
|
H = ImportanceSampleVisibleGGX(RandSample.xy, Data.Alpha, V).xyz;
|
|
L = reflect(-V, H);
|
|
if (L.z <= 0)
|
|
{
|
|
// invalid output direction, exit early
|
|
return NullMaterialSample();
|
|
}
|
|
}
|
|
|
|
// With a valid direction in hand -- now evaluate the BxDF (taking advantage of already computed terms)
|
|
|
|
// transform to world space
|
|
const float3 L_World = normalize(mul(L, Data.Basis));
|
|
|
|
const float NoL = saturate(L.z);
|
|
const float VoH = saturate(dot(V, H));
|
|
|
|
const float2 GGXResult = GGXEvalReflection(L, V, H, Data.Alpha);
|
|
const float SpecPdf = GGXResult.y;
|
|
const float DiffPdf = 1 / (2 * PI);
|
|
|
|
FMaterialSample Result = CreateMaterialSample(L_World, 0.0, 0.0, 1.0, 1.0, PATHTRACER_SCATTER_DIFFUSE);
|
|
if (bSampledDiffuse)
|
|
{
|
|
const float IrisMask = Payload.GetEyeIrisMask();
|
|
const float3 IrisNormal = Payload.GetEyeIrisNormal();
|
|
const float3 CausticNormal = Payload.GetEyeCausticNormal();
|
|
const float IrisNoL = saturate(dot(IrisNormal, L_World));
|
|
const float Power = lerp(12, 1, IrisNoL);
|
|
const float Caustic = 0.8 + 0.2 * (Power + 1) * pow(saturate(dot(CausticNormal, L_World)), Power);
|
|
const float Iris = IrisNoL * Caustic;
|
|
const float Sclera = NoL;
|
|
|
|
const float EyeDiffuseTweak = 2 * lerp(Sclera, Iris, IrisMask);
|
|
|
|
// Diffuse Lobe
|
|
Result.AddLobeWithMIS(Data.DiffWeight * EyeDiffuseTweak, DiffPdf, Data.LobeProb);
|
|
|
|
Result.Pdf += (1 - Data.LobeProb) * SpecPdf;
|
|
}
|
|
else
|
|
{
|
|
// Specular lobe
|
|
const float3 F = F_Schlick(Payload.SpecularColor, VoH);
|
|
const float3 SpecWeight = F * GGXResult.x * Data.Spec.W;
|
|
|
|
Result.AddLobeWithMIS(SpecWeight, SpecPdf, 1.0 - Data.LobeProb);
|
|
Result.Pdf += Data.LobeProb * DiffPdf;
|
|
Result.Roughness = Payload.GetEyeRoughness();
|
|
Result.ScatterType = PATHTRACER_SCATTER_SPECULAR;
|
|
}
|
|
Result.Weight *= Payload.BSDFOpacity;
|
|
return Result;
|
|
}
|