The goal of this project is to implement a PBR renderer. You are asked to implement:
- A Lambertian diffuse BRDF
- A Cook-Torrance GGX specular BRDF
To learn about:
- The subject, please reach the Assignment section
- The provided code, please have a look at the Provided Code section.
After cloning the repository, install the dependencies using:
yarn # Alternatively you can run `npm install`
You can start the development server using:
yarn dev # Alternatively you can run `npm run dev`
You can now reach localhost:8080 to try your code. The development server supports Hot-Reload, which means that when saving your code, the page will automatically auto-reload with the latest changes.
- Spector.js: Chrome extensions that will help you analyze data sent to webgl, visualize framebuffers, etc... The best debugging tool for WebGL!
You are free to proceed the way you want. However, I would advise you to go step by step and to check intermediate results.
It's important to ensure intermediate results are correct. Otherwise, you will spend time trying to figure out why your specular is off, when the issue might actually comes from a different part of the pipeline.
You can implement either directional lights or point lights (or both!). For better visual results, I would advise you to go for point lights :)
This is the steps I followed when implementing this subject, and I do recommend it to ensure every intermediate result is correct:
- Draw a basic sphere with a simple color
- Draw geometric properties, such as the
normal
, theviewDirection
etc... - Send simple light data to the shader, and display them
- Implement the Lambertian diffuse BRDF
- Implement the Cook-Torrance GGX specular BRDF
This is the kind of results you should get with 4 point lights:
The tasks to accomplish to lit your objects with the diffuse IBL are:
- Load one of the
diffuse
files provied in the folderassets/env
- Use the geometry normal to sample the texture. Be careful here, the texture is saved as a spherical projection. Thus, you will need to convert from cartesian coordinates to polar coordinates
- Apply the texture contribution to the indirect lighting
This is the kind of results you should get with the diffuse texture Alexs_Apt_2k-diffuse-RGBM.png
:
For the specular IBL, the texture encodes different version of the environment for different roughness values. There is a total of 6 roughness levels, starting at the bottom of the texture.
Each level is half the size of the previous one. Thus, you will need to compute the good position of the UV from the roughness value.
In order to get proper blending, you are advised to sample two roughness levels simultaneously, and to blend them together.
The tasks can be summed up as:
- Load one of the
specular
files provied in the folderassets/env
- Load the texture
assets/ggx-brdf-integrated.png
containing the precomputed BRDF - Convert the reflected ray from cartesian to polar
- Offset the polar coordinates according to the roughness level
- Repeat step 2 and 3 for a second level
- Fetch both levels and blend them together according to how far between the two the sample was
- Apply the result to the rendering equation using the pre-computed BRDF
This is the kind of results you should get with the diffuse texture Alexs_Apt_2k-specular-RGBM.png
:
Now that you implemented both the diffuse and the specular IBL, take a look at the combined results:
The feature described here aren't mandatory but will make you learn a lot of stuff!
PBR is meaningless without carefully authored textures bringing complexity to materials.
You can download some texture that would map well to a sphere, such as those ones.
There are a lot of other BRDFs, whether it is for the diffuse component or the specular one. Try to experiment with some of them and compare how they look. You can try any BRDFs you want, such that the Burley diffuse.
For this project, you have worked with pre-convolved diffuse data. Instead of using the asset in the repository, try to generate yourself the convolved diffuse of an environment texture.
Just like you did for the diffuse, you can generate the specular probe. This task is harder, but will definitely make you stronger.
There are so many fun things you can do:
- Loading more complex models
- Add several light probe with blending
- ...
The index is the entry point of your application. The game loop is started there
and resources are initialized in the Application
class.
In this repository, I created a simple shader that sets a uniform color on a triangle. This sample will help you start to implement your PBR shader.
The context is one of the most important. It abstracts WebGL calls and resources management. Without that, you would need to spend quite a bit of code to setup:
- Geometries (Vertex Buffers)
- Textures
- Shaders
- etc...
I didn't you to spend your time writing an abstraction, so I made one for you. If you want fancier features, please feel free to update it with your own changes.
For the most curious ones, the file uses WeakMap
(basically hash tables) to retrieve uploaded GL objects
from your own instances (textures, geometries, etc...).
The Shader just contains the two shaders (vertex and fragment) as strings.
It also contains a dictionnary (defines
) that can allow you to conditionnally compile code or not.
When working on big rendering project, we often want several versions of a same shader with some differences.
Using #define
, we take advantage of the preproccessor to compile different variants.
The values in the defines
dictionnary will basically be preprended too your shader before compiling it.