Specular weight > 1 can cause energy gain in metals, and NaNs in dielectrics
On testing we noticed that if specular_weight > 1 and the material is metallic, then there is energy gain, e.g.:
specular_weight 1 |
specular_weight 6 |
|---|---|
This happens because the specular_weight multiplies the metallic lobe as below:
We forgot to add a clamp to prevent the Fresnel factor exceeding 1 when the weight exceeds 1 though, which IMO is a mistake in the spec itself. We could either clamp the specular_weight before multiplying, or clamp each component of the final metallic Fresnel factor. The latter is closer to what we do for the dielectric case, so probably best.
Another issue we noted is that the formula below from the spec, for the dielectric Fresnel IOR ratio, produces inf if specular_weight is high, since $\epsilon=1$ then results (due to the clamp) which produces zero in the denominator (and this will later propagate into NaNs). This needs to be checked for and avoided, e.g. by clamping the denominator to be < 1.
This is not really an error in the spec (though arguably it is, since an infinite IOR doesn't make physical sense), but it's a rather easy mistake to make in implementing it (and thus generate NaNs in the render), so I suggest we point out the need to clamp explicitly in the spec.
NB, I think this bug is also present in the current MaterialX implementation.
Also, we currently say the specular_weight full range is $(0, \infty)$ for dielectrics, but $[0,1]$ for metals, which doesn't make sense as there's only 1 parameter that has to have the same range for both cases. We should instead make it $(0, \infty)$ for both, and add the clamp to the metal description as noted above.
Just to note, the implementation would be simpler if we just removed the facility to set specular_weight > 1, i.e. make the range be [0,1]. That seems like a reasonable simplification that is easier for UI and texturing. There is no loss of expressivity since specular_ior controls the base level reflectivity.
That also avoids the issue described here, i.e. having to insert awkward clamping logic to avoid unphysical energy gain.
The suggestion above is implemented in https://github.com/AcademySoftwareFoundation/OpenPBR/pull/228
Here are a few observations on our side:
Specular weight for metal
I don't have any feedback on this part and I suspect (to be confirmed) it is not a use case for us. Intuitively, I think it makes sense to permit the specular weight to be greater than 1, as this allows artists to tweak a metal appearance after the fact.
As for the solution proposed to avoid energy gain, I agree with the suggestion of clamping per channel. It could result in slightly unintuitive behaviour due to the hue shift, but as this happens when stretching the domain of the material, I think that's an acceptable tradeoff.
Specular weight for dielectrics
I am still gathering feedback and, more importantly, actual use cases, so I don't have a definitive answer yet. Here are some elements I've noted so far.
- In general, artists don't have immediate examples of above 1 use cases (as opposed to examples of below 1 use cases, which they have plenty of). This suggest this is a rare use case.
- That being said, artists prefer to have more freedom than less, and given the choice they will request to have the ability to increase the weight beyond 1.
- One use case we have for specular weight above 1 is for scanned materials. My understanding is that it comes from two reasons:
- A typical material scanning device won't measure IOR.
- Assets are made to work on a wide range of platforms, and most assume a fixed IOR. Therefore the reflectivity is controlled with the specular weight only.
- Technically, specular weight is another way to control IOR and therefore, any limitation in range could be worked around by using the IOR. However, artists tell me they associate IOR with the interior look, in particular refraction. In their mental model, IOR has nothing to do with reflection, and they find it counter intuitive to change it to adjust reflectivity.
From those observations, it looks like it might be harmless to clamp the weight, since scanned materials could always be processed. What I am concerned about though, are the repercussions such a decision would have, especially on workflows with many artists making assets meant to be rendered together. In such workflows, artists typically have to follow conventions defined upfront. But if reflectivity has to be controlled with IOR, how would they define a sensible convention that doesn't prevent them from achieving the look of a particular asset later on?
We decided to allow the specular weight > 1 case, and added the clamping logic to deal with it properly, in https://github.com/AcademySoftwareFoundation/OpenPBR/pull/238.
So this can be closed.