Skip to content

Project3: Mengxuan Huang #7

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

Open
wants to merge 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f83b745
Naive global illumination, with problem
MengxuanHUANG Sep 21, 2023
39eb69f
add Application & Sanbox Class to encapsule global varibles.
MengxuanHUANG Sep 23, 2023
4b8cc7c
remove preview and add cameraController
MengxuanHUANG Sep 23, 2023
c87fcd7
add triangle intersection test
MengxuanHUANG Sep 24, 2023
8737b0d
1. fix random number problem & add jittering the camera ray
MengxuanHUANG Sep 26, 2023
1e12b32
finish BVH middle-split method
MengxuanHUANG Sep 27, 2023
c7b0e54
finish SAH BVH and Barycentric Interpolation
MengxuanHUANG Sep 28, 2023
7e1a1e5
add scroll callback to control camera zoom in/out and fix horizontal …
MengxuanHUANG Sep 28, 2023
5b08dbd
texture and albedo map
MengxuanHUANG Sep 29, 2023
fb6ac45
add environment map
MengxuanHUANG Sep 29, 2023
491190f
add specular refelction and refraction
MengxuanHUANG Oct 1, 2023
57977b6
add shared memory for material loading
MengxuanHUANG Oct 1, 2023
09fe537
remove end path segments
MengxuanHUANG Oct 2, 2023
a5a8cf8
Test shared memory for BVH traverse
MengxuanHUANG Oct 3, 2023
42b53d0
Load normal map and fix bug when loading textures
MengxuanHUANG Oct 3, 2023
b1ce8fb
finish subsurface scattering
MengxuanHUANG Oct 4, 2023
d13ef4c
finish len camera
MengxuanHUANG Oct 5, 2023
7b8d0f4
finish microfacet
MengxuanHUANG Oct 5, 2023
7f5885c
finish microfacet
MengxuanHUANG Oct 6, 2023
94a0e62
Support to read material from .obj(.mtl) file
MengxuanHUANG Oct 6, 2023
79ddea7
Fix bug in resize and save image
MengxuanHUANG Oct 6, 2023
121ce65
modify scene files
MengxuanHUANG Oct 6, 2023
c1dabc1
fix bug and enable to be executed in cmd
MengxuanHUANG Oct 7, 2023
2ba5ed0
add basic resources(mesh, textures, env maps)
MengxuanHUANG Oct 7, 2023
6167149
add basic meshes
MengxuanHUANG Oct 7, 2023
aabb63e
add rendered images and finish readme
MengxuanHUANG Oct 8, 2023
ee91a3c
Update README.md
MengxuanHUANG Oct 8, 2023
0b19722
fix link error in readme
MengxuanHUANG Oct 8, 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
4 changes: 1 addition & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ install_manifest.txt
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
Expand Down Expand Up @@ -276,7 +275,6 @@ artifacts/
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
Expand Down Expand Up @@ -557,4 +555,4 @@ xcuserdata
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcuserstate
Expand Down
84 changes: 31 additions & 53 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Enable C++11 for host code
set(CMAKE_CXX_STANDARD 11)
# Enable C++20 for host code
set(CMAKE_CXX_STANDARD 20)

# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
Expand All @@ -23,7 +23,7 @@ endif()
########################################
# CUDA Setup
########################################
find_package(CUDA 10 REQUIRED)
find_package(CUDA 11 REQUIRED)
include(${CMAKE_MODULE_PATH}/CUDAComputesList.cmake)

list(APPEND CUDA_NVCC_FLAGS ${CUDA_GENERATE_CODE})
Expand Down Expand Up @@ -62,60 +62,38 @@ set(GLM_ROOT_DIR "external")
find_package(GLM REQUIRED)
include_directories(${GLM_INCLUDE_DIRS})

set(headers
src/main.h
src/image.h
src/interactions.h
src/intersections.h
src/glslUtility.hpp
src/pathtrace.h
src/scene.h
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
src/main.cpp
src/stb.cpp
src/image.cpp
src/glslUtility.cpp
src/pathtrace.cu
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)
list(SORT sources)

source_group(Headers FILES ${headers})
source_group(Sources FILES ${sources})
set(EXTERAL_ROOT_DIR "external")

set(PT_SRC_DIR "src")

file(GLOB_RECURSE PathTracer_Headers
"${PT_SRC_DIR}/*.h",
"${PT_SRC_DIR}/*.cuh"
)

file(GLOB_RECURSE PathTracer_Sources
"${PT_SRC_DIR}/*.cpp",
"${PT_SRC_DIR}/*.cu"
)

file(TO_CMAKE_PATH ${CMAKE_SOURCE_DIR} PROJ_BASE_PATH_NORMALIZED)
add_definitions(-DPROJ_BASE_PATH=${PROJ_BASE_PATH_NORMALIZED})

list(SORT PathTracer_Headers)
list(SORT PathTracer_Sources)

source_group(Headers FILES ${PathTracer_Headers})
source_group(Sources FILES ${PathTracer_Sources})

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

cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers})
cuda_add_executable(${CMAKE_PROJECT_NAME} ${PathTracer_Sources} ${PathTracer_Headers})
target_include_directories(${CMAKE_PROJECT_NAME}
PUBLIC
${EXTERAL_ROOT_DIR}
)
target_link_libraries(${CMAKE_PROJECT_NAME}
${LIBRARIES}
#stream_compaction # TODO: uncomment if using your stream compaction
)
)
27 changes: 27 additions & 0 deletions CMakeSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": []
}
]
}
194 changes: 189 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,197 @@
CUDA Path Tracer
================
A GPU Path Tracer implemented on CUDA C++.

**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)
* Mengxuan Huang
* [LinkedIn](https://www.linkedin.com/in/mengxuan-huang-52881624a/)
* Tested on: Windows 11, i9-13980HX @ 2.22GHz 64.0 GB, RTX4090-Laptop 16384MB
## Outcome
Astartes of Warhammer 40,000
![](/img/astartes.png)

### (TODO: Your README)
- **Thanks [Constantine Nikolaenko](https://www.cgtrader.com/badmaker91) from [cgtrader](https://www.cgtrader.com/) and [Games Workshop](https://www.games-workshop.com/en-US/Warhammer-40-000?_requestid=20431942) for this fantastic [Astartes of Steppe Hawks chapter Free 3D model](https://www.cgtrader.com/free-3d-models/character/sci-fi-character/astartes-of-steppe-hawks-chapter)!!**
- **Thanks for this [Rathaus Environment Map](https://polyhaven.com/a/rathaus) HDR environment map.**

*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.
## Features
- [Camera Controll & GUI](#camera-control--gui)
- [Customized JSON scene file](#json-scene-file)
- [Stochastic Sampled Anti-aliasing](#stochastic-sampled-anti-aliasing)
- [Bounding Volume Hierarchy](#bounding-volume-hierarchy)
- [Tone mapping](#tone-mapping)
- [Mesh Loader(obj) and texture mapping](#mesh-loaderobj-and-texture-mapping)
- [BSDFs](#bsdfs)
- Diffuse Reflection
- Specular Reflection
- Specular Refraction
- Microfacet Reflection
- Subsurface Scattering
- [Physically-based depth-of-field](#physically-based-depth-of-field)
### Camera Control & GUI
-----------------------------
#### Camera
- `ctrl + LMB` : Rotate camera around reference point
- `shift + LMB` : Pan camera and reference point
- `mouse scroll whell`: camera zomm in/out
#### GUI
|Description|ImGui|
|-------|------|
|Display fram time, frame rate per second, and same image button|![](/img/gui_1.png)|
|Display and adjust camera configuration|![](/img/gui_2.png)|
|Display and adjust parameters of the default material|![](/img/gui_3.png)|

### JSON scene file
-----------------------------
To accelerate develop, testing, and scene set-up, I defined json-basde scene files as well as implemented a json reader based on [Json File Reader](https://github.com/nlohmann/json).
Here is a simple example of a scene with a camera, a Cube and a Light.
```
{
"resources path": "resources/",
"camera": {
"ref": [ 0, 2.5, 0 ],
"position": [ 0, 5.5, -30 ],
"fovy": 19.5,
"resolution": [ 680, 680 ],
"interation": 1000,
"depth": 8
},
"materials": [
{
"name": "WhiteLight",
"albedo": [ 1, 1, 1 ],
"emittance": 40.0
},
{
"name": "MatteWhite",
"type": "DiffuseReflection",
"albedo": [ 0.85, 0.81, 0.78 ]
}
],
"geomerties": [
{
"type": "obj",
"path": "meshes/plane.obj",
"name": "light",
"material": "WhiteLight",
"translation": [ 0, 7.45, 0 ],
"rotation": [ 0, 0, 0 ],
"scale": [ 1.5, 1, 1.5 ]
},
{
"type": "obj",
"path": "meshes/cube.obj",
"name": "Cube",
"material": "MatteWhite",
"translation": [ -2, -1, 0.75 ],
"rotation": [ 0, -17.5, 0 ],
"scale": [ 1.5, 1.5, 1.5 ]
}
]
}
```
This is an example of [CornellBox scene](/resources/scenes/cornellBox.json). You can find more samples in [Resources](/resources/scenes/)
<p align = "center">
<img src = "/img/cornellBox.png"/>
</p>

**Defualt material will be applied to a geomertiy if not explicit indicate its material in both scene file and obj file**

### Stochastic Sampled Anti-aliasing
-----------------------------------
|Without Anti-aliasing|With Anti-aliasing|
|:---------:|:---------:|
|![](img/cornellBox_without_AA_detial.png)|![](img/cornellBox_with_AA_detial.png)|
|![](img/cornellBox_without_AA.png)|![](img/cornellBox_with_AA.png)|

### Bounding Volume Hierarchy
----------------------------------
If we want to make the scene interesting, polygons with more triangles are required, which means more ray-scene intersection testing time! To optimize this, I implemented Bounding Volume Herearchy (BVH) in the project to accelerate the intersection testing process.

I test the BVH with a [Astartes of Steppe Hawks chapter Free 3D model](https://www.cgtrader.com/free-3d-models/character/sci-fi-character/astartes-of-steppe-hawks-chapter) *338869 triangles*

*2560x1369 resolution with only 1 ray-intersection test per pixel per frame*
![](/img/astartes_normal.png)
||without BVH| Middle Split BVH| SAH BVH|
|------|------|------|------|
|fps|0.1|130.27|134.7|

### Tone mapping
-----------------------------
|Without tone mapping|With tone mapping|
|---------|---------|
|![](img/cornellBox_without_tm.png)|![](img/cornellBox_with_AA.png)|

In this project, I simply used $x = \frac{x}{1 + x}$. However, there are more interesting tone mapping to be tried.

### Mesh Loader(obj) and texture mapping
-----------------------------
Now, it is time to make the scene vivid! I implemented a mesh loader based on [TinyObjLoader](https://github.com/tinyobjloader/tinyobjloader) to load obj files with materials(albedo map, normal map, roughness map, and metallic map).
|Without normal mapping|With normal mapping|
|---------|---------|
|![](img/without_normal.png)|![](img/with_normal.png)|

Here are two image render with diffuse reflection material
|mario|astartes|
|---------|---------|
|![](img/mario_diffuse.png)|![](img/astartes_diffuse.png)|

### BSDFs
-----------------------------
To make the scene more fancy, I implement multiple BSDFS
<p align = "center">
<img src = "/img/demo_1.png"/>
</p>

|Diffuse Reflection|Specular Reflection|Specular Refraction|Microfacet Reflection|Microfacet Reflection(with metallic parameter)|
|------|-------|-------|------|------|
|![](/img/diffuse_ball.png)|![](/img/specular_reflect_ball.png)|![](/img/specular_refract_ball.png)|![](/img/microfacet_reflect_ball.png)|![](/img/microfacet_mix_ball.png)|

#### Subsurface Scattering
<p align = "center">
<img src = "/img/subsurface_cow.png"/>
</p>
I implemented a simple subsurface scattering by allowing rays to scatter randomly within the object, which requires large path depth(usually larger than 16) to obtain a relatively clear image.

#### BSDF with texture mapping
After applying texture mapping, we can have an impressive rendered Astartes!
![](/img/astertes.png)

### Physically-based depth-of-field
Finally, I implemented Physically-based depth-of-field to make photo-realistic image.
|CornellBox | Material Ball| Environment only|
|------|-------|------|
|![](/img/cornell_dof.png)|![](/img/ball_dof.png)|![](/img/env_dof.png)|

### Performance Analysis
-----------------------------
#### Compact terminated pathes
![](img/performance_chart_1.png)
- *[Astartes of Steppe Hawks chapter Free 3D model](https://www.cgtrader.com/free-3d-models/character/sci-fi-character/astartes-of-steppe-hawks-chapter) *338869 triangles*
- *1 ray-intersection test per pixel per frame*
- *Trace depth is 8*

As shown in this chart, compact terminated pathes are not always an optimization. When pixel count is small. This might because when the number of path is small, GPU computation resources are not fully utilized, compact path-segments will not accelerate GPU computation but introduce extra time for compacting.

Therefore, I set a threshold of pixel count to dynamic determine whether to compact terminated pathes.

#### Sort by materials
I tried this method, but it increased the frame time significantly, up to 150 ms/frame, even for a simple scene. I suppose the sorting is costly and morden GPU can group threads that executing same instructions without we explicitly do that.

#### First intersection cache
This is a common technique used in real-time ray tracing, which is based on the G-Buffer computed by rasterization. However, this is not a feasible optimization on path tracer since we need to stochastic sample each pixel to perform anti-aliasing and we have physically-based depth of field camera, which means the intersection point of each frame (or interation) are not fixed.

#### Try used shared memory as stack when traverse BVH
Considering the use of large number of registers in thread will limit the occupancy. I tried to used shared memeory performanced as `stack` when traverse the BVH. This won't have bank conflict when each thread within a warp use a `bank` as a `stack`. However, this method increased the frame time and the traverse slower.

I guess this might because large shared memory also limits the occupany, which is the even worse than using registers.

### Third Party Credit
-----------------------------
#### Third party Resources
- [Astartes of Steppe Hawks chapter Free 3D model](https://www.cgtrader.com/free-3d-models/character/sci-fi-character/astartes-of-steppe-hawks-chapter)
- [Rathaus Environment Map](https://polyhaven.com/a/rathaus)

#### Third Party Library
- [Json File Reader](https://github.com/nlohmann/json)
- [TinyObjLoader](https://github.com/tinyobjloader/tinyobjloader)
Loading