Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
8421472
Remove unused freeglut copyrights
shehzan10 Jan 16, 2021
a79ca55
Update CUDA Computes List
shehzan10 Sep 10, 2021
78e028a
Retab
shehzan10 Sep 10, 2021
c03780d
Update instructions for Fall 2021
shehzan10 Sep 18, 2021
80ad206
Add vulkan option
shehzan10 Sep 18, 2021
cc3da39
Add sample readmes for inspiration
shehzan10 Sep 19, 2021
784f5ca
Merge pull request #1 from CIS565-Fall-2021/update-instructions-2021
shehzan10 Sep 21, 2021
6d7e696
Added Imgui Integration Files
codeplay9800 Sep 19, 2022
8462d52
Updated Instruction.md
codeplay9800 Sep 19, 2022
c44fccb
Update Instruction.md
codeplay9800 Sep 19, 2022
7165f5c
Merge branch 'main' into Integrate_Imgui
codeplay9800 Sep 19, 2022
26e8bf3
Imgui Integrated
codeplay9800 Sep 20, 2022
3dac24e
Added GUIDataContainer Class
codeplay9800 Sep 20, 2022
e666e6a
Removed ImGUI Cmake
codeplay9800 Sep 21, 2022
5000086
Update INSTRUCTION.md
shehzan10 Sep 21, 2022
98f098c
Fix a bug that causes MouseOverImGuiWindow() to not work
dw218192 Sep 22, 2022
16d6638
Merge pull request #1 from dw218192/patch-1
codeplay9800 Sep 22, 2022
fa270e5
Update INSTRUCTION.md
HummaWhite Sep 16, 2023
0f1be54
Added a section for optimization
wayne-wu Sep 18, 2023
c5d6523
Update INSTRUCTION.md
HummaWhite Sep 19, 2023
023038c
naive sampler
YueZhang1027 Sep 24, 2023
5d33e98
cache first bounce
YueZhang1027 Sep 24, 2023
04adff3
bounding box
YueZhang1027 Sep 24, 2023
975b73f
refraction pure
YueZhang1027 Sep 26, 2023
a152e48
focus depth-of-field
YueZhang1027 Sep 27, 2023
24b2d26
antialiasing
YueZhang1027 Sep 27, 2023
488eabc
fresnel
YueZhang1027 Sep 27, 2023
d882a25
mis part 1
YueZhang1027 Sep 28, 2023
d5c7c05
Fix fresnel, mis cont
YueZhang1027 Sep 28, 2023
5152694
mis complete
YueZhang1027 Sep 29, 2023
f6330e1
change file structure
YueZhang1027 Sep 29, 2023
8af3127
full
YueZhang1027 Sep 29, 2023
fdd1d65
obj load - cat!
YueZhang1027 Sep 30, 2023
2b72b87
Stratified sampling
YueZhang1027 Sep 30, 2023
164b6c8
microfacet
YueZhang1027 Oct 1, 2023
bbbd4d3
change obj normal
YueZhang1027 Oct 1, 2023
ca56041
remove triangles array from scene
YueZhang1027 Oct 1, 2023
ac8a573
kdTree
YueZhang1027 Oct 2, 2023
8129e47
fix mis
YueZhang1027 Oct 2, 2023
7ba01a1
Envmap
YueZhang1027 Oct 5, 2023
82e2f60
add normal barycentric interpolation, fix mis
YueZhang1027 Oct 5, 2023
d69d2b7
russian roulette
YueZhang1027 Oct 5, 2023
3b8782d
sub scattering medium
YueZhang1027 Oct 5, 2023
cbafb39
texture mapping
YueZhang1027 Oct 9, 2023
36ca9a2
readme
YueZhang1027 Oct 11, 2023
e6b54c4
readme
YueZhang1027 Oct 12, 2023
0d5a672
integrate gbuffer pixel
YueZhang1027 Oct 18, 2023
009413c
add UI control, implement G-Buffers for normals and positions
YueZhang1027 Oct 18, 2023
8212abe
a trous denoiser
YueZhang1027 Oct 19, 2023
b44499e
add measure
YueZhang1027 Oct 19, 2023
64ecd96
Gbuffer z
YueZhang1027 Oct 19, 2023
7f53d9e
Gbuffer oct
YueZhang1027 Oct 19, 2023
e940941
gauss blur
YueZhang1027 Oct 20, 2023
d65e40b
readme
YueZhang1027 Oct 20, 2023
aef9f73
change folder name
YueZhang1027 Oct 20, 2023
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
30 changes: 30 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,24 @@ set(headers
src/sceneStructs.h
src/preview.h
src/utilities.h
src/material.h
src/light.h
src/sample.h
src/medium.h
src/hdrloader.h

src/ImGui/imconfig.h
src/ImGui/imgui.h
src/ImGui/imconfig.h
src/ImGui/imgui_impl_glfw.h
src/ImGui/imgui_impl_opengl3.h
src/ImGui/imgui_impl_opengl3_loader.h
src/ImGui/imgui_internal.h
src/ImGui/imstb_rectpack.h
src/ImGui/imstb_textedit.h
src/ImGui/imstb_truetype.h

src/tiny_obj_loader.h
)

