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

97 lines
3.1 KiB
HLSL

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
///////////////////////////////////////////////////////////////////////////////////////////////////
// Hair components
// Hair reflectance component (R, TT, TRT, Local Scattering, Global Scattering, Multi Scattering,...)
#define HAIR_COMPONENT_R 0x1u
#define HAIR_COMPONENT_TT 0x2u
#define HAIR_COMPONENT_TRT 0x4u
#define HAIR_COMPONENT_LS 0x8u
#define HAIR_COMPONENT_GS 0x10u
#define HAIR_COMPONENT_MULTISCATTER 0x20u
#define HAIR_COMPONENT_TT_MODEL 0x40u
///////////////////////////////////////////////////////////////////////////////////////////////////
// Transmittance functions
struct FHairTransmittanceData
{
bool bUseLegacyAbsorption;
bool bUseSeparableR;
bool bUseBacklit;
bool bClampBSDFValue;
float OpaqueVisibility;
float3 LocalScattering;
float3 GlobalScattering;
uint ScatteringComponent;
};
FHairTransmittanceData InitHairTransmittanceData(bool bMultipleScatterEnable = true)
{
FHairTransmittanceData o;
o.bUseLegacyAbsorption = true;
o.bUseSeparableR = true;
o.bUseBacklit = false;
o.bClampBSDFValue = true;
o.OpaqueVisibility = 1;
o.LocalScattering = 0;
o.GlobalScattering = 1;
o.ScatteringComponent = HAIR_COMPONENT_R | HAIR_COMPONENT_TT | HAIR_COMPONENT_TRT | (bMultipleScatterEnable ? HAIR_COMPONENT_MULTISCATTER : 0);
return o;
}
FHairTransmittanceData InitHairStrandsTransmittanceData(bool bMultipleScatterEnable = false)
{
FHairTransmittanceData o = InitHairTransmittanceData(bMultipleScatterEnable);
o.bUseLegacyAbsorption = false;
o.bUseBacklit = true;
return o;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Hair Absorption
// Reference: A Practical and Controllable Hair and Fur Model for Production Path Tracing.
float3 HairAbsorptionToColor(float3 A, float B=0.3f)
{
const float b2 = B * B;
const float b3 = B * b2;
const float b4 = b2 * b2;
const float b5 = B * b4;
const float D = (5.969f - 0.215f * B + 2.532f * b2 - 10.73f * b3 + 5.574f * b4 + 0.245f * b5);
return exp(-sqrt(A) * D);
}
// Reference: A Practical and Controllable Hair and Fur Model for Production Path Tracing.
float3 HairColorToAbsorption(float3 C, float B = 0.3f)
{
const float b2 = B * B;
const float b3 = B * b2;
const float b4 = b2 * b2;
const float b5 = B * b4;
const float D = (5.969f - 0.215f * B + 2.532f * b2 - 10.73f * b3 + 5.574f * b4 + 0.245f * b5);
return Pow2(log(C) / D);
}
// Reference: An Energy-Conserving Hair Reflectance Model
// Adapated for [0..1] range
float3 GetHairColorFromMelanin(float InMelanin, float InRedness, float3 InDyeColor)
{
InMelanin = saturate(InMelanin);
InRedness = saturate(InRedness);
const float Melanin = -log(max(1 - InMelanin, 0.0001f));
const float Eumelanin = Melanin * (1 - InRedness);
const float Pheomelanin = Melanin * InRedness;
const float3 DyeAbsorption = HairColorToAbsorption(saturate(InDyeColor));
const float3 Absorption = Eumelanin * float3(0.506f, 0.841f, 1.653f) + Pheomelanin * float3(0.343f, 0.733f, 1.924f);
return HairAbsorptionToColor(Absorption + DyeAbsorption);
}