4.20.3 Fix for broken Backlit property in Hair shader

The “Backlit” input in the hair shader has been broken for some time - it ignores any input and is apparently set to max. There’s a “Backlogged” bug report for it here: Unreal Engine Issues and Bug Tracker (UE-39061)

A fix for it was described by **stororokw **here. However, this seems to apply to an older version of the engine, and the shader files in 4.20.3 have changed since then.

I seem to have been able to fix it in 4.20.3 by modifying Engine/Shaders/Private/ShadingModels.ush. I changed the line:


Lighting.Transmission = AreaLight.FalloffColor * Falloff * HairShading( GBuffer, L, V, N, Shadow.TransmissionShadow, **1**, 0, uint2(0,0) );

to:


Lighting.Transmission = AreaLight.FalloffColor * Falloff * HairShading( GBuffer, L, V, N, Shadow.TransmissionShadow, **GBuffer.CustomData.z**, 0, uint2(0,0) );

I guess the engine needs to recompile all shaders after making this change, so opening a project immediately afterwards will take a long time, but should be normal speed after that.

For me this bug made the hair shader unusable, but it seems like a great option with the fix. Hope others will find it useful.

Just wanted to add this is to prevalent in 4.25.1

The fix still works, however the should be updated to:


Lighting.Transmission = AreaLight.FalloffColor * Falloff * HairShading( GBuffer, L, V, N, Shadow.TransmissionShadow, Shadow.HairTransmittance, GBuffer.CustomData.z, 0, uint2(0,0), bEvalMultiScatter);

Note, the new **Shadow.HairTransmittance **parameter. The goal of the fix is still to replace, the constant 1 value.

I never looked into it, but I wonder if this could potentially also address the fact that transmission doesn’t fade to 0 but starts at .01 or .11 can’t remember witch, creating a line on skin…

I found better solution that was related to my problem.
So If anyone reach to here as i needed the fix, in 4.26.2,

The solution is change those

const float3 BsdfValue = HairShading(GBuffer, L, V, N, Shadow.TransmissionShadow, Shadow.HairTransmittance, 1, 0, uint2(0, 0));

to This

FHairTransmittanceData o = InitHairStrandsTransmittanceData();
const float3 BsdfValue = HairShading(GBuffer, L, V, N, Shadow.TransmissionShadow, o, 1, 0, uint2(0, 0));

The explanation :
in my case Hair shader doesn’t receive lights from surrounding or it is just no reflections
after updating a project from 4.20 to 4.26.2
applied above solution as a fix but didn’t the good quality that was in 4.20

checked the file the solution and traced the hair shader function found that implementation of new shader is in include “HairBsdf.ush”
opened the file found that the new function need a FHairTransmittanceData object
which is a part from the shadow object but actually is not procced (or initialized )
the “HairBsdf.ush” file has an initialization function that is actually not called in both files
after checking the 4.20 files too, i think the 1 value is not a problem, cuz based on initialization it is the max for backlit, and the initialization will let ue to use GBuffer.CustomData.z internally if good initialization done.

initialization functions in “HairBsdf.ush” , you can see it enable backlit when init strands is called.

FHairTransmittanceData InitHairTransmittanceData(bool bMultipleScatterEnable = true)
{
	FHairTransmittanceData o;
	o.bUseLegacyAbsorption = true;
	o.bUseSeparableR = true;
	o.bUseBacklit = false;

	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;
}

and this line will be called inside HairShading function automatically to let backlit used

const float Backlit	= min(InBacklit, HairTransmittance.bUseBacklit ? GBuffer.CustomData.z : 1);

so the solution was to call the function that initialize an hair transmit data correctly as it was newly added part of the shadow struct without initializing

FHairTransmittanceData o = InitHairStrandsTransmittanceData();

and pass that object to HairShaderFunction, and keep the value ‘1’ as it is.

that what i think may be the solution, i’m not aware if init is done on any other place, you can correct me , i hope it help as i spend hours on it to find solution as i can’t upgrade the project to more higher verison

thanks in advance

1 Like