Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coat roughening convolution formula #172

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
face56c
Add suggested physically-based approximate formula for coat roughening.
portsmouth Apr 15, 2024
b5e7af8
Merge branch 'main' into coat_roughening
jstone-lucasfilm Apr 16, 2024
6c66e3b
Take into account TT mode in coat roughening formula.
portsmouth Apr 28, 2024
c5b4a1b
Merge branch 'main' into coat_roughening
portsmouth Apr 29, 2024
3b0fd12
Merge branch 'main' into coat_roughening
portsmouth Apr 30, 2024
1edaca3
Merge branch 'main' into coat_roughening
portsmouth Apr 30, 2024
5569167
Merge branch 'main' into coat_roughening
portsmouth May 10, 2024
d7de8b4
Remove approx. roughening formula.
portsmouth May 10, 2024
7529555
Merge remote-tracking branch 'upstream/main' into coat_roughening
portsmouth May 10, 2024
5eb4dbb
Add MaterialX implementation of the more realistic coat roughening fo…
portsmouth May 10, 2024
930ce21
Merge branch 'coat_roughening' of https://github.com/portsmouth/OpenP…
portsmouth May 10, 2024
54b5ec8
Fix mix node
portsmouth May 10, 2024
9c018c1
Merge remote-tracking branch 'upstream/main' into coat_roughening
portsmouth May 11, 2024
5a12a38
Improve wording.
portsmouth May 11, 2024
875f0dc
Merge remote-tracking branch 'upstream/main' into coat_roughening
portsmouth May 13, 2024
a635385
Merge branch 'coat_roughening' of https://github.com/portsmouth/OpenP…
portsmouth May 13, 2024
a5fd61a
Merge remote-tracking branch 'upstream/main' into coat_roughening
portsmouth May 13, 2024
32e0a08
Merge branch 'main' into coat_roughening
jstone-lucasfilm May 13, 2024
4f61868
Fix minor typo
jstone-lucasfilm May 13, 2024
e6b11f6
Fix minor typo
jstone-lucasfilm May 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -864,16 +864,14 @@
* +-------------------------------------------------+ *
*******************************************************

The absorption of the medium $V_\mathrm{coat}$ is parametrized by **`coat_color`**, which is assumed to specify the _square_ of the transmittance $T_\mathrm{coat}$ of the coat at normal incidence (i.e. $T^2_\mathrm{coat}$ = **`coat_color`**). Thus at normal incidence, the observed tint color of the underlying base due to absorption in the coat is approximately given by **`coat_color`** due to the absorption along both the incident and outgoing rays (note that the specular reflection from the coat itself is _not_ tinted).
The absorption of the medium $V_\mathrm{coat}$ is parametrized by **`coat_color`**, which is assumed to specify the _square_ of the transmittance $T_\mathrm{coat}$ of the coat at normal incidence (i.e. $T^2_\mathrm{coat}$ = **`coat_color`**). Thus at normal incidence, the observed tint color of the underlying base due to absorption in the coat is approximately given by **`coat_color`** due to the absorption along the incident and outgoing rays (note that the specular reflection from the coat itself is _not_ tinted).

The IOR $n_\mathrm{coat} = \mathtt{coat\_ior}$ of the coat medium $V_\mathrm{coat}$ will alter the Fresnel factor of both the coat top interface and the underlying metal or dielectric. If there is a fractional $\mathtt{coat\_weight}$ $\mathtt{C}$, then the surrounding IOR of the base dielectric or metal varies statistically across the surface depending on whether the coat is locally present (and the fuzz layer can be assumed to have the ambient IOR $n_\mathrm{ambient}$). The ratio between the specular IOR $n_\mathrm{specular} = \mathtt{specular\_ior}$ and the surrounding medium can thus reasonably be approximated as
\begin{equation} \label{specular_ior_ratio}
\eta_s = \mathrm{lerp}(n_\mathrm{specular}/n_\mathrm{ambient}, n_\mathrm{specular}/n_\mathrm{coat}, \mathtt{C}) \ .
\end{equation}
This ratio then determines the specular Fresnel factor, as in equation [modulated_ior].



