79 lines
3.1 KiB
HLSL
79 lines
3.1 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "ShadingCommon.ush"
|
|
|
|
#pragma once
|
|
|
|
#define THIN_TRANSLUCENT_USE_DOTNV_THICKNESS 1
|
|
|
|
#if MATERIAL_SHADINGMODEL_THIN_TRANSLUCENT
|
|
void AccumulateThinTranslucentModel(inout float3 DualBlendSurfaceLuminancePostCoverage,
|
|
inout float3 DualBlendSurfaceTransmittancePreCoverage,
|
|
inout float DualBlendSurfaceCoverage,
|
|
FMaterialPixelParameters MaterialParams,
|
|
FGBufferData GBuffer,
|
|
float3 DiffuseColor,
|
|
float3 SpecularColor,
|
|
float3 EmissiveColor,
|
|
float TopMaterialCoverage)
|
|
{
|
|
const float3 N = MaterialParams.WorldNormal;
|
|
const float3 V = MaterialParams.CameraVector;
|
|
|
|
const float NoV = saturate( abs( dot(N, V) ) + 1e-5 );
|
|
|
|
// how much to multiply the background color by
|
|
float3 Transmittance = float3(1.0,1.0,1.0);
|
|
|
|
// how much to add for foreground color
|
|
float3 SurfaceColor = float3(0.0f,0.0f,0.0f);
|
|
|
|
const float3 TransmittanceColor = GetThinTranslucentMaterialOutput0(MaterialParams);
|
|
const float SurfaceCoverage = GetThinTranslucentMaterialOutput1(MaterialParams);
|
|
|
|
// color is for normalized thickness
|
|
#if THIN_TRANSLUCENT_USE_DOTNV_THICKNESS
|
|
// TODO: in theory this should account for the IOR as well, see the path tracing code for a reference
|
|
// However in practice the difference is subtle, so keep using this simple logic for now.
|
|
float PathLength = rcp(NoV);
|
|
#else
|
|
float PathLength = 1.0f;
|
|
#endif
|
|
float3 NegativeAbsorptionCoefficient = log(TransmittanceColor);
|
|
float3 BottomMaterialTransmittance = exp(NegativeAbsorptionCoefficient * PathLength);
|
|
|
|
// Light goes from background -> solid surface -> camera, and we need fresnel at both interactions.
|
|
const float3 FresnelRatio = F_Schlick(GBuffer.SpecularColor, NoV);
|
|
|
|
// FresnelRatio light is reflected back into the background, and the rest refracts into the surface.
|
|
Transmittance = Transmittance * (1-FresnelRatio);
|
|
|
|
// Light gets lost from absorption through the surface
|
|
Transmittance = Transmittance * BottomMaterialTransmittance;
|
|
|
|
// Exiting the surface, the Fresnel ratio is the same! This is technically only true for F_Fresnel, but since we are using
|
|
// F_Schlick as a stand-in, applying the same logic is a valid approximation
|
|
// In mathematica, using fr[cos,eta] we can verify that:
|
|
// fr[c_, eta_] := 1 / 2 * A ^ 2 * (1 + B ^ 2) /.A -> (g - c) / (g + c) /.B -> (c * (g + c) - 1) / (c * (g - c) + 1) /.g->Sqrt[eta ^ 2 - 1 + c ^ 2];
|
|
// FullSimplify[fr[c, 1/ior] == fr[Sqrt[1 - (1 - c ^ 2) * ior ^ 2], ior], Assumptions->ior > 1 && c > 0 && c < 1]
|
|
// evaluates to
|
|
// True
|
|
Transmittance = Transmittance * (1-FresnelRatio);
|
|
|
|
// We are treating the BaseColor and Emissive color as a layer on top of the absorbing media, but below specular layer.
|
|
float3 DefaultLitColor = DiffuseColor + EmissiveColor;
|
|
|
|
SurfaceColor += DefaultLitColor * TopMaterialCoverage;
|
|
Transmittance *= (1.0f - TopMaterialCoverage);
|
|
|
|
SurfaceColor += SpecularColor;
|
|
|
|
// Luminance and transmitance assumin a full coverage of 1.
|
|
DualBlendSurfaceCoverage = SurfaceCoverage;
|
|
DualBlendSurfaceLuminancePostCoverage = SurfaceColor * DualBlendSurfaceCoverage;
|
|
DualBlendSurfaceTransmittancePreCoverage = Transmittance;
|
|
}
|
|
#endif
|
|
|
|
|