diff --git a/.gitignore b/.gitignore
index 89942d9e..ba0155ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,7 +23,8 @@ build
.LSOverride
# Icon must end with two \r
-Icon
+Icon
+
# Thumbnails
._*
@@ -558,3 +559,6 @@ xcuserdata
*.xccheckout
*.moved-aside
*.xcuserstate
+
+*.txt
+scenes*
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0e535f5d..5cac6222 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,7 @@ 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)
if(NOT DEFINED CMAKE_CUDA_STANDARD)
@@ -61,6 +62,14 @@ set(headers
src/sceneStructs.h
src/preview.h
src/utilities.h
+ src/Bounds3.hpp
+ src/BVH.h
+ src/material.h
+ src/tiny_obj_loader.hpp
+ src/lightSample.h
+ src/distribution1D.h
+ src/distribution2D.h
+ src/ImGui/imconfig.h
)
set(sources
@@ -69,11 +78,14 @@ set(sources
src/image.cpp
src/glslUtility.cpp
src/pathtrace.cu
- src/intersections.cu
- src/interactions.cu
src/scene.cpp
src/preview.cpp
src/utilities.cpp
+ src/BVH.cpp
+ src/material.cpp
+ src/tiny_obj_loader.cpp
+ src/distribution1D.cpp
+ src/distribution2D.cpp
)
set(imgui_headers
diff --git a/README.md b/README.md
index 110697ce..9ea2718a 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,87 @@ 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)
+* Zhiyi Zhou
+* Tested on: Windows 11, i9-13900H @ 2.6GHz 64GB, RTX4060 Laptop
-### (TODO: Your README)
+
+
+
-*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
+- OBJ & glTF Loading
+- BVH(MTBVH) Acceleration
+- Stochastic Sampled Anti-Aliasing
+- Physically-Based Materials
+- Texture Mapping & Normal Mapping
+- Environment Mapping
+- Multiple Importance Sampling of different kind of light(sphere, cube, mesh and environment light)
+### OBJ & glTF Loading
+The glTF (GL Transmission Format) file is a streamlined, efficient format for transmitting 3D models and scenes, designed specifically for real-time rendering applications such as 3D games, web platforms, and virtual reality. Developed by the Khronos Group, the same organization behind OpenGL and Vulkan, it is lightweight and optimized for performance. A glTF file can encompass an entire scene, including meshes, materials, animations, cameras, and lights. However, I focus on utilizing only its meshes and materials in my projects.
+
+
+
Avocado
+
+glTF file: [Avocado](https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/Avocado/glTF)
+
+### BVH(MTBVH) Acceleration
+[BVH](https://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies)
+[MTBVH](https://cs.uwaterloo.ca/~thachisu/tdf2015.pdf)
+
+Computing intersections is the most time consuming part in our path tracer.
+A BVH organizes a set of geometric objects, like triangles or meshes, into a hierarchy of nested bounding volumes, which allows for efficient spatial queries and reduces the computational cost of determining which objects are relevant in a given operation.
+
+
+
+ | with BVH |
+ without BVH |
+
+
+  |
+  |
+
+
+
+My computer struggles to traverse millions of triangles, but thanks to BVH, the speedup is significant.
+
+### Stochastic Sampled Anti-Aliasing
+
+
+
+ | with Anti-Aliasing |
+ without Anti-Aliasing |
+
+
+  |
+  |
+
+
+
+### Physically-Based Materials
+I implemented Microfacet material and metallic workflow in my path tracer.
+Here, the ball with high metallic and high roughness looks weird, this is because in microfacet model high roughness will cause energy loss.
+
+
+### Texture Mapping & Normal Mapping
+To improve the visual quality of the scene, texture mapping is crucial. Normal mapping can further enhance surface detail, adding greater realism.
+
+### Multiple Importance Sampling
+| Direct Light sample(20spp) | BSDF Sample (20spp) | MIS(20spp) |
+| :-----------------------: | :----------------------: | --------------------------- |
+|  | |  |
+
+| Direct Light sample(2000spp) | BSDF Sample (2000spp) | MIS(2000spp) |
+| :-----------------------: | :----------------------: | --------------------------- |
+|  | |  |
+
+
+## Third-party code
+1. [tinygltf](https://github.com/syoyo/tinygltf)
+2. [Tinyobjloader](https://github.com/tinyobjloader/tinyobjloader)
+
+## Reference
+
+1. [glTF™ 2.0 Specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#appendix-b-brdf-implementation).
+2. [Poly Haven](https://polyhaven.com/)
+3. [Gundam Mk-II](https://sketchfab.com/3d-models/gundam-rx-178-mk-ii-8d4bf8343fd346e4a18bde44fb129fd1)
\ No newline at end of file
diff --git a/cmake/CUDAComputesList.cmake b/cmake/CUDAComputesList.cmake
new file mode 100644
index 00000000..7ff7a99a
--- /dev/null
+++ b/cmake/CUDAComputesList.cmake
@@ -0,0 +1,102 @@
+## CUDA Compute detection code
+## Sourced from ArrayFire https://github.com/arrayfire/arrayfire/
+## Under BSD-3 Clause License https://github.com/arrayfire/arrayfire/blob/devel/LICENSE
+
+#Disables running cuda_compute_check.c when build windows using remote
+OPTION(CUDA_COMPUTE_DETECT "Run autodetection of CUDA Architecture" ON)
+MARK_AS_ADVANCED(CUDA_COMPUTE_DETECT)
+
+IF(CUDA_COMPUTE_DETECT AND NOT DEFINED COMPUTES_DETECTED_LIST)
+ #############################
+ #Sourced from:
+ #https://raw.githubusercontent.com/jwetzl/CudaLBFGS/master/CheckComputeCapability.cmake
+ #############################
+ # Check for GPUs present and their compute capability
+ # based on http://stackoverflow.com/questions/2285185/easiest-way-to-test-for-existence-of-cuda-capable-gpu-from-cmake/2297877#2297877 (Christopher Bruns)
+
+ IF(CUDA_FOUND)
+ MESSAGE(STATUS "${CMAKE_MODULE_PATH}/cuda_compute_capability.cpp")
+
+ TRY_RUN(RUN_RESULT_VAR COMPILE_RESULT_VAR
+ ${PROJECT_BINARY_DIR}
+ ${CMAKE_MODULE_PATH}/cuda_compute_capability.cpp
+ CMAKE_FLAGS
+ -DINCLUDE_DIRECTORIES:STRING=${CUDA_TOOLKIT_INCLUDE}
+ -DLINK_LIBRARIES:STRING=${CUDA_CUDART_LIBRARY}
+ COMPILE_OUTPUT_VARIABLE COMPILE_OUTPUT_VAR
+ RUN_OUTPUT_VARIABLE RUN_OUTPUT_VAR)
+
+ MESSAGE(STATUS "COMPILE_OUTPUT_VAR: ${COMPILE_OUTPUT_VAR}")
+ MESSAGE(STATUS "CUDA Compute Detection Output: ${RUN_OUTPUT_VAR}")
+ MESSAGE(STATUS "CUDA Compute Detection Return: ${RUN_RESULT_VAR}")
+
+ # COMPILE_RESULT_VAR is TRUE when compile succeeds
+ # Check Return Value of main() from RUN_RESULT_VAR
+ # RUN_RESULT_VAR is 0 when a GPU is found
+ # RUN_RESULT_VAR is 1 when errors occur
+
+ IF(COMPILE_RESULT_VAR AND RUN_RESULT_VAR EQUAL 0)
+ MESSAGE(STATUS "CUDA Compute Detection Worked")
+ # Convert output into a list of computes
+ STRING(REPLACE " " ";" COMPUTES_DETECTED_LIST ${RUN_OUTPUT_VAR})
+ SET(CUDA_HAVE_GPU TRUE CACHE BOOL "Whether CUDA-capable GPU is present")
+ ELSE()
+ MESSAGE(STATUS "CUDA Compute Detection Failed")
+ SET(CUDA_HAVE_GPU FALSE CACHE BOOL "Whether CUDA-capable GPU is present")
+ ENDIF()
+ ENDIF(CUDA_FOUND)
+ENDIF()
+
+IF( CUDA_COMPUTE_20
+ OR CUDA_COMPUTE_30
+ OR CUDA_COMPUTE_32
+ OR CUDA_COMPUTE_35
+ OR CUDA_COMPUTE_37
+ OR CUDA_COMPUTE_50
+ OR CUDA_COMPUTE_52
+ OR CUDA_COMPUTE_53
+ OR CUDA_COMPUTE_60
+ OR CUDA_COMPUTE_61
+ OR CUDA_COMPUTE_62
+ OR CUDA_COMPUTE_70
+ OR CUDA_COMPUTE_72
+ OR CUDA_COMPUTE_75
+ OR CUDA_COMPUTE_80
+ OR CUDA_COMPUTE_86
+ )
+ SET(FALLBACK OFF)
+ELSE()
+ SET(FALLBACK ON)
+ENDIF()
+
+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" "80")
+ MESSAGE(STATUS "No computes detected. Fall back to 30, 50, 60, 70, 80")
+ENDIF()
+
+LIST(LENGTH COMPUTES_DETECTED_LIST COMPUTES_LEN)
+MESSAGE(STATUS "Number of Computes Detected = ${COMPUTES_LEN}")
+
+FOREACH(COMPUTE_DETECTED ${COMPUTES_DETECTED_LIST})
+ SET(CUDA_COMPUTE_${COMPUTE_DETECTED} ON CACHE BOOL "" FORCE)
+ENDFOREACH()
+
+MACRO(SET_COMPUTE VERSION)
+ SET(CUDA_GENERATE_CODE_${VERSION} "-gencode arch=compute_${VERSION},code=sm_${VERSION}")
+ SET(CUDA_GENERATE_CODE ${CUDA_GENERATE_CODE} ${CUDA_GENERATE_CODE_${VERSION}})
+ LIST(APPEND COMPUTE_VERSIONS "${VERSION}")
+ ADD_DEFINITIONS(-DCUDA_COMPUTE_${VERSION})
+ MESSAGE(STATUS "Setting Compute ${VERSION} to ON")
+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 80 86)
+ OPTION(CUDA_COMPUTE_${VER} "CUDA Compute Capability ${VER}" OFF)
+ MARK_AS_ADVANCED(CUDA_COMPUTE_${VER})
+ IF(${CUDA_COMPUTE_${VER}})
+ SET_COMPUTE(${VER})
+ ENDIF()
+ENDFOREACH()
diff --git a/cmake/cuda_compute_capability.cpp b/cmake/cuda_compute_capability.cpp
new file mode 100644
index 00000000..d320f714
--- /dev/null
+++ b/cmake/cuda_compute_capability.cpp
@@ -0,0 +1,60 @@
+/*
+* Copyright (C) 2011 Florian Rathgeber, florian.rathgeber@gmail.com
+*
+* This code is licensed under the MIT License. See the FindCUDA.cmake script
+* for the text of the license.
+*
+* Based on code by Christopher Bruns published on Stack Overflow (CC-BY):
+* http://stackoverflow.com/questions/2285185
+*/
+
+#include
+#include
+#include
+#include
+
+int main() {
+ int deviceCount;
+ int gpuDeviceCount = 0;
+ struct cudaDeviceProp properties;
+
+ if (cudaGetDeviceCount(&deviceCount) != cudaSuccess)
+ {
+ printf("Couldn't get device count: %s\n", cudaGetErrorString(cudaGetLastError()));
+ return 1;
+ }
+
+ std::set computes;
+ typedef std::set::iterator iter;
+
+ // machines with no GPUs can still report one emulation device
+ for (int device = 0; device < deviceCount; ++device) {
+ int major = 9999, minor = 9999;
+ cudaGetDeviceProperties(&properties, device);
+ if (properties.major != 9999) { // 9999 means emulation only
+ ++gpuDeviceCount;
+ major = properties.major;
+ minor = properties.minor;
+ if ((major == 2 && minor == 1)) {
+ // There is no --arch compute_21 flag for nvcc, so force minor to 0
+ minor = 0;
+ }
+ computes.insert(10 * major + minor);
+ }
+ }
+ int i = 0;
+ for(iter it = computes.begin(); it != computes.end(); it++, i++) {
+ if(i > 0) {
+ printf(" ");
+ }
+ // IF CMAKE CAN NOT CAPTURE THE OUTPUT OF printf, USE fprintf INSTEAD
+ fprintf(stderr, "%d", *it);
+ // printf("%d", *it);
+ }
+ /* don't just return the number of gpus, because other runtime cuda
+ errors can also yield non-zero return values */
+ if (gpuDeviceCount <= 0 || computes.size() <= 0) {
+ return 1; // failure
+ }
+ return 0; // success
+}
diff --git a/external/include/gltf/tiny_gltf.h b/external/include/gltf/tiny_gltf.h
new file mode 100644
index 00000000..d80e3aac
--- /dev/null
+++ b/external/include/gltf/tiny_gltf.h
@@ -0,0 +1,8854 @@
+//
+// Header-only tiny glTF 2.0 loader and serializer.
+//
+//
+// The MIT License (MIT)
+//
+// Copyright (c) 2015 - Present Syoyo Fujita, Aurlien Chatelain and many
+// contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Version: - v2.9.*
+// See https://github.com/syoyo/tinygltf/releases for release history.
+//
+// Tiny glTF loader is using following third party libraries:
+//
+// - jsonhpp: C++ JSON library.
+// - base64: base64 decode/encode library.
+// - stb_image: Image loading library.
+//
+#ifndef TINY_GLTF_H_
+#define TINY_GLTF_H_
+
+#include
+#include
+#include // std::fabs
+#include
+#include
+#include
+#include
+#include
+#include