Home PBR: Real-time Implementation
Post
Cancel

PBR: Real-time Implementation

Lien de la note Hackmd

Site du cours

Before we start

Comment on genere une image ?

  • On a vu le raytracing
  • On a vu la rasterization

Old Times

Lambert

On a tous fait un Lambert model

  • Plus l’angle est eleve entre la normal et la lumiere, moins il n’y a d’energie

Il existe d’autres modeles mais la difference visuelle n’est pas assez bonne pour etre utilises

Phong

  • Approximation pas tres bonne
  • MAIS precurseur a son epoque ($’70s$)

Pas de conservation d’energie:

Pseudocode

Lambert

1
2
3
4
5
void main()
{
 vec3 diffuse = kD * dot(normal, lightDirection) * color;
 gl_FragColor.rgba = vec4(diffuse, 1.0);
}

Phong

1
2
3
4
5
6
7
void main()
{
 vec3 r = reflect(- viewDirection, normal);
 vec3 diffuse = kD * dot(normal, lightDirection) * color;
 vec3 specular = kS * pow(max(dot(lightDirection, r)), exponent);
 gl_FragColor.rgba = vec4(diffuse + specular, 1.0);
}

What and why

Introduction

Si on a un artiste qui fait une scene en exterieur puis on lui dit qu’on doit aller dans un tunnel en voiture, l’artiste pleure Il doit tweaker les materiaux pour que ca ait l’air joli en fonction de la lumiere

What is PBR ?

Pourquoi c’est populaire ?

Decrit le monde plus precisement, donne des rendus realistes Tout le monde utilise plus ou moins les memes inputs Moins de tweaking

Microfacets Theory

Ce modele approxime ce qu’il se passe dans la vraie vie

C’est quoi la difference entre un miroir et un plastique ?

Notre premier cas sera un miroir Le second est un materiaux super diffus

Dielectrics vs Conductors

Conductors

La couleur diffuse serait une approximation du sub-surface scattering

  • Les conducteurs reflete $0-20\%$ de la lumiere

  • Les conducteurs refletent $60-90\%$ de la lumiere
  • Certains conducteurs ont leur couleur propre due aux longueurs d’ondes absorbees

BRDF

BRDF Simplification

\[f_r(p,\omega_0,\omega_i)=f_d(p,\omega_0,\omega_i) + f_s(p,\omega_0, \omega_i)\]

On peut remplacer par ce qu’on veut du moment que $\int\le1$

Implementation notes

\[f_r(p,\omega_0,\omega_i)=k_df_d(p,\omega_0,\omega_i) + k_sf_s(p,\omega_0, \omega_i)\\ k_d+k_d\le1\]

Diffuse Lobe

\[f_d(p,\omega_0,\omega_i) = \frac{\rho}{\pi}\]
  • $\rho$: reflectance spectrum

Specular Lobe

\[f_s(p,\omega_0,\omega_i)=\frac{D(\omega_0,\omega_i)F(\omega_0,\omega_i)G(\omega_0,\omega_i)}{4(\omega_0,\omega_i)(\omega_i\times n)}\]

Specular BRDF

\[D_{GGX}(n,h,a)=\frac{\alpha^2}{\pi((n\times h)^2(\alpha^2-1)+1)^2}\\ \vec h=\frac{\vec v+\vec L}{\Vert\vec v+\vec L\Vert}\]
  • Normal distribution function $D(\omega_0, \omega_i)$
  • Estimates the area of microfacets aligned to give perfect specular
  • As usual, lots of different NDF equations…
  • To be consistent, let’s implement the Trowbridge-Reitz equation
  • Low roughness means few samples contributing a lot to specular

Shadowing term $G(\omega_0,\omega_i)$

\[G(n,v,l,k)=\underbrace{G_{SchlickGGX}(n,v,k)}_{Obstruction}\underbrace{G_{Schlik}(n,l,k)}_{Shadowing}\\ G_{SchlickGGX}(n,v,k)=\frac{n\times v}{(n\times v)(1-k)+k}\]
  • On va approximer $k=\alpha$
  • Approximation de l’occlusion

Effet Fresnel

On a un joli coucher de soleil sur la mer (ou ocean) L’eau est un miroir modulo les vagues

\[F_{Schlik}(v,h,f_0,f_{90}) = f_0+(f_{90}-f_0)(1-v\times h)^5\\ F_{Schlik}(v,h,f_0) = f_0+(1-f_0)(1-v\times h)^5\\ F_0(ior)=\frac{(1-ior)^2}{(ior+1)^2}\]
  • $f_0$: base reflectivity at normal incidence
  • $f_{90}$: base reflectivity at grazing angle
    • Almost always 1 for conductors

Fresnel reflectance for common materials

  • For dialectics, $f_0$ is often approximated with $0.04$
  • Some materials $f_0$ are tainted (gold, copper)
  • Implementation note:
    • For dielectics, pick $0.04$ $f_0$
    • For conductors, store $f_0$ in albedo texture
    • Use metallic input to lerp between the 2

Demo !

Direct-Lightning pseudocode

