Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b5d2ffe
fix(hair): marschner with weird coloring under volumetric shadows
jiayev Feb 26, 2026
e22f3b2
Update features/Hair Specular/Shaders/Hair/Hair.hlsli
jiayev Feb 26, 2026
6c6ad7b
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 26, 2026
7bff545
fix ai error
jiayev Feb 26, 2026
ea92f69
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 26, 2026
0ad300b
ughhh ai
jiayev Feb 26, 2026
0e72e08
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 26, 2026
70f0d8f
fix(hair): update shadow calculations for hair transmission and diffu…
jiayev Feb 27, 2026
bdd9d88
test(hair): add HLSL unit tests for hair specular features
jiayev Feb 27, 2026
f5227e2
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 27, 2026
08c54d4
prevent redefinition
jiayev Feb 27, 2026
5cc79f9
fix(hair): enhance HLSL unit tests for hair specular features and imp…
jiayev Feb 27, 2026
c35b54a
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 27, 2026
e0bd064
fix(tests): update shader test dependencies and include feature shade…
jiayev Feb 27, 2026
4e7b31b
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 27, 2026
f51dda7
feat(hair): add PBR lighting constants and include common dependencie…
jiayev Feb 27, 2026
138ebc9
fix(hair): add stub function for screen depth in SharedData namespace
jiayev Feb 27, 2026
4d8149b
style: 🎨 apply pre-commit.ci formatting
pre-commit-ci[bot] Feb 27, 2026
091fdda
add hair define
jiayev Feb 27, 2026
26d3d13
add HAIR define to test
jiayev Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions features/Hair Specular/Shaders/Hair/Hair.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,8 @@ namespace Hair

// [Scheuermann 2004, "Hair Rendering and Shading"]
// https://web.engr.oregonstate.edu/~mjb/cs557/Projects/Papers/HairRendering.pdf
void GetHairDirectLightScheuermann(out float3 dirDiffuse, out float3 dirSpecular, out float3 dirTransmission, float3 T, float3 L, float3 V, float3 N, float3 VN, float3 lightColor, float shininess, float selfShadow, float2 uv, float3 baseColor)
void GetHairDirectLightScheuermann(out float3 dirDiffuse, out float3 dirSpecular, out float3 dirTransmission, float3 T, float3 L, float3 V, float3 N, float3 VN, DirectContext context, float shininess, float2 uv, float3 baseColor)
{
lightColor *= selfShadow;
const float3 H = normalize(L + V);
const float oNdotL = dot(N, L);
const float NdotL = saturate(oNdotL);
Expand All @@ -71,6 +70,9 @@ namespace Hair
const float HdotL = saturate(dot(H, L));
const float wrapped = 0.5;

float3 lightColor = context.lightColor * context.detailedShadow;
float3 softColor = context.lightColor * context.softShadow * context.hairShadow;

// [Yibing Jiang 2016, "The Process of Creating Volumetric-based Materials in Uncharted 4"]
// https://advances.realtimerendering.com/s2016
dirDiffuse = saturate(oNdotL + wrapped) / (1 + wrapped);
Expand All @@ -97,7 +99,7 @@ namespace Hair
float scatterFresnel2 = saturate(pow(abs(1 - VNdotV), 20));
float3 specT = (scatterFresnel1 + scatterFresnel2 * scatterColor) * SharedData::hairSpecularSettings.Transmission;
dirSpecular = specR * lightColor * SharedData::hairSpecularSettings.SpecularMult;
dirTransmission = specT * lightColor * SharedData::hairSpecularSettings.SpecularMult;
dirTransmission = specT * softColor * SharedData::hairSpecularSettings.SpecularMult;
}

float Hair_g(float B, float Theta)
Expand Down Expand Up @@ -192,9 +194,9 @@ namespace Hair
return max(S, 0);
}

