Computer Graphics 2024 - Project
Published:
Team Members
Bao-Huy Nguyen & Anh Dang Le Tran
Motivation
When I saw the topic, I quickly recalled to my working place. Messy, unorganized, chaostic sometimes dirty maybe are the words that other people would use to describe it. However, somehow, strangely, to me it’s still really “organised” since I know where things are in my desk (or somehow I purposely and unconsciously put them there), and they are there just because of balance and harmony.
In addition, we are really interested in the nostalgia trend recently hence we want to model a scene that reminds everyone (maybe mostly boys) about their childhoods, video games in late night and no homework. Chilling time, peaceful moment in the messy place.
Layout of the scene
Inspired Image
Table of content:
A. Simple Features
1. Shading Normals
Shadding Normals/ Normal Mapping is a cheap and easiy way to add more details to a geometry without having to model a complex and detailed mesh. We employ this technique to render the highly detailed and complex objects like a wooden floor. To implement this, we include normal map texture property ref<Texture> m_normals
in the class instance.hpp
to get the normal texture if provided. Then we re-compute the tangent
vector based on the new shading normal in Instance::transformFrame()
.
Code:
include\lightwave\instance.hpp
src\core\instance.cpp
Below is the result before and after including normal map texture to a simple rectangle shape to increase its realism.
Without | With |
---|---|
![]() | ![]() |
2. Alpha Masking
For our scene, we want to have several transparent sticker notes attached to the CRT television as decorations. These objects is not fully opaque and we can see other objects behind it. To this end, we implement alpha masking similar to shading normals above. The instance class will find the provided alpha texture in a xml file. For alpha = 0
, the object is fully transparent meaning that Scene::intersect
method will ignore the ray intersection. When alpha = 1
, the intersection is always valid.
Code:
include\lightwave\instance.hpp
src\core\instance.cpp
Below is the result with alpha=0.2
.
3. Halton Sampler
The Independent
sampler sometimes, unluckly, produces many samples in a same region and that leads to high variant results. This may require a large number of sample to cover all the possible incoming light directions to an intersection point to achieve less variance. However, the more samples, the slower renderer is. To get better visual quality with the same amount of samples, we follow the intruction from PBR to implement Halton Sampler. The visual quality is significantly enhanced compared to Independent
sampler with the same amount of samples per pixel.
Code:
src\samplers\halton.cpp
src\utils\lowdiscrepancy.hpp
Below are the results of using Independent Sampler and Halton sampler with 3 different randomizer strategies. All of them use same number of samples, 64.
Indepedent | OwenScramble |
---|---|
![]() | ![]() |
![]() | ![]() |
PermuteDigit | RadicalInverse |
---|---|
![]() | ![]() |
![]() | ![]() |
4. Post Processing
Bloom
In real life, sometimes, the extreme brightness from the light source can overwhelm the human eyes and camera, producing the effects of extending the borders of light area in the scene. Simulating this effect directly in is not an easy task hence we follow the guidline from LearnOpenGL to achieve the bloom effects for the lamp in our scene.
Code:
src\postprocess\bloom.cpp
Below is the result after applying bloom. We can clearly see the effects of extending edges of two emissive objects.
Reinhard
Although human visual perception has a relatively high dynamic range, most of monitors can only represent RGB color in range [0, 255] or [0, 1]. Output of our renderer is an high dynamic range image without an upper intensity limitation. To map a high dynamic range image to [0, 1] to display it, we refer this guidline to implement tonemapping alogrithms.
Code:
src\postprocess\tonemapping.cpp
src\utils\imageprocessing.hpp
Before | After |
---|---|
![]() | ![]() |
5. Image Denoising
Since our render uses the Monte Carlo method to compute the high-dimensional integral in the rendering equation, a large of number of samples is required to achieve a visally appealing result, which presents a computational burden. Our scene has a considerable number of objects in which using a low number of samples would produce noisy results. To this end, we integrate Intel®Open Image Denoise library to our renderer to reduce noise of outputs.
Code:
src\postprocess\denoise.cpp
6. Rough Dielectric
We want to increase a little bit of realism to our glass material, hence implement rough dielectric bsdf to add a little bit of roughness to our Coca-Cola bottle . We follow the Microfacet Models for Refraction to implement that bsdf class.
Code:
src\bsdfs\roughdielectric.cpp
Roughness 0.0 | Roughness 0.1 | Roughness 0.2 |
---|---|---|
![]() | ![]() | ![]() |
Roughness 0.3 | Roughness 0.4 | Roughness 0.5 |
---|---|---|
![]() | ![]() | ![]() |
7. Area Light
We implement area light class for the lamp’ bulb and the screen of CRT television (which are natuarlly area lights).
Code:
src\lights\area.cpp
src\shapes\mesh.cpp
src\shapes\rectangle.cpp
src\shapes\sphere.cpp
include\lightwave\shape.hpp
8. Spot Light
Our scene has the vibe of late game night and sometimes we only want to shine a specific area but not the whole sence. Point light and directional light are not a good choice in this case. To this end, we refer to PBR to implement another light class, spotlight, to handle this task.
Code:
src\lights\spot.cpp
pointlight | spotlight |
---|---|
![]() | ![]() |
B. Intermediate Features
1. Thinlens Camera
The perspective pin pole camera model in our renderer could not capture the focus effect like real life camera, which may reduce the realism. To simulate the depth of field effect of the real life cameras, we follow PBR to implement a thin lens camera model.
Code:
src\cameras\thinlens.cpp
Lens Radius
Lens Radius 0.05 | Lens Radius 0.10 | Lens Radius 0.15 |
---|---|---|
![]() | ![]() | ![]() |
Lens Radius 0.20 | Lens Radius 0.25 | Lens Radius 0.05 |
---|---|---|
![]() | ![]() | ![]() |
Plane of Focus Distance
Plane of Focus Distance 1.0 | Plane of Focus Distance 3.0 | Plane of Focus Distance 5.0 |
---|---|---|
![]() | ![]() | ![]() |
Plane of Focus Distance 7.0 | Plane of Focus Distance 9.0 | Plane of Focus Distance 1.0 |
---|---|---|
![]() | ![]() | ![]() |
2. MIS Path Tracer
Faithfully tracing each ray in BSDF sampling will produce unbias results in rendering but requires a large number of samples and high depth to achieve those results. On the other hand NEE although significantly reduce noise by directly accounting direct illuminace from light source, will fail in case of smooth surfaces which requires idirect illumination. To balance both, we refer the video lectures of Prof. Ravi Ramamoorthi to implement MIS Path Tracer.
Code:
src\integrators\mis_pathtracer.cpp
3. Disney Bsdf
We want to model plastic material for our NES Console (which is made of plastic) that sometimes reflects light at grazing angles. The reflectance is modeled by coating a layer on the diffuse material. We faithfully follow the instruction from the UCSD homework to implement Disney Bsdf. This bsdf unifies all the material that we have implemented so far. Although not 100% physcially accurate, it still gives good and reasonable results.
Code:
src\bsdfs\disney.cpp
Subsurface
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
Anisotropic
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
Clearcoat
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
ClearcoatGloss
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
Metallic
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
Roughness
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
0.3 | 0.4 | 0.5 |
---|---|---|
![]() | ![]() | ![]() |
0.6 | 0.7 | 0.8 |
---|---|---|
![]() | ![]() | ![]() |
0.9 | 1.0 | 0.0 |
---|---|---|
![]() | ![]() | ![]() |
SpecularTransmittance 1.0, and Roughness
0.0 | 0.1 | 0.2 |
---|---|---|
![]() | ![]() | ![]() |
Comparison of Disney Coatting and Principle Specular for Plastic Material
Dinesy | Principle |
---|---|
![]() | ![]() |
Disney Coatting gives a little bit more realism than Principle Specular since the coatting layer of the Bsdf (not physcially accurate) reflects sufficient amount of light but not too much compared to Principle bsdf.
C. Other Features
CRT TV Effect
The old CRT TVs in 80s have an interesting effect, CRT effect, which if we look closely to the screen, we can easily notice with our naked eyes that there are many separate red, green and blue pixels. And because the screen is curved, we can see some curved line strips in the screen. Although we can implement a texture class to simulate that effect, for the sake of simplicty, we modify the texture of screen byt multiplying it with a CRT pattern.
Pattern | After |
---|---|
![]() | ![]() |