Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project 3: Mufeng Xu #26

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ build
.LSOverride

# Icon must end with two \r
Icon
Icon


# Thumbnails
._*
Expand Down Expand Up @@ -558,3 +559,6 @@ xcuserdata
*.xccheckout
*.moved-aside
*.xcuserstate


*.m
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ set(sources
src/intersections.cu
src/interactions.cu
src/scene.cpp
src/sceneStructs.cpp
src/preview.cpp
src/utilities.cpp
)
Expand Down
187 changes: 182 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,188 @@ CUDA Path Tracer

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3**

* (TODO) YOUR NAME HERE
* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
* Mufeng Xu
* [LinkedIn](https://www.linkedin.com/in/mufeng-xu/)
* Tested on: Windows 11, i9-13900H @ 2.6GHz 32GB, RTX 4080 Laptop 12282MB (Personal Computer)

### (TODO: Your README)
## Features

*DO NOT* leave the README to the last minute! It is a crucial part of the
project, and we will not be able to grade you without a good README.
- Core
- Diffuse
- Perfectly Specular-Reflective Surfaces
- Imperfect Specular
- Stream Compaction
- Sort Path Segments by Materials
- Stochastic Sampled Anti-aliasing
- Extra
- Refraction 2️⃣
- Dispersion 3️⃣
- Physics-based DoF 2️⃣
- Motion blur 3️⃣
- Re-startable path tracing 5️⃣

### Refraction

The implementation of refraction uses [Schlick's Approximation](https://en.wikipedia.org/wiki/Schlick'**s_approximation**)
to produce Fresnel Effect.

| IoR = 1.2 | IoR = 1.52 |
|:------------------------------------:|:------------------------------------:|
| ![](img/cornell_refraction=1.2.png) | ![](img/cornell_refraction=1.52.png) |

And imperfect refraction is also implemented with BRDF and BTDF:

![](img/BSDF.png)

The following demos are rendered with ***Roughness = 0.03***.
| IoR = 1.2 | IoR = 1.52 |
|:---------------------------------------------------:|:---------------------------------------------------:|
| ![](img/cornell_roughness=0.03_refrection=1.2.png) | ![](img/cornell_roughness=0.03_refrection=1.52.png) |

**Performance**: Refraction adds new branches to the `scatterRay` kernel,
and more branching causes more waste of GPU clock cycles.
The measured performance impact is about 5%.

**Compare w/. CPU**: N/A

**Possible Improvement**: Sorting by materials might improve the performance if the geometry/scene is more complicated,
however this is not the case with my simple scenes.

### Dispersion

Dispersion happens because for the some material,
the index of refraction (IoR) is varies for light with different wavelengths (colors).
In my implementation, the program samples different colors (RGB) in different iterations,
and each component has a different IoR, creating a realistic dispersion effect.

| Without Dispersion | With Dispersion |
|:---------------------------------------:|:------------------------------------:|
| ![](img/cornell_without_dispersion.png) | ![](img/cornell_with_dispersion.png) |

**Performance**: While the dispersion simply separately samples different colors
at each iteration, it is almost "free". There is no observable negative impact on
the performance.

**Compare w/. CPU**: N/A

**Possible Improvement**: My implementation assumes the white color is composed of red, green and blue colors,
however the natural light is composed of the whole spectrum, including red, orange, yellow, green, cyan, blue and
purple etc. To create the dispersion effect like a rainbow, it probably requires to decompose the white light into
many different colors and ray trace them separately.

### Depth of Field

For an ideal pinhole camera, the aperture size is infinitesimally small, and the Depth of Field (DoF) is infinite.
To create the effect of Depth of Field, we just modify the ideal pinhole camera model,
to make the aperture size greater than 0.

In the implementation, what we did is to modify the ray origin in `generateRayFromCamera` kernel,
the new origin is selected randomly within the size of the aperture.
And to update the ray direction, the `view` vector is computed by `glm::normalize(cam.lookAt - segment.ray.origin)`
instead of `normalize(cam.lookAt - cam.position)`.

| Aperture | Focus $z=-3.0$ | Focus $z=0.0$ | Focus $z=+3.0$ |
|:--------:|:-------------------------------:|:------------------------------:|:-------------------------------:|
| **20** | ![](img/cornell_A20_L-3.0.png) | ![](img/cornell_A20_L0.0.png) | ![](img/cornell_A20_L+3.0.png) |
| **200** | ![](img/cornell_A200_L-3.0.png) | ![](img/cornell_A200_L0.0.png) | ![](img/cornell_A200_L+3.0.png) |

From the demo we can conclude that larger the aperture, the more blurry will the objects not in focus would be.
This is exactly what the real-world physics tells us. Notice that when Aperture is 20, the DoF is large and the
whole scene seem to be in focus, as they look exactly like that without DoF effect.

**Performance**: Physics-based DoF is achieved almost "free",
since it just randomly chooses an origin for rays.
There is no observable impact introduced by the feature.

**Compare w/. CPU**: N/A

### Motion Blur

To implement motion blur, a `motion` array and a `exposure` float is added to the scene file.
The former indicates the velocity (magnitude and direction) of an object,
while the latter is the exposure time.
The renderer (uniformly) randomly samples the moving objects in the exposure interval,
and update the transform matrices at the beginning of every iteration.
And then the renderer uses the new transform matrices perform ray-tracing,
after statistically large number of iterations, you can observe the object "moving".

![](img/cornell_motion_blur.png)

**Performance**: Motion Blur is achieved almost "free",
because it computes the new transform matrices for each moving object only once per iteration.
There is no observable impact introduced by the feature.

**Compare w/. CPU**: A kernel is invoked for each moving object,
the kernel generate a random number to sample within the time interval,
and then update the transform matrices for the object.
If the number of moving objects is small, the overhead of the GPU implementation might cause it
to be slower than a CPU implementation. However, if the number is large enough, GPU will beat CPU.

**Possible Improvement**: If the whole scene is moving the same way, it is actually equal to the
camera moving. Similarly we can randomly place the camera at its moving path,
to create a motion blurred photo.

### Re-startable Path Tracing

All the path tracing state (except the scene) has been save in `renderState`.
To enable re-startable rendering, `serialize()` method is implemented for `class RenderState`,
which write the object into a binary file when dumping the rendering state.
To resume the rendering process,
the program loads the binary file, and use `deserialize()` to recover `renderState`.

***Press `D` to save the current state into a binary file,
and pass `-r NAME.ITERATION.bin` parameter to the program to restart rendering.***

![](img/restart.gif)****

**Performance**: No impact on rendering performance.

**Compare w/. CPU**: N/A

### Stream Compaction

![](img/sc.png)

Stream Compaction terminates path segments early,
it closes the threads occupied by the "dead" rays, and accelerate ray tracing.
There are 2 conditions that the rays are terminated before the depths run out:
first is when a ray hits a light source, another is when a ray has no intersection
with any of the objects in the scene.

The percentage of remaining path segments decreases with depth when stream compaction is applied.
At depth 0, stream compaction does not reduce the path count,
but as the depth increases, the reduction becomes more significant.
There is only about 25% of the rays remaining at the 8th depth.
And the FPS increase was significant.

As a comparison, in a closed box scene the number of remaining rays doesn't significantly reduce.
Thus the boost in FPS is minor. The reason is that without the opening, a ray will only terminate
because it hits a light source, while the amount of rays hitting some light source is very small,
there would be a lot of photons still traveling around after a few tracing depths.
One possible workaround is to terminate a ray if the color intensity it records is lower than some
threshold, say 0.02, which means the contribution of the ray to the pixel is negligible.

***Blooper time***

![](img/blooper.png)

### Sorting by Materials

Theoretically, sorting the path segments by materials would reduce branching
and boost the performance. However, in my simple scenes, the overhead of sorting
the path segments overmatches the cost of branching. The FPS dropped with the
implementation of sorting by materials.

### Anti-aliasing

***Notice the cyan sphere, with anti-aliasing, the edge appears to be much smoother.***

| Without Anti-aliasing | With Anti-aliasing |
|:---------------------------------:|:-----------------------------:|
| ![](img/cornell_noAA.png) | ![](img/cornell_AA.png) |

**Performance**: Anti-aliasing with stochastic sampling is almost "free".
Just jitter the camera ray direction with a uniform random distribution within a pixel every iteration,
the anti-aliasing is automatically achieved. There is no observable impact on the performance.

**Compare w/. CPU**: N/A
Binary file added img/BSDF.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/blooper.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A200_L+3.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A200_L-3.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A200_L0.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A20_L+3.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A20_L-3.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_A20_L0.0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_AA.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_motion_blur.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_noAA.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_refraction=1.2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_refraction=1.52.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_roughness=0.03_refrection=1.2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_roughness=0.03_refrection=1.52.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_with_dispersion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_without_dispersion.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/restart.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 59 additions & 5 deletions scenes/cornell.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,43 @@
"TYPE":"Diffuse",
"RGB":[0.35, 0.85, 0.35]
},
"diffuse_cyan":
{
"TYPE":"Diffuse",
"RGB":[0.35, 0.85, 0.85]
},
"specular_white":
{
"TYPE":"Specular",
"RGB":[0.98, 0.98, 0.98],
"ROUGHNESS":0.5
},
"metal_aluminum":
{
"TYPE":"Specular",
"RGB":[0.95, 0.95, 0.95],
"ROUGHNESS":0.5
},
"metal_gold":
{
"TYPE":"Specular",
"RGB":[0.98, 0.74, 0.02],
"ROUGHNESS":0.2
},
"glass_white":
{
"TYPE":"Transparent",
"RGB":[0.99, 0.99, 0.99],
"REFRACTION":1.52,
"ROUGHNESS":0.03
},
"glass_dispersion":
{
"TYPE":"Transparent",
"RGB":[0.99, 0.99, 0.99],
"REFRACTION":[1.7, 1.825, 1.88],
"ROUGHNESS":0.0
}
}
},
"Camera":
{
Expand All @@ -38,16 +69,18 @@
"FILE":"cornell",
"EYE":[0.0,5.0,10.5],
"LOOKAT":[0.0,5.0,0.0],
"UP":[0.0,1.0,0.0]
"UP":[0.0,1.0,0.0],
"APERTURE":100.0,
"EXPOSURE":1
},
"Objects":
[
{
"TYPE":"cube",
"MATERIAL":"light",
"TRANS":[0.0,10.0,0.0],
"TRANS":[0.0,10.05,0.0],
"ROTAT":[0.0,0.0,0.0],
"SCALE":[3.0,0.3,3.0]
"SCALE":[3.0,0.15,3.0]
},
{
"TYPE":"cube",
Expand Down Expand Up @@ -86,10 +119,31 @@
},
{
"TYPE":"sphere",
"MATERIAL":"specular_white",
"MATERIAL":"diffuse_white",
"TRANS":[-1.0,4.0,-1.0],
"ROTAT":[0.0,0.0,0.0],
"SCALE":[3.0,3.0,3.0]
},
{
"TYPE":"sphere",
"MATERIAL":"glass_white",
"TRANS":[-1.2,3.0,3.0],
"ROTAT":[0.0,0.0,0.0],
"SCALE":[3.0,3.0,3.0]
},
{
"TYPE":"sphere",
"MATERIAL":"metal_gold",
"TRANS":[3.0,2.0,0.0],
"ROTAT":[0.0,0.0,0.0],
"SCALE":[3.0,3.0,3.0]
},
{
"TYPE":"sphere",
"MATERIAL":"diffuse_cyan",
"TRANS":[-0.1,2.6,0.6],
"ROTAT":[0.0,0.0,0.0],
"SCALE":[2.0,2.0,2.0]
}
]
}
Loading