void GetHairDirectLightMarschner(out float3 dirDiffuse, out float3 dirSpecular, out float3 dirTransmission, float3 T, float3 L, float3 V, float3 N, float3 VN, float3 lightColor, float shininess, float selfShadow, float2 uv, float3 baseColor)
void GetHairDirectLightMarschner(out float3 dirDiffuse, out float3 dirSpecular, out float3 dirTransmission, float3 T, float3 L, float3 V, float3 N, float3 VN, DirectContext context, float shininess, float2 uv, float3 baseColor)
{
lightColor *= Color::PBRLightingCompensation;
float3 lightColor = context.lightColor * Color::PBRLightingCompensation;
dirDiffuse = 0;
dirSpecular = 0;
dirTransmission = 0;
Expand All @@ -205,10 +207,10 @@ namespace Hair
T = ShiftTangent(T, N, shift);
}

float backlit = SharedData::hairSpecularSettings.Transmission * selfShadow;
float shadow = context.hairShadow * context.detailedShadow;

dirTransmission += D_Marschner(L, V, T, roughness, baseColor, 0, backlit) * lightColor * SharedData::hairSpecularSettings.SpecularMult;
dirTransmission += GetHairDiffuseAttenuationKajiyaKay(T, V, L, selfShadow, baseColor) * lightColor * SharedData::hairSpecularSettings.DiffuseMult;
dirTransmission += D_Marschner(L, V, T, roughness, baseColor, 0, SharedData::hairSpecularSettings.Transmission) * lightColor * shadow * SharedData::hairSpecularSettings.SpecularMult;
dirTransmission += GetHairDiffuseAttenuationKajiyaKay(T, V, L, shadow, baseColor) * lightColor * shadow * SharedData::hairSpecularSettings.DiffuseMult;
}

void GetHairDirectLight(out DirectLightingOutput lightingOutput, DirectContext context, MaterialProperties material, float3x3 tbnTr, float2 uv)
Expand All @@ -219,13 +221,10 @@ namespace Hair
const float3 VN = normalize(tbnTr[2]);
const float3 L = normalize(context.lightDir);

float3 lightColor = context.lightColor * context.detailedShadow;
float selfShadow = context.hairShadow * context.softShadow;

if (SharedData::hairSpecularSettings.HairMode == 0) {
GetHairDirectLightScheuermann(lightingOutput.diffuse, lightingOutput.specular, lightingOutput.transmission, T, L, V, N, VN, lightColor, material.Shininess, selfShadow, uv, material.BaseColor);
GetHairDirectLightScheuermann(lightingOutput.diffuse, lightingOutput.specular, lightingOutput.transmission, T, L, V, N, VN, context, material.Shininess, uv, material.BaseColor);
} else {
GetHairDirectLightMarschner(lightingOutput.diffuse, lightingOutput.specular, lightingOutput.transmission, T, L, V, N, VN, lightColor, material.Shininess, selfShadow, uv, material.BaseColor);
GetHairDirectLightMarschner(lightingOutput.diffuse, lightingOutput.specular, lightingOutput.transmission, T, L, V, N, VN, context, material.Shininess, uv, material.BaseColor);
}
}

Expand Down Expand Up @@ -299,4 +298,4 @@ namespace Hair
return lerp(1.0, shadow, SharedData::hairSpecularSettings.SelfShadowStrength);
}
}
#endif //__HAIR_DEPENDENCY_HLSL__
#endif //__HAIR_DEPENDENCY_HLSL__
4 changes: 4 additions & 0 deletions package/Shaders/Common/Color.hlsli
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ namespace Color
return ENABLE_LL ? SharedData::linearLightingSettings.vanillaDiffuseColorMult : 1.0f;
}
#else
const static float PBRLightingScale = 1.0;
const static float ReflectionNormalisationScale = 1.0;
const static float PBRLightingCompensation = Math::PI;

float3 Diffuse(float3 color)
{
# if defined(TRUE_PBR)
Expand Down
Loading