# PBR: Real-time Implementation [Site du cours](https://davidpeicho.github.io/teaching/) # Before we start *Comment on genere une image ?* - On a vu le raytracing - On a vu la rasterization :::success On va se focus sur le temps reel avec de la rasterization ::: # Old Times ## Lambert ![](https://i.imgur.com/oleyxt6.png) 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 :::warning Il n'y a pas de modele $100\%$ diffus ::: :::success En une seule operation on a notre BRDF ::: > Il existe d'autres modeles mais la difference visuelle n'est pas assez bonne pour etre utilises ## Phong ![](https://i.imgur.com/eFnmhj1.png) - Approximation pas tres bonne - MAIS precurseur a son epoque ($'70s$) Pas de conservation d'energie: ![](https://i.imgur.com/yKPb7ft.png) ## Pseudocode ### Lambert ```glsl void main() { vec3 diffuse = kD * dot(normal, lightDirection) * color; gl_FragColor.rgba = vec4(diffuse, 1.0); } ``` ### Phong ```glsl 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 :::warning Non-physical model requires a lot of tweaking ::: > 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 :::success C'est pour ca qu'il y a eu l'avenement du **Real Time Rendering** vers 2013 ::: :::warning C'est dur de definir le PBR ::: :::info **Definition: PBR** Modele mathematiques et approximations que nous allons tous suivre pour decrire les interactions entre la lumiere et la matiere ::: ## What is PBR ? ![](https://i.imgur.com/opZAa4s.png) *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 :::success Win-win pour les ingenieurs et artistes ::: # Microfacets Theory ![](https://i.imgur.com/Kgyv2AT.png) > Ce modele approxime ce qu'il se passe dans la vraie vie :::info On dit que tous les materiaux sont composes de miroirs plus ou moins alignes ::: ![](https://i.imgur.com/3xOhCri.png) ![](https://i.imgur.com/DCGx8E9.png) *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 ![](https://i.imgur.com/BehJABt.png) ## Conductors ![](https://i.imgur.com/FLY4bUa.png) La couleur diffuse serait une approximation du sub-surface scattering ![](https://i.imgur.com/2nt0t5nAd.png) - Les conducteurs reflete $0-20\%$ de la lumiere :::warning Les metaux n'ont pas de sub-surface scattering ::: ![](https://i.imgur.com/LiDb9rJ.png) - 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) $$ ![](https://i.imgur.com/teFQIK6.png) :::success Notre BRDF devient pulg & play ::: > 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 ![](https://i.imgur.com/D4TjB54.png) ## 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)} $$ ![](https://i.imgur.com/AQemlwI.png) ### 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 ![](https://i.imgur.com/FGdwVds.png) ### Shadowing term $G(\omega_0,\omega_i)$ ![](https://i.imgur.com/zblR4rX.png) $$ 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 :::warning L'orientation des facettes peut *pieger* la lumiere ::: ![](https://i.imgur.com/jBMa2j0.png) ### Effet Fresnel ![](https://i.imgur.com/acaVBPu.png) > On a un joli coucher de soleil sur la mer (ou ocean) > L'eau est un miroir modulo les vagues :::info Pour tout materiaux, la reflectance va etre maximale aux **angles rasants** ::: :::danger L'effet Fresnel c'est le poids du *specular lobe* $k_s$ ::: $$ 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 ![](https://i.imgur.com/yqpy1aK.png) ![](https://i.imgur.com/3Sz2oqI.png) > 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 ! ![](https://i.imgur.com/1MkiBjt.png) ### Direct-Lightning pseudocode ```glsl 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 ![](https://i.imgur.com/YnKZiob.png) > 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 $$ ![](https://i.imgur.com/nvZM6gv.png) :::warning Cette lumiere n'existe pas dans la vraie vie ::: ### 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 ![](https://i.imgur.com/F1YWzrP.png) - 4 points lights ![](https://i.imgur.com/dbOlXwe.png) - 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 $$ ![](https://i.imgur.com/QnEpTEC.png) *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. ![](https://i.imgur.com/TTsOV4U.png) - 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 $$ ![](https://i.imgur.com/8rspkCX.png) $$ 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 $$ ![](https://i.imgur.com/9dMsNTc.png) > 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 ![](https://i.imgur.com/Z9XpfPY.png) ### 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 ![](https://i.imgur.com/pAtF0cE.png) 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 ```glsl 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 ![](https://i.imgur.com/uCfnJup.png) - 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 :::warning On va eviter de faire nos calculs en sRGB ::: - 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 ![](https://i.imgur.com/Azsqnoz.png) :::info HDR: High Dynamic Range ::: 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 ![](https://i.imgur.com/SmKlFAT.png) > Examples: hair, skin, cloud, etc.