Sheen: linkWithAlbedo issue

Hi there!

I faced strange behaviour of how does sheen link to albedo works. I’ve prepared small playground to show:

There is also an image.

The 2nd sphere doesn’t looks like expected. So the question is:
Is it an issue or I’m doing something wrong or I expect wrong result?
I expect something that looks like that (The properties of 2nd sphere in 2nd image were manually tweaked just for example).

@sebavan @Evgeni_Popov . I pinged you guys because I saw you were involved in more or less the same issue.
linked topic: Sheen - Link to Albedo?

What would you expect from the flag ? (trying to understand the issue you are facing)

Thanks for the reply! @sebavan

I expected the sheen color to be taken from the albedo, meaning both the color and the texture. But for some reason the mesh becomes much darker in the first screenshot, case 2, than when I use a red sheen color, as shown in the second screenshot, case 2 (and not use link to albedo).

This does not happen when metallic is set to 1. It looks like the sheen itself works and has the right color, but the mesh surface becomes much darker when the material behaves as non metallic.

So I am trying to understand if this is expected behavior.

And if it is, what is linkToAlbedo meant for, and what physical case does it represent? In other words, why does the surface become darker?

Copilot nailed it so well I would simply copy paste. It did a way better job than I could have :slight_smile:

What linkSheenWithAlbedo does

It switches the sheen layer into a legacy “energy-conserving” model where three things change (see pbrBlockSheen.fx:94-101):

#ifdef SHEEN_LINKWITHALBEDO
    float sheenFactor = pow5(1.0 - sheenIntensity);
    vec3 sheenColor = baseColor.rgb * (1.0 - sheenFactor);
    float sheenRoughness = sheenIntensity;
    outParams.surfaceAlbedo = surfaceAlbedo * sheenFactor;
  1. Sheen color is taken from the albedo/base color, not from the color property you set. (sheenColor = baseColor * (1 - sheenFactor))
  2. intensity is repurposed as the sheen roughness — it replaces the roughness value in the lighting pass lightFragment.fx:183-185, comment: “BE Careful: Sheen intensity is replacing the roughness value”).
  3. The diffuse albedo is darkened by pow5(1 - intensity) to “make room” for the sheen lobe, and that result is written back to surfaceAlbedo in pbr.fragment.fx:403-404.

Why the forum user sees the surface getting much darker

That’s expected behavior of this old model, caused entirely by step 3:

surfaceAlbedo∗=(1−intensity)5surfaceAlbedo∗=(1−intensity)5

The 5th-power falloff crushes the diffuse term very aggressively. At intensity = 1 the diffuse goes fully black, so a non-metallic surface looks dramatically darker as you raise the sheen intensity.

Why it doesn’t happen at metallic = 1: metals already have ~0 diffuse albedo, so multiplying that ~0 by sheenFactor changes nothing visible. Only the non-metallic case (which has a real diffuse albedo) shows the darkening. So the user’s observation is correct, not a bug.

The recommendation for the forum thread

linkSheenWithAlbedo is a non-physically-based approximation kept for backward compatibility. For “sheen colored like the base material” without the diffuse going dark, the modern path is:

  • Leave linkSheenWithAlbedo = false
  • Set sheen.color explicitly (or use sheen.texture)
  • Enable albedoScaling = true for energy conservation

With albedoScaling, the sheen is layered above the base BRDF (sheenIntensity *= (1 - reflectance) is skipped and a proper albedo-scaling factor is applied via the environment BRDF instead — see pbrBlockSheen.fx:130-133, so the base color is preserved instead of being driven to black.

Thank you for explanation. It’s seems clear now!