213 lines
5.5 KiB
HLSL
213 lines
5.5 KiB
HLSL
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#define HAIR_CUSTOM_BSDF 1
|
|
|
|
#include "../Common.ush"
|
|
#include "../ShadingCommon.ush"
|
|
#include "../ShadingModels.ush"
|
|
#include "../HairBsdf.ush"
|
|
|
|
|
|
float2 SampleMp(float2 u, float Roughness, float cosThetaO, float sinThetaO)
|
|
{
|
|
const float v = Pow2(Roughness); // Roughness to variance
|
|
|
|
u.x = max(u.x, float(1e-5));
|
|
|
|
float cosTheta = 1 + v * log(u.x + (1 - u.x) * exp(-2 / v));
|
|
float sinTheta = sqrt(max(0.f, 1 - Pow2(cosTheta)));
|
|
float cosPhi = cos(2 * PI * u.y);
|
|
float sinThetaI = -cosTheta * sinThetaO + sinTheta * cosPhi * cosThetaO;
|
|
float cosThetaI = sqrt(max(0.f, 1 - Pow2(sinThetaI)));
|
|
|
|
return float2(cosThetaI, sinThetaI);
|
|
}
|
|
|
|
float Phi(int p, float gammaO, float gammaT)
|
|
{
|
|
return 2 * p * gammaT - 2 * gammaO + p * PI;
|
|
}
|
|
|
|
float3 SampleNp(float h, float cosThetaO, float sinThetaO)
|
|
{
|
|
const float eta = 1.55f;
|
|
const float s = 0.11715981f; // For radial roughness of 0.3
|
|
const float gammaO = asin(h);
|
|
|
|
// Compute $\gammat$ for refracted ray
|
|
float etap = sqrt(eta * eta - Pow2(sinThetaO)) / cosThetaO;
|
|
float sinGammaT = h / etap;
|
|
float gammaT = asin(sinGammaT);
|
|
return float3(
|
|
Phi(0, gammaO, gammaT),
|
|
Phi(1, gammaO, gammaT),
|
|
Phi(2, gammaO, gammaT));
|
|
// +SampleTrimmedLogistic(u, s, -PI, PI);
|
|
}
|
|
|
|
float3 asinFast3(float3 a)
|
|
{
|
|
return float3(
|
|
asinFast(a.x),
|
|
asinFast(a.y),
|
|
asinFast(a.z));
|
|
}
|
|
|
|
void SampleHair(
|
|
float Roughness,
|
|
float3 BaseColor,
|
|
float Specular,
|
|
float Backlit,
|
|
float3 V,
|
|
float3 T,
|
|
float2 u0,
|
|
float2 u1,
|
|
uint HairComponents,
|
|
inout float3 OutDirection,
|
|
inout float3 OutWeight)
|
|
{
|
|
//float h = (floor(hh*4)+0.5f)/4;
|
|
const float h = clamp(u1.x * 2 - 1, -1, 1);
|
|
|
|
const float Area = 0;
|
|
const float ClampedRoughness = clamp(Roughness, 1 / 255.0f, 1.0f);
|
|
|
|
const float SinThetaV = dot(T, V);
|
|
const float CosThetaV = sqrt(1 - SinThetaV * SinThetaV);
|
|
const float phiO = atan2(V.z, V.y);
|
|
|
|
const float3 dPhiL = SampleNp(h, CosThetaV, SinThetaV);
|
|
const float3 CosPhi = cos(dPhiL);
|
|
const float3 CosHalfPhi = cos(0.5f * dPhiL);
|
|
|
|
float Shift = 0.035;
|
|
|
|
const float sa = sin(-Shift * 2);
|
|
const float ca = cos(-Shift * 2);
|
|
const float ShiftR = 2 * sa* (ca * CosHalfPhi[0] * sqrt(1 - SinThetaV * SinThetaV) + sa * SinThetaV);
|
|
|
|
float3 Alpha = float3
|
|
(
|
|
ShiftR,
|
|
Shift,
|
|
Shift * 4
|
|
);
|
|
float B[] =
|
|
{
|
|
Area + Pow2(ClampedRoughness),// * sqrt(CosHalfPhi[0] * sqrt(2)),
|
|
Area + Pow2(ClampedRoughness) / 2,
|
|
Area + Pow2(ClampedRoughness) * 2,
|
|
};
|
|
|
|
// 1. Take mirror direction + offset
|
|
const float3 SinThetaL = sin(asin(SinThetaV) + Alpha);
|
|
const float3 CosThetaD = cos(0.5 * abs(asinFast(SinThetaV).xxx - asinFast3(SinThetaL)));
|
|
|
|
|
|
uint p = 0;
|
|
float3 Ap[3];
|
|
Ap[0] = 0.0;
|
|
Ap[1] = 0.0;
|
|
Ap[2] = 0.0;
|
|
|
|
// 2. Lobe selection
|
|
// R Energy
|
|
if (HairComponents & HAIR_COMPONENT_R)
|
|
{
|
|
const float VoL = cos(abs(asinFast(SinThetaV) - asinFast(SinThetaL[0])));
|
|
|
|
float Np = 0.25 * CosHalfPhi[0];
|
|
float Fp = Hair_F(sqrt(saturate(0.5 + 0.5 * VoL)));
|
|
|
|
Ap[0] = Np * Fp * (Specular * 2);
|
|
}
|
|
// TT Energy
|
|
if (HairComponents & HAIR_COMPONENT_TT)
|
|
{
|
|
const float n = 1.55;
|
|
const float n_prime = 1.19 / CosThetaD[1] + 0.36 * CosThetaD[1];
|
|
float a = 1 / n_prime;
|
|
float h = CosHalfPhi[1] * (1 + a * (0.6 - 0.8 * CosPhi[1]));
|
|
float f = Hair_F(CosThetaD[1] * sqrt(saturate(1 - h * h)));
|
|
float Fp = Pow2(1 - f);
|
|
float3 Tp = pow(BaseColor, 0.5 * sqrt(1 - Pow2(h * a)) / CosThetaD[1]);
|
|
float Np = exp(-3.65 * CosPhi[1] - 3.98);
|
|
|
|
Ap[1] = Np * Fp * Tp * Backlit;
|
|
}
|
|
// TRT Energy
|
|
if (HairComponents & HAIR_COMPONENT_TRT)
|
|
{
|
|
//float h = 0.75;
|
|
float f = Hair_F(CosThetaD[2] * 0.5);
|
|
float Fp = Pow2(1 - f) * f;
|
|
float3 Tp = pow(BaseColor, 0.8 / CosThetaD[2]);
|
|
float Np = exp(17 * CosPhi[2] - 16.78);
|
|
|
|
Ap[2] = Np * Fp * Tp;
|
|
}
|
|
|
|
const float3 AverageAp = float3(dot(Ap[0],0.333f), dot(Ap[1],0.333f), dot(Ap[2],0.333f));
|
|
const float Wp = max(1e-4, AverageAp.x + AverageAp.y + AverageAp.z);
|
|
const float3 LobePdf = AverageAp / Wp;
|
|
if (u1.y <= LobePdf.x)
|
|
{
|
|
p = 0;
|
|
}
|
|
else if (u1.y < (LobePdf.x + LobePdf.y))
|
|
{
|
|
p = 1;
|
|
}
|
|
else
|
|
{
|
|
p = 2;
|
|
}
|
|
|
|
|
|
// 3. Sample Mp
|
|
const float SinThetaVp = sin(asin(SinThetaV) - Alpha[p]);
|
|
const float CosThetaVp = cos(acos(CosThetaV) - Alpha[p]);
|
|
|
|
const float2 CosSinThetaL = SampleMp(u0, B[p], CosThetaVp, SinThetaVp);
|
|
const float PhiL = phiO + dPhiL[p];
|
|
|
|
// 4. Weight computation
|
|
// Importance Sampling for Physically-Based Hair Fiber Models - Section 3.2
|
|
OutWeight = clamp(Ap[p] / Wp, 0, 2);
|
|
OutDirection = float3(CosSinThetaL.y, CosSinThetaL.x * cos(PhiL), CosSinThetaL.x * sin(PhiL));
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
float2 Rand1SPPDenoiserInput(uint2 PixelPos, uint FrameIndexMod8)
|
|
{
|
|
uint2 Random = Rand3DPCG16(int3(PixelPos, FrameIndexMod8)).xy;
|
|
float2 E = float2(Random) * rcp(65536.0); // equivalent to Hammersley16(0, 1, Random).
|
|
|
|
return E;
|
|
}
|
|
|
|
// Example on how to sample the BSDF
|
|
// * you need to provide material property such as Roughness/BaseColor, but also ideally the
|
|
// BackLit is often used in card based groom
|
|
// * the sampling need 4 random numbers. This example show a simple correlated sample pattern
|
|
{
|
|
const uint TileOffset = 17; // Arbitrary, but larger than the reconstruction kernel window
|
|
const float2 RandU = Rand1SPPDenoiserInput(PixelCoord);
|
|
const float2 RandV = Rand1SPPDenoiserInput(PixelCoord + TileOffset);
|
|
|
|
const float Specular = 0.5;
|
|
const float Backlit = 1;
|
|
|
|
float3 OutDirection = float3(0, 0, 1);
|
|
float OutWeight = 1;
|
|
const uint HairComponents = HAIR_COMPONENT_R | HAIR_COMPONENT_TT | HAIR_COMPONENT_TRT;
|
|
SampleHair(Roughness, BaseColor, V, T, RandU, RandV, HairComponents, OutDirection, OutWeight);
|
|
|
|
}
|
|
|
|
#endif |