set(sources
Expand All @@ -84,6 +102,17 @@ set(sources
src/scene.cpp
src/preview.cpp
src/utilities.cpp
src/hdrloader.cpp

src/ImGui/imgui.cpp
src/ImGui/imgui_demo.cpp
src/ImGui/imgui_draw.cpp
src/ImGui/imgui_impl_glfw.cpp
src/ImGui/imgui_impl_opengl3.cpp
src/ImGui/imgui_tables.cpp
src/ImGui/imgui_widgets.cpp

src/tiny_obj_loader.cc
)

list(SORT headers)
Expand All @@ -92,6 +121,7 @@ list(SORT sources)
source_group(Headers FILES ${headers})
source_group(Sources FILES ${sources})

#add_subdirectory(src/ImGui)
#add_subdirectory(stream_compaction) # TODO: uncomment if using your stream compaction

cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers})
Expand Down
382 changes: 131 additions & 251 deletions INSTRUCTION.md

Large diffs are not rendered by default.

103 changes: 95 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,100 @@
CUDA Path Tracer
================
CUDA Denoiser For CUDA Path Tracer
==================================

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

* (TODO) YOUR NAME HERE
* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
* Yue Zhang
* [LinkedIn](https://www.linkedin.com/in/yuezhang027/), [personal website](https://yuezhanggame.com/).
* Tested on: Windows 11, i9-13900H @ 2.60GHz 32GB, NVIDIA GeForce RTX 4070 Laptop 8GB (Personal Laptop)
* Compute capability: 8.9

### (TODO: Your README)
## Project View

*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.
A diffuse rabbit denoised with À-Trous filter after 30 iterations.

![](img/bunny_comp.png)

Custom painter scene with denoiser.

![](final.png)

## GBuffer Visualization
Here are the visualized GBuffer result:
per-pixel normals | per-pixel positions (scaled down) |
|---|---|
|![](img/normal.png)|![](img/position.png)|

## Performance Analysis
* How much time denoising adds to your renders?

I setup a cpu timer to take all time `denoise()` function cost into account, including CUDA memory operation since they are all additional to the original show image process. Here is the table comparing results along different optimzation methods (filter size = 80, iter = 10, resolution = 800 x 800):

![](img/avg_time_cornell.png)

The average time with optimization on gbuffer struct performs a little worse the the baseline. That should be the extra call to encode and decode z-depth and oct-normal in the short denoise process. In the other side, the gBuffer will require a smaller memory size and will be an optimization in a complicated enough scene (when memory bandwidth becomes a bottleneck).

* How denoising influences the number of iterations needed to get an "acceptably smooth" result?

|Ground Truth (5000 iter)|Iter = 1|Iter = 5|Iter = 10|
|------|------|-------|-------|
![](img/reflective.png)|![](img/1iter.png)|![](img/5iter.png)|![](img/10iter_with_weight.png)|

After 10 iterations, the result is visually close to the final ground truth and the following iterations doesn't improve the result strongly as in the first 10 iterations. Denoising largely decrease the iteration to get a smooth result due to its scene-aware blur feature.

* How denoising at different resolutions impacts runtime?

Here is a line chart for the average denoising time for different resolutions:

![](img/avg_time_resolution.png)

Larger resolution increases the pixel count to run denoise algorithm. When the resolution is large enough, the increase of average denoise time is close to the multiple of the two pixel counts. In the smaller case, the memory operation will be the main time cost.

* How varying filter sizes affect performance?

Here is a line chart for the average denoising time for different filter sizes:

![](img/avg_time_filter_size.png)

Since the cost of À-Trous filter relates direct with the iteration count determined from the log of filter size, the average denoising time with respect to filter size is linear to the log of filter size, as reflected in this chart. The image with lower filter size obtain less average denoising time, but requires more iterations to achieve the acceptably smooth result.

* How different is À-Trous filter and gaussian filter in visual effect?

|Ground Truth (5000 iter)|À-Trous filter(10 iter)|Gaussian filter(10 iter)|Gaussian filter(50 iter)|Gaussian filter(100 iter)|
|------|------|------|------|------|
|![](img/reflective.png)|![](img/10iter_with_weight.png)|![](img/10_gauss.png)|![](img/50_gauss.png)|![](img/100_gauss.png)|

Since gaussian filter only computes a global blur effect upon the image, it makes the image blurrier than À-Trous filter and requires longer time to remove all the noise point.

* How visual results vary with filter size -- does the visual quality scale uniformly with filter size?

Here are the visual output for three different filter size: 20, 40 and 80 in the same scene `cornell_ceiling_light.txt` with À-Trous filter and the same size on the other scene `cornell.txt` with only plain blur occurred (without weight from G-Buffer).

||Filter Size = 20|Filter Size = 40|Filter Size = 80|
|------|------|-------|-------|
|Plain blurry|![](img/20_filter_atrous_100iter.png)|![](img/40_filter_atrous_100iter.png)|![](img/80_filter_atrous_100iter.png)|
|À-Trous|![](img/20filter.png)|![](img/80filter.png)|![](img/40filter.png)|

The larger filter gives a better removal of noise point since the noise point take less account in the final averaged result, with an obviously blurry effect. Since the iteration count is determined by log of the filter size, the increment of visual quality (suggested by removal of noise point here) is not uniformly increase. There will be an obvious increase when each level of À-Trous wavelet transform increases.

* How effective/ineffective is this method with different material types?

We compare diffuse, reflective and refractive ball here for the visual effect along different material types.

||Diffuse|Reflective|Refractive|
|------|------|------|-------|
|Ground Truth|![](img/diffuse.png)|![](img/reflective.png)|![](img/refractive.png)|
|Original (10 iter)|![](img/raw_diffuse.png)|![](img/raw_reflective.png)|![](img/raw_refractive.png)|
|Denoised (10 iter)|![](img/80_diffuse.png)|![](img/80filter.png)|![](img/80_refractive.png)|

In this comparision, diffuse ball performs best in the output. The surface of reflective and refractive ball is blurry due to failure to avoid edge by normal buffer (its normal is always continous) and position buffer on it. The color buffer for reflective material will compute a blurry effect upon the surface.

* How do results compare across different scenes - for example, between `cornell.txt` and `cornell_ceiling_light.txt`. Does one scene produce better denoised results? Why or why not?

Here are the comparision for reflective material and refractive material in these two different scene:

|`cornell.txt`|`cornell_ceiling_light.txt`|
|------|------|
|![](img/diffuse_small_light.png)|![](img/80_diffuse.png)|
|![](img/reflective_small_light.png)|![](img/80filter.png)|

The scene with larger light source obviously perform better since the chance for rays to shoot at the light surface is higher. Since the image converges better in the same iteration, the denoiser works better based on better path-traced result.
8 changes: 5 additions & 3 deletions cmake/CUDAComputesList.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ IF( CUDA_COMPUTE_20
OR CUDA_COMPUTE_70
OR CUDA_COMPUTE_72
OR CUDA_COMPUTE_75
OR CUDA_COMPUTE_80
OR CUDA_COMPUTE_86
)
SET(FALLBACK OFF)
ELSE()
Expand All @@ -70,8 +72,8 @@ LIST(LENGTH COMPUTES_DETECTED_LIST COMPUTES_LEN)
IF(${COMPUTES_LEN} EQUAL 0 AND ${FALLBACK})
MESSAGE(STATUS "You can use -DCOMPUTES_DETECTED_LIST=\"AB;XY\" (semicolon separated list of CUDA Compute versions to enable the specified computes")
MESSAGE(STATUS "Individual compute versions flags are also available under CMake Advance options")
LIST(APPEND COMPUTES_DETECTED_LIST "30" "50" "60" "70")
MESSAGE(STATUS "No computes detected. Fall back to 30, 50, 60 70")
LIST(APPEND COMPUTES_DETECTED_LIST "30" "50" "60" "70" "80")
MESSAGE(STATUS "No computes detected. Fall back to 30, 50, 60, 70, 80")
ENDIF()

LIST(LENGTH COMPUTES_DETECTED_LIST COMPUTES_LEN)
Expand All @@ -90,7 +92,7 @@ MACRO(SET_COMPUTE VERSION)
ENDMACRO(SET_COMPUTE)

# Iterate over compute versions. Create variables and enable computes if needed
FOREACH(VER 20 30 32 35 37 50 52 53 60 61 62 70 72 75)
FOREACH(VER 20 30 32 35 37 50 52 53 60 61 62 70 72 75 80 86)
OPTION(CUDA_COMPUTE_${VER} "CUDA Compute Capability ${VER}" OFF)
MARK_AS_ADVANCED(CUDA_COMPUTE_${VER})
IF(${CUDA_COMPUTE_${VER}})
Expand Down
96 changes: 48 additions & 48 deletions cmake/FindGLFW.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,66 @@
include(FindPackageHandleStandardArgs)

if (WIN32)
# Find include files
find_path(
GLFW_INCLUDE_DIR
NAMES GLFW/glfw3.h
PATHS
$ENV{PROGRAMFILES}/include
${GLFW_ROOT_DIR}/include
DOC "The directory where GLFW/glfw.h resides")
# Find include files
find_path(
GLFW_INCLUDE_DIR
NAMES GLFW/glfw3.h
PATHS
$ENV{PROGRAMFILES}/include
${GLFW_ROOT_DIR}/include
DOC "The directory where GLFW/glfw.h resides")

# Use glfw3.lib for static library
if (GLFW_USE_STATIC_LIBS)
set(GLFW_LIBRARY_NAME glfw3)
else()
set(GLFW_LIBRARY_NAME glfw3dll)
endif()
# Use glfw3.lib for static library
if (GLFW_USE_STATIC_LIBS)
set(GLFW_LIBRARY_NAME glfw3)
else()
set(GLFW_LIBRARY_NAME glfw3dll)
endif()

# Find library files
find_library(
GLFW_LIBRARY
NAMES ${GLFW_LIBRARY_NAME}
PATHS
$ENV{PROGRAMFILES}/lib
${GLFW_ROOT_DIR}/lib)
# Find library files
find_library(
GLFW_LIBRARY
NAMES ${GLFW_LIBRARY_NAME}
PATHS
$ENV{PROGRAMFILES}/lib
${GLFW_ROOT_DIR}/lib)

unset(GLFW_LIBRARY_NAME)
unset(GLFW_LIBRARY_NAME)
else()
# Find include files
find_path(
GLFW_INCLUDE_DIR
NAMES GLFW/glfw.h
PATHS
/usr/include
/usr/local/include
/sw/include
/opt/local/include
DOC "The directory where GL/glfw.h resides")
# Find include files
find_path(
GLFW_INCLUDE_DIR
NAMES GLFW/glfw.h
PATHS
/usr/include
/usr/local/include
/sw/include
/opt/local/include
DOC "The directory where GL/glfw.h resides")

# Find library files
# Try to use static libraries
find_library(
GLFW_LIBRARY
NAMES glfw3
PATHS
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/sw/lib
/opt/local/lib
${GLFW_ROOT_DIR}/lib
DOC "The GLFW library")
# Find library files
# Try to use static libraries
find_library(
GLFW_LIBRARY
NAMES glfw3
PATHS
/usr/lib64
/usr/lib
/usr/local/lib64
/usr/local/lib
/sw/lib
/opt/local/lib
${GLFW_ROOT_DIR}/lib
DOC "The GLFW library")
endif()

# Handle REQUIRD argument, define *_FOUND variable
find_package_handle_standard_args(GLFW DEFAULT_MSG GLFW_INCLUDE_DIR GLFW_LIBRARY)

# Define GLFW_LIBRARIES and GLFW_INCLUDE_DIRS
if (GLFW_FOUND)
set(GLFW_LIBRARIES ${OPENGL_LIBRARIES} ${GLFW_LIBRARY})
set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_DIR})
set(GLFW_LIBRARIES ${OPENGL_LIBRARIES} ${GLFW_LIBRARY})
set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_DIR})
endif()