1
2
3
4
5
6
7
8
9
10
11
vec3 radiance = vec3(0.0);
for(int i = 0; i < NB_LIGHTS; ++i)
{
 vec3 w_i = lights[i].direction;
 vec3 kS = FresnelShlick(f0, wi, w_o);
 vec3 specularBRDFEval = kS * f_s(p, w_i, w_o);
 vec3 diffuseBRDFEval = (1.0 - kS) * f_d(p, w_i, w_o);

 radiance += (diffuseBRDFEval + specularBRDFEval) * sampleLight(lights[i], p, w_i) * dot(normal, w_i);
}

Textures

Les artistes font plusieurs textures

To remember !

  • Diffuse is an approximation of sub-surface scattering
  • La plupart des moteurs connus vont avoir des metallics workflow
  • Ca simplifie beaucoup la vie

Ponctual light

Point light

  • Infinitely small
  • Isotropic
  • Describe only by a position
  • Simple to code and fast to sample
  • Power unit should be set using Lumens
  • How to select a proper value ?
  • Not as accurate as Area Light
\[L_i(p,\omega_i)=\frac{\phi}{4\pi r^2}n\times\omega_i\]

Note

  • On ne va pas parler de directionnal light (deja fait)
  • Si on utilise une directionnal light, il faudra tweaker les parametres
  • Ce n’est pas aussi fidele que les Area lights

Image Based Lightning

  • 4 points lights

  • Avec environnement
\[L_0(p,\omega_0)=\int_{\Omega}(f_d(p,\omega_0,\omega_i) + f_s(p,\omega_0,\omega_i))L_i(p,\omega_i)n\times w_i\\ L_0(p,\omega_0)=\int_{\Omega}f_d(p,\omega_0,\omega_i)L_i(p,\omega_i)m\times\omega_i+\int_{\Omega}f_s(p,\omega_0,\omega_i)L_i(p,\omega_i)m\times\omega_i\]

IBL Diffuse

\[\int_{\Omega}f_d(p,\omega_0,\omega_i)L_i(p,\omega_i)m\times\omega_i\]

Mais c’est juste un flou gaussien ?

C’est pas si faux que ca, c’est assez proche

\[L_0(p,n)=\int_{\Omega}\frac{\rho}{\pi}L_i(p,\omega_i)n\times\omega_id\omega_i\\ L_0(p,n)=\frac{\rho}{\pi}\int_{\Omega}L_i(p,\omega_i)n\times\omega_id\omega_i\]

Il faut faire une integration par angle solide, et c’est complique.

  • Utilisation des coordonnees spheriques pour l’integration
  • Discretiser l’integrale avec la somme de Riemann
  • Calculer pour chaque texel, avec la direction $N$ du centre

IBL Specular

\[\int_{\Omega}f_s(p,\omega_0,\omega_i)L_i(p,\omega_i)m\times\omega_i\]

\[L_0(p,\omega_0)=\int_{\Omega}L_i(p,\omega_i)d\omega_i\times\int_{\Omega}f_r(p,\omega_0,\omega_i)n\times\omega_i d\omega_i\]

Ca a ete teste et ca marche: c’est ca la 3D

Changer le niveau de roughness c’est faire du downsampling, pourquoi par appliquer la roughness en faisant des images de plus en plus petites

Pre-computed BRDF

\[\begin{aligned} \int_{\Omega}f_r(p,\omega_0,\omega_i)n\times\omega_id\omega_i &= F_0\int_{\Omega}f_r(p,\omega_0,\omega_i)(1-(1-\omega_0\times h)^5)n\times\omega_id\omega_i\\ &+\int_{\Omega}f_r(p,\omega_0,\omega_i)(1-\omega_0\times h)^5n\times\omega_id\omega_i \end{aligned}\]

Obtained bu substituting Fresnel Shlick Only 2 inputs left: roughness, viewing angle

At runtime:

  1. Fetch pre-integrated BRDF texture
  2. Fetch convoluted environment
  3. Apply the above equation to get the full specular component

Specular: compisistion

1
2
3
c2 brdf = GetIntegratedBRDF(NdotV, roughness);
vec3 prefilteredSpecular = GetPrefilteredSpecular((NdotV, roughness);
vec3 specular = prefilteredSpecular * (F * brdf.x + brdf.y);
  • F: Fresnel term

To remember

  • C’est juste du pre-filtering

Colorspace and color precision

  • sRGB vs Linear
  • Monitors apply pow function to luminance
  • Toute l’industrie a du se base sur les ecran qui font ca donc ils ont cree le $sRGB$
  • Sur photoshop, une image sera encodee en sRGB pour retrouver les couleurs imaginees
  • Soit on fait tout en sRGB
  • Soit on fait tout en lineaire $\Rightarrow$ OUI
    • On applique a la fin la fonction sRGB pour convertir en lineaire

HDR vs LDR

Reinhard Tonemapping:

\[color_{final}=\frac{c}{c+1}\]
  • HDR has larger range of values
  • Units will create radiance color outside the $0\dots1$ range
  • Perform computation in HDR, tonemap to LDR is required
  • HDR is required to get correct PBR result
  • Especially important for IBL

Going further

Advanced materials

Examples: hair, skin, cloud, etc.

This post is licensed under CC BY 4.0 by the author.