97 lines
3.1 KiB
HLSL
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);
|
|
} |