diff --git a/README.md b/README.md index f5d065b9..09cb78d6 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ CUDA Path Tracer * Tested on: Tested on: Windows 10, i3-10100F @ 3.6GHz 16GB, GeForce 1660 Super 6GB ### Features -![nice image or two showing off some features]() +![Stanford tryranosaurus](img/trex.png) +![DOF example](img/DOF.png) This is a GPU based forward path tracer, which renders scenes by calculating "camera rays" bouncing around the scene, simulating individual light rays. The renderer supports the following features: @@ -16,24 +17,31 @@ simulating individual light rays. The renderer supports the following features: - Multiple shader BSDFs, including refraction - Anti-aliasing - Depth of Field -- Minor optimizations +- Several optimizations - Adaptive Sampling* (not fully implemented) - Bloopers ### Arbitrary mesh loading -The renderer supports loading arbitrary meshes via .obj files. +The renderer supports loading arbitrary meshes via .obj files using +(`tinyobjloader`)[https://github.com/tinyobjloader/tinyobjloader]. -One issue discovered was that the triangle intersection detection function -initially used (`glm::intersectRayTriangle()`) does not compute intersections -with the "back" of faces. This caused problems for open meshes like the Newell Teapot -or for meshes assigned a refraction shader, as can be seen here: -![newell teapot hole image]() -![incomplete refraction image]() A bounding box is calculated at load time and used to optimize ray intersection detection. The bounding box is a mesh itself, consisting of tris. Each ray in the scene is initially tested for intersection with these tris, and only if an intersection is found will the ray be checked against the mesh's tris. +One issue discovered was that the triangle intersection detection function +initially used (`glm::intersectRayTriangle()`) does not compute intersections +with the "back" of faces. This caused problems for open meshes like the Newell Teapot +or for meshes assigned a refraction shader, as can be seen here: +![newell teapot hole image](img/back_face_cull_issue.png) +Also somewhat visible through the noise is a secondary effect of this back face +issue: collisions with the bounding box are not detected from within the +bounding box. Notice the sharp lines on the floor cutting off the diffuse +bounce close to the teapot. This is from rays on the floor near the teapot +casting outward and missing the teapot bounding box, and therefore not +checking for collisions with any of the teapots actual tris. + Performance impacts: - no spatial optimizations are made (other than the bounding box), so each ray that hits the bounding box is checked against every triangle in the mesh. @@ -48,16 +56,16 @@ inherit whatever memory value the normals were initialized to. BSDFs are implemented to allow for pure diffuse objects, objects with diffuse and reflections, as well as objects with both reflection and refraction. The Fresnel effect is calculated using Schlick's approximation -![image showing off different materials]() Since physically correct models do not always provide the preferred result, the Fresnel effect is tuneable via a user parameter. Note this is separate from the index of refraction (also tuneable), this is an additional parameter which controls the power used in Schlick's approximation. -![image showing different Fresnel powers]() - -Performance impacts: -- TODO: compare scene performance with/without some shader types +![Fresnel power comparison](img/fresnel_comparison.png) +The sphere on the right has a Fresnel power of 1, which dramatically changes +the reflect/refract ratio in favor of reflection. The sphere in the middle has +a Fresnel power of 3, which is only a subltle change from the (standard) +Fresnel power of 5 on the rightmost sphere. Known limitations: - objects with refractions are assumed to have reflection. An object can be reflective without @@ -65,8 +73,10 @@ refraction, but not vice-versa. ### Anti-aliasing anti-aliasing was accomplished by jittering the origin of camera rays for the initial bounce. -![image without anti-aliasing]() -![image with anti-aliasing]() +![image without anti-aliasing](img/antialias_off.png) +![image with anti-aliasing](img/antialias_on.png) +The first image has no antialiasing and has jagged pixelated edges along +horizontal lines. The second image has cleaner lines with no notable "jaggies". Performance impacts: - An unnoticeable impact to the time it takes each pixel to converge as a result of adding some small randomness. @@ -76,7 +86,11 @@ slightly varied camera ray origins each iteration. ### Depth of Field Depth of field can optionally be simulated, with tuneable parameters for aperture size, lens radius, and focal distance. -![image showing off depth of field]() +![DOF example](img/DOFOFF.png) +![DOF example](img/DOF.png) +The first image shows a scene with no simulated depth of field. The second +image has depth of field turned on, simulating the blur according to distance +in the same way a physical camera lens would. Performance impacts: - Using DOF requires a greater number of iterations to produce a clean image. The blur is a result @@ -84,7 +98,7 @@ of a stochastic process, and as a result the greater the blur the larger the var Known limitations: - This can not be combined with the "first bounce cache" optimization as it depends on slightly varied camera rays each iteration. -### Minor optimizations +### Optimizations - first bounce cache An option is provided to cache the first bounce of each camera ray from iteration 1, and use that cache for each subsequent iteration (until the camera is moved, generating a new iteration 1 and a new cache). @@ -94,13 +108,25 @@ different code paths as a result of conditionals), rays can optionally be sorted by their material id. This manimizes the number of warps with different materials, which may take different amounts of time as a result of calculated differing BSDFs. -- cull dead bounces +- use stream compaction to cull dead bounces Bounces that do not hit an object (i.e. which go off into space) are culled every iteration. +The following data was gathered from a single test scene using multiple +shaders, across all available BRDFS. All renders were run to 100 iterations at +a resolution of 720x480. Here is the test scene at 5000 iterations: +![test scene full render](img/test_scene.png) + +![optimization comparison](img/optimization_comparison.png) Performance impacts: -- first bounce cache provides a noticeable improvement (TODO add a metric for this) -- Sorting materials is noteably worse. (TODO provide a metric) -- culling dead bounces (I think?) has a relatively neutral impact (TODO confirm and add metric) +- notably, all optimizations are slightly worse for a trace depth of 8, when +the benefit of these optimizations has not yet outweighed their overhead. +- first bounce cache provides a steady, but minor improvement. +- Stream compaction provides the most dramatic improvement, even in a scene +that is mostly filled by collideable objects. +- sorting materials provides a notable decrease in render times which increases +slightly as the trace depth increases. +- All optimizations provide a performance increase of approximately 2x! + Known limitations: - As noted above, first bounce cache cannot be combined with DOF or anti-aliasing. ### Adaptive Sampling* (incomplete) @@ -136,3 +162,12 @@ of paths when calling some relevant function. This has not been fixed in time. ![with]() ![explanations]() +### Notable Sources +- As noted above, +(`tinyobjloader`)[https://github.com/tinyobjloader/tinyobjloader] was used for +mesh loading. +- As noted in the comments, Stack Exchange and Stack overflow +provided the math for two vector manipulation methods +- Matt Pharr & Grep Humphreys Physically Based Rendering Texbook provided useful context + + diff --git a/img/DOF.png b/img/DOF.png new file mode 100644 index 00000000..6e8520b2 Binary files /dev/null and b/img/DOF.png differ diff --git a/img/DOFOFF.png b/img/DOFOFF.png new file mode 100644 index 00000000..a38a4684 Binary files /dev/null and b/img/DOFOFF.png differ diff --git a/img/adaptiveSampleBug.png b/img/adaptiveSampleBug.png new file mode 100644 index 00000000..6061f1e6 Binary files /dev/null and b/img/adaptiveSampleBug.png differ diff --git a/img/antialias_off.png b/img/antialias_off.png new file mode 100644 index 00000000..1b00d024 Binary files /dev/null and b/img/antialias_off.png differ diff --git a/img/antialias_on.png b/img/antialias_on.png new file mode 100644 index 00000000..f55f2c2e Binary files /dev/null and b/img/antialias_on.png differ diff --git a/img/back_face_cull_issue.png b/img/back_face_cull_issue.png new file mode 100644 index 00000000..522b6dc2 Binary files /dev/null and b/img/back_face_cull_issue.png differ diff --git a/img/fresnel_comparison.png b/img/fresnel_comparison.png new file mode 100644 index 00000000..3a3f8e68 Binary files /dev/null and b/img/fresnel_comparison.png differ diff --git a/img/heatmap.png b/img/heatmap.png new file mode 100644 index 00000000..5537c1d8 Binary files /dev/null and b/img/heatmap.png differ diff --git a/img/optimization_comparison.png b/img/optimization_comparison.png new file mode 100644 index 00000000..d50cf11f Binary files /dev/null and b/img/optimization_comparison.png differ diff --git a/img/refraction_mesh_blooper.png b/img/refraction_mesh_blooper.png new file mode 100644 index 00000000..0cb90161 Binary files /dev/null and b/img/refraction_mesh_blooper.png differ diff --git a/img/refraction_mesh_blooper2.png b/img/refraction_mesh_blooper2.png new file mode 100644 index 00000000..eab143de Binary files /dev/null and b/img/refraction_mesh_blooper2.png differ diff --git a/img/stream_compaction_blooper.png b/img/stream_compaction_blooper.png new file mode 100644 index 00000000..fc46a207 Binary files /dev/null and b/img/stream_compaction_blooper.png differ diff --git a/img/subpixel_sampling_blooper.png b/img/subpixel_sampling_blooper.png new file mode 100644 index 00000000..e69e3d31 Binary files /dev/null and b/img/subpixel_sampling_blooper.png differ diff --git a/img/test_scene.png b/img/test_scene.png new file mode 100644 index 00000000..1560bc1d Binary files /dev/null and b/img/test_scene.png differ diff --git a/img/trex.png b/img/trex.png new file mode 100644 index 00000000..69672f0a Binary files /dev/null and b/img/trex.png differ diff --git a/scenes/DOF.txt b/scenes/DOF.txt index 85e41e68..c572ee4f 100644 --- a/scenes/DOF.txt +++ b/scenes/DOF.txt @@ -165,7 +165,7 @@ EMITTANCE 0 // Camera CAMERA -RES 720 480 +RES 1080 720 FOVY 40 ITERATIONS 5000 DEPTH 8 diff --git a/scenes/cornell.txt b/scenes/cornell.txt index 6fbb8ad6..68ff0d6b 100644 --- a/scenes/cornell.txt +++ b/scenes/cornell.txt @@ -5,8 +5,8 @@ CACHE_BOUNCE 1 USE_DOF 0 ANTIALIAS 1 USE_BBOX 1 -ADAPTIVE_SAMPLING 1 -MIN_SAMPLES 2 +ADAPTIVE_SAMPLING 0 +MIN_SAMPLES 2000 PIX_VARIANCE 0.2 @@ -19,7 +19,7 @@ REFL 0 REFR 0 REFRIOR 0 FRESNELPOW 5 -EMITTANCE 5 +EMITTANCE 15 // Diffuse white MATERIAL 1 @@ -111,7 +111,7 @@ EMITTANCE 0 // Camera CAMERA -RES 800 800 +RES 800 600 FOVY 45 ITERATIONS 5000 DEPTH 8 @@ -119,21 +119,12 @@ FILE cornell FOCALDIST 8 APERTURE 0.5 LENSRAD 1 -EYE 0.0 5 10.5 -LOOKAT 0 5 0 +EYE 0.0 9 6 +LOOKAT 0 5 -5.5 UP 0 1 0 - -// Ceiling light -OBJECT 0 -cube -material 0 -TRANS 0 10 0 -ROTAT 0 0 0 -SCALE 3 .3 3 - // Floor -OBJECT 1 +OBJECT 0 cube material 1 TRANS 0 0 0 @@ -141,7 +132,7 @@ ROTAT 0 0 0 SCALE 10 .01 10 // Ceiling -OBJECT 2 +OBJECT 1 cube material 1 TRANS 0 10 0 @@ -149,7 +140,7 @@ ROTAT 0 0 90 SCALE .01 10 10 // Back wall -OBJECT 3 +OBJECT 2 cube material 5 TRANS 0 5 -5 @@ -157,7 +148,7 @@ ROTAT 0 90 0 SCALE .01 10 10 // Left wall -OBJECT 4 +OBJECT 3 cube material 2 TRANS -5 5 0 @@ -165,13 +156,61 @@ ROTAT 0 0 0 SCALE .01 10 10 // Right wall -OBJECT 5 +OBJECT 4 cube material 3 TRANS 5 5 0 ROTAT 0 0 0 SCALE .01 10 10 +// Floor light +OBJECT 5 +cube +material 0 +TRANS -3 0.05 2 +ROTAT 0 -25 0 +SCALE 3 .1 .1 + +// Floor light +OBJECT 6 +cube +material 0 +TRANS 3 0.05 2 +ROTAT 0 30 0 +SCALE 3 .1 .1 + +// Floor light +OBJECT 7 +cube +material 0 +TRANS 2 0.05 1 +ROTAT 0 -5 0 +SCALE 3 .1 .1 + +// Floor light +OBJECT 8 +cube +material 0 +TRANS -1 0.05 1 +ROTAT 0 10 0 +SCALE 3 .1 .1 + +// t-rex +OBJECT 9 +C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\tyraLoPoly.obj +material 7 +TRANS 0 0 -2 +ROTAT 0 90 0 +SCALE -2.25 2.25 2.25 + +// Sphere +OBJECT 10 +sphere +material 4 +TRANS 5 10 -5 +ROTAT 0 0 0 +SCALE 8 8 8 + //// bunny //OBJECT 6 //C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\bunnyLoPoly.obj @@ -179,14 +218,6 @@ SCALE .01 10 10 //TRANS 1 0 -2 //ROTAT 0 0 0 //SCALE 1 1 1 - -//// Sphere -//OBJECT 6 -//sphere -//material 4 -//TRANS -3 4 -2 -//ROTAT 0 0 0 -//SCALE 3 3 3 // //// platform //OBJECT 7 @@ -195,20 +226,20 @@ SCALE .01 10 10 //TRANS -3 1.25 -1 //ROTAT 0 0 0 //SCALE 3 2.5 7 - -//// teapot -//OBJECT 6 -//C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\teapotTris.obj -//material 7 -//TRANS 0 0 0 -//ROTAT 0 0 0 -//SCALE .5 .5 .5 - +// +////// teapot +////OBJECT 6 +////C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\teapotTris.obj +////material 7 +////TRANS 0 0 0 +////ROTAT 0 0 0 +////SCALE .5 .5 .5 +// //// glass Sphere //OBJECT 8 //sphere //material 6 -//TRANS 0 1.5 -2 +//TRANS 0 2 -2 //ROTAT 0 0 0 //SCALE 3 3 3 // @@ -259,19 +290,3 @@ SCALE .01 10 10 //TRANS 0 8 0 //ROTAT 0 0 45 //SCALE 3 .1 3 - -//// Oren-Nayar Sphere -//OBJECT 9 -//sphere -//material 6 -//TRANS 3 4 -2 -//ROTAT 0 0 0 -//SCALE 3 3 3 -// -//// Floor light -//OBJECT 10 -//cube -//material 0 -//TRANS 0 0 0 -//ROTAT 0 0 0 -//SCALE 10 1 1 diff --git a/scenes/dinobox.txt b/scenes/dinobox.txt index bb727bf7..32f67712 100644 --- a/scenes/dinobox.txt +++ b/scenes/dinobox.txt @@ -97,27 +97,27 @@ REFRIOR 1 FRESNELPOW 5 EMITTANCE 0 -////// purple glass -//MATERIAL 8 -//RGB .98 .38 .98 -//SPECEX 0 -//SPECRGB .98 .98 .98 -//REF L 1 -//REFR 1 -//REFRIOR 1.5 -//FRESNELPOW 2.5 -//EMITTANCE 0 -// -//// dark floor -//MATERIAL 9 -//RGB .5 .5 .5 -//SPECEX 0 -//SPECRGB 0 0 0 -//REFL 0 -//REFR 0 -//REFRIOR 1 -//FRESNELPOW 5 -//EMITTANCE 0 +// dark floor +MATERIAL 8 +RGB .5 .5 .5 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 1 +FRESNELPOW 5 +EMITTANCE 0 + +// dull light +MATERIAL 9 +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +FRESNELPOW 5 +EMITTANCE 5 // Camera CAMERA @@ -136,7 +136,7 @@ UP 0 1 0 // Floor OBJECT 0 cube -material 9 +material 8 TRANS 0 0 0 ROTAT 0 0 0 SCALE 10 .01 10 @@ -221,90 +221,10 @@ TRANS 5 10 -5 ROTAT 0 0 0 SCALE 8 8 8 -//// Sphere -//OBJECT 11 -//sphere -//material 0 -//TRANS 3 8 10.5 -//ROTAT 0 0 0 -//SCALE 1 1 1 - -//// bunny -//OBJECT 6 -//C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\bunnyLoPoly.obj -//material 8 -//TRANS 1 0 -2 -//ROTAT 0 0 0 -//SCALE 1 1 1 -// -//// platform -//OBJECT 7 -//cube -//material 5 -//TRANS -3 1.25 -1 -//ROTAT 0 0 0 -//SCALE 3 2.5 7 -// -////// teapot -////OBJECT 6 -////C:\Users\elser\class\gpu\pathTracer\Project3-CUDA-Path-Tracer\scenes\teapotTris.obj -////material 7 -////TRANS 0 0 0 -////ROTAT 0 0 0 -////SCALE .5 .5 .5 -// -//// glass Sphere -//OBJECT 8 -//sphere -//material 6 -//TRANS 0 2 -2 -//ROTAT 0 0 0 -//SCALE 3 3 3 -// -//// grid line -//OBJECT 8 -//cube -//material 7 -//TRANS 0 1 -4.5 -//ROTAT 0 0 0 -//SCALE 10 1 0.1 -// -//// grid line -//OBJECT 9 -//cube -//material 7 -//TRANS 0 3 -4.5 -//ROTAT 0 0 0 -//SCALE 10 1 0.1 -// -//// grid line -//OBJECT 10 -//cube -//material 7 -//TRANS 0 5 -4.5 -//ROTAT 0 0 0 -//SCALE 10 1 0.1 -// -//// grid line -//OBJECT 11 -//cube -//material 7 -//TRANS 0 7 -4.5 -//ROTAT 0 0 0 -//SCALE 10 1 0.1 -// -//// grid line -//OBJECT 12 -//cube -//material 7 -//TRANS 0 5 -4.5 -//ROTAT 0 0 0 -//SCALE 1 10 0.1 -// -//// mirror cube -//OBJECT 13 -//cube -//material 4 -//TRANS 0 8 0 -//ROTAT 0 0 45 -//SCALE 3 .1 3 +// Spot light +OBJECT 11 +cube +material 0 +TRANS 0 7 9 +ROTAT 0 0 0 +SCALE .5 5 .1 diff --git a/scenes/refract.txt b/scenes/refract.txt new file mode 100644 index 00000000..7179f8a8 --- /dev/null +++ b/scenes/refract.txt @@ -0,0 +1,214 @@ +// Scene settings +SETTINGS +SORT_MATERIALS 0 +CACHE_BOUNCE 1 +USE_DOF 0 +ANTIALIAS 0 +USE_BBOX 1 +ADAPTIVE_SAMPLING 0 +MIN_SAMPLES 2000 +PIX_VARIANCE 0.2 + + +// Emissive material (light) +MATERIAL 0 +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +FRESNELPOW 5 +EMITTANCE 20 + +// floor +MATERIAL 1 +RGB .98 .98 .98 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +FRESNELPOW 5 +EMITTANCE 0 + +// Grid +MATERIAL 2 +RGB .8 .2 .8 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 1 +FRESNELPOW 5 +EMITTANCE 0 + +// Glass 1 +MATERIAL 3 +RGB .98 .98 .98 +SPECEX 0 +SPECRGB .98 .98 .98 +REFL 1 +REFR 1 +REFRIOR 1.5 +FRESNELPOW 1 +EMITTANCE 0 + +// Glass 2 +MATERIAL 4 +RGB .98 .98 .98 +SPECEX 0 +SPECRGB .98 .98 .98 +REFL 1 +REFR 1 +REFRIOR 1.5 +FRESNELPOW 2.5 +EMITTANCE 0 + +// Glass 3 +MATERIAL 5 +RGB .98 .98 .98 +SPECEX 0 +SPECRGB .98 .98 .98 +REFL 1 +REFR 1 +REFRIOR 1.5 +FRESNELPOW 5 +EMITTANCE 0 + +// purple glass +MATERIAL 4 +RGB .8 .2 .8 +SPECEX 0 +SPECRGB .98 .98 .98 +REF L 1 +REFR 1 +REFRIOR 1.5 +FRESNELPOW 2.5 +EMITTANCE 0 + +// Camera +CAMERA +RES 1080 420 +FOVY 10 +ITERATIONS 5000 +DEPTH 16 +FILE cornell +FOCALDIST 8 +APERTURE 0.5 +LENSRAD 1 +EYE 0.0 4 30 +LOOKAT 0 4 0 +UP 0 1 0 + +// Floor +OBJECT 0 +cube +material 1 +TRANS 0 0 10 +ROTAT 0 0 0 +SCALE 50 .01 30 + +// Light +OBJECT 1 +cube +material 0 +TRANS 0 9.5 4 +ROTAT 30 0 0 +SCALE 40 .1 1 + +// grid line +OBJECT 2 +cube +material 2 +TRANS 0 1 -5.5 +ROTAT 0 0 0 +SCALE 40 1 0.1 + +// grid line +OBJECT 3 +cube +material 2 +TRANS 0 3 -5.5 +ROTAT 0 0 0 +SCALE 40 1 0.1 + +// grid line +OBJECT 4 +cube +material 2 +TRANS 0 5 -5.5 +ROTAT 0 0 0 +SCALE 40 1 0.1 + +// grid line +OBJECT 5 +cube +material 2 +TRANS 0 7 -5.5 +ROTAT 0 0 0 +SCALE 40 1 0.1 + +// grid line +OBJECT 6 +cube +material 2 +TRANS 0 9 -5.5 +ROTAT 0 0 0 +SCALE 40 1 0.1 + +// vert grid line +OBJECT 7 +cube +material 2 +TRANS 0 5 -5.5 +ROTAT 0 0 0 +SCALE 1 10 0.1 + +// vert grid line +OBJECT 8 +cube +material 2 +TRANS -10 5 -5.5 +ROTAT 0 0 0 +SCALE 1 10 0.1 + +// vert grid line +OBJECT 9 +cube +material 2 +TRANS 10 5 -5.5 +ROTAT 0 0 0 +SCALE 1 10 0.1 + +// Sphere +OBJECT 10 +sphere +material 3 +TRANS -9 4 -1 +ROTAT 0 0 0 +SCALE 8 8 8 + +// Sphere +OBJECT 11 +sphere +material 4 +TRANS 0 4 -1 +ROTAT 0 0 0 +SCALE 8 8 8 + +// Sphere +OBJECT 12 +sphere +material 5 +TRANS 9 4 -1 +ROTAT 0 0 0 +SCALE 8 8 8 + +// Floor +OBJECT 13 +cube +material 1 +TRANS 0 9.5 10 +ROTAT 0 0 0 +SCALE 50 .01 30