Closed portsmouth closed 2 months ago
An specific side effect of the new proposal would be that it would eliminate any nonphysical mismatch of the Fresnel reflection and the corresponding Fresnel transmission. Any misalignment can be particularly noticeable when going from high IOR to low IOR due to the visible discontinuity where total internal reflection begins.
We had much discussion on Slack about how the layering (e.g. of the specular layer on the diffuse base) should be implemented in code, and described physically in the spec. We eventually came up with a proposal for a modification that clarifies and simplifies the model: to reinterpret
specular_weight
as the existingspecular_ior_level
, thus merging the two parameters and removing the latter from the model. (Also, removingcoat_ior_level
).We originally settled on retaining both
specular_weight
andspecular_ior_level
from the ADSK and Adobe models as a sort of compromise solution. It seems though that it would be an improvement to merge them, both from the point of view of simplifying the user experience, and clarifying what the parameters are supposed to correspond to physically for implementers.I try to summarize the discussion below (the background from Slack, then the proposal).
Background
Currently in the spec, we say about
specular_weight
that it functions as follows:As discussed in https://github.com/AcademySoftwareFoundation/OpenPBR/issues/145, this intepretation of
specular_color
is problematic since it implies there will be a complementary color. So we will need to modify this to say that thespecular_color
only affects the reflection Fresnel factor, not the transmission.But we also need to clarify what
specular_weight
does (in code, and physically). It actually doesn't make sense forspecular_weight
to only multiply the reflection Fresnel factor, since this would mean there would be darkening of the base even whenspecular_weight
goes to zero. For example, in the case of the glossy-diffuse layer, this is supposed to be a layer of dielectric on top of a diffuse base. Ifspecular_weight
only modulates the reflection Fresnel factor, then dialing it to zero still generates darkening of the base due to the internal reflections in the layer, which are explicitly unaffected. In terms of the albedo-scaling approximation, specifying that the weight only multiplies the reflection Fresnel factor implies:where
specular_weight
$W$ andspecular_color
$\mathbf{C}$ multiply the first term. Then the $\left(1 - E_{\mathrm{dielectric}}\right)$ factor remains in the second term asspecular_weight
$W \rightarrow 0$, which produces darkening.In standard surface, instead what we had was a formula like:
which ensures that as $W \rightarrow 0$, only the undarkened $f_{\mathrm{diffuse}}$ remains. Except, this generates the complementary color tint of the diffuse lobe.
It was proposed to alter this to (e.g. this is how MaterialX implements their dielectric layering):
Physically, this can be interpreted as meaning that the
specular_weight
is functioning as the presence weight of the dielectric layer (this interpretation leads to the formula above, in albedo-scaling approximation, as is easy to prove).This makes some sense for the glossy-diffuse part of the specular lobe, but not really for the subsurface and transparent base, where the dielectric base is supposed to be the semi-infinite bulk. Putting this in a statistical superposition of present and absent is physically dubious (it also was for the glossy-diffuse layer really, as the dielectric was supposed to embed the diffuse medium, not just sit on top of it). So to use this presence interpretation of
specular_weight
we would have to specialize that to the glossy-diffuse case only, and say something different for the subsurface/transmission (e.g. thatspecular_weight
reverts to being a non-physical multiplier of the Fresnel factor).Simplification proposal
Rethinking the issue, Peter and I propose that we can achieve the desired the behaviour more simply just by having
specular_weight
function exactly asspecular_ior_level
does now, then omitting the latter parameter. That is, thespecular_weight
specifies a multiplier of the reflection Fresnel factor, achieved by modulating the IOR of the entire dielectric base. The corresponding albedo scaling formula will be:as now the
specular_weight
$W$ functions by altering the IOR of $f{\mathrm{dielectric}}$ (thus the Fresnel factor). As $W \rightarrow 0$, the specular BRDF $f{\mathrm{dielectric}} \rightarrow 0$ automatically, and thus its reflectance $E_{\mathrm{dielectric}} \rightarrow 0$. We would retainspecular_color
$C$ as a non-physical tint of the reflection Fresnel factor.This approach:
makes the reflection Fresnel factor go to zero as
specular_weight
$\rightarrow 0$, but does this in a more physically correct way, keeping the grazing angle highlight but having it narrow to zero width, rather than just killing the highlight.makes the physical description clearer in the spec, and obvious how to implement. The dielectric base is now always present (embedding the media described by the transmission, subsurface, and diffuse slabs). The
specular_weight
is just modulating the IOR of this dielectric base.removes a parameter which was practically redundant (as
specular_weight
andspecular_ior_level
had a very similar effect, apart from the former being less physically plausible with a damped highlight). The more obscure soundingspecular_ior_level
was likely to be a source of confusion to artists, especially given its extremely similar behaviour tospecular_weight
.retains the ability to non-physically modulate the reflection lobe color/intensity, independently of the transmission, via
specular_color
. (So no functionality is actually lost).It is optional whether we want to have the
specular_weight
increase the Fresnel factor at the top end of the range (e.g. default at 0.5, and max out at 1, where the Fresnel is doubled, as the currentspecular_ior_level
works) or not. It would be reasonable to just omit this, and have the weight default to 1, and only decrease the Fresnel.Additionally, we propose to remove
coat_ior_level
, as it is functionally equivalent tocoat_weight
(the presence weight of the coat) for the purposes of modulating the coat reflection strength. Removing this also simplifies implementation of the coat lobe.