From ca24c56f786f19bbba47333f49cce5d8f0fd8dbc Mon Sep 17 00:00:00 2001 From: Jamie Portsmouth Date: Tue, 24 Jun 2025 03:20:11 +0100 Subject: [PATCH 1/3] Add suggested formulas for roughening effect of coat and fuzz --- index.html | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 6f53c488..a9644618 100644 --- a/index.html +++ b/index.html @@ -1022,12 +1022,14 @@ 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. -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) +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). +The effect of the coat roughening can then be modeled as the convolution of these Gaussian NDFs, which corresponds to adding the variances (double counting the coat variance since the reflection passes through the coat boundary twice). The IOR ratio of the coat and ambient medium $\eta_\mathrm{ca}$ also needs to be accounted for, since as $\eta_\mathrm{ca} \rightarrow 1$ the roughening due to the coat goes to zero. +This leads to the following suggested approximate formula for the modified roughness $r'_\mathrm{B}$ of the base due to the coat: +\begin{equation} \label{coat_roughening_heuristic} +r'_\mathrm{B} = \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 x_C r^4_\mathrm{C} \bigr)^\frac{1}{4} \quad \textrm{with } x_C = 1 - \mathrm{min}(\eta_\mathrm{ca}, 1/\eta_\mathrm{ca}) \end{equation} where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**. - +Of course, the presence weight of the coat ($\mathtt{C}=$ **`coat_weight`**) also needs to be taken into account, ideally by blending between the effect with and without the coat present. Alternatively, a cruder approximation would be to just set the roughness of the base to $\mathrm{lerp}(r_\mathrm{B}, r'_\mathrm{B}, \mathtt{C})$. ### Total internal reflection @@ -1094,9 +1096,9 @@ The form of this model is the following (with $\mu_i, \mu_o$ the angle cosines to the normal of $\omega_i, \omega_o$): \begin{equation} -\mu_i \, f_\mathrm{fuzz}(\omega_i, \omega_o) = \mathbf{F} \, E_\mathrm{fuzz}(\mu_o, \alpha) \, D(\mu_i | \mu_o, \alpha) +\mu_i \, f_\mathrm{fuzz}(\omega_i, \omega_o) = \mathbf{F} \, E_\mathrm{fuzz}(\mu_o, r_F) \, D(\mu_i | \mu_o, r_F) \end{equation} -where $\mathbf{F}$ = **`fuzz_color`**, $E_\mathrm{fuzz}(\mu_o, \alpha)$ (termed $R$ in [#Zeltner2022]) is the reflectance at angle cosine $\mu_o$ given roughness $\alpha$ = **`fuzz_roughness`** $\in [0,1]$, and $D(\mu_i | \mu_o, \alpha)$ is a lobe defined by linear transformations of a cosine lobe (LTCs), where the transformation matrices (and $E_\mathrm{fuzz}$) are tabulated in a grid in the $(\mu_o, \alpha)$ plane, with values fitted to a simulation of the scattering in the volumetric fuzz microflake layer. Since the LTC lobe $D$ is a normalized PDF over the hemisphere, the resulting albedo of $f_\mathrm{fuzz}$ is $\mathbf{F} \, E_\mathrm{fuzz}(\mu_o, \alpha)$. +where $\mathbf{F}$ = **`fuzz_color`**, $E_\mathrm{fuzz}(\mu_o, r_F)$ (termed $R$ in [#Zeltner2022]) is the reflectance at angle cosine $\mu_o$ given roughness $r_F$ = **`fuzz_roughness`** $\in [0,1]$ (termed $\alpha$ in [#Zeltner2022]), and $D(\mu_i | \mu_o, r_F)$ is a lobe defined by linear transformations of a cosine lobe (LTCs), where the transformation matrices (and $E_\mathrm{fuzz}$) are tabulated in a grid in the $(\mu_o, r_F)$ plane, with values fitted to a simulation of the scattering in the volumetric fuzz microflake layer. Since the LTC lobe $D$ is a normalized PDF over the hemisphere, the resulting albedo of $f_\mathrm{fuzz}$ is $\mathbf{F} \, E_\mathrm{fuzz}(\mu_o, r_F)$. If using the albedo-scaling interpretation of layering, a reasonable approximation of the reflection from the fuzz layer combined with the reflection from the base is to take \begin{eqnarray} @@ -1110,6 +1112,13 @@ The fuzz shading normal is assumed to inherit from that of the substrate layer, the physical picture being that the fuzz volume settles and conforms to the geometry of the substrate. The substrate is generally a mixture of coat and uncoated base. Thus physically the fuzz model should be evaluated with each of the **`geometry_coat_normal`** and **`geometry_normal`** separately (if they differ), and the final result blended according to the **`coat_weight`**. As a practical approximation, it may be more convenient and efficient to instead approximate the fuzz normal by interpolating the coat and base normal according to **`coat_weight`**. +The scattering within the fuzz layer will have the effect of roughening the appearance of the substrate beneath it. +A simple suggested approximation for this can adapted from the formula used to model the coat roughening, in equation [coat_roughening_heuristic]. If we consider the fuzz layer to generate roughening by scattering, we can approximate its effective roughness as being proportional to the albedo of the layer, as well as to the tint color (since darker fuzz will physically scatter less and absorb more). This leads to the following heuristic for the modified roughness $r'_\mathrm{B}$ of the substrate lobe: +\begin{equation} \label{fuzz_roughening_heuristic} +r'_\mathrm{B} = \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 R^4_\mathrm{F} \bigr)^\frac{1}{4} \quad \textrm{with $R_F = \mathrm{lum}(\mathbf{F} E_\mathrm{fuzz})$} +\end{equation} +where $r_\mathrm{B}$ is the original substrate roughness, and $\mathrm{lum}(\cdots)$ computes the luminance of the RGB argument. This should be applied to both the coat (if present) and the base lobes. If both the fuzz and the coat are present, then the base lobe roughness will be broadened by both the coat and fuzz formulas successively. The presence weights of the fuzz and coat should be accounted for appropriately. + Fuzz params | Label | Type | Range | Default | Description ---------------------|-----------|----------|:------------:|:-------------:|---------------------------------------------- From 5cd6858fcf3f5f777506f4171532776fadb3d5de Mon Sep 17 00:00:00 2001 From: Jamie Portsmouth Date: Tue, 24 Jun 2025 03:32:13 +0100 Subject: [PATCH 2/3] typo fix --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index a9644618..3de24698 100644 --- a/index.html +++ b/index.html @@ -1113,7 +1113,7 @@ The fuzz shading normal is assumed to inherit from that of the substrate layer, the physical picture being that the fuzz volume settles and conforms to the geometry of the substrate. The substrate is generally a mixture of coat and uncoated base. Thus physically the fuzz model should be evaluated with each of the **`geometry_coat_normal`** and **`geometry_normal`** separately (if they differ), and the final result blended according to the **`coat_weight`**. As a practical approximation, it may be more convenient and efficient to instead approximate the fuzz normal by interpolating the coat and base normal according to **`coat_weight`**. The scattering within the fuzz layer will have the effect of roughening the appearance of the substrate beneath it. -A simple suggested approximation for this can adapted from the formula used to model the coat roughening, in equation [coat_roughening_heuristic]. If we consider the fuzz layer to generate roughening by scattering, we can approximate its effective roughness as being proportional to the albedo of the layer, as well as to the tint color (since darker fuzz will physically scatter less and absorb more). This leads to the following heuristic for the modified roughness $r'_\mathrm{B}$ of the substrate lobe: +A simple suggested approximation for this can be adapted from the formula used to model the coat roughening, in equation [coat_roughening_heuristic]. If we consider the fuzz layer to generate roughening by scattering, we can approximate its effective roughness as being proportional to the albedo of the layer, as well as to the tint color (since darker fuzz will physically scatter less and absorb more). This leads to the following heuristic for the modified roughness $r'_\mathrm{B}$ of the substrate lobe: \begin{equation} \label{fuzz_roughening_heuristic} r'_\mathrm{B} = \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 R^4_\mathrm{F} \bigr)^\frac{1}{4} \quad \textrm{with $R_F = \mathrm{lum}(\mathbf{F} E_\mathrm{fuzz})$} \end{equation} From f87ac26979bff730fab1751b365209a0e9a72664 Mon Sep 17 00:00:00 2001 From: Jamie Portsmouth Date: Tue, 31 Mar 2026 16:02:22 +0100 Subject: [PATCH 3/3] Use improved validated coat roughening heuristic Omit fuzz roughening explicitly. --- index.html | 25 +++---- reference/open_pbr_surface.mtlx | 111 ++++++++++++++++++++++++++------ 2 files changed, 103 insertions(+), 33 deletions(-) diff --git a/index.html b/index.html index 1ab64b48..4ae5332c 100644 --- a/index.html +++ b/index.html @@ -1093,14 +1093,20 @@ 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. -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). -The effect of the coat roughening can then be modeled as the convolution of these Gaussian NDFs, which corresponds to adding the variances (double counting the coat variance since the reflection passes through the coat boundary twice). The IOR ratio of the coat and ambient medium $\eta_\mathrm{ca}$ also needs to be accounted for, since as $\eta_\mathrm{ca} \rightarrow 1$ the roughening due to the coat goes to zero. -This leads to the following suggested approximate formula for the modified roughness $r'_\mathrm{B}$ of the base due to the coat: +We work in GGX $\alpha$-space, where $\alpha = r^2$. Let $\alpha_\mathrm{B} = r_\mathrm{B}^2$ and $\alpha_\mathrm{C} = r_\mathrm{C}^2$ denote the GGX alphas of the base and coat respectively, and let $\eta_\mathrm{ca} = n_c/n_a$ be the IOR of the coat relative to the ambient medium (i.e. **`coat_ior`**). A base lobe with GGX alpha $\alpha_\mathrm{B}$ inside the coat appears broadened to $\eta_\mathrm{ca}\,\alpha_\mathrm{B}$ when viewed from outside, due to Snell's law angular expansion at the exit interface. The coat contributes additional broadening via refraction through its tilted microfacets, with both entry and exit refractions adding variance independently. This motivates an IOR-dependent coat broadening coefficient: +\begin{equation} +B(\eta_\mathrm{ca}) = 1.05\;\frac{(\eta_\mathrm{ca}-1)\sqrt{1+\eta_\mathrm{ca}^2}}{\eta_\mathrm{ca}} +\end{equation} +where the prefactor $1.05$ is fit to Monte Carlo simulations. Adding the base and coat contributions in quadrature gives the raw broadened alpha: \begin{equation} \label{coat_roughening_heuristic} -r'_\mathrm{B} = \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 x_C r^4_\mathrm{C} \bigr)^\frac{1}{4} \quad \textrm{with } x_C = 1 - \mathrm{min}(\eta_\mathrm{ca}, 1/\eta_\mathrm{ca}) +\alpha_\mathrm{raw} = \sqrt{\bigl(\eta_\mathrm{ca}\,\alpha_\mathrm{B}\bigr)^2 + \bigl(B(\eta_\mathrm{ca})\,\alpha_\mathrm{C}\bigr)^2} \end{equation} -where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**. -Of course, the presence weight of the coat ($\mathtt{C}=$ **`coat_weight`**) also needs to be taken into account, ideally by blending between the effect with and without the coat present. Alternatively, a cruder approximation would be to just set the roughness of the base to $\mathrm{lerp}(r_\mathrm{B}, r'_\mathrm{B}, \mathtt{C})$. +At high roughness, total internal reflection at the coat exit prevents steeply angled rays from escaping, imposing an upper limit on the observable lobe width. This is modeled with a smooth $\tanh$ saturation: +\begin{equation} +\alpha_\mathrm{eff} = \alpha_\mathrm{max}\,\tanh\!\left(\frac{\alpha_\mathrm{raw}}{\alpha_\mathrm{max}}\right), \qquad \alpha_\mathrm{max} = 0.85 +\end{equation} +The effective roughness is then $r'_\mathrm{B} = \sqrt{\alpha_\mathrm{eff}}$, where $r_\mathrm{B}=$ **`specular_roughness`** and $r_\mathrm{C}=$ **`coat_roughness`**. +The presence weight of the coat ($\mathtt{C}=$ **`coat_weight`**) is accounted for by blending: $\mathrm{lerp}(r_\mathrm{B},\, r'_\mathrm{B},\, \mathtt{C})$. ### Total internal reflection @@ -1183,12 +1189,7 @@ The fuzz shading normal is assumed to inherit from that of the substrate layer, the physical picture being that the fuzz volume settles and conforms to the geometry of the substrate. The substrate is generally a mixture of coat and uncoated base. Thus physically the fuzz model should be evaluated with each of the **`geometry_coat_normal`** and **`geometry_normal`** separately (if they differ), and the final result blended according to the **`coat_weight`**. As a practical approximation, it may be more convenient and efficient to instead approximate the fuzz normal by interpolating the coat and base normal according to **`coat_weight`**. -The scattering within the fuzz layer will have the effect of roughening the appearance of the substrate beneath it. -A simple suggested approximation for this can be adapted from the formula used to model the coat roughening, in equation [coat_roughening_heuristic]. If we consider the fuzz layer to generate roughening by scattering, we can approximate its effective roughness as being proportional to the albedo of the layer, as well as to the tint color (since darker fuzz will physically scatter less and absorb more). This leads to the following heuristic for the modified roughness $r'_\mathrm{B}$ of the substrate lobe: -\begin{equation} \label{fuzz_roughening_heuristic} -r'_\mathrm{B} = \mathrm{min} \bigl(1, r^4_\mathrm{B} + 2 R^4_\mathrm{F} \bigr)^\frac{1}{4} \quad \textrm{with $R_F = \mathrm{lum}(\mathbf{F} E_\mathrm{fuzz})$} -\end{equation} -where $r_\mathrm{B}$ is the original substrate roughness, and $\mathrm{lum}(\cdots)$ computes the luminance of the RGB argument. This should be applied to both the coat (if present) and the base lobes. If both the fuzz and the coat are present, then the base lobe roughness will be broadened by both the coat and fuzz formulas successively. The presence weights of the fuzz and coat should be accounted for appropriately. +Unlike the coat, the fuzz layer is index-matched with the ambient medium (IOR $n_a$), so refraction does not alter the direction of unscattered rays passing through it. Consequently, *we recommend that the base lobe should not be roughened by the fuzz layer.* The base lobe retains its original angular distribution, attenuated only by the extinction through the fuzz volume. Any apparent broadening of the overall reflected lobe arises from the scattered fuzz contribution sitting alongside the unmodified base lobe, not from widening the base lobe itself. Fuzz params | Label | Type | Range | Default | Description diff --git a/reference/open_pbr_surface.mtlx b/reference/open_pbr_surface.mtlx index 26a6b3c9..8c91b40d 100644 --- a/reference/open_pbr_surface.mtlx +++ b/reference/open_pbr_surface.mtlx @@ -266,31 +266,100 @@ - - + + + - - - - - + - + - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +