Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 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
f84ad53
update readme
Zenfendson Sep 26, 2023
3024c8f
Part1 & refraction
Zenfendson Oct 6, 2023
16cdf38
add & test mesh loader
Zenfendson Oct 7, 2023
79ccc8b
add depthoffield
Zenfendson Oct 7, 2023
f4dca5f
add antialiasing
Zenfendson Oct 7, 2023
8aeb369
add direct light
Zenfendson Oct 8, 2023
ece4780
add Open Image AI Denoiser
Zenfendson Oct 9, 2023
1e0782c
update readme
Zenfendson Oct 11, 2023
22a67c1
update readme
Zenfendson Oct 11, 2023
34de324
add mesh obj picture
Zenfendson Oct 11, 2023
92a7093
update readme
Zenfendson Oct 11, 2023
6330c21
update readme
Zenfendson Oct 11, 2023
8f75ce1
update readme
Zenfendson Oct 12, 2023
93a71b2
update for project 4
Zenfendson Oct 20, 2023
2969e1a
Merge remote-tracking branch 'project4/base-code' into denoiser
Zenfendson Oct 20, 2023
04ac6c8
solve merge errors
Zenfendson Oct 20, 2023
25a39fd
basic denoiser work
Zenfendson Oct 22, 2023
b5b87f0
fix bug and add cudaEvent timer
Zenfendson Oct 22, 2023
59d9329
add gaussian filter
Zenfendson Oct 22, 2023
76512c4
update readme
Zenfendson Nov 4, 2023
060d252
update readme
Zenfendson Nov 4, 2023
e430380
update readme
Zenfendson Nov 4, 2023
31ef827
update readme
Zenfendson Nov 4, 2023
fefdeea
update readme
Zenfendson Nov 4, 2023
e5dc53f
update readme
Zenfendson Nov 4, 2023
793e07a
update readme
Zenfendson Nov 4, 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
19 changes: 18 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ set(CUDA_VERBOSE_BUILD ON)

if(WIN32)
# Set up include and lib paths
set(CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH "Host side compiler used by NVCC" FORCE)
set(CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER} CACHE FILEPATH "Host side compiler used by NVCC" FORCE)
endif(WIN32)
########################################

Expand Down Expand Up @@ -110,10 +110,27 @@ source_group(Headers FILES ${headers})
source_group(Sources FILES ${sources})
source_group(imgui FILES ${imgui})

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

include_directories(./external/include)
link_directories(./external/lib)

#cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers})
cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers} ${imgui})
target_link_libraries(${CMAKE_PROJECT_NAME}
${LIBRARIES}
#stream_compaction # TODO: uncomment if using your stream compaction
OpenImageDenoise
)

if (WIN32)
# Copy all DLL files from OIDN's bin directory to your executable's directory
file(GLOB OIDN_DLLS "${CMAKE_SOURCE_DIR}/external/bin/*.dll")

foreach(OIDN_DLL IN LISTS OIDN_DLLS)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${OIDN_DLL} ${CMAKE_BINARY_DIR})
endforeach()
endif()
6 changes: 3 additions & 3 deletions INSTRUCTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,9 @@ The template of the comment section of your pull request is attached below, you

