Anisotropy issue in shaders

Hi!

I have a setup for adding these small scratches to my metallic shaders, however I have noticed a small issue when using it.

Here are my image textures:

I am basically using image textures for the scratches. I have a normal map, random value per scratch for the anisotropy strength (between 0 and 1), and I have a map for the anisotropic rotation per scratch.

My issue is that if I take a Glossy BSDF, and a Principled BSDF with the same basic settings, and I connect the same image textures to it, I get completely different results.

Here is my setup:

Based on what I have read so far it seems like these two shaders use different methods internally. And based on my testing it seems like I get much stronger anisotropic results from the Glossy.

Here is the result from the Glossy BSDF:

And here is the result from the Principle BSDF:

Now it seems like this is to do something with how each shader internally deals with the anisotropy, but I am unsure if it is a bug, or if one of them is more accurate in terms of energy conservation or something similar.

I have also made tests where I just use a constant anisotropy value and it seems like if I set the anisotropy to about 0.78 on the Glossy and 1 on the Principled, then I get similar results.

It seems to me like the principled BSDF is perhaps inaccurate? although dont quote me on that, I just prefer the stronger scratches look from the glossy.

I’d also prefer to use the Principled BSDF, because then I can add the thin film layer to the scratches to give them some color, and then I could also use them for materials that are non metallic.

If anyone knows some more info on this, then please do let me know!

Cheers!

Both use the same GGX base; the difference lies in the internal calculation of the anisotropy factor.

Principled

| `    float aspect = sqrt(1.0 - clamp(Anisotropic, 0.0, 1.0) * 0.9);`<br> |
|----|
| `    alpha_x /= aspect;`<br> |
| `    alpha_y *= aspect;` |

Glossy

| `    float aniso = clamp(Anisotropy, -0.99, 0.99);
| `    if (aniso < 0.0) {`<br> |
|----|
| `      roughness_u = roughness / (1.0 + aniso);`<br> |
| `      roughness_v = roughness * (1.0 + aniso);`<br> |
| `    }`<br> |
| `    else {`<br> |
| `      roughness_u = roughness * (1.0 - aniso);`<br> |
| `      roughness_v = roughness / (1.0 - aniso);`<br> |
| `    }` |

If I’m not mistaken, the “Glossy” setting allows for a difference between the two roughness values that is 1,000 times greater than the “Principled” setting.

The “Principled” setting could, theoretically, go higher, but you’d have to change the coefficient from *0.9 to *0.99.

A question to ask the Blender developers.

Thanks for the answer!

It seems kind of odd that there is such an discrepancy between the two, however I’m not sure whether this would qualify as a bug, or if this is intentional.

Anyhow, I will probably ask a dev at some point.

Cheers!

It’s intentional in order to be closer to other renderers. And quite unfortunate. Principled/Metallic don’t allow us to get anisotropy with fake adequate backscattering in some circumstances. I’m just not using them anymore.

Check if rotation produces the same result if multiplied by 0.5. The rotation doesn’t care if it’s offset by 180° (unlike nap direction for diffuse/sheen, which I don’t think is implemented yet in any renderer). Either glossy or principled should also have 0.25 added to the rotation, as they are 90° apart. Principled max anisotropy is approx 0.7 on glossy node, set them both to 0.69 to be sure when comparing them.

Thanks for the reply!

I’ll take a look at the rotation map of the scratches themselves. Based on my experimentations I also reached the conclusion that if I just set the anisotropy on the Glossy shader to 0.7 I get the same effect as the anisotropy set to 1 on the Principled bsdf.

The reason why I am having this issue in the first place is that I want to use the thin film effect on my scratches to add that realistic color shifting that you see in real life. So far that has not been added to the glossy shader, so that is the reason why I wanted to stick to the principled bsdf.

Cheers!

If you can live with the 0.7 limitation, then it should just be a matter of adding 0.25 to the rotation map going into one of them to better match eachother. You’ll have to experiment with which one looks b better/produces closer to expected result..

Yeah, What I did was just add 90 degrees to the tangent with a vector rotate, and I do get the same pattern. My issue with the whole thig is that I like the look of the glossy BSDF at full strength and I cant get that with the principled BSDF. And I cannot live with the 0.7 value strength. :smiling_face_with_tear:

Do you have an example of this, from real life? I’m not completely sure where a color shift would come from due to thin film in the metal scratches itself. Wouldn’t a scratch remove the coating and expose the bare metal itself? Or is there a clearcoat with scratches on top of a metal with thinfilm?

Anywho, for a thinfilm based metal with anisotropic based scratches, I’d probably try to mix in regular Glossy (with anisotropy) for the scratches only, using a fairly low mix and intensity value, using Metallic shader for the rest. The example also show the main metal and how I tend to approach “hazy gloss” hard mixing several Metallic BSDF with varying roughness.

I also think there is a slight misunderstanding here, I am looking to replicate the effect of the scratches themselves causing the slight color shift within the scratches themselves. The overall metal does not have iridescence.

After doing some research there seems to also be some research papers on how to replicate it in render engines: https://dl.acm.org/doi/10.1145/3130800.3130840

“it is caused by diffraction of the incident light by surface features on the order of the optical wavelength.”

In my case I am trying to get the thin film effect only within the scratches, so that they at least give the illusion of a little color.

I didn’t even initially try the Metallic BSDF, but now I did, and it gives the same result as the Principled BSDF. I’d prefer to use the Principled BSDF however since then I can add scratches to porcelain-like materials as well, which typically also have such micro scratches. ( I realized this while doing my dishes…:sweat_smile:)

My suggestion: Just fake it.

You don’t have access to the light source directions in the shader calls. And the correct iridescence effect requires this information for calculating the correct interference of wavelengths.
Not only that, the smoothing function on anisotropic reflection only takes into account the luminance, which makes the diffraction difficult to converge correctly without brute-forcing an enormously amount of samples.

https://youtu.be/uz8PIi3ELJg?si=GeBHaM3sEYvLqIt6

This is a great source for learning metallic shaders.

Oh, I think I’ve seen this before and just completely forgot about it. As Secrop says, maybe just try to fake it? If the scratches appear better using regular glossy, why not try to mix it in with the intensity map? For coloring, maybe the old trick of using Magic Texture in combination with Texture Coordinate/Reflected, where the output drives a map range → Wavelength/Color ramp that in turn sets the scratch Glossy color? From the manual on Magic Texture Node:

It can be used for “Thin Film Interference” if you assign a Reflection Texture Coordinate to the Vector input and use a relatively high Turbulence.

While we have thin film now, this was a trick used in the past. Improved anisotropic is on the OpenPBR horizon. Glints/groove (scratches/machining)/flake rendering improvements have also been rumored, although I’m not sure if they intend to go all in on grating/thin film effects, or if Blender devs will try to get it all in (likely not).