Rendering Layered Materials

by Markus Worchel and Alexander Lelidis


The paper "A Comprehensive Framework for Rendering Layered Materials" by Jakob Wenzel et al. [1] presents a new method for rendering materials consisting of multiple layers by precomputing an effective reflection model. The technique supports arbitrary compositions of materials and correctly accounts for multiple scattering within and between layers. It yields a model that is not only efficient to evaluate but also space efficient. By exploiting a sparse matrix representation, the precomputed values can be stored efficiently, even for highly glossy materials, and be reused for different scenes.

Overview

In this section we are providing an overview of the basic theory of the utilized technique. Since we focused on the preprocessing part of the model proposed by Wenzel et al. we only explain how layers of materials can be represented by scattering tensors and how these tensors can be combined. For the final rendering we used PBRT V3 framework [2].

A layered material is a material consisting of single distinct material layers which are stacked on top of each other. Each layer can be classified as either a boundary or medium, where a boundary layer is modeled by a BSDF and a medium layer is modeled by a phase function. Wenzel et al. propose a discretized form of these functions which enables processing and storage of materials according to the used technique. In the following part we are only going to look at the discretization of BSDFs, because phase functions can be handled analogously.

A BSDF is a function of 4 parameters, which models the reflective and transmittive behavior of a material given in and outgoing directions. \( (\mu_i = cos \; \theta_i, \phi_i) \) and \( (\mu_o = cos \; \theta_o, \phi_o) \), respectively: $$ S^2 \times S^2 \to \mathbb{R} : f(\mu_i, \phi_i, \mu_o, \phi_o). $$ where \(\mu\), \(\phi\) is the standard parametrization for the sphere. Assuming the BSDF is symmetric around the normal direction, we are able to reduce the function to a function of 3 parameters: $$ \mathbb{R}^3 \to \mathbb{R} : f(\mu_i, \mu_o, \phi_d). $$ where \( \phi_d = |\phi_i - \phi_o| \). In order to get a partially discretized representation, we sample \( \mu \) from \( [-1, 1] \). For thus we use the Gauss-Lobatto points. The BSDF then only depends on one continuous parameter: $$ \mathbb{R} \to \mathbb{R} : f_{\mu_i, \mu_o}(\phi_d). $$ For obtaining a fully discretized representation the function is then projected into Fourier space: $$ f_{\mu_i, \mu_o}(\phi_d) = \sum\limits_{l = 0}^{k} c_{\mu_i, \mu_o}(l) \cos(l \phi_d). $$ An even Fourier basis approximation up to order \(k\) is used where \(c(l)\) denotes the l-th Fourier coefficient of \(f\) as a function of azimuth for fixed \(\mu_i\) and \(\mu_o\).

A major challenge in this sequence of transformations is to compute the Fourier representation of a BSDF model. In the paper they choose the microfacet model by Walter et al. [3]. This model consists of a reflection and a transmission term. $$ f(\mu_i, \phi_i, \mu_o, \phi_o) = f_r(\mu_i, \mu_o, \phi_i - \phi_o) + f_t(\mu_i, \mu_o, \phi_i - \phi_o). $$ The reflection term \(f_r\) is defined as $$ f_r(\mu_i, \mu_o, \phi_i - \phi_o) = \frac{F(\mu_h)D(\mu_h)G(\mu_i, \mu_o)}{4|\mu_i\mu_o|}. $$ where \(F\) specifies the Fresnel reflectance, \(D\) is the Beckmann distribution, \(G\) is a shadowing-masking term, and \(\mu_h\) denotes the cosine of the angle between the normal and the half-direction vector of the incident and outgoing directions. Since it is extremly rare that an analytical transformation in Fourier space for a function of this complexity exists, in the paper they used numerical integration for this task instead.

The final discretized function is represented as a tensor. For every Fourier mode \(l\) it has a quadratic scattering matrix, which contains the coefficents for this mode. The size depends on the amount of samples in \(\mu\). For a mode \(l\) we get the following scattering matrix: $$ \left[ \begin{array}{c|c} T_l^{tb} & R_l^b \\ \hline R_l^t & T_l^{bt} \end{array} \right] = \pi (1 + \delta_{0l}) \left[ \begin{array}{c|c} F_l^{tb} & F_l^b \\ \hline F_l^t & F_l^{bt} \end{array} \right] W \overline{M} $$ where $$ F_l := (c_{\mu_i, \mu_o}(l))_{ij} \in \mathbb{R}^{n \times n} $$ $$ W := (\delta_{ij}w_i)_{ij} \in \mathbb{R}^{n \times n} $$ $$ \overline{M} := (\delta_{ij}|\mu_i|)_{ij} \in \mathbb{R}^{n \times n} $$ The matrix \(\overline{M}\) is formed by the samples of the Gauss-Lobatto method and \(W\) contains the corresponding weights. The result is a block matrix where \(R\) represents the reflective part and \(T\) the transmissive one of the current BSDF for the given fourier mode.

The scattering tensor \(S \in \mathbb{R}^{n \times n \times k}\) provides a discrete approximation of the BSDF reflection and transmission behavior. In order to stack single material layers into a layered material, the individual tensors have to be combined. For this step they use the so-called adding equations: $$ \overline{R}^t = R^t_1 + T^{bt}_1(I - R_2^t R_1^b)^{-1} R_2^t T_1^{tb} $$ $$ \overline{R}^b = R^b_2 + T^{tb}_2(I - R_1^b R_2^t)^{-1} R_1^b T_2^{bt} $$ $$ \overline{T}^{tb} = T_2^{tb}(I - R_1^b R_2^t)^{-1} T_1^{tb} $$ $$ \overline{T}^{bt} = T_1^{bt}(I - R_2^t R_1^b)^{-1} T_2^{bt} $$ This results in new scattering matrices for each level of the combined material.

Implementation

For our implementation used the script language python 3.4, together with the packages numpy and scipy. Visualizations were generated using matplotlib. For the data exchange between our implementation of the precomputation and the renderer we used the format proposed by the paper, which is also supported by PBRT V3. The following code snippet shows how to create layers in our implementation and how to combine them to a new layered material.

            
eta_top = 1.5      
eta_bot = get_rgb(gold)

alpha_top = 0.1  # Beckmann roughness of top layer (coating)
alpha_bot = 0.1  # Beckmann roughness of bottom layer (gold)

n = 196                
m = 267        
mu, w = gaussLobatto(n)

# 1. Creating coating layer
coating = layer(mu, w, m)
coating.setMicrofacet(eta_top, alpha_top)

output = []
for channel in range(3):
    # Construct gold bottom layer for each channel
    # 2. Creating metal layer
    l = layer(mu, w, m)
    l.setMicrofacet(eta_bot[channel], alpha_bot)

    # Apply coating
    # 3. Applying coating..
    output.append(layer.addToTop(coating, l))          
            
            

Results

In this section we present our results. At first we show a comparison of the original microfacet BSDF with its Fourier approximation computed by our implementation. Afterwards we show a comparison of our scattering tensors/matrices for single layers and the ones obtained by using the reference implementation. Finally we visually compare our results of rendering layered materials with reference images from the paper.

Fourier approximation

The error plot reveals that with the choice of our parameters the error vanishes beyond \(k = 82\). This means that 82 Fourier coefficients are in this case sufficient to reconstruct the original function. Since the BSDF gets more spiky the more glossy it is, variation in the roughness \(\alpha\) affects the number of Fourier coefficients needed to satisfyingly reconstruct the function. If we had chosen a lower \(\alpha\) value, the required number of coefficients would have been much higher.

BSDF fourier

Comparison of original microfacet BSDF and our reconstruction from 100 fourier coefficents. We used the following values: \(\mu_i = 0.5\), \(\mu_o = -0.6\), \(\alpha = 0.05\) and \(\eta = 1.1\)

BSDF fourier error

This plot shows the absolute error between the approximation and the original BSDF with increasing number of fourier coefficents. We use the same parameters as before.

Scattering matrices

Diffuse
Reference Our

Comparison of our scattering matrix of first fourier level of a diffuse layer with a reference matrix (albedo: 0.8)

Microfacet
Reference Our

Comparison between our and the reference implementation of a microfacet BSDF scattering matrix of fourier level 3 representing a rough dielectric. We used 64 samples in \(\mu\), \(\eta = 1.1\) and \(\alpha = 0.6\).

Adding equations

Reference Our

In this image the scattering matrices for the first 30 fourier levels of each RGB channel are compared between our and the reference implementation. The represented material is a combined material, composed of a gold layer and a coating layer. The adding equations were used to create the scattering tensors.

Renderings

Diffuse
Reference Our

Comparison of our rendering and reference rendering of a diffuse material on a teapot represented by a single fourier level scattering matrix. We're using 256 samples per pixel and 128 samples in \(\mu\).

Rough dielectric,Silver and copper
Reference Our

Rendering of three bunnies, one copper, one silver metal and one rough dielectric. The image shows a comparison of our rendering and the reference rendering. The materials were represented by scattering matrices each with different fourier orders and samples in \(\mu\).

Coated Gold (Dragons 2 types coated and not coated gold)
Reference Our

Rendering of multiple dragons. One half of the dragons has a usual gold layer as material and the other half has a multi-layered material composed from gold and a glass coating. One can clearly see the scattering in the transparent layer of the coated material.

References