* [Repo Link](https://link-to-your-repo)
* (Briefly) Mentions features that you've completed. Especially those bells and whistles you want to highlight
* Feature 0
* Feature 1
* ...
* Feature 0
* Feature 1
* ...
* Feedback on the project itself, if any.

References
Expand Down
109 changes: 104 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,110 @@ CUDA Denoiser For CUDA Path Tracer

**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)
* Xitong Zheng
* [LinkedIn](https://www.linkedin.com/in/xitong-zheng-5b6543205/), [Instagram](https://www.instagram.com/simonz_zheng/), etc.
* Tested on: Windows 11, i7-12700k 32GB, GTX 4090 24GB

### (TODO: Your README)
## Brief Intro
This project focuses on implementing CUDA denoiser from the paper [Edge-Avoiding À-Trous Wavelet Transform for fast Global
Illumination Filtering](https://jo.dreggn.org/home/2010_atrous.pdf)

*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.
### Details
| raw | denoised |
|-----| ----- |
|![](./img/intro_raw.png) | ![](./img/intro_denoised.png) |

### À-Trous Wavelet Filter
It approximates gaussian filter by iteratively applying sparse blurs of increasing size (stride size *= 2). It uses a small filter which spaces out the samples going through it, achieving far less read per pixels compared to gaussian filter when blur size increases. As for the À-Trous Wavelet Filter, increasing blur size means more iterations instead of larger filter size.
![](./img/filter_intro.png)
The above picture shows that using a 5x5 filter to achieve 16x16 blur.

Simply running a À-Trous Wavelet Filter serves as a gaussian filter.

| raw | À-Trous Wavelet Filter (no G-buffer)| Blur from GLSL |
|-----| ----- | ----- |
|![](./img/intro_raw.png) | ![](./img/A_trous_wo_edge_avoid.png) |![](./img/raw_after_glmp_blur.png) |

### G-buffer
Edge-avoiding filtering is achieved by introducing a weighting function, which is related to weights calculated from the G-buffer that contains the normal and position data per-pixel. It diminshes the influence of neighboring samples that has far different values in G-buffers, making nice smoothing on planar surfaces and keeping the original edges.

Simple visualizations for the normal and position info of the G-buffer.

| Normal | Position |
|---|---|
|![](img/my_normal_G.png)|![](img/my_pos_G.png)|


### Performance Analysis

#### How much time denoising adds to your renders?
when the denoiser is activated, I made denoiser run just after each time the call of pathtracer() finish.
Under resolution 800 * 800, the following two scenes are compared to see the denoising time impact.
| pathtracing (with no denoiser) | pathtracing (with denoiser) |
|---|---|
| 11.87(ms ) | 3.11(ms) |

It can be oberseved that the denoiser can add extra 3.11ms to the render time per frame.

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

| Denoised Output with 10 spp | Output with 500 spp | reference output at 5000 spp |
|---|---|---|
|![](img/intro_denoised.png)|![](img/500spp.png)|![](/img/ground_truth.png)|

Denoising can achieve the same smoothness in image with far less render iterations. When looking at the denoisied image at 10 iterations, most of the noise can be removed except that there are some issues around the edge and shadow of the scene. But when we focus on the walls and the floor, the image quality is quite good. You can see 500 iterations of standard the pathtracer can achieve similar result. So the denoiser can save around 50x iterations to achieve similar result.

#### How denoising at different resolutions impacts runtime?
![](./img/denoiser_runtime_resolution_(filter_size=80%20_%2080).png)
It can be observed that the denoiser runtime is linearly related to the resolution of the image. The denoiser runtime is around 6.8ms per frame at resolution 1600 * 1600, and it is around 26.5ms per frame at resolution 3200 * 3200.

#### How varying filter sizes affect performance?
![](./img/Denoiser_runtime_VS_Filter_size_(resolution=1600%20_1600_10spp).png)

It can be observed that denoiser time increases as filter size increase. The relation seems to be linear. This can be explained by when filter size is increased, more iterations are runned so that the 5x5 B3-spline kernel can be extended to the set filter size.

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

| 10 * 10 filter | 20 * 20 filter | 40 * 40 filter | 80 * 80 filter |
|---|---|---|---|
|![](img/10_10.png) | ![](img/20_20.png) | ![](img/40_40.png) | ![](img/80_80.png) |

The image quality improves significantly as the filter size increases from 10 * 10 to 40 * 40. But when the filter size is increased to 80 * 80, the image quality does not improve much. So the visual quality does not scale uniformly with filter size.

#### How effective/ineffective is this method with different material types?
The scene is run under 10 spp and 1600 * 1600 resolution. The following two scenes are compared to see the denoising effect on different material types.

| Matarial Type | Original | Denoised |
|---|---|---|
| Diffuse | ![](img/diffuse_original.png) | ![](img/diffuse.png) |
| Specular | ![](img/specular_original.png) | ![](img/specular.png) |

It can be observed that the denoiser works more effective on diffuse material than specular material. The blurry effect on reflection is still visible after denoising.

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

| scene | Original | Denoised |
|---|---|---|
| cornell | ![](img/cornell_original.png) | ![](img/cornell_denoised.png) |
| cornell_ceiling_light | ![](img/original_cornell_light.png) | ![](img/denoised_cornell_light.png) |
| cornell_light_emittance = 1 | ![](img/original_cornell_e1.png) | ![](img/denoised_cornell_e1.png) |

It can be observed that the denoiser works better on the scene with more light source. The denoiser can remove the noise on the wall and the floor of the scene with more light source. This may because the default cornell scene under 10 spp is too much noiser than the scene with more light source. So the denoiser can not remove all the noise in the scene with less light source.

I further change the light emitance of the cornell scene to 1 and do not change the size of ceilling light. The denoiser can remove most the noise in the scene, which indirectly proves that the denoiser works better on the scene with less noisier input.

### Comparing A-trous and Gaussian filtering
The filter can be toggle between A-trous and Gaussian filtering by changing the macro `GAUSSIAN_FILTER` in pathtrace.cu.
Below scenes are all runned under 10 spp and 1600 * 1600 resolution.

| A-trous | Gaussian |
|---|---|
|![](img/A_wave_filter.png) | ![](img/gaussian_filter.png) |

You can see that the two picture do not vary a lot. But there are more noise on the white wall of Gaussian filtering and A-trous filtering is better. It may be because the A-trous filtering use G-buffer to achieve a more reasonable sparse sample.

| A-trous | Gaussian |
|---|---|
| 6.85ms | 139.71ms |

The runtime of A-trous filtering is far less than Gaussian filtering, nearly 20x faster. It can significantly increase the performance of the pathtracer than Gaussian filtering as the runtime of pathtracer without any filter is around 28ms.
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