# Hide some variables
Expand Down
44 changes: 22 additions & 22 deletions cmake/FindGLM.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
# Find GLM
#
# Try to find GLM : OpenGL Mathematics.
# This module defines
# This module defines
# - GLM_INCLUDE_DIRS
# - GLM_FOUND
#
# The following variables can be set as arguments for the module.
# - GLM_ROOT_DIR : Root library directory of GLM
# - GLM_ROOT_DIR : Root library directory of GLM
#
# References:
# - https://github.com/Groovounet/glm/blob/master/util/FindGLM.cmake
Expand All @@ -18,34 +18,34 @@
include(FindPackageHandleStandardArgs)

if (WIN32)
# Find include files
find_path(
GLM_INCLUDE_DIR
NAMES glm/glm.hpp
PATHS
$ENV{PROGRAMFILES}/include
${GLM_ROOT_DIR}/include
DOC "The directory where glm/glm.hpp resides")
# Find include files
find_path(
GLM_INCLUDE_DIR
NAMES glm/glm.hpp
PATHS
$ENV{PROGRAMFILES}/include
${GLM_ROOT_DIR}/include
DOC "The directory where glm/glm.hpp resides")
else()
# Find include files
find_path(
GLM_INCLUDE_DIR
NAMES glm/glm.hpp
PATHS
/usr/include
/usr/local/include
/sw/include
/opt/local/include
${GLM_ROOT_DIR}/include
DOC "The directory where glm/glm.hpp resides")
# Find include files
find_path(
GLM_INCLUDE_DIR
NAMES glm/glm.hpp
PATHS
/usr/include
/usr/local/include
/sw/include
/opt/local/include
${GLM_ROOT_DIR}/include
DOC "The directory where glm/glm.hpp resides")
endif()

# Handle REQUIRD argument, define *_FOUND variable
find_package_handle_standard_args(GLM DEFAULT_MSG GLM_INCLUDE_DIR)

# Define GLM_INCLUDE_DIRS
if (GLM_FOUND)
set(GLM_INCLUDE_DIRS ${GLM_INCLUDE_DIR})
set(GLM_INCLUDE_DIRS ${GLM_INCLUDE_DIR})
endif()

# Hide some variables
Expand Down
Loading