Coat params | Label | Type | Range | Norm | Default | Description
--------------------------------|------------|----------|:---------------:|:----------:|:-------------:|----------------------------------------------
**`coat_weight`** | Weight | `float` | $ [0, 1] $ | | $ 0 $ | Coverage weight of coat slab
Expand All @@ -883,19 +881,32 @@
**`coat_ior`** | IOR | `float` | $ (0, \infty) $ | $ [1, 3] $ | $ 1.6 $ | Refractive index of $V_\mathrm{coat}$
**`coat_darkening`** | Darkening | `float` | $ [0, 1] $ | | $ 0 $ | Modulates the physical coat [darkening](index.html#model/coat/darkening) effect.


![](images/coat_0.png width=90% align=right) ![](images/coat_1.png width=90% align=left)
<div class="shifted-caption">
![Figure [coat]: Coat adds a secondary specular highlight and optional absorption tint](dummy)
</div>

In the full light transport, the observed color of the coated base is darkened and saturated due to multiple internal reflections from the inside of the coat, which causes light to strike the underlying material multiple times and undergo more absorption, and the observed **`coat_color`** tint also darkens as the incidence angle changes due to the change in path length in the medium. Also, the presence of a rough coat will increase the apparent roughness of the BSDF lobes of the underlying base. We assume that in the ground truth appearance, all these physical effects are accounted for. In the following sub-sections, we detail recommendations for implementation of them.
In the full light transport, the observed color of the coated base is darkened and saturated due to multiple internal reflections from the inside of the coat, which causes light to strike the underlying material multiple times and undergo more absorption, and the observed **`coat_color`** tint also darkens as the incidence angle changes due to the change in path length in the medium. Also, the presence of a rough coat will increase the apparent roughness of the BSDF lobes of the underlying base.

We assume that in the ground truth appearance, all these physical effects are accounted for [^porosity]. In the following sub-sections, we detail recommendations for implementation of them.


### Roughening

If the coat is rough, the microfacet BSDF lobes of the underlying base substrate (metal and dielectric) are also effectively roughened. If this is not otherwise accounted for by the light transport, it can instead be reasonably approximated by directly altering the NDF of the base BSDFs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


A formula we recommend for this is obtained by identifying the NDF of each microfacet lobe as corresponding approximately to a Gaussian in slope-space with variance given by $\alpha_t^2 + \alpha_b^2 = r^4$ (in the notation of the [Microfacet model](index.html#model/microfacetmodel) section). Modeling the effect of the roughening as the convolution of these Gaussian NDFs (and double counting the coat variance since the reflection passes through the coat boundary twice), the resulting modified roughness of the base, $r'_\mathrm{B}$, (taking into account the presence weight of the coat, $\mathtt{C}=$ **`coat_weight`**) is given by
\begin{equation}
r'_\mathrm{B} = \mathrm{lerp}\Bigl( r_\mathrm{B}, \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 r^4_\mathrm{C} \bigr)^\frac{1}{4}, \mathtt{C} \Bigr)
\end{equation}
where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**.


### Darkening

Figure [coat_darkening_grid] shows the physically-correct change in appearance (at normal incidence) of a textured diffuse base with a wood texture and smooth clear-coat as the IOR of the clear-coat is varied, exhibiting darkening due to the internal reflections which increases as IOR increases. [^porosity]
Figure [coat_darkening_grid] shows the physically-correct change in appearance (at normal incidence) of a textured diffuse base with a wood texture and smooth clear-coat as the IOR of the clear-coat is varied, exhibiting darkening of the base -- due to the internal reflections in the coat -- which increases as IOR increases.

![Figure [coat_darkening_grid]: Diffuse base with a clear-coat, for coats of different coat IOR $\eta_c$](images/coat_darkening_grid.png width="60%")
![Figure [coat_darkening_grid]: Diffuse base with a clear-coat, for coats of different relative IOR $\eta_c$](images/coat_darkening_grid.png width="60%")

However this darkening may not always be desirable artistically, as in some applications it is beneficial for the observed color of the coated color to "match" the input base color (in a sense defined more precisely below in equation [undarkened_coat_albedo]). We allow for this by introducing a **`coat_darkening`** parameter, $\delta$. In the case **`coat_darkening`** $\delta$ = $1$, the physically correct darkening effect due to internal reflections occurs as normal. In the case **`coat_darkening`** $\delta$ = $0$ (the default), the base albedo is instead _boosted_ uniformly by just enough to counteract the darkening effect. The boost factor is reduced to 1 linearly as $\delta \rightarrow 1$.

Expand Down Expand Up @@ -1503,7 +1514,7 @@
E_F(\eta) = 1 - \eta^2 \bigl(1 - E_F(1/\eta)\bigr) \ .
\end{equation}

[^absorption_effect_on_K]: Technically, the coefficient $K$ should also be modified to account for the absorption, but the effect of this can reasonably be ignored.
[^absorption_effect_on_K]: Technically, the _internal diffuse reflection coefficient_ $K$ described in the Darkening section should also be modified to account for the absorption, but the effect of this can reasonably be ignored.

[^BSDF_BSSRDF_sum]: This sum of BSDF and BSSRDF can be justified mathematically by interpreting a BSDF as the special case of a BSSRDF restricted to equal exit and entry points.

Expand Down
43 changes: 30 additions & 13 deletions reference/open_pbr_surface.mtlx
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,40 @@
-->
<nodegraph name="NG_open_pbr_surface_surfaceshader" nodedef="ND_open_pbr_surface_surfaceshader">

<!-- Roughness influence by coat-->
<!-- Calculate main specular roughness -->
<multiply name="coat_affect_roughness_multiply1" type="float">
<input name="in1" type="float" value="1.0" />
<input name="in2" type="float" interfacename="coat_weight" />
</multiply>
<multiply name="coat_affect_roughness_multiply2" type="float">
<input name="in1" type="float" nodename="coat_affect_roughness_multiply1" />
<input name="in2" type="float" interfacename="coat_roughness" />
<!-- Roughening due to coat-->
<power name="coat_roughness_to_power_4" type="float">
<input name="in1" type="float" interfacename="coat_roughness" />
<input name="in2" type="float" value="4.0" />
</power>
<multiply name="two_times_coat_roughness_to_power_4" type="float">
<input name="in1" type="float" nodename="coat_roughness_to_power_4" />
<input name="in2" type="float" value="2.0" />
</multiply>
<mix name="coat_affected_roughness" type="float">
<input name="fg" type="float" value="1.0" />
<power name="specular_roughness_to_power_4" type="float">
<input name="in1" type="float" interfacename="specular_roughness" />
<input name="in2" type="float" value="4.0" />
</power>
<add name="add_coat_and_spec_roughnesses_to_power_4" type="float">
<input name="in1" type="float" nodename="two_times_coat_roughness_to_power_4" />
<input name="in2" type="float" nodename="specular_roughness_to_power_4" />
</add>
<min name="min_1_add_coat_and_spec_roughnesses_to_power_4" type="float">
<input name="in1" type="float" value="1.0" />
<input name="in2" type="float" nodename="add_coat_and_spec_roughnesses_to_power_4" />
</min>
<power name="coat_affected_specular_roughness" type="float">
<input name="in1" type="float" nodename="min_1_add_coat_and_spec_roughnesses_to_power_4" />
<input name="in2" type="float" value="0.25" />
</power>
<mix name="effective_specular_roughness" type="float">
<input name="fg" type="float" nodename="coat_affected_specular_roughness" />
<input name="bg" type="float" interfacename="specular_roughness" />
<input name="mix" type="float" nodename="coat_affect_roughness_multiply2" />
<input name="mix" type="float" interfacename="coat_weight" />
</mix>

<!-- Calculate main specular roughness -->
<open_pbr_anisotropy name="main_roughness" type="vector2">
<input name="roughness" type="float" nodename="coat_affected_roughness" />
<input name="roughness" type="float" nodename="effective_specular_roughness" />
<input name="anisotropy" type="float" interfacename="specular_roughness_anisotropy" />
</open_pbr_anisotropy>

Expand Down