Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 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
230dc7c
bug fox
HanLinSun Sep 29, 2022
cd3b4a5
gltf stage save
HanLinSun Oct 1, 2022
28e2ffc
add mesh loading and intersection
HanLinSun Oct 3, 2022
de82e8e
ting gltf bug fix
HanLinSun Oct 3, 2022
9e970ed
ting gltf bug fix
HanLinSun Oct 3, 2022
4944499
fix intersection bug
HanLinSun Oct 7, 2022
621f47b
bug fix
HanLinSun Oct 7, 2022
ff67c9f
gltf load finish
HanLinSun Oct 7, 2022
e6b1ab5
save progress
HanLinSun Oct 8, 2022
fb5f655
readme setter
HanLinSun Oct 9, 2022
e182e18
readme upd
HanLinSun Oct 9, 2022
bac04a5
update readme
HanLinSun Oct 9, 2022
6fdbdce
update readme (Does not change implementation, only modify gltf mater…
HanLinSun Oct 10, 2022
165e0a4
update readme
HanLinSun Oct 10, 2022
675f2e4
readme complete
HanLinSun Oct 10, 2022
ed8ae34
show Gbuffer in proj 3
HanLinSun Oct 16, 2022
e1bcb29
merge project 3 and add depth buffer
HanLinSun Oct 20, 2022
a6ca206
fix bug
HanLinSun Oct 21, 2022
27adb40
update readme
HanLinSun Oct 22, 2022
1cf19d3
fix readme
HanLinSun Oct 22, 2022
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
20 changes: 20 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,17 @@ set(headers
src/sceneStructs.h
src/preview.h
src/utilities.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
)

set(sources
Expand All @@ -84,6 +95,14 @@ set(sources
src/scene.cpp
src/preview.cpp
src/utilities.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
)

list(SORT headers)
Expand All @@ -92,6 +111,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
185 changes: 89 additions & 96 deletions INSTRUCTION.md

Large diffs are not rendered by default.

127 changes: 119 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,124 @@
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)
* Hanlin Sun
* [LinkedIn](https://www.linkedin.com/in/hanlin-sun-7162941a5/)
* Tested on: Windows 10, i7-8750H @ 2.82GHz 32GB, NVIDIA Quadro P3200

### (TODO: Your README)
## Background

*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.
This project implements a **CUDA denoiser** based on the following paper: ["Edge-Avoiding A-Trous Wavelet Transform for fast Global Illumination Filtering,"](https://jo.dreggn.org/home/2010_atrous.pdf).

## Result

### Simple Blur

The A-Trous Wavelet filter is first implemented without any data weighting to achieve a simple blur effect. The result is compared to a Gaussian blur filter.
There are some artifacts in this implementation most noticeable around the edges of the image. However, for the most part the blur effect is achieved properly and indicates that the wavelet kernel is working well.

Original | Gaussian
:-------------------------:|:-------------------------:
![](img/unDenoise.JPG) | ![](img/simpleBlur.JPG)

### G-Buffer

For edge-avoiding weights, the normal, depth and position data per-pixel are stored in the G-buffer.

Position | Normal | Depth |
:-------------------------:|:-------------------------:|:------------------:|
![](img/Position.JPG) | ![](img/NormalBuffer.JPG) |![](img/Depth.JPG)

### Blur with Edge-Avoiding (A-trous method)

Denoising is achieved by adding the effect of weights in the convolution.
The parameters are tuned to produce a desirably smooth output.

Original | Simple Blur | Blur with Edge-Avoiding (Final Result)
:-------------------------:|:-------------------------:|:-----------:
![](img/unDenoise.JPG) | ![](img/simpleBlur.JPG) | ![](img/denoise.JPG)

### Depth Reconstruct World Space Position

To achieve this, I first convert the ray intersection point(in world space) to the NDC space, and then remap the Z from [-1,1] to [0,1].
Then based on the depth buffer and corresponding ray intersection pixel position, successfully recompute the position value.

Without Depth Reconstruction | With Depth Reconstruction |
:-------------------------:|:-------------------------:|
![](img/NoGBufferConstruct.JPG) | ![](img/WithDepth.JPG) |


## Visual Analysis
### How visual results vary with filter size -- does the visual quality scale uniformly with filter size ?

From the images below, we can find out that the visual quality improves with increasing filter size.
However, they do not scale uniformly. There is a noticeable difference from 5x5 to 30x30. However, the difference is less significant from 30x30 to 60x60, and barely noticeable from 60x60 to 90x90, so it's not a linear improvement.
Render iterations: 10

5x5 |30x30 | 60x60 | 90x90
:-----:|:-------------------------:|:-------------------------:|:-----------:
![](img/5x5.JPG)|![](img/30x30.JPG)| ![](img/60x60.JPG) | ![](img/90x90.JPG)

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

The method is effective for diffuse materials and less effective for reflective materials. As shown below, the denoised result for the diffuse scene is representable of the actual outcome. However, in the specular scene, there will have noticeable blurs in the reflected surface, and if the position weight is increased, this blur will become larger.

Material Type | Original | Denoised (Low Weight) | Denoised (High Weight)
:------------:|:------------------:|:-------------------------:|:----------------------:|
Diffuse |![](img/diffuse_origin.JPG) | ![](img/diffuse_denoise_low.JPG) | ![](img/diffuse_denoise_high.JPG)
Specular |![](img/specular_origin.JPG) | ![](img/specular_denoised_low.JPG) | ![](img/specular_denoised_high.JPG)


### 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 ?

In general, the denoised result is dependent on how noisy the input image is.
For the default Cornell scene with smaller light area, the path traced result at 10 iterations is still very noisy. As such, denoising does not output good results.
However, for the Cornell scene with ceiling light, the path tracer converges faster with larger light area and thus produce significantly less noisy image. Accordingly, the output of the denoiser is much better.


Scene | Original (10 Iterations) | Denoised
:-----:|:------------------:|:-------------------------:|
Cornell |![](img/diffuse_origin.JPG) | ![](img/diffuse_denoise.JPG)
Cornell Ceiling Light |![](img/specular_noise.JPG) | ![](img/specular_denoise.JPG)

## Performance Analysis

### How much time denoising adds to your renders ?

Since the denoising kernel is executed once during the last iteration of path tracing, the additional time from denoising is independent of the number of iterations that is run.

![](img/denoiseTimeChart.JPG)

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

The purpose of denoising is to achieve the same smoothness/visual quality in image with less render iterations. Using a rendered image at 2000 iterations as the ground truth, we can see that the original input at 10 iterations is very noisy, But after applying denoising at 10 iterations render result, we immediately remove most of the noise. There are noticeable differences around the edge and shadow areas of the scene, which is a known limitation in the original reference paper. For the purpose of this project, we only look at smooth areas such as the walls and the floor for quality comparison. After 450 iterations of the path tracer, we roughly see the same amount of noise on the floor compared to the denoised version. Because of this, we consider 450 iterations as the acceptably smooth result, and thus the denoising reduces the required iterations for this specific example by **97.7%**!

Type |Reference (2000 Iterations) | 10 Iterations (Input) | Denoised (Output) | 450 Iterations (Acceptably Smooth)
:------:|:------------------:|:-------------------------:|:------------------:|:-------------------:
Image |![](img/groundTruth.JPG) | ![](img/diffuse_origin.JPG) | ![](img/diffuse_denoise_high.JPG) | ![](img/diffuse_450.JPG)

### How denoising at different resolutions impacts runtime ?

The denoising time increases proportionally with increasing image resolution.
From 800x800 to 1200x1200, there are 2.25x more pixels mapping to 88.5% increase in time.
From 1200x1200 to 1600x1600, there are 1.78x more pixels mapping to 75.7% increase in time.
From 1600x1600 to 2000x2000, there are 1.57x more pixels mapping to 49.16% increase in time.

Render iterations: 20

![](img/resolution.JPG)

### How varying filter sizes affect performance ?
The denoising time increases with increasing filter size. With increasing filter size, more passes/iterations are required to expand the 5x5 B3-spline kernel to cover the filter/blur size.

Render iterations: 20

![](img/fliterSizeChart.JPG)

### How Depth Reconstruct affect performance ?
Using Depth to recompute world space position bring a lot of performance increase. Since it's no longer need to read from another buffer and compute its value instead, save the time from reading position buffer and also the space for saving position buffer.

Render iterations: 20

![](img/DepthOptimize.JPG)
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