diff --git a/README.md b/README.md
index f044c82..1b8f5b0 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,105 @@ 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)
+* Xiaoxiao Zou
+ * [LinkedIn](https://www.linkedin.com/in/xiaoxiao-zou-23482a1b9/)
+* Tested on: Windows 11, AMD Ryzen 9 7940HS @ 4.00 GHz, RTX 4060 Laptop
-### (TODO: Your README)
+Implement Edge avoiding A-Trous wavelet transform and Edge avoiding Guassian filtering
-*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.
+### Performance & Analysis
+
+
+ | SPP at original image/noisy image |
+ original images |
+ noisy image at lower spp |
+ denoised image |
+
+
+ | 2000spp/204 spp |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ | 3500spp/504 spp |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ | 5000spp/1140 spp |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+Denoising will give an "acceptably smooth" result at lower iteration as shown above, however, the image also get somehow blurred out due to the denoising filter.
+
+#### Denoising Runtime - filter size, resolution
+
+
+
+
+Denoising will add more time to the renders. For A-Trous, it usually slow down the renderer about 10-20FPS. For Guassian, it slower the renderer a lot especially when the filter size is large. Larger filter size will genuinely add more time to the renders. For A-Trous, it adds slightly more time since number of levels need to compute did not increase much as the filter size goes larger and larger. However, for guassian, FPS get a huge markdown due to increasing size of kernel. For resolution, smaller resolution will give better runtime for both unfiltered and denoised image. Denoising will be a good technique for smaller resolution since the image will be blurry anyway for small image, this gives a better approximation for image.
+
+#### Denoising Visual effect - Filter size, material type, etc.
+
+Denoising visual effect does depends on filter size, however, the visual quality does not scale uniformly with filter size. For image that itself contains a lot of details, when filter size is large, it will lose the smaller details as the filter size get larger. The visual quality scale with image only if it does not exceed the threshold that it will starts to blur out the details. Here are images with filter size 10,20,40,80. Note the details of teapot lower bottom with light reflection starts to fade out when filter size is large.
+
+
+
+Denoising filter gives good result when there is huge change in color contrast or object contrast, however, for objects that is smooth and simple color shaded, it will genuinely lose details for small shading in the geometry. For materials such as metallic or glass, it genuinely gives better result. For materials such as diffuse, sometimes, it will lose the details. Same scene as last section but change the material, the glass gives good approximation at around 500spp, whereas the lambert one gives good appromixation around 1000spp.
+
+
+

+

+
+
+For scene between cornell.txt and cornell_ceiling_light.txt, denoising filter gives better approximation for cornell_ceiling_light. In the ceiiling_light scene, there is larger ligt object, that allows the scene to be less noisy (larger possibility to hit the light source). Here are images at 21 spp for two scenes with same filter size.
+
+Cornell:
+
+
+

+

+
+
+Cornell_ceiling_light:
+
+
+

+

+
+
+Guassian filter-a Trous filter
+As I observed, I did not find any obvious visual difference between these two filters. Image shown with a-Trous and guassian.
+
+

+

+
\ No newline at end of file
diff --git a/img/CL_21_d.png b/img/CL_21_d.png
new file mode 100644
index 0000000..54c604c
Binary files /dev/null and b/img/CL_21_d.png differ
diff --git a/img/CL_21_n.png b/img/CL_21_n.png
new file mode 100644
index 0000000..4668571
Binary files /dev/null and b/img/CL_21_n.png differ
diff --git a/img/C_21_d.png b/img/C_21_d.png
new file mode 100644
index 0000000..9a38049
Binary files /dev/null and b/img/C_21_d.png differ
diff --git a/img/C_21_n.png b/img/C_21_n.png
new file mode 100644
index 0000000..58217e6
Binary files /dev/null and b/img/C_21_n.png differ
diff --git a/img/atrous.png b/img/atrous.png
new file mode 100644
index 0000000..6695650
Binary files /dev/null and b/img/atrous.png differ
diff --git a/img/cornell.png b/img/cornell.png
new file mode 100644
index 0000000..674a165
Binary files /dev/null and b/img/cornell.png differ
diff --git a/img/cornell_d.png b/img/cornell_d.png
new file mode 100644
index 0000000..dfe7353
Binary files /dev/null and b/img/cornell_d.png differ
diff --git a/img/cornell_n.png b/img/cornell_n.png
new file mode 100644
index 0000000..83531f0
Binary files /dev/null and b/img/cornell_n.png differ
diff --git a/img/filter_size.png b/img/filter_size.png
new file mode 100644
index 0000000..7586dc4
Binary files /dev/null and b/img/filter_size.png differ
diff --git a/img/guassian.png b/img/guassian.png
new file mode 100644
index 0000000..6695650
Binary files /dev/null and b/img/guassian.png differ
diff --git a/img/resolution.png b/img/resolution.png
new file mode 100644
index 0000000..9951319
Binary files /dev/null and b/img/resolution.png differ
diff --git a/img/teapot.png b/img/teapot.png
new file mode 100644
index 0000000..ef99094
Binary files /dev/null and b/img/teapot.png differ
diff --git a/img/teapot2.png b/img/teapot2.png
new file mode 100644
index 0000000..0308f55
Binary files /dev/null and b/img/teapot2.png differ
diff --git a/img/teapot2_d.png b/img/teapot2_d.png
new file mode 100644
index 0000000..099f0ac
Binary files /dev/null and b/img/teapot2_d.png differ
diff --git a/img/teapot2_n.png b/img/teapot2_n.png
new file mode 100644
index 0000000..35afac6
Binary files /dev/null and b/img/teapot2_n.png differ
diff --git a/img/teapot3_d_500.png b/img/teapot3_d_500.png
new file mode 100644
index 0000000..79efd4b
Binary files /dev/null and b/img/teapot3_d_500.png differ
diff --git a/img/teapot3_n_500.png b/img/teapot3_n_500.png
new file mode 100644
index 0000000..72f280c
Binary files /dev/null and b/img/teapot3_n_500.png differ
diff --git a/img/teapot_10_d.png b/img/teapot_10_d.png
new file mode 100644
index 0000000..734a286
Binary files /dev/null and b/img/teapot_10_d.png differ
diff --git a/img/teapot_20_d.png b/img/teapot_20_d.png
new file mode 100644
index 0000000..fa0ada0
Binary files /dev/null and b/img/teapot_20_d.png differ
diff --git a/img/teapot_40_d.png b/img/teapot_40_d.png
new file mode 100644
index 0000000..b317e5e
Binary files /dev/null and b/img/teapot_40_d.png differ
diff --git a/img/teapot_80_d.png b/img/teapot_80_d.png
new file mode 100644
index 0000000..a994e13
Binary files /dev/null and b/img/teapot_80_d.png differ
diff --git a/img/teapot_d.png b/img/teapot_d.png
new file mode 100644
index 0000000..174eb75
Binary files /dev/null and b/img/teapot_d.png differ
diff --git a/img/teapot_n.png b/img/teapot_n.png
new file mode 100644
index 0000000..ba110a8
Binary files /dev/null and b/img/teapot_n.png differ
diff --git a/mesh/bathroom/10-14-13-Texture-28.jpg b/mesh/bathroom/10-14-13-Texture-28.jpg
new file mode 100644
index 0000000..3c95eb7
Binary files /dev/null and b/mesh/bathroom/10-14-13-Texture-28.jpg differ
diff --git a/mesh/bathroom/2.jpg b/mesh/bathroom/2.jpg
new file mode 100644
index 0000000..dff4511
Binary files /dev/null and b/mesh/bathroom/2.jpg differ
diff --git a/mesh/bathroom/4839707-black-soil-texture.jpg b/mesh/bathroom/4839707-black-soil-texture.jpg
new file mode 100644
index 0000000..955296b
Binary files /dev/null and b/mesh/bathroom/4839707-black-soil-texture.jpg differ
diff --git a/mesh/bathroom/5696510-Closeup-of-seamless-white-marble-chips-wall-texture-Stock-Photo.jpg b/mesh/bathroom/5696510-Closeup-of-seamless-white-marble-chips-wall-texture-Stock-Photo.jpg
new file mode 100644
index 0000000..a995b5a
Binary files /dev/null and b/mesh/bathroom/5696510-Closeup-of-seamless-white-marble-chips-wall-texture-Stock-Photo.jpg differ
diff --git a/mesh/bathroom/Tileable marble floor tile texture (2) bump.jpg b/mesh/bathroom/Tileable marble floor tile texture (2) bump.jpg
new file mode 100644
index 0000000..854075a
Binary files /dev/null and b/mesh/bathroom/Tileable marble floor tile texture (2) bump.jpg differ
diff --git a/mesh/bathroom/Tileable marble floor tile texture (2).jpg b/mesh/bathroom/Tileable marble floor tile texture (2).jpg
new file mode 100644
index 0000000..55eef47
Binary files /dev/null and b/mesh/bathroom/Tileable marble floor tile texture (2).jpg differ
diff --git a/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk bump.jpg b/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk bump.jpg
new file mode 100644
index 0000000..13c244a
Binary files /dev/null and b/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk bump.jpg differ
diff --git a/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk.jpg b/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk.jpg
new file mode 100644
index 0000000..e2e04d9
Binary files /dev/null and b/mesh/bathroom/bathroom-tiles-texture-seamless-ygwkprdk.jpg differ
diff --git a/mesh/bathroom/bathroom.max b/mesh/bathroom/bathroom.max
new file mode 100644
index 0000000..e1642d3
Binary files /dev/null and b/mesh/bathroom/bathroom.max differ
diff --git a/mesh/bathroom/natural-spacious-house-with-stunning-nature-landscape-view.jpg b/mesh/bathroom/natural-spacious-house-with-stunning-nature-landscape-view.jpg
new file mode 100644
index 0000000..c2a1e61
Binary files /dev/null and b/mesh/bathroom/natural-spacious-house-with-stunning-nature-landscape-view.jpg differ
diff --git a/mesh/bathroom/q.jpg b/mesh/bathroom/q.jpg
new file mode 100644
index 0000000..b483d90
Binary files /dev/null and b/mesh/bathroom/q.jpg differ
diff --git a/mesh/bathroom/q.tga b/mesh/bathroom/q.tga
new file mode 100644
index 0000000..92f63a2
Binary files /dev/null and b/mesh/bathroom/q.tga differ
diff --git a/mesh/bathroom/towel bump.jpg b/mesh/bathroom/towel bump.jpg
new file mode 100644
index 0000000..86cf95d
Binary files /dev/null and b/mesh/bathroom/towel bump.jpg differ
diff --git a/mesh/bathroom/towel.jpg b/mesh/bathroom/towel.jpg
new file mode 100644
index 0000000..f150d8a
Binary files /dev/null and b/mesh/bathroom/towel.jpg differ
diff --git a/mesh/bathroom/vase_of_cat_memories_by_pie_is_why_we_live-d36nazw.jpg b/mesh/bathroom/vase_of_cat_memories_by_pie_is_why_we_live-d36nazw.jpg
new file mode 100644
index 0000000..08c06a5
Binary files /dev/null and b/mesh/bathroom/vase_of_cat_memories_by_pie_is_why_we_live-d36nazw.jpg differ
diff --git a/mesh/bathroom/white_wall bump.png b/mesh/bathroom/white_wall bump.png
new file mode 100644
index 0000000..9e3c171
Binary files /dev/null and b/mesh/bathroom/white_wall bump.png differ
diff --git a/mesh/bathroom/white_wall.png b/mesh/bathroom/white_wall.png
new file mode 100644
index 0000000..1b5cd82
Binary files /dev/null and b/mesh/bathroom/white_wall.png differ
diff --git a/mesh/bathroom/wood-texture bump.jpg b/mesh/bathroom/wood-texture bump.jpg
new file mode 100644
index 0000000..8c33e03
Binary files /dev/null and b/mesh/bathroom/wood-texture bump.jpg differ
diff --git a/mesh/bathroom/wood-texture.jpg b/mesh/bathroom/wood-texture.jpg
new file mode 100644
index 0000000..84c65d3
Binary files /dev/null and b/mesh/bathroom/wood-texture.jpg differ
diff --git a/mesh/cube.mtl b/mesh/cube.mtl
new file mode 100644
index 0000000..2820eee
--- /dev/null
+++ b/mesh/cube.mtl
@@ -0,0 +1,5 @@
+newmtl initialShadingGroup
+illum 4
+Kd 1.00 1.00 0.00
+Ka 0.00 0.00 0.00
+Ni 0.00
diff --git a/mesh/cube_diffuse.png b/mesh/cube_diffuse.png
new file mode 100644
index 0000000..15b95a6
Binary files /dev/null and b/mesh/cube_diffuse.png differ
diff --git a/mesh/cube_norm.mtl b/mesh/cube_norm.mtl
new file mode 100644
index 0000000..50cda27
--- /dev/null
+++ b/mesh/cube_norm.mtl
@@ -0,0 +1,9 @@
+newmtl blinn1SG
+illum 2
+Kd 0.00 0.00 0.00
+Ka 0.00 0.00 0.00
+Tr 0.00
+//map_Kd cube_diffuse.png
+//norm cube_norm.png
+Ni 1.00
+Ks 0.50 0.50 0.50
diff --git a/mesh/cube_norm.png b/mesh/cube_norm.png
new file mode 100644
index 0000000..1b76102
Binary files /dev/null and b/mesh/cube_norm.png differ
diff --git a/mesh/cube_text2.mtl b/mesh/cube_text2.mtl
new file mode 100644
index 0000000..e3f1d01
--- /dev/null
+++ b/mesh/cube_text2.mtl
@@ -0,0 +1,7 @@
+newmtl lambert2SG
+illum 2
+Kd 1.00 1.00 1.00
+Ka 0.00 0.00 0.00
+Tr 0.0
+map_Kd cube_text2.png
+Ni 1.00
diff --git a/mesh/cube_text2.png b/mesh/cube_text2.png
new file mode 100644
index 0000000..029a8a7
Binary files /dev/null and b/mesh/cube_text2.png differ
diff --git a/mesh/default.jpg b/mesh/default.jpg
new file mode 100644
index 0000000..d3bc65a
Binary files /dev/null and b/mesh/default.jpg differ
diff --git a/mesh/sponza/material.mtl b/mesh/sponza/material.mtl
new file mode 100644
index 0000000..4df3214
--- /dev/null
+++ b/mesh/sponza/material.mtl
@@ -0,0 +1,282 @@
+# Aspose.3D Wavefront OBJ Exporter
+# Copyright 2004-2023 Aspose Pty Ltd.
+# File created: 10/07/2023 10:16:57
+
+newmtl m24vase_round
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/vase_hanging_ddn.tga.png
+
+newmtl m23vase_hanging
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/vase_hanging_ddn.tga.png
+
+newmtl m22vase
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.06972357630729675 0.06972357630729675 0.06972357630729675
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/vase_ddn.dds.tga.png
+
+newmtl m21roof
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0 0 0
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_roof_ddn.tga.png
+
+newmtl m20leaf
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_thorn_ddn.tga.png
+
+newmtl m19floor
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+//norm sponza/textures/sponza_floor_a_ddn.tga.png
+
+newmtl m18flagpole
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_flagpole_ddn.tga.png
+
+newmtl m17fabric_g
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.02500000037252903 0.02500000037252903 0.02500000037252903
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_curtain_blue_diff.tga.png
+norm sponza/textures/sponza_curtain_ddn.tga.png
+
+newmtl m16fabric_f
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.02500000037252903 0.02500000037252903 0.02500000037252903
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_curtain_green_diff.tga.png
+norm sponza/textures/sponza_curtain_ddn.tga.png
+
+newmtl m15fabric_e
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_fabric_green_diff.tga.png
+norm sponza/textures/sponza_fabric_ddn.tga.png
+
+newmtl m14fabric_d
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_fabric_blue_diff.tga.png
+norm sponza/textures/sponza_fabric_ddn.tga.png
+
+newmtl m13fabric_c
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.02500000037252903 0.02500000037252903 0.02500000037252903
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_curtain_diff.tga.png
+norm sponza/textures/sponza_curtain_ddn.tga.png
+
+newmtl m12fabric_a
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+map_Kd sponza/textures/sponza_fabric_diff.tga.png
+norm sponza/textures/sponza_fabric_ddn.tga.png
+
+newmtl m11details
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_details_ddn.tga.png
+
+newmtl m10column_c
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_column_c_ddn.tga.png
+
+newmtl m9column_b
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_column_b_ddn.tga.png
+
+newmtl m8column_a
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_column_a_ddn.tga.png
+
+newmtl m7chain
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0 0 0
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/chain_texture_ddn.tga.png
+
+newmtl m6ceiling
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_ceiling_a_ddn.tga.png
+
+newmtl m5bricks
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/spnza_bricks_a_ddn.tga.png
+
+newmtl m4arch
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/sponza_arch_ddn.tga.png
+
+newmtl m3Material__57
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.25 0.25 0.25
+Ns 7.45098018646240232
+d 1
+Tr 0
+
+newmtl m2Material__47
+Ka 0 0 0
+Kd 0.73500001430511472 0.73500001430511472 0.73500001430511472
+Ke 0 0 0
+illum 2
+Ks 0 0 0
+Ns 7.45098018646240232
+d 1
+Tr 0
+
+newmtl m1Material__298
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.06975000351667404 0.06972357630729675 0.06972357630729675
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/background_ddn.tga.png
+
+newmtl m0Material__25
+Ka 0 0 0
+Kd 1 1 1
+Ke 0 0 0
+illum 2
+Ks 0.02107499912381172 0.02107021585106849 0.02107021585106849
+Ns 7.45098018646240232
+d 1
+Tr 0
+norm sponza/textures/lion_ddn.tga.png
diff --git a/mesh/sponza/textures/background_ddn.tga.png b/mesh/sponza/textures/background_ddn.tga.png
new file mode 100644
index 0000000..c5cfe5a
Binary files /dev/null and b/mesh/sponza/textures/background_ddn.tga.png differ
diff --git a/mesh/sponza/textures/chain_texture_ddn.tga.png b/mesh/sponza/textures/chain_texture_ddn.tga.png
new file mode 100644
index 0000000..aa564f1
Binary files /dev/null and b/mesh/sponza/textures/chain_texture_ddn.tga.png differ
diff --git a/mesh/sponza/textures/lion_ddn.tga.png b/mesh/sponza/textures/lion_ddn.tga.png
new file mode 100644
index 0000000..5e1d12a
Binary files /dev/null and b/mesh/sponza/textures/lion_ddn.tga.png differ
diff --git a/mesh/sponza/textures/spnza_bricks_a_ddn.tga.png b/mesh/sponza/textures/spnza_bricks_a_ddn.tga.png
new file mode 100644
index 0000000..ea6081b
Binary files /dev/null and b/mesh/sponza/textures/spnza_bricks_a_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_arch_ddn.tga.png b/mesh/sponza/textures/sponza_arch_ddn.tga.png
new file mode 100644
index 0000000..edd5fd5
Binary files /dev/null and b/mesh/sponza/textures/sponza_arch_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_ceiling_a_ddn.tga.png b/mesh/sponza/textures/sponza_ceiling_a_ddn.tga.png
new file mode 100644
index 0000000..ec7609b
Binary files /dev/null and b/mesh/sponza/textures/sponza_ceiling_a_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_column_a_ddn.tga.png b/mesh/sponza/textures/sponza_column_a_ddn.tga.png
new file mode 100644
index 0000000..8814d8a
Binary files /dev/null and b/mesh/sponza/textures/sponza_column_a_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_column_b_ddn.tga.png b/mesh/sponza/textures/sponza_column_b_ddn.tga.png
new file mode 100644
index 0000000..74d57b1
Binary files /dev/null and b/mesh/sponza/textures/sponza_column_b_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_column_c_ddn.tga.png b/mesh/sponza/textures/sponza_column_c_ddn.tga.png
new file mode 100644
index 0000000..a322343
Binary files /dev/null and b/mesh/sponza/textures/sponza_column_c_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_curtain_blue_diff.tga.png b/mesh/sponza/textures/sponza_curtain_blue_diff.tga.png
new file mode 100644
index 0000000..87094e3
Binary files /dev/null and b/mesh/sponza/textures/sponza_curtain_blue_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_curtain_ddn.tga.png b/mesh/sponza/textures/sponza_curtain_ddn.tga.png
new file mode 100644
index 0000000..c4dd457
Binary files /dev/null and b/mesh/sponza/textures/sponza_curtain_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_curtain_diff.tga.png b/mesh/sponza/textures/sponza_curtain_diff.tga.png
new file mode 100644
index 0000000..2832343
Binary files /dev/null and b/mesh/sponza/textures/sponza_curtain_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_curtain_green_diff.tga.png b/mesh/sponza/textures/sponza_curtain_green_diff.tga.png
new file mode 100644
index 0000000..51b2e92
Binary files /dev/null and b/mesh/sponza/textures/sponza_curtain_green_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_details_ddn.tga.png b/mesh/sponza/textures/sponza_details_ddn.tga.png
new file mode 100644
index 0000000..1fc5ac6
Binary files /dev/null and b/mesh/sponza/textures/sponza_details_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_fabric_blue_diff.tga.png b/mesh/sponza/textures/sponza_fabric_blue_diff.tga.png
new file mode 100644
index 0000000..22e0044
Binary files /dev/null and b/mesh/sponza/textures/sponza_fabric_blue_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_fabric_ddn.tga.png b/mesh/sponza/textures/sponza_fabric_ddn.tga.png
new file mode 100644
index 0000000..5dac033
Binary files /dev/null and b/mesh/sponza/textures/sponza_fabric_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_fabric_diff.tga.png b/mesh/sponza/textures/sponza_fabric_diff.tga.png
new file mode 100644
index 0000000..d28ab00
Binary files /dev/null and b/mesh/sponza/textures/sponza_fabric_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_fabric_green_diff.tga.png b/mesh/sponza/textures/sponza_fabric_green_diff.tga.png
new file mode 100644
index 0000000..3a510ab
Binary files /dev/null and b/mesh/sponza/textures/sponza_fabric_green_diff.tga.png differ
diff --git a/mesh/sponza/textures/sponza_flagpole_ddn.tga.png b/mesh/sponza/textures/sponza_flagpole_ddn.tga.png
new file mode 100644
index 0000000..a875d9c
Binary files /dev/null and b/mesh/sponza/textures/sponza_flagpole_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_floor_a_ddn.tga.png b/mesh/sponza/textures/sponza_floor_a_ddn.tga.png
new file mode 100644
index 0000000..6003d01
Binary files /dev/null and b/mesh/sponza/textures/sponza_floor_a_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_roof_ddn.tga.png b/mesh/sponza/textures/sponza_roof_ddn.tga.png
new file mode 100644
index 0000000..d27694e
Binary files /dev/null and b/mesh/sponza/textures/sponza_roof_ddn.tga.png differ
diff --git a/mesh/sponza/textures/sponza_thorn_ddn.tga.png b/mesh/sponza/textures/sponza_thorn_ddn.tga.png
new file mode 100644
index 0000000..330e995
Binary files /dev/null and b/mesh/sponza/textures/sponza_thorn_ddn.tga.png differ
diff --git a/mesh/sponza/textures/vase_ddn.dds.tga.png b/mesh/sponza/textures/vase_ddn.dds.tga.png
new file mode 100644
index 0000000..bb527d0
Binary files /dev/null and b/mesh/sponza/textures/vase_ddn.dds.tga.png differ
diff --git a/mesh/sponza/textures/vase_hanging_ddn.tga.png b/mesh/sponza/textures/vase_hanging_ddn.tga.png
new file mode 100644
index 0000000..bd81e8e
Binary files /dev/null and b/mesh/sponza/textures/vase_hanging_ddn.tga.png differ
diff --git a/mesh/sponza/textures/vase_plant_alpha.tga.png b/mesh/sponza/textures/vase_plant_alpha.tga.png
new file mode 100644
index 0000000..3dd5cf4
Binary files /dev/null and b/mesh/sponza/textures/vase_plant_alpha.tga.png differ
diff --git a/mesh/teapot_n_glass.mtl b/mesh/teapot_n_glass.mtl
new file mode 100644
index 0000000..89c2bbc
--- /dev/null
+++ b/mesh/teapot_n_glass.mtl
@@ -0,0 +1,10 @@
+# Blender MTL File: 'teapot_n_glass.blend'
+# Material Count: 1
+
+newmtl None
+Ns 0
+Ka 0.000000 0.000000 0.000000
+Kd 0.8 0.8 0.8
+Ks 0.8 0.8 0.8
+d 1
+illum 2
diff --git a/mesh/teapot_reduce.mtl b/mesh/teapot_reduce.mtl
new file mode 100644
index 0000000..469f838
--- /dev/null
+++ b/mesh/teapot_reduce.mtl
@@ -0,0 +1,9 @@
+newmtl teapot:default1
+illum 4
+Kd 1.00 1.00 1.00
+Ka 1.00 1.00 1.00
+Tf 1.00 1.00 1.00
+Ni 1.50
+Ks 0.20 0.20 0.20
+Ns 10.00
+
diff --git a/mesh/teapot_reduce_1.mtl b/mesh/teapot_reduce_1.mtl
new file mode 100644
index 0000000..e29a5db
--- /dev/null
+++ b/mesh/teapot_reduce_1.mtl
@@ -0,0 +1,9 @@
+newmtl teapot:default1
+illum 4
+Kd 0.00 0.00 0.00
+Ka 1.00 1.00 1.00
+Tf 1.00 1.00 1.00
+map_Kd default.jpg
+Ni 1.50
+Ks 0.20 0.20 0.20
+Ns 10.00
diff --git a/scenes/cornell_ceiling_light.txt b/scenes/cornell_ceiling_light.txt
index 15af5f1..07253de 100644
--- a/scenes/cornell_ceiling_light.txt
+++ b/scenes/cornell_ceiling_light.txt
@@ -52,7 +52,7 @@ EMITTANCE 0
CAMERA
RES 800 800
FOVY 45
-ITERATIONS 10
+ITERATIONS 1000
DEPTH 8
FILE cornell
EYE 0.0 5 10.5
diff --git a/scenes/cornell_teapot.txt b/scenes/cornell_teapot.txt
new file mode 100644
index 0000000..c548e82
--- /dev/null
+++ b/scenes/cornell_teapot.txt
@@ -0,0 +1,87 @@
+BACKGROUND_COLOR 0.0 0.0 0.0
+
+// Emissive material (light)
+MATERIAL 0
+RGB 1 1 1
+SPECEX 0
+SPECRGB 0 0 0
+REFL 0
+REFR 0
+REFRIOR 0
+EMITTANCE 10
+
+// Diffuse white
+MATERIAL 1
+RGB .98 .98 .98
+SPECEX 1.0
+SPECRGB .98 .98 .98
+REFL 0
+REFR 0
+REFRIOR 1.0
+EMITTANCE 0
+
+// Diffuse red
+MATERIAL 2
+RGB .85 .35 .35
+SPECEX 0
+SPECRGB 0 0 0
+REFL 0
+REFR 0
+REFRIOR 0
+EMITTANCE 0
+
+// Diffuse green
+MATERIAL 3
+RGB 1 1 .93
+SPECEX 0.5
+SPECRGB 1 1 .93
+REFL 0.0
+REFR 0.0
+REFRIOR 1.5
+EMITTANCE 0
+
+// Specular white
+MATERIAL 4
+RGB .98 .98 .98
+SPECEX 0.5
+SPECRGB .98 .98 .98
+REFL 0.1
+REFR 0.8
+REFRIOR 1.5
+EMITTANCE 0
+
+// Camera
+CAMERA
+RES 800 800
+FOVY 45
+ITERATIONS 5000
+DEPTH 10
+FILE cornell
+EYE 0.0 5 10.5
+LOOKAT 0 6 0
+UP 0 1 0
+
+// Ceiling light
+OBJECT 0
+cube
+material 0
+TRANS 0 20 0
+ROTAT 0 0 0
+SCALE 10 .3 10
+
+// Floor
+OBJECT 1
+cube
+material 1
+TRANS 0 0 0
+ROTAT 0 0 0
+SCALE 100 .01 100
+
+// Sphere
+OBJECT 2
+mesh
+./../mesh/teapot_n_glass.obj
+material 3
+TRANS 0 3.0 0
+ROTAT 0 0 0
+SCALE 1.5 1.5 1.5
\ No newline at end of file
diff --git a/src/image.cpp b/src/image.cpp
index 9405155..424c192 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -1,6 +1,7 @@
#include
#include
#include
+#include
#include "image.h"
@@ -10,6 +11,22 @@ image::image(int x, int y) :
pixels(new glm::vec3[x * y]) {
}
+image::image(const std::string &baseFilename){
+ int width, height, bpp;
+
+ uint8_t* rgb_image = stbi_load(baseFilename.c_str(), &width, &height, &bpp, 3);
+ pixels=new glm::vec3[width*height];
+ ySize=height;
+ xSize=width;
+ for(int i=0;i u01(0, 1);
- float up = sqrt(u01(rng)); // cos(theta)
+ float up = pow(u01(rng),exponent); // cos(theta)
float over = sqrt(1 - up * up); // sin(theta)
float around = u01(rng) * TWO_PI;
@@ -40,23 +41,304 @@ glm::vec3 calculateRandomDirectionInHemisphere(
+ sin(around) * over * perpendicularDirection2;
}
+__host__ __device__
+float reflectance(float cosine, float ref_idx) {
+ // Use Schlick's approximation for reflectance.
+ float r0 = (1.0f-ref_idx) / (1.0f+ref_idx);
+ r0 = r0*r0;
+ return r0 + (1.0f-r0)*pow((1.0f - cosine),5.0f);
+}
+
+__host__ __device__
+glm::vec3 refract(glm::vec3& uv, glm::vec3& n, float etai_over_etat) {
+ float cos_theta = glm::min(dot(-uv, n), 1.0f);
+ glm::vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n);
+ glm::vec3 r_out_parallel = -glm::sqrt(glm::abs(1.0f - glm::length2(r_out_perp))) * n;
+ return r_out_perp + r_out_parallel;
+}
+__host__ __device__
+void sampleLight(glm::vec3 &dist,Geom & light,
+ float & lightsize,thrust::default_random_engine &rng,float &pdf,glm::vec3& orig){
+ thrust::uniform_real_distribution u01(0, 1);
+ float r1=u01(rng);
+ float r2=u01(rng);
+ float r3=u01(rng);
+ glm::vec3 point;
+ if(light.type==TRIANGLE){
+ float u=r2*r3;
+ float v=r2*(1-r3);
+ point=(1.0f-u-v)*light.tri.vertices[0]+u*light.tri.vertices[1]+v*light.tri.vertices[2];
+ }else if(light.type==CUBE){
+ point=glm::vec3(r1-0.5f,r2-0.5f,r3-0.5f);
+ }else {
+ float theta=r1* TWO_PI;
+ float phi=r2* PI;
+ point=glm::vec3(glm::cos(theta)*glm::sin(phi),glm::cos(phi),glm::sin(theta)*glm::sin(phi))*0.5f;
+ }
+ dist=multiplyMV(light.transform, glm::vec4(point, 1.f));
+}
+__host__ __device__
+float computeG(glm::vec3 w,glm::vec3 normal,float expoenent){
+ float cos=glm::dot(w,normal);
+ float sin=glm::sqrt(1.0f-cos*cos);
+ float a=glm::sqrt(0.5f* expoenent +1)/(sin/cos);
+ if(a<1.6f){
+ return (3.535*a+2.181*a*a)/(1.0+2.276*a+2.577*a*a);
+ }else{
+ return 1.0f;
+ }
+}
+
+__host__ __device__
+void diffuseScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,thrust::default_random_engine &rng, Geom & light,
+ float & lightsize){
+ float cos=glm::dot(-glm::normalize(pathSegment.ray.direction), intersection.surfaceNormal);
+ thrust::uniform_real_distribution u01(0, 1);
+ float r2=u01(rng);
+ pathSegment.color *= materialColor;
+ pathSegment.remainingBounces--;
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+ /*if(r2<0.5f){
+ glm::vec3 dist;
+ float pdf;
+ sampleLight(dist,light,lightsize,rng,pdf,pathSegment.ray.origin);
+
+ pathSegment.ray.direction=glm::normalize(dist-pathSegment.ray.origin);
+ pathSegment.color*=glm::abs(glm::dot(pathSegment.ray.direction, intersection.surfaceNormal))/PI;
+ pathSegment.remainingBounces=1;
+ //float pdf=glm::length2(dist-pathSegment.ray.origin)/cos;
+ //pathSegment.color/=pdf;
+ }else{*/
+ pathSegment.ray.direction=glm::normalize(calculateRandomDirectionInHemisphere(intersection.surfaceNormal,rng,1.0f));
+ //}
+
+}
+
+__host__ __device__
+void refractScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,const float ior,thrust::default_random_engine &rng){
+ thrust::uniform_real_distribution u01(0, 1);
+ float refraction_ratio = intersection.outside ? (1.0f/ior):(ior);
+ float cos_theta = glm::min(glm::dot(-glm::normalize(pathSegment.ray.direction), intersection.surfaceNormal), 1.0f);
+ bool cannot_refract = ((glm::sqrt(1.0f - cos_theta * cos_theta)*refraction_ratio ) > 1.0f);
+
+ bool fresnel = reflectance(cos_theta, refraction_ratio) > u01(rng);
+ if (cannot_refract||fresnel){
+ //pathSegment.color *= glm::vec3(1.0f)-reflectance(cos_theta, refraction_ratio);
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+ pathSegment.ray.direction=glm::reflect(glm::normalize(pathSegment.ray.direction),intersection.surfaceNormal);
+ }
+ else{
+ //pathSegment.color *= glm::vec3(1.0f)-reflectance(cos_theta, refraction_ratio);
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t+0.0002f);
+ pathSegment.ray.direction =glm::refract(glm::normalize(pathSegment.ray.direction), intersection.surfaceNormal, refraction_ratio);
+
+ }
+ pathSegment.remainingBounces--;
+}
+
+__host__ __device__
+void specularScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,float exponent,thrust::default_random_engine &rng, Geom & light,
+ float & lightsize){
+ thrust::uniform_real_distribution u01(0, 1);
+ float r2=u01(rng);
+ float cos=glm::dot(-glm::normalize(pathSegment.ray.direction), intersection.surfaceNormal);
+ pathSegment.color *= materialColor;
+ pathSegment.remainingBounces--;
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+ /*if(r2<0.5f){
+ glm::vec3 dist;
+ float pdf;
+ sampleLight(dist,light,lightsize,rng,pdf,pathSegment.ray.origin);
+
+ pathSegment.ray.direction=glm::normalize(dist-pathSegment.ray.origin);
+ //pathSegment.color*=(exponent+1)*pow(glm::abs(glm::dot(pathSegment.ray.direction, intersection.surfaceNormal)),exponent)/TWO_PI;
+ pathSegment.remainingBounces=1;
+ }else{*/
+ glm::vec3 reflected=glm::reflect(pathSegment.ray.direction,intersection.surfaceNormal);
+ pathSegment.ray.direction = glm::normalize(calculateRandomDirectionInHemisphere(reflected,rng,exponent));
+ //}
+ //glass apperance at top
+ //bool fresnel = reflectance(cos_theta, refraction_ratio) > u01(rng);
+
+ if(dot(pathSegment.ray.direction,intersection.surfaceNormal)<0){
+ pathSegment.remainingBounces=0;
+ pathSegment.color=glm::vec3(0.0f);
+ return;
+ }
+
+}
+
+__host__ __device__
+void blinnScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,float exponent,thrust::default_random_engine &rng, Geom & light,
+ float & lightsize){
+
+ glm::vec3 h =glm::normalize(calculateRandomDirectionInHemisphere(intersection.surfaceNormal,rng,exponent));
+ glm::vec3 wo=glm::reflect(pathSegment.ray.direction,h);
+
+ glm::vec3 color = materialColor + ((float)pow(1.0f - glm::dot(h, wo), 5.0f)) * (glm::vec3(1.0f) - materialColor);
+ float bsdf=(exponent+2.0f)/(2.0f*(2.0f-pow(2.0f,-exponent/2.0f)));
+ float pdf= (exponent + 1.0f) /(4.0f*glm::dot(h,wo));
+ pathSegment.color *= materialColor;
+ //color*bsdf/pdf;
+ pathSegment.remainingBounces--;
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+ pathSegment.ray.direction=wo;
+
+ if(dot(pathSegment.ray.direction,intersection.surfaceNormal)<0){
+ pathSegment.remainingBounces=0;
+ pathSegment.color=glm::vec3(0.0f);
+ return;
+ }
+
+}
+
+__host__ __device__
+void blinnMicScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,float exponent,thrust::default_random_engine &rng, Geom & light,
+ float & lightsize){
+
+ glm::vec3 h =glm::normalize(calculateRandomDirectionInHemisphere(intersection.surfaceNormal,rng,exponent));
+ glm::vec3 wo=glm::reflect(pathSegment.ray.direction,h);
+
+ glm::vec3 color=materialColor+ ((float)pow(1.0f - glm::dot(h, wo), 5))*(glm::vec3(1.0f)-materialColor);
+ float D=(exponent+1.0f)/TWO_PI*pow(glm::dot(intersection.surfaceNormal,h),exponent);
+ float G=computeG(-glm::normalize(pathSegment.ray.direction),intersection.surfaceNormal,exponent)*computeG(wo,intersection.surfaceNormal,exponent);
+ float bsdf=D*G/(4*glm::dot(-glm::normalize(pathSegment.ray.direction),intersection.surfaceNormal));
+ float pdf=(exponent+1)*pow(glm::dot(intersection.surfaceNormal,h),exponent)/(4.0f*TWO_PI*glm::dot(h,wo));
+ pathSegment.color *= color*bsdf/pdf;
+ pathSegment.remainingBounces--;
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+
+ pathSegment.ray.direction=wo;
+
+ if(dot(pathSegment.ray.direction,intersection.surfaceNormal)<0){
+ pathSegment.remainingBounces=0;
+ pathSegment.color=glm::vec3(0.0f);
+ return;
+ }
+
+}
+
+__host__ __device__
+void diffuseMicScatter(PathSegment & pathSegment,
+ ShadeableIntersection& intersection,
+ glm::vec3 &materialColor,thrust::default_random_engine &rng, Geom & light,
+ float & lightsize){
+
+ float exponent=1.0f;
+ glm::vec3 h =glm::normalize(calculateRandomDirectionInHemisphere(intersection.surfaceNormal,rng,exponent));
+ glm::vec3 wo=glm::reflect(pathSegment.ray.direction,h);
+
+ glm::vec3 color=materialColor+ ((float)pow(1.0f - glm::dot(h, wo), 5))*(glm::vec3(1.0f)-materialColor);
+ float D=(exponent+1.0f)/TWO_PI*pow(glm::dot(intersection.surfaceNormal,h),exponent);
+ float G=computeG(-glm::normalize(pathSegment.ray.direction),intersection.surfaceNormal,exponent)*computeG(wo,intersection.surfaceNormal,exponent);
+ float bsdf=D*G/(4*glm::dot(-glm::normalize(pathSegment.ray.direction),intersection.surfaceNormal));
+ float pdf=(exponent+1)*pow(glm::dot(intersection.surfaceNormal,h),exponent)/(4.0f*TWO_PI*glm::dot(h,wo));
+ pathSegment.color *= color*bsdf/pdf;
+ pathSegment.remainingBounces--;
+ pathSegment.ray.origin=getPointOnRay(pathSegment.ray, intersection.t);
+
+ pathSegment.ray.direction=wo;
+
+ if(dot(pathSegment.ray.direction,intersection.surfaceNormal)<0){
+ pathSegment.remainingBounces=0;
+ pathSegment.color=glm::vec3(0.0f);
+ return;
+ }
+
+}
+
/**
- * Simple ray scattering with diffuse and perfect specular support.
+ * Scatter a ray with some probabilities according to the material properties.
+ * For example, a diffuse surface scatters in a cosine-weighted hemisphere.
+ * A perfect specular surface scatters in the reflected ray direction.
+ * In order to apply multiple effects to one surface, probabilistically choose
+ * between them.
+ *
+ * The visual effect you want is to straight-up add the diffuse and specular
+ * components. You can do this in a few ways. This logic also applies to
+ * combining other types of materias (such as refractive).
+ *
+ * - Always take an even (50/50) split between a each effect (a diffuse bounce
+ * and a specular bounce), but divide the resulting color of either branch
+ * by its probability (0.5), to counteract the chance (0.5) of the branch
+ * being taken.
+ * - This way is inefficient, but serves as a good starting point - it
+ * converges slowly, especially for pure-diffuse or pure-specular.
+ * - Pick the split based on the intensity of each material color, and divide
+ * branch result by that branch's probability (whatever probability you use).
+ *
+ * This method applies its changes to the Ray parameter `ray` in place.
+ * It also modifies the color `color` of the ray in place.
+ *
+ * You may need to change the parameter list for your purposes!
*/
__host__ __device__
void scatterRay(
- PathSegment & pathSegment,
- glm::vec3 intersect,
- glm::vec3 normal,
- const Material &m,
- thrust::default_random_engine &rng) {
- glm::vec3 newDirection;
- if (m.hasReflective) {
- newDirection = glm::reflect(pathSegment.ray.direction, normal);
- } else {
- newDirection = calculateRandomDirectionInHemisphere(normal, rng);
+ PathSegment& pathSegment,
+ ShadeableIntersection& intersection,
+ Material& m,
+ thrust::default_random_engine& rng,
+ glm::vec3* textPixel,
+ glm::vec3 back,
+ Geom & light,
+ float & lightsize,
+ int shading) {
+ thrust::uniform_real_distribution u01(0, 1);
+ // TODO: implement this.
+ // A basic implementation of pure-diffuse shading will just call the
+ // calculateRandomDirectionInHemisphere defined above.
+
+ if(glm::dot(-glm::normalize(pathSegment.ray.direction), intersection.surfaceNormal)<=0.0f){
+ pathSegment.color *= back;
+ pathSegment.remainingBounces=0;
+ return;
+ }
+
+ glm::vec3 materialColor=m.color;
+ if(m.dimg!=-1){
+ int x=(int)(intersection.uv.x*m.dwidth);
+ int y=(int)((1.0f-intersection.uv.y)*m.dheight);
+ int imgidx= y*m.dwidth+x+m.dimgidx;
+ materialColor=textPixel[imgidx];
+ }
+
+ if(m.nimg!=-1){
+ int x=(int)(intersection.uv.x*m.nwidth);
+ int y=(int)((1.0f-intersection.uv.y)*m.nheight);
+ int imgidx= y*m.nwidth+x+m.nimgidx;
+ glm::vec3 Bump=textPixel[imgidx];
+ Bump=glm::normalize(2.0f*Bump-glm::vec3(1.0f));
+ intersection.surfaceNormal=glm::normalize(Bump[0]*intersection.dpdu+Bump[1]*intersection.dpdv+Bump[2]*intersection.surfaceNormal);
+ //glm::normalize(Bump[0]*intersection.dpdu+Bump[1]*intersection.dpdv+Bump[2]*intersection.surfaceNormal);
}
- pathSegment.ray.direction = newDirection;
- pathSegment.ray.origin = intersect + (newDirection * 0.0001f);
+ if (m.emittance > 0.0f) {
+ pathSegment.color *= (materialColor * m.emittance);
+ pathSegment.remainingBounces=0;
+ }else{
+ float r1=u01(rng);
+ if(r1 -0.0000001f && a < 0.0000001f) {
+ return -1; // This ray is parallel to this triangle.
+ }
+
+ f = 1.0f / a;
+ glm::vec3 s=rt.origin-triangle.vertices[0];
+ u = f * (glm::dot(s,h));
+
+ if (u < 0.0 || u > 1.0) {
+ return -1;
+ }
+
+ glm::vec3 q=glm::cross(s, edge1);
+ v = f *glm::dot(rt.direction,q);
+
+ if (v < 0.0 || u + v > 1.0) {
+ return -1;
+ }
+
+ // At this stage we can compute t to find out where the intersection point is on the line.
+ float t = f *glm::dot(edge2,q);
+ if (t > 0.0000001f) // ray intersection
+ {
+ intersectionPoint = getPointOnRay(rt, t);
+ normal=(1.0f-u-v)*triangle.normals[0]+u*triangle.normals[1]+v*triangle.normals[2];
+ uv=(1.0f-u-v)*triangle.uvs[0]+u*triangle.uvs[1]+v*triangle.uvs[2];
+ //normal=triangle.g_norm;
+ if(glm::dot(triangle.g_norm,rt.direction)>0.0f){
+ outside=false;
+ }
+ } else // This means that there is a line intersection but not a ray intersection.
+ {
+ return -1;
+ }
+ dpdu=glm::normalize(multiplyMV(geom.transform, glm::vec4(triangle.dpdu, 0.f)));
+ dpdv=glm::normalize(multiplyMV(geom.transform, glm::vec4(triangle.dpdv, 0.f)));
+ intersectionPoint = multiplyMV(geom.transform, glm::vec4(intersectionPoint, 1.f));
+ normal = glm::normalize(multiplyMV(geom.invTranspose, glm::vec4(normal, 0.f)));
+ if(outside==false){
+ normal=-normal;
+ }
+ return glm::length(r.origin - intersectionPoint);
+}
+
+__host__ __device__ float aabbIntersectionTest(BVHnode box, Ray r,
+ glm::vec3 &intersectionPoint, glm::vec3 &normal, bool &outside) {
+
+ float tmin = -1e38f;
+ float tmax = 1e38f;
+ for (int xyz = 0; xyz < 3; ++xyz) {
+ float qdxyz = r.direction[xyz];
+ /*if (glm::abs(qdxyz) > 0.00001f)*/ //{
+ float t1 = (box.min[xyz] - r.origin[xyz]) / qdxyz;
+ float t2 = (box.max[xyz] - r.origin[xyz]) / qdxyz;
+ float ta = glm::min(t1, t2);
+ float tb = glm::max(t1, t2);
+ if (ta > -0.0001f && ta > tmin) {
+ tmin = ta;
+ }
+ if (tb < tmax) {
+ tmax = tb;
+ }
+ //}
+ }
+
+ if (tmax >= tmin && tmax > 0) {
+ if (tmin <= -0.0001f)
+ tmin = tmax;
+ return tmin;
+ }
+ return -1;
+}
diff --git a/src/main.cpp b/src/main.cpp
index 4092ae4..e568ef9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,6 +24,8 @@ int startupIterations = 0;
int lastLoopIterations = 0;
bool ui_showGbuffer = false;
bool ui_denoise = false;
+bool ui_gdenoise = false;
+float ui_sigma=1.0f;
int ui_filterSize = 80;
float ui_colorWeight = 0.45f;
float ui_normalWeight = 0.35f;
@@ -106,7 +108,12 @@ void saveImage() {
for (int y = 0; y < height; y++) {
int index = x + (y * width);
glm::vec3 pix = renderState->image[index];
- img.setPixel(width - 1 - x, y, glm::vec3(pix) / samples);
+ if(ui_denoise){
+ img.setPixel(width - 1 - x, y, glm::vec3(pix));
+ }else{
+ img.setPixel(width - 1 - x, y, glm::vec3(pix) / samples);
+ }
+
}
}
@@ -164,13 +171,17 @@ void runCuda() {
int frame = 0;
pathtrace(frame, iteration);
}
-
if (ui_showGbuffer) {
showGBuffer(pbo_dptr);
- } else {
+ }else if(ui_denoise) {
+ if(ui_gdenoise){
+ showGDenoisImage(pbo_dptr,ui_filterSize,ui_sigma,ui_colorWeight,ui_normalWeight,ui_positionWeight,iteration);
+ }
+ showDenoisImage(pbo_dptr,ui_filterSize,ui_colorWeight,ui_normalWeight,ui_positionWeight,iteration);
+ }else {
showImage(pbo_dptr, iteration);
}
-
+ //showDenoisImage(pbo_dptr,9,ui_colorWeight,ui_normalWeight,ui_positionWeight,iteration,levels);
// unmap buffer object
cudaGLUnmapBufferObject(pbo);
diff --git a/src/main.h b/src/main.h
index 06d311a..f7d6472 100644
--- a/src/main.h
+++ b/src/main.h
@@ -36,6 +36,8 @@ extern int ui_iterations;
extern int startupIterations;
extern bool ui_showGbuffer;
extern bool ui_denoise;
+extern bool ui_gdenoise;
+extern float ui_sigma;
extern int ui_filterSize;
extern float ui_colorWeight;
extern float ui_normalWeight;
diff --git a/src/pathtrace.cu b/src/pathtrace.cu
index 23e5f90..5f26385 100644
--- a/src/pathtrace.cu
+++ b/src/pathtrace.cu
@@ -4,6 +4,8 @@
#include
#include
#include
+#include
+#include
#include "sceneStructs.h"
#include "scene.h"
@@ -15,6 +17,7 @@
#include "interactions.h"
#define ERRORCHECK 1
+#define STACKSIZE 8192
#define FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define checkCUDAError(msg) checkCUDAErrorFn(msg, FILENAME, __LINE__)
@@ -67,30 +70,150 @@ __global__ void sendImageToPBO(uchar4* pbo, glm::ivec2 resolution,
}
}
+
+
__global__ void gbufferToPBO(uchar4* pbo, glm::ivec2 resolution, GBufferPixel* gBuffer) {
int x = (blockIdx.x * blockDim.x) + threadIdx.x;
int y = (blockIdx.y * blockDim.y) + threadIdx.y;
if (x < resolution.x && y < resolution.y) {
int index = x + (y * resolution.x);
- float timeToIntersect = gBuffer[index].t * 256.0;
+ /*float timeToIntersect = gBuffer[index].t * 256.0;
pbo[index].w = 0;
pbo[index].x = timeToIntersect;
pbo[index].y = timeToIntersect;
- pbo[index].z = timeToIntersect;
+ pbo[index].z = timeToIntersect;*/
+ /*glm::vec3 normal = glm::normalize(gBuffer[index].normal);
+
+ pbo[index].w = 0;
+ pbo[index].x = glm::abs(normal.x)* 255.0f;
+ pbo[index].y = glm::abs(normal.y)* 255.0f;
+ pbo[index].z = glm::abs(normal.z)* 255.0f;*/
+
+ glm::vec3 position = gBuffer[index].position/10.0f;
+ if(gBuffer[index].t==-1)
+ position=glm::vec3(0.0f);
+ pbo[index].w = 0;
+ pbo[index].x = glm::abs(position.x)* 255.0f;
+ pbo[index].y = glm::abs(position.y)* 255.0f;
+ pbo[index].z = glm::abs(position.z)* 255.0f;
}
}
+__global__ void KernelGenerate(int gridLength, float* k1D, float* kernel, glm::ivec2* offset)
+{
+ int x = (blockIdx.x * blockDim.x) + threadIdx.x;
+ int y = (blockIdx.y * blockDim.y) + threadIdx.y;
+ if(x()*phi*phi)*glm::exp(-((float)((x-center)*(x-center)+(y-center)*(y-center)))/(2*phi*phi));
+ offset[y*gridLength+x]=glm::ivec2(x-gridLength/2,y-gridLength/2);
+ }
+}
+
static Scene * hst_scene = NULL;
static glm::vec3 * dev_image = NULL;
+static glm::vec3 * dev_denoise_image = NULL;
+static glm::vec3 * dev_denoise_imageC = NULL;
static Geom * dev_geoms = NULL;
static Material * dev_materials = NULL;
static PathSegment * dev_paths = NULL;
static ShadeableIntersection * dev_intersections = NULL;
+
static GBufferPixel* dev_gBuffer = NULL;
+static float kernelHost[5]={1.0f/16.0f,1.0f/4.0f,3.0f/8.0f,1.0f/4.0f,1.0f/16.0f};
+static float* kernel;
+static glm::ivec2* offset;
+static float* kernel1D;
+static float* Gkernel;
+static glm::ivec2* Goffset;
+
+static int *dev_keys;
+static int *dev_values;
+static PathSegment* dev_pathR;
+static ShadeableIntersection* dev_intersectionsR;
+static PathSegment* finalbuffer;
+static ShadeableIntersection* firstBounce = NULL;
+static PathSegment* firstBounceP=NULL;
+static BVHnode* dev_tree=NULL;
+static glm::vec3* textimgpixel=NULL;
+static int* dev_lights=NULL;
+static float* dev_lights_area=NULL;
// TODO: static variables for device memory, any extra info you need, etc
// ...
+__global__ void getImage(glm::ivec2 resolution, glm::vec3* image, int iter){
+ int x = (blockIdx.x * blockDim.x) + threadIdx.x;
+ int y = (blockIdx.y * blockDim.y) + threadIdx.y;
+
+ if (x < resolution.x && y < resolution.y) {
+ int index = x + (y * resolution.x);
+ image[index]/=(float)iter;
+ }
+}
+
+__global__ void KernelConvolve(GBufferPixel* gBuffer,glm::ivec2 resolution,
+ glm::vec3* image, glm::vec3* den_image,float* kernel,glm::ivec2* offset,int length,float c_phi,float n_phi,float p_phi,int stepwidth,int max_step) {
+ int x = (blockIdx.x * blockDim.x) + threadIdx.x;
+ int y = (blockIdx.y * blockDim.y) + threadIdx.y;
+
+ if (x < resolution.x && y < resolution.y) {
+ int index = x + (y * resolution.x);
+
+ if(gBuffer[index].t==-1){
+ den_image[index]= image[index];
+ return;
+ }
+
+ glm::ivec2 cuv=glm::ivec2(x,y);
+ glm::vec3 sum = glm::vec3(0.0f);
+ glm::vec3 cval = image[index];
+ glm::vec3 nval = gBuffer[index].normal;
+ glm::vec3 pval = gBuffer[index].position;
+ float cum_w = 0.0f;
+ for(int i = 0; i < length*length; i++) {
+ glm::ivec2 uv = cuv + offset[i]*stepwidth;
+ if(offset[i].x*stepwidth>max_step/2||offset[i].y*stepwidth>max_step/2||offset[i].x*stepwidth<-max_step/2||offset[i].y*stepwidth<-max_step/2){
+ continue;
+ }
+ uv.x=glm::clamp(uv.x,0,resolution.x);
+ uv.y=glm::clamp(uv.y,0,resolution.y);
+
+ int newIdx=uv.x + (uv.y * resolution.x);
+ if(gBuffer[newIdx].t==-1){
+ continue;
+ }
+ glm::vec3 ctmp = image[newIdx];
+ glm::vec3 t = cval - ctmp;
+ float dist2 = dot(t,t);
+ float c_w = glm::min((float)glm::exp(-(dist2)/c_phi), 1.0f);
+ glm::vec3 ntmp = gBuffer[newIdx].normal;
+ t = nval - ntmp;
+ dist2 = glm::max(dot(t,t)/(stepwidth*stepwidth),0.0f);
+ float n_w = glm::min((float)glm::exp(-(dist2)/n_phi), 1.0f);
+ glm::vec3 ptmp = gBuffer[newIdx].position;
+ t = pval - ptmp;
+ dist2 = dot(t,t);
+ float p_w = glm::min((float)glm::exp(-(dist2)/p_phi),1.0f);
+ float weight = c_w * n_w * p_w;
+ sum += ctmp * weight * kernel[i];
+ cum_w += weight*kernel[i];
+ /*sum += ctmp * kernel[i];
+ cum_w += kernel[i];*/
+ }
+ den_image[index]=sum/cum_w;
+ }
+}
void pathtraceInit(Scene *scene) {
hst_scene = scene;
@@ -100,6 +223,12 @@ void pathtraceInit(Scene *scene) {
cudaMalloc(&dev_image, pixelcount * sizeof(glm::vec3));
cudaMemset(dev_image, 0, pixelcount * sizeof(glm::vec3));
+ cudaMalloc(&dev_denoise_image, pixelcount * sizeof(glm::vec3));
+ cudaMemset(dev_denoise_image, 0, pixelcount * sizeof(glm::vec3));
+
+ cudaMalloc(&dev_denoise_imageC, pixelcount * sizeof(glm::vec3));
+ cudaMemset(dev_denoise_imageC, 0, pixelcount * sizeof(glm::vec3));
+
cudaMalloc(&dev_paths, pixelcount * sizeof(PathSegment));
cudaMalloc(&dev_geoms, scene->geoms.size() * sizeof(Geom));
@@ -108,12 +237,46 @@ void pathtraceInit(Scene *scene) {
cudaMalloc(&dev_materials, scene->materials.size() * sizeof(Material));
cudaMemcpy(dev_materials, scene->materials.data(), scene->materials.size() * sizeof(Material), cudaMemcpyHostToDevice);
+ cudaMalloc(&dev_tree, scene->BVH.size() * sizeof(BVHnode));
+ cudaMemcpy(dev_tree, scene->BVH.data(), scene->BVH.size() * sizeof(BVHnode), cudaMemcpyHostToDevice);
+
cudaMalloc(&dev_intersections, pixelcount * sizeof(ShadeableIntersection));
cudaMemset(dev_intersections, 0, pixelcount * sizeof(ShadeableIntersection));
+ cudaMalloc(&Gkernel, pixelcount * sizeof(float));
+ cudaMalloc(&Goffset, pixelcount * sizeof(glm::vec2));
+
+ cudaMalloc(&textimgpixel, scene->imgtext.size() * sizeof(glm::vec3));
+ cudaMemcpy(textimgpixel, scene->imgtext.data(), scene->imgtext.size() * sizeof(glm::vec3), cudaMemcpyHostToDevice);
+
cudaMalloc(&dev_gBuffer, pixelcount * sizeof(GBufferPixel));
+
+ cudaMalloc(&kernel1D,5* sizeof(float));
+ cudaMemcpy(kernel1D,kernelHost,5 * sizeof(float),cudaMemcpyHostToDevice);
+
+ cudaMalloc(&kernel, 25 * sizeof(float));
+ cudaMalloc(&offset, 25 * sizeof(glm::ivec2));
// TODO: initialize any extra device memeory you need
+ const dim3 blockSize2d(8, 8);
+ const dim3 blocksPerGrid2dKernel(
+ (5 + blockSize2d.x - 1) / blockSize2d.x,
+ (5 + blockSize2d.y - 1) / blockSize2d.y);
+
+ KernelGenerate<<>>(5,kernel1D,kernel,offset);
+
+ cudaMalloc(&dev_lights, scene->Lights.size() * sizeof(int));
+ cudaMemcpy(dev_lights, scene->Lights.data(), scene->Lights.size() * sizeof(int), cudaMemcpyHostToDevice);
+ cudaMalloc(&dev_lights_area, scene->LightArea.size() * sizeof(int));
+ cudaMemcpy(dev_lights_area, scene->LightArea.data(), scene->LightArea.size() * sizeof(int), cudaMemcpyHostToDevice);
+ cudaMalloc((void**)&dev_keys, pixelcount * sizeof(int));
+ cudaMalloc((void**)&dev_values, pixelcount * sizeof(int));
+ cudaMalloc((void**)&finalbuffer, pixelcount * sizeof(PathSegment));
+
+ cudaMalloc(&dev_intersectionsR, pixelcount * sizeof(ShadeableIntersection));
+ cudaMalloc(&firstBounce, pixelcount * sizeof(ShadeableIntersection));
+ cudaMalloc(&firstBounceP, pixelcount * sizeof(PathSegment));
+ cudaMalloc(&dev_pathR, pixelcount * sizeof(PathSegment));
checkCUDAError("pathtraceInit");
}
@@ -126,7 +289,16 @@ void pathtraceFree() {
cudaFree(dev_intersections);
cudaFree(dev_gBuffer);
// TODO: clean up any extra device memory you created
-
+ cudaFree(kernel);
+ cudaFree(offset);
+ cudaFree(kernel1D);
+ cudaFree(dev_values);
+ cudaFree(dev_pathR);
+ cudaFree(dev_intersectionsR);
+ cudaFree(firstBounce);
+ cudaFree(firstBounceP);
+ cudaFree(dev_keys);
+ cudaFree(finalbuffer);
checkCUDAError("pathtraceFree");
}
@@ -163,11 +335,11 @@ __global__ void generateRayFromCamera(Camera cam, int iter, int traceDepth, Path
__global__ void computeIntersections(
int depth
, int num_paths
- , PathSegment * pathSegments
- , Geom * geoms
+ , PathSegment* pathSegments
+ , Geom* geoms
, int geoms_size
- , ShadeableIntersection * intersections
- )
+ , ShadeableIntersection* intersections
+)
{
int path_index = blockIdx.x * blockDim.x + threadIdx.x;
@@ -178,27 +350,37 @@ __global__ void computeIntersections(
float t;
glm::vec3 intersect_point;
glm::vec3 normal;
+ glm::vec2 uv=glm::vec2(0.0f);
float t_min = FLT_MAX;
int hit_geom_index = -1;
bool outside = true;
+ bool temp_outside=true;
+ glm::vec3 temp_dpdu=glm::vec3(0.0f);
+ glm::vec3 temp_dpdv=glm::vec3(0.0f);
glm::vec3 tmp_intersect;
glm::vec3 tmp_normal;
+ glm::vec2 tmp_uv=glm::vec2(0.0f);
+ glm::vec3 dpdu=glm::vec3(0.0f);
+ glm::vec3 dpdv=glm::vec3(0.0f);
// naive parse through global geoms
for (int i = 0; i < geoms_size; i++)
{
- Geom & geom = geoms[i];
+ Geom& geom = geoms[i];
if (geom.type == CUBE)
{
- t = boxIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, outside);
+ t = boxIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
}
else if (geom.type == SPHERE)
{
- t = sphereIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, outside);
+ t = sphereIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
+ }else if (geom.type == TRIANGLE){
+ t = triIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_uv,temp_dpdu, temp_dpdv, tmp_normal, temp_outside);
}
+ // TODO: add more intersection tests here... triangle? metaball? CSG?
// Compute the minimum t from the intersection tests to determine what
// scene geometry object was hit first.
@@ -208,6 +390,10 @@ __global__ void computeIntersections(
hit_geom_index = i;
intersect_point = tmp_intersect;
normal = tmp_normal;
+ uv=tmp_uv;
+ outside=temp_outside;
+ dpdu=temp_dpdu;
+ dpdv=temp_dpdv;
}
}
@@ -219,58 +405,160 @@ __global__ void computeIntersections(
{
//The ray hits something
intersections[path_index].t = t_min;
+ intersections[path_index].outside=outside;
intersections[path_index].materialId = geoms[hit_geom_index].materialid;
intersections[path_index].surfaceNormal = normal;
+ intersections[path_index].uv = uv;
+ intersections[path_index].dpdu = dpdu;
+ intersections[path_index].dpdv = dpdv;
}
}
}
-__global__ void shadeSimpleMaterials (
- int iter
- , int num_paths
- , ShadeableIntersection * shadeableIntersections
- , PathSegment * pathSegments
- , Material * materials
- )
+__global__ void computeIntersectionsBVH(
+ int depth
+ , int num_paths
+ , PathSegment* pathSegments
+ , Geom* geoms
+ , BVHnode* tree
+ , int tree_size
+ , ShadeableIntersection* intersections
+)
{
- int idx = blockIdx.x * blockDim.x + threadIdx.x;
- if (idx < num_paths)
- {
- ShadeableIntersection intersection = shadeableIntersections[idx];
- PathSegment segment = pathSegments[idx];
- if (segment.remainingBounces == 0) {
- return;
- }
+ int path_index = blockIdx.x * blockDim.x + threadIdx.x;
+
+ if (path_index < num_paths)
+ {
+ PathSegment pathSegment = pathSegments[path_index];
- if (intersection.t > 0.0f) { // if the intersection exists...
- segment.remainingBounces--;
- // Set up the RNG
- thrust::default_random_engine rng = makeSeededRandomEngine(iter, idx, segment.remainingBounces);
-
- Material material = materials[intersection.materialId];
- glm::vec3 materialColor = material.color;
-
- // If the material indicates that the object was a light, "light" the ray
- if (material.emittance > 0.0f) {
- segment.color *= (materialColor * material.emittance);
- segment.remainingBounces = 0;
- }
- else {
- segment.color *= materialColor;
- glm::vec3 intersectPos = intersection.t * segment.ray.direction + segment.ray.origin;
- scatterRay(segment, intersectPos, intersection.surfaceNormal, material, rng);
- }
- // If there was no intersection, color the ray black.
- // Lots of renderers use 4 channel color, RGBA, where A = alpha, often
- // used for opacity, in which case they can indicate "no opacity".
- // This can be useful for post-processing and image compositing.
- } else {
- segment.color = glm::vec3(0.0f);
- segment.remainingBounces = 0;
- }
+ float t;
+ glm::vec3 intersect_point;
+ glm::vec3 normal;
+ glm::vec2 uv = glm::vec2(0.0f);
+ glm::vec3 dpdu=glm::vec3(0.0f);
+ glm::vec3 dpdv=glm::vec3(0.0f);
+ float t_min = FLT_MAX;
+ int hit_geom_index = -1;
+ bool outside = true;
+ bool temp_outside=true;
+ int stack[STACKSIZE];
+ int stackptr=0;
+ int stacksize=0;
+ stack[0]=tree_size-1;
+ glm::vec3 tmp_intersect;
+ glm::vec3 tmp_normal;
+ glm::vec2 tmp_uv= glm::vec2(0.0f);
+ glm::vec3 temp_dpdu=glm::vec3(0.0f);
+ glm::vec3 temp_dpdv=glm::vec3(0.0f);
- pathSegments[idx] = segment;
- }
+ // naive parse through global geoms
+ while(true){
+ BVHnode& node=tree[stack[stackptr]];
+ stackptr=(stackptr+1)%STACKSIZE;;
+ if(node.leaf){
+ Geom& geom = geoms[node.geom];
+ if (geom.type == CUBE)
+ {
+ t = boxIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
+ }
+ else if (geom.type == SPHERE)
+ {
+ t = sphereIntersectionTest(geom, pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
+ }else if (geom.type == TRIANGLE){
+ t = triIntersectionTest(geom, pathSegment.ray, tmp_intersect,tmp_uv,temp_dpdu, temp_dpdv,tmp_normal, temp_outside);
+ }
+ if (t > 0.0f && t_min > t)
+ {
+ t_min = t;
+ hit_geom_index = geom.materialid;
+ intersect_point = tmp_intersect;
+ normal = tmp_normal;
+ uv= tmp_uv;
+ dpdu=temp_dpdu;
+ dpdv=temp_dpdv;
+ outside=temp_outside;
+ }
+ }else{
+ float dist1=aabbIntersectionTest(tree[node.leftchild], pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
+ if(dist1>=0.0f){
+ stacksize=(stacksize+1)%STACKSIZE;;
+ stack[stacksize]=node.leftchild;
+ }
+ if(node.rightchild!=-1){
+ float dist2=aabbIntersectionTest(tree[node.rightchild], pathSegment.ray, tmp_intersect, tmp_normal, temp_outside);
+ if(dist2>=0.0f){
+ stacksize=(stacksize+1)%STACKSIZE;
+ stack[stacksize]=node.rightchild;
+ }
+ }
+ }
+ if(stackptr==stacksize+1){
+ break;
+ }
+ }
+
+ if (hit_geom_index == -1)
+ {
+ intersections[path_index].t = -1.0f;
+ }
+ else
+ {
+ //The ray hits something
+ intersections[path_index].t = t_min;
+ intersections[path_index].outside=outside;
+ intersections[path_index].materialId = hit_geom_index;
+ intersections[path_index].surfaceNormal = normal;
+ intersections[path_index].uv = uv;
+ intersections[path_index].dpdu = dpdu;
+ intersections[path_index].dpdv = dpdv;
+ }
+ }
+}
+
+__global__ void shadeFakeMaterial(
+ int iter
+ , int num_paths
+ , ShadeableIntersection* shadeableIntersections
+ , PathSegment* pathSegments
+ , Material* materials
+ , glm::vec3 back
+ , glm::vec3* textPixel
+ , Geom* geoms
+ , int* Lights
+ , float* LightArea
+ , int lightsize
+ , int shading
+)
+{
+ int idx = blockIdx.x * blockDim.x + threadIdx.x;
+ if (idx < num_paths)
+ {
+ ShadeableIntersection intersection = shadeableIntersections[idx];
+ if (intersection.t > 0.0f) { // if the intersection exists...
+ // Set up the RNG
+ // LOOK: this is how you use thrust's RNG! Please look at
+ // makeSeededRandomEngine as well.
+ thrust::default_random_engine rng = makeSeededRandomEngine(iter, idx, 0);
+
+ thrust::uniform_real_distribution u01(0, 1);
+ int index=((int)(u01(rng)*((float)lightsize/2)));
+ int start=Lights[index*2];
+ int end=Lights[index*2+1];
+ int gidx=u01(rng)*(end-start)+start;
+ if (intersection.materialId == 5)
+ int test = 1;
+ scatterRay(pathSegments[idx],intersection,materials[intersection.materialId],rng,textPixel,back,geoms[gidx],LightArea[index],shading);
+ // If the material indicates that the object was a light, "light" the ray
+ // If there was no intersection, color the ray black.
+ // Lots of renderers use 4 channel color, RGBA, where A = alpha, often
+ // used for opacity, in which case they can indicate "no opacity".
+ // This can be useful for post-processing and image compositing.
+ }
+ else {
+ pathSegments[idx].color *= back;
+ pathSegments[idx].remainingBounces=0;
+ }
+ }
}
__global__ void generateGBuffer (
@@ -282,6 +570,15 @@ __global__ void generateGBuffer (
if (idx < num_paths)
{
gBuffer[idx].t = shadeableIntersections[idx].t;
+ gBuffer[idx].normal=shadeableIntersections[idx].surfaceNormal;
+ gBuffer[idx].position=getPointOnRay(pathSegments[idx].ray,gBuffer[idx].t);
+ /*
+ glm::vec3 normal=shadeableIntersections[idx].surfaceNormal;
+ gBuffer[idx].normal=glm::vec3(glm::abs(normal.x),glm::abs(normal.y),glm::abs(normal.z));
+ glm::vec3 position=getPointOnRay(pathSegments[idx].ray,gBuffer[idx].t)/10.0f;
+ gBuffer[idx].position=glm::vec3(glm::abs(position.x),glm::abs(position.y),glm::abs(position.z));
+ */
+ //atomicAdd(c_phi, float val);
}
}
@@ -297,58 +594,96 @@ __global__ void finalGather(int nPaths, glm::vec3 * image, PathSegment * iterati
}
}
+__global__ void setfinalbuffer(int nPaths, PathSegment* iterationPaths)
+{
+ int index = (blockIdx.x * blockDim.x) + threadIdx.x;
+
+ if (index < nPaths)
+ {
+ iterationPaths[index].pixelIndex=index;
+ iterationPaths[index].color=glm::vec3(0.0f);
+
+ }
+}
+
+__global__ void materialRemap(int num_paths,
+ PathSegment* dev_paths,
+ ShadeableIntersection* intersection,
+ int *dev_keys,
+ int *dev_values){
+
+ int index = (blockIdx.x * blockDim.x) + threadIdx.x;
+
+ if (index < num_paths)
+ {
+ dev_keys[index]=intersection[index].materialId;
+ dev_values[index]=index;
+ }
+}
+
+
+struct is_zero
+{
+ __host__ __device__
+ bool operator()(PathSegment x)
+ {
+ return x.remainingBounces == 0;
+ }
+};
+
+/**
+ * Performs scatter on an array. That is, for each element in idata,
+ * if bools[idx] == 1, it copies idata[idx] to odata[indices[idx]].
+ */
+ __global__ void kernScatter(int n, PathSegment* idata,PathSegment* finaldata) {
+ // TODO
+ int index = threadIdx.x + (blockIdx.x * blockDim.x);
+ if (index >= n) {
+ return;
+ }
+ if (idata[index].remainingBounces == 0) {
+ finaldata[idata[index].pixelIndex].color=idata[index].color;
+ }
+
+}
+
+
+__global__ void kernReshuffle(int N, int* particleArrayIndices, PathSegment* pos,
+ PathSegment* posR, ShadeableIntersection* vel, ShadeableIntersection* velR){
+ int index = threadIdx.x + (blockIdx.x * blockDim.x);
+ if (index >= N) {
+ return;
+ }
+ posR[index]=pos[particleArrayIndices[index]];
+ velR[index]=vel[particleArrayIndices[index]];
+
+}
+
/**
* Wrapper for the __global__ call that sets up the kernel calls and does a ton
* of memory management
*/
+
void pathtrace(int frame, int iter) {
- const int traceDepth = hst_scene->state.traceDepth;
- const Camera &cam = hst_scene->state.camera;
- const int pixelcount = cam.resolution.x * cam.resolution.y;
+ const int traceDepth = hst_scene->state.traceDepth;
+ const Camera& cam = hst_scene->state.camera;
+ const int pixelcount = cam.resolution.x * cam.resolution.y;
// 2D block for generating ray from camera
- const dim3 blockSize2d(8, 8);
- const dim3 blocksPerGrid2d(
- (cam.resolution.x + blockSize2d.x - 1) / blockSize2d.x,
- (cam.resolution.y + blockSize2d.y - 1) / blockSize2d.y);
+ const dim3 blockSize2d(8, 8);
+ const dim3 blocksPerGrid2d(
+ (cam.resolution.x + blockSize2d.x - 1) / blockSize2d.x,
+ (cam.resolution.y + blockSize2d.y - 1) / blockSize2d.y);
// 1D block for path tracing
const int blockSize1d = 128;
-
- ///////////////////////////////////////////////////////////////////////////
-
- // Pathtracing Recap:
- // * Initialize array of path rays (using rays that come out of the camera)
- // * You can pass the Camera object to that kernel.
- // * Each path ray must carry at minimum a (ray, color) pair,
- // * where color starts as the multiplicative identity, white = (1, 1, 1).
- // * This has already been done for you.
- // * NEW: For the first depth, generate geometry buffers (gbuffers)
- // * For each depth:
- // * Compute an intersection in the scene for each path ray.
- // A very naive version of this has been implemented for you, but feel
- // free to add more primitives and/or a better algorithm.
- // Currently, intersection distance is recorded as a parametric distance,
- // t, or a "distance along the ray." t = -1.0 indicates no intersection.
- // * Color is attenuated (multiplied) by reflections off of any object
- // * Stream compact away all of the terminated paths.
- // You may use either your implementation or `thrust::remove_if` or its
- // cousins.
- // * Note that you can't really use a 2D kernel launch any more - switch
- // to 1D.
- // * Shade the rays that intersected something or didn't bottom out.
- // That is, color the ray by performing a color computation according
- // to the shader, then generate a new ray to continue the ray path.
- // We recommend just updating the ray's PathSegment in place.
- // Note that this step may come before or after stream compaction,
- // since some shaders you write may also cause a path to terminate.
- // * Finally:
- // * if not denoising, add this iteration's results to the image
- // * TODO: if denoising, run kernels that take both the raw pathtraced result and the gbuffer, and put the result in the "pbo" from opengl
-
- generateRayFromCamera <<>>(cam, iter, traceDepth, dev_paths);
- checkCUDAError("generate camera ray");
-
+ if(iter==1)
+ generateRayFromCamera << > > (cam, iter,traceDepth, dev_paths);
+ else
+ cudaMemcpy(dev_paths,firstBounceP,pixelcount*sizeof(PathSegment),cudaMemcpyDeviceToDevice);
+ checkCUDAError("generate camera ray");
+
+
int depth = 0;
PathSegment* dev_path_end = dev_paths + pixelcount;
int num_paths = dev_path_end - dev_paths;
@@ -356,57 +691,106 @@ void pathtrace(int frame, int iter) {
// --- PathSegment Tracing Stage ---
// Shoot ray into scene, bounce between objects, push shading chunks
- // Empty gbuffer
- cudaMemset(dev_gBuffer, 0, pixelcount * sizeof(GBufferPixel));
+ bool iterationComplete = false;
+ dim3 numBlocksPixels = (pixelcount + blockSize1d - 1) / blockSize1d;
+ setfinalbuffer<<>>(num_paths,finalbuffer);
+ //thrust::device_vector dev_thrust_out(pixelcount);
+ while (!iterationComplete) {
- // clean shading chunks
- cudaMemset(dev_intersections, 0, pixelcount * sizeof(ShadeableIntersection));
+ // clean shading chunks
+ cudaMemset(dev_intersections, 0, pixelcount * sizeof(ShadeableIntersection));
+
+ // tracing
+ dim3 numblocksPathSegmentTracing = (num_paths + blockSize1d - 1) / blockSize1d;
+ if(depth==0&&iter>1){
+ cudaMemcpy(dev_intersections,firstBounce,num_paths*sizeof(ShadeableIntersection),cudaMemcpyDeviceToDevice);
+ depth++;
+ }else{
+ computeIntersectionsBVH << > > (
+ iter
+ , num_paths
+ , dev_paths
+ , dev_geoms
+ , dev_tree
+ , hst_scene->BVH.size()
+ , dev_intersections
+ );
+
+ checkCUDAError("trace one bounce");
+ cudaDeviceSynchronize();
+ depth++;
+
+ materialRemap << > >(
+ num_paths,
+ dev_paths,
+ dev_intersections,
+ dev_keys,
+ dev_values
+ );
+ thrust::sort_by_key(thrust::device,dev_keys, dev_keys+num_paths, dev_values);
+ kernReshuffle<<>>(num_paths,dev_values,dev_paths,dev_pathR,dev_intersections,dev_intersectionsR);
+
+ PathSegment *tempdev_paths=dev_pathR;
+ dev_pathR=dev_paths;
+ dev_paths=tempdev_paths;
+ ShadeableIntersection* tempdev_intersections=dev_intersectionsR;
+ dev_intersectionsR=dev_intersections;
+ dev_intersections=tempdev_intersections;
+ }
- bool iterationComplete = false;
- while (!iterationComplete) {
+ if(depth==1&&iter==1){
+ cudaMemcpy(firstBounce,dev_intersections,num_paths*sizeof(ShadeableIntersection),cudaMemcpyDeviceToDevice);
+ cudaMemcpy(firstBounceP,dev_paths,num_paths*sizeof(PathSegment),cudaMemcpyDeviceToDevice);
+ }
- // tracing
- dim3 numblocksPathSegmentTracing = (num_paths + blockSize1d - 1) / blockSize1d;
- computeIntersections <<>> (
- depth
- , num_paths
- , dev_paths
- , dev_geoms
- , hst_scene->geoms.size()
- , dev_intersections
+ shadeFakeMaterial << > > (
+ iter,
+ num_paths,
+ dev_intersections,
+ dev_paths,
+ dev_materials,
+ hst_scene->backColor,
+ textimgpixel,
+ dev_geoms,
+ dev_lights,
+ dev_lights_area,
+ hst_scene->Lights.size(),
+ 0
);
- checkCUDAError("trace one bounce");
- cudaDeviceSynchronize();
-
- if (depth == 0) {
- generateGBuffer<<>>(num_paths, dev_intersections, dev_paths, dev_gBuffer);
- }
- depth++;
+ kernScatter << > > (
+ num_paths,
+ dev_paths,
+ finalbuffer
+ );
+
+ PathSegment* new_end=thrust::remove_if(thrust::device,dev_paths,dev_paths+num_paths,is_zero());
+
+ num_paths=new_end-dev_paths;
- shadeSimpleMaterials<<>> (
- iter,
- num_paths,
- dev_intersections,
- dev_paths,
- dev_materials
- );
- iterationComplete = depth == traceDepth;
+ if(depth>traceDepth || num_paths==0){
+ iterationComplete = true; // TODO: should be based off stream compaction results.
+ }
+
}
- // Assemble this iteration and apply it to the image
- dim3 numBlocksPixels = (pixelcount + blockSize1d - 1) / blockSize1d;
- finalGather<<>>(num_paths, dev_image, dev_paths);
+
+
+ finalGather << > > (pixelcount, dev_image, finalbuffer);
+
+
+ // Assemble this iteration and apply it to the image
+
- ///////////////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////////
- // CHECKITOUT: use dev_image as reference if you want to implement saving denoised images.
- // Otherwise, screenshots are also acceptable.
- // Retrieve image from GPU
- cudaMemcpy(hst_scene->state.image.data(), dev_image,
- pixelcount * sizeof(glm::vec3), cudaMemcpyDeviceToHost);
+ // Send results to OpenGL buffer for rendering
- checkCUDAError("pathtrace");
+ // Retrieve image from GPU
+ cudaMemcpy(hst_scene->state.image.data(), dev_image,
+ pixelcount * sizeof(glm::vec3), cudaMemcpyDeviceToHost);
+
+ checkCUDAError("pathtrace");
}
// CHECKITOUT: this kernel "post-processes" the gbuffer/gbuffers into something that you can visualize for debugging.
@@ -431,3 +815,50 @@ const Camera &cam = hst_scene->state.camera;
// Send results to OpenGL buffer for rendering
sendImageToPBO<<>>(pbo, cam.resolution, iter, dev_image);
}
+
+void showDenoisImage(uchar4 *pbo,int ui_filterSize, float ui_colorWeight,float ui_normalWeight,float ui_positionWeight,int iter){
+ const Camera &cam = hst_scene->state.camera;
+ const dim3 blockSize2d(8, 8);
+ const dim3 blocksPerGrid2d(
+ (cam.resolution.x + blockSize2d.x - 1) / blockSize2d.x,
+ (cam.resolution.y + blockSize2d.y - 1) / blockSize2d.y);
+
+ int filter_iter=ceil(log2(((float)ui_filterSize)/4.0f));
+ //int filter_iter=1;
+ const int pixelcount = cam.resolution.x * cam.resolution.y;
+ cudaMemcpy(dev_denoise_image,dev_image,pixelcount*sizeof(glm::vec3),cudaMemcpyDeviceToDevice);
+ int stepwidth=1;
+ getImage<<>>( cam.resolution, dev_denoise_image,iter);
+
+ for(int i=0;i>>(dev_gBuffer, cam.resolution, dev_denoise_image,dev_denoise_imageC,kernel,offset,5,ui_colorWeight,ui_normalWeight,ui_positionWeight,stepwidth,ui_filterSize);
+ stepwidth*=2;
+ ui_colorWeight = ui_colorWeight / 2;
+ glm::vec3* temp=dev_denoise_image;
+ dev_denoise_image=dev_denoise_imageC;
+ dev_denoise_imageC=temp;
+ }
+
+ sendImageToPBO<<>>(pbo, cam.resolution, 1, dev_denoise_image);
+ cudaMemcpy(hst_scene->state.image.data(), dev_denoise_image,
+ pixelcount * sizeof(glm::vec3), cudaMemcpyDeviceToHost);
+}
+
+void showGDenoisImage(uchar4 *pbo,int ui_filterSize, float phi,float ui_colorWeight,float ui_normalWeight,float ui_positionWeight,int iter){
+ const Camera &cam = hst_scene->state.camera;
+ const dim3 blockSize2d(8, 8);
+ const dim3 blocksPerGrid2d(
+ (cam.resolution.x + blockSize2d.x - 1) / blockSize2d.x,
+ (cam.resolution.y + blockSize2d.y - 1) / blockSize2d.y);
+ const dim3 blocksPerGrid2dKernel(
+ (ui_filterSize + blockSize2d.x - 1) / blockSize2d.x,
+ (ui_filterSize + blockSize2d.y - 1) / blockSize2d.y);
+ const int pixelcount = cam.resolution.x * cam.resolution.y;
+
+ generateGuassianKernel<<>>(ui_filterSize,Gkernel,phi,Goffset);
+ KernelConvolve<<>>(dev_gBuffer, cam.resolution, dev_image,dev_denoise_image,Gkernel,offset,ui_filterSize,ui_colorWeight,ui_normalWeight,ui_positionWeight,1,ui_filterSize);
+
+ sendImageToPBO<<>>(pbo, cam.resolution, 1, dev_denoise_image);
+ cudaMemcpy(hst_scene->state.image.data(), dev_denoise_image,
+ pixelcount * sizeof(glm::vec3), cudaMemcpyDeviceToHost);
+}
diff --git a/src/pathtrace.h b/src/pathtrace.h
index 9e12f44..f2cc691 100644
--- a/src/pathtrace.h
+++ b/src/pathtrace.h
@@ -8,3 +8,5 @@ void pathtraceFree();
void pathtrace(int frame, int iteration);
void showGBuffer(uchar4 *pbo);
void showImage(uchar4 *pbo, int iter);
+void showDenoisImage(uchar4 *pbo,int ui_filterSize, float ui_colorWeight,float ui_normalWeight,float ui_positionWeight,int iter);
+void showGDenoisImage(uchar4 *pbo,int ui_filterSize, float phi, float ui_colorWeight,float ui_normalWeight,float ui_positionWeight,int iter);
diff --git a/src/preview.cpp b/src/preview.cpp
index 3ca2718..567546d 100644
--- a/src/preview.cpp
+++ b/src/preview.cpp
@@ -211,10 +211,12 @@ void drawGui(int windowWidth, int windowHeight) {
}
ImGui::SliderInt("Iterations", &ui_iterations, 1, startupIterations);
-
+ ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);
ImGui::Checkbox("Denoise", &ui_denoise);
+ ImGui::Checkbox("Guassian", &ui_gdenoise);
+ ImGui::SliderFloat("Standard Deviation for Guassian filter", &ui_sigma, 0.0f, 10.0f);
- ImGui::SliderInt("Filter Size", &ui_filterSize, 0, 100);
+ ImGui::SliderInt("Filter Size", &ui_filterSize, 1, 100);
ImGui::SliderFloat("Color Weight", &ui_colorWeight, 0.0f, 10.0f);
ImGui::SliderFloat("Normal Weight", &ui_normalWeight, 0.0f, 10.0f);
ImGui::SliderFloat("Position Weight", &ui_positionWeight, 0.0f, 10.0f);
diff --git a/src/scene.cpp b/src/scene.cpp
index cbae043..ce1ac32 100644
--- a/src/scene.cpp
+++ b/src/scene.cpp
@@ -3,6 +3,170 @@
#include
#include
#include
+#define TINYOBJLOADER_IMPLEMENTATION
+#include "tiny_obj_loader.h"
+
+void printvec3(glm::vec3 vec){
+ cout< BVH, std::vector& geoms){
+ cout<<"BVH leaves count "< &boxes,BVHnode &parent){
+ parent.min=boxes[0].min;
+ parent.max=boxes[0].max;
+ for (const BVHnode &b : boxes) {
+ parent.min=glm::vec3(fmin(b.min.x,parent.min.x),fmin(b.min.y,parent.min.y),fmin(b.min.z,parent.min.z));
+ parent.max=glm::vec3(fmax(b.max.x,parent.max.x),fmax(b.max.y,parent.max.y),fmax(b.max.z,parent.max.z));
+ }
+}
+
+int largest_axis(BVHnode &box){
+ glm::vec3 middle=box.max-box.min;
+ float max=cmax(middle.x,middle.y,middle.z);
+ if(max==middle.x){
+ return 0;
+ }else if(max==middle.y){
+ return 1;
+ }else{
+ return 2;
+ }
+}
+int constructBVH(std::vector &boxes,std::vector &node_pool){
+ if (boxes.size() == 1) {
+ node_pool.push_back(boxes[0]);
+ return node_pool.size() - 1;
+ }else if(boxes.size() == 2){
+ BVHnode parent;
+ parent.leaf=false;
+ node_pool.push_back(boxes[0]);
+ parent.leftchild=node_pool.size() - 1;
+ node_pool.push_back(boxes[1]);
+ parent.rightchild=node_pool.size() - 1;
+ mergeBox(boxes,parent);
+ node_pool.push_back(parent);
+ return node_pool.size() - 1;
+ }
+
+ BVHnode big_box;
+ big_box.leaf=false;
+ mergeBox(boxes,big_box);
+ int axis = largest_axis(big_box);
+ std::vector local_boxes = boxes;
+ std::sort(local_boxes.begin(), local_boxes.end(),
+ [&](const BVHnode &b1, const BVHnode &b2) {
+ glm::vec3 center1 = (b1.max + b1.min) / 2.0f;
+ glm::vec3 center2 = (b2.max + b2.min) / 2.0f;
+ return center1[axis] < center2[axis];
+ });
+ std::vector left_boxes(
+ local_boxes.begin(),
+ local_boxes.begin() + local_boxes.size() / 2);
+ std::vector right_boxes(
+ local_boxes.begin() + local_boxes.size() / 2,
+ local_boxes.end());
+
+
+ big_box.leftchild= constructBVH(left_boxes, node_pool);
+ big_box.rightchild = constructBVH(right_boxes, node_pool);
+ node_pool.push_back(big_box);
+ return node_pool.size() - 1;
+}
+
+void buildBVH(std::vector &BVH, std::vector& geoms){
+ //aabb building
+ for(int i=0;i pool;
+ constructBVH(BVH,pool);
+ BVH=pool;
+ printvec3(BVH[BVH.size()-1].min);
+ printvec3(BVH[BVH.size()-1].max);
+ /*int start=0;
+ int end=BVH.size();
+ while (true){
+ int size=end-start;
+ for(int i=0;i<(size+1)/2;i++){
+ BVHnode newnode;
+ newnode.leaf=false;
+ int index1=i*2+start;
+ int index2=-1;
+ BVHnode b=BVH[i*2+start];
+ if(i*2+1+start shapes;
+ std::vector meshmaterials;
+ std::string warn;
+ std::string err;
+ int materialStartIdx=materials.size();
+ bool ret = tinyobj::LoadObj(&attrib, &shapes, &meshmaterials, &warn, &err, line.c_str(),"./../mesh/");
+ /*cout<<"material count "<0){
+ mat.emittance=length(emissive);
+ lightmat.push_back(materials.size());
+ mat.color=glm::normalize(emissive);
+ }else{
+ mat.emittance=0.0f;
+ }
+ //cout<<"material loading diffuse color"<0){
+ //cout<<"?"< tokens = utilityCore::tokenizeString(line);
- newGeom.materialid = atoi(tokens[1].c_str());
- cout << "Connecting Geom " << objectid << " to Material " << newGeom.materialid << "..." << endl;
+ int materialid = atoi(tokens[1].c_str());
+ cout << "Connecting Geom " << objectid << " to Material " << materialid << "..." << endl;
+ bool isLight=std::find(lightmat.begin(), lightmat.end(), materialid) != lightmat.end();
+ if(newGeom.type == MESH){
+ if(materialid!=-1){
+
+
+ cout<<"not here"<());
+ else
+ LightArea.push_back(6.0f);
+ }
+
+ //BVH[starting_index].geom.materialid=materialid;
+ }
}
//load transformations
utilityCore::safeGetline(fp_in, line);
while (!line.empty() && fp_in.good()) {
vector tokens = utilityCore::tokenizeString(line);
-
+
//load tranformations
+ glm::vec3 translation;
+ glm::vec3 rotation;
+ glm::vec3 scale;
if (strcmp(tokens[0].c_str(), "TRANS") == 0) {
- newGeom.translation = glm::vec3(atof(tokens[1].c_str()), atof(tokens[2].c_str()), atof(tokens[3].c_str()));
+ translation = glm::vec3(atof(tokens[1].c_str()), atof(tokens[2].c_str()), atof(tokens[3].c_str()));
+ if(newGeom.type == MESH){
+ for(int i=starting_index;i0)
+ lightmat.push_back(materials.size());
}
}
materials.push_back(newMaterial);
diff --git a/src/scene.h b/src/scene.h
index f29a917..1b1bec0 100644
--- a/src/scene.h
+++ b/src/scene.h
@@ -7,7 +7,7 @@
#include "glm/glm.hpp"
#include "utilities.h"
#include "sceneStructs.h"
-
+#include "image.h"
using namespace std;
class Scene {
@@ -21,6 +21,12 @@ class Scene {
~Scene();
std::vector geoms;
+ std::vector BVH;
+ std::vector lightmat;
+ std::vector Lights;
+ std::vector LightArea;
std::vector materials;
+ std::vector imgtext;
+ glm::vec3 backColor=glm::vec3(0.0f);
RenderState state;
};
diff --git a/src/sceneStructs.h b/src/sceneStructs.h
index da7e558..c4cd43f 100644
--- a/src/sceneStructs.h
+++ b/src/sceneStructs.h
@@ -3,13 +3,17 @@
#include
#include
#include
+#include "image.h"
#include "glm/glm.hpp"
+#include "utilities.h"
#define BACKGROUND_COLOR (glm::vec3(0.0f))
enum GeomType {
SPHERE,
CUBE,
+ MESH,
+ TRIANGLE
};
struct Ray {
@@ -17,9 +21,21 @@ struct Ray {
glm::vec3 direction;
};
+struct Triangle {
+ glm::vec3 vertices[3];
+ glm::vec3 normals[3];
+ glm::vec2 uvs[3];
+ glm::vec3 g_norm;
+ int matID;
+ float size;
+ glm::vec3 dpdu;
+ glm::vec3 dpdv;
+};
+
struct Geom {
enum GeomType type;
int materialid;
+ Triangle tri;
glm::vec3 translation;
glm::vec3 rotation;
glm::vec3 scale;
@@ -28,6 +44,15 @@ struct Geom {
glm::mat4 invTranspose;
};
+struct BVHnode {
+ glm::vec3 min;
+ glm::vec3 max;
+ int leftchild;
+ int rightchild;
+ bool leaf;
+ int geom;
+};
+
struct Material {
glm::vec3 color;
struct {
@@ -38,6 +63,14 @@ struct Material {
float hasRefractive;
float indexOfRefraction;
float emittance;
+ int dimg;
+ int dheight;
+ int dwidth;
+ int dimgidx;
+ int nimg;
+ int nheight;
+ int nwidth;
+ int nimgidx;
};
struct Camera {
@@ -60,10 +93,10 @@ struct RenderState {
};
struct PathSegment {
- Ray ray;
- glm::vec3 color;
- int pixelIndex;
- int remainingBounces;
+ Ray ray;
+ glm::vec3 color;
+ int pixelIndex;
+ int remainingBounces;
};
// Use with a corresponding PathSegment to do:
@@ -72,11 +105,15 @@ struct PathSegment {
struct ShadeableIntersection {
float t;
glm::vec3 surfaceNormal;
+ glm::vec2 uv;
int materialId;
+ bool outside;
+ glm::vec3 dpdu;
+ glm::vec3 dpdv;
};
-// CHECKITOUT - a simple struct for storing scene geometry information per-pixel.
-// What information might be helpful for guiding a denoising filter?
struct GBufferPixel {
float t;
+ glm::vec3 normal;
+ glm::vec3 position;
};
diff --git a/src/tiny_obj_loader.h b/src/tiny_obj_loader.h
new file mode 100644
index 0000000..28d5d84
--- /dev/null
+++ b/src/tiny_obj_loader.h
@@ -0,0 +1,3459 @@
+/*
+The MIT License (MIT)
+
+Copyright (c) 2012-Present, Syoyo Fujita 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 2.0.0 : Add new object oriented API. 1.x API is still provided.
+// * Support line primitive.
+// * Support points primitive.
+// * Support multiple search path for .mtl(v1 API).
+// * Support vertex weight `vw`(as an tinyobj extension)
+// * Support escaped whitespece in mtllib
+// * Add robust triangulation using Mapbox earcut(TINYOBJLOADER_USE_MAPBOX_EARCUT).
+// version 1.4.0 : Modifed ParseTextureNameAndOption API
+// version 1.3.1 : Make ParseTextureNameAndOption API public
+// version 1.3.0 : Separate warning and error message(breaking API of LoadObj)
+// version 1.2.3 : Added color space extension('-colorspace') to tex opts.
+// version 1.2.2 : Parse multiple group names.
+// version 1.2.1 : Added initial support for line('l') primitive(PR #178)
+// version 1.2.0 : Hardened implementation(#175)
+// version 1.1.1 : Support smoothing groups(#162)
+// version 1.1.0 : Support parsing vertex color(#144)
+// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138)
+// version 1.0.7 : Support multiple tex options(#126)
+// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124)
+// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43)
+// version 1.0.4 : Support multiple filenames for 'mtllib'(#112)
+// version 1.0.3 : Support parsing texture options(#85)
+// version 1.0.2 : Improve parsing speed by about a factor of 2 for large
+// files(#105)
+// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104)
+// version 1.0.0 : Change data structure. Change license from BSD to MIT.
+//
+
+//
+// Use this in *one* .cc
+// #define TINYOBJLOADER_IMPLEMENTATION
+// #include "tiny_obj_loader.h"
+//
+
+#ifndef TINY_OBJ_LOADER_H_
+#define TINY_OBJ_LOADER_H_
+
+#include