Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Project 3: Gabriel Naghi #18

Open
wants to merge 31 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
62efcb9
initial shader implementation
gabenaghi Oct 5, 2016
0696c2b
added stream compaction. Not working yet.
Oct 5, 2016
2ed9468
sync device. num_paths never decrements
gabenaghi Oct 6, 2016
476ead6
god please let this fix something
Oct 9, 2016
5331323
still doesnt work
gabenaghi Oct 9, 2016
2dc4cfb
diffuse only
Oct 9, 2016
4be3053
color ALL teminated rays black. problem- pure decrement iterating doe…
gabenaghi Oct 9, 2016
3f99ac5
beacuse apparently -- != -=
gabenaghi Oct 9, 2016
15ff049
Update README.md
gabenaghi Oct 9, 2016
e8a34d2
most basic path tracer working
gabenaghi Oct 9, 2016
fadd6e4
Merge branch 'master' of https://github.com/gabenaghi/Project3-CUDA-P…
gabenaghi Oct 9, 2016
e277046
images
gabenaghi Oct 9, 2016
d66085e
readme basic implementation update
Oct 9, 2016
ebd46bf
fix image locatin
Oct 9, 2016
fe16a14
better basic image
gabenaghi Oct 9, 2016
0d0d58b
initial stream compaction and image. Not working/
gabenaghi Oct 9, 2016
6602c11
initial stream compaction and image. Not working/
gabenaghi Oct 9, 2016
82d05fb
readme add compaction
Oct 9, 2016
a917fea
Merge branch 'master' of https://github.com/gabenaghi/Project3-CUDA-P…
gabenaghi Oct 9, 2016
674711c
stream compaction with thrust::partition and picture
gabenaghi Oct 9, 2016
827d08f
add bsdf code and pic
gabenaghi Oct 10, 2016
7982e42
readme bsdf
Oct 10, 2016
a50d715
implement first bounce caching
gabenaghi Oct 10, 2016
f9ba7b8
initial contiguous implementation. Seg faults
gabenaghi Oct 10, 2016
d1de85c
Merge branch 'master' of https://github.com/gabenaghi/Project3-CUDA-P…
gabenaghi Oct 10, 2016
be1846e
contiguous done. this is why we sleep.
gabenaghi Oct 10, 2016
08beb8f
add schlick and better hemisphere
gabenaghi Oct 10, 2016
ab61943
add feature documentation
Oct 10, 2016
ca3f3ec
add contiguous documentation
Oct 10, 2016
082e9ef
mostly done with readme
Oct 10, 2016
aac4ee8
spelling is hard
Oct 10, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 1 addition & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1 @@
CUDA Path Tracer
================

**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3**

* (TODO) YOUR NAME HERE
* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)

### (TODO: Your README)

*DO NOT* leave the README to the last minute! It is a crucial part of the
project, and we will not be able to grade you without a good README.

CUDA Path Tracer================**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3*** Gabriel Naghi* Tested on: Windows 10, i7-2600 @ 3.40GHz 8GB, GT 730 1024 MB## OverviewIn this project, we are asked to implement a basic parallel path tracer. In computer graphics, a path tracer is a rendering technique in which light rays are bounced into a scene through a camera and, based on the trajectory and collisions incurred, pixels colored accordingly. In short, the algorithm for a path tracer is as follows:1. Fire rays into the scene.2. Calculate if any object exists on the ray's trajectory.3. If no collisions occur or object hits a light, color the ray black or white, respectively. If there is a collision, color the ray according to the material and generate a new ray emanating from the object's surface. 4. Repeat steps 2 and 3 until all rays have been colored or until a maximum number of bounces has been reached.5. Color pixels in an output image according to the map generated by the rays.6. Repeat as desired from step 1. The more iterations, the more refined the image will become. ### Basic Path TracerFor the basic path tracer, we were asked only to treat objects in the scene as diffuse surfaces. Unfortunately, I had some trouble exacerbated by the fact that I tried to throw in spectral surfaces and stream compaction. This worked OK for the basic sphere.txt scene depicted here:![](img/sphere1.png)Unfortunately, it didn't seem to do as well for the Cornell scene. The image I stared at for many hours looked like this:![](img/cornell_big_bang.png)A few things were evidently wrong here. The light was completely black; the sphere was completely white; the pixels colored by the walls seemed to pick up only the most basic coloring. After much time, the logical thing to do (and that suggested by the TAs) was to cut features and try to get a more basic implementation working; obviously. So after some code snipping and slight patching, my images started to take form:![](img/cornell_extra_white.png)Much better, but not quite. The image didn't stabilize at this point either. It would continue to increase in whiteness until more or less the whole image was flushed out. It was pretty obvious that this was an issue with repeatedly lighting rays. To be frank, I'm not sure exactly what fixed this, but after I rearranged some code relating to rays bottoming out, the implementation suddenly began to work like a charm. ![](img/cornell_basic_working.png)####Stream CompactionI fell into the trap reported in the google group: thrust::remove_if does not move the "removed" elements to the end of the array per se. So my initial implementation looked like this: ![](img/cornell_inital_compact.png)We see here a lot of the color concentration nastiness observed in the first picture above.The solution was to rather use thrust::partition, moving the elements with bounces left to the front of the array while pushing those which had already bottomed out to the end of the array. The resulting image is even nicer than the bas implementation (for some reason) :![](img/cornell_partition_compact.png)####BSDFAnother basic feature we were asked to implement was a BSDF shader. In essence, a BSDF shader combines spectral and diffuse shading. (The above images are pure-diffuse)It was entirely unclear to me based on instructions what we were intended to do for this component. As far as I could tell, on a given iteration, we were supposed to randomly choose one of the two features, do the computation for that type, and divide by half (multipy by 2). But that resulted in this: ![](img/cornell_initial_spectral.png) Luckily, @dgrosman was able to enlighten me as to a proper way to do this, taking the components proportionally if they existed. That turned out this nice image: ![](img/cornell_bsdf.png)#### Contiguous Memory OptimizationOne problem faced by our shader is the possibility of branching in adjacent threads in a warp. This leads to inefficiencies because all threads must wait for all other threads in a warp, so incongruous execution is costly. This can be avoided by ensuring that adjacent threads (nearly) always take the same branch. In the case of our shader, that means making sure that the material properties and thus shading algorithm is the same. The way to do this is to sort the paths and intersections arrays by material ID. I was able to do this using a very simple thrust::sort_by_key call, using intersections as keys and comparing them based on their material ID, while using the paths as values. Many individuals had trouble with this optimization, saying that it in fact caused their iterations to take longer. Indeed, I found the same problem to be present in my performance analysis:![](img/material_sort_duration.png)At first, I thought I could be this problem by selectively applying the material sort. Id made sense to me that when there are a large number of paths present, this would be most helpful. But alas, analysis revealed that any number of sortions negatively impacted performance. ![](img/sort_compact_times.png)### Feature 1.1- Schlick ApproximationFor my first personal feature, I implemented Schlick's approximation of the Fresnel factor -- in essence, it allows us to accurately model the specular reflection of light between media. This is made easier in our case, since one of the two media is always air, which has index of refraction of 1. So our equations are:~~~R(theta) = R0 + (1 - R0)(1 - cos(theta))^5R0 = ((1 - refraction_index)/(1 + refraction_index))^2cos(theta) = dot(normal, ray_direction)~~~ This is easily calculable since normal, ray\_direction, and refraction_index are readily available in the shader. ***non purely spectral image here***### Feature 1.2- Anti Aliasing***Not completed***### Feature 2- Hemisphere SamplingIn our ray scattering function, we what to scatter rays in a cosine-weighted hemisphere when refracting from a diffuse surface. The way to do this as described by [UCSD Graphics](http://graphics.ucsd.edu/courses/cse168_s14/ucsd/CSE168_11_Random.pdf) is as follows:~~~Choose a random point (s,t)u = 2πsv = sqrt(1-t)px = v * cos(u)py = sqrt(t)pz = v * sin(u)~~~Unfortunately, although this may be an efficient implementation, it doesn’t look very good. Here is an image with the new cosine-weighted hemisphere sampling:![](img/cornell_hemisphere.png)## Performance AnalysisStream compaction was definitely one of the more significant optimizations made over the course of this project. It is interesting how the effect varies from scene to scene. For example, in the Cornell scene, Stream Compaction is significant but only whittles away a relatively small number of paths per iteration. On the other hand, on an open scene like the Sphere, Stream compaction immediately removes all the paths, which have been terminated. ![](img/path_numbers.png)Indeed the duratin of a single iteration is sharply reduced by the compaction of paths. ![](img/stream_compaction_duration.png)
Expand Down
Binary file added img/cache_first_time.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_basic_working.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_big_bang.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_bsdf.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_extra_white.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_hemisphere.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_inital_compact.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_initial_spectral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_partition_compact.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/cornell_schlick.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/material_sort_duration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/path_numbers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sort_compact_times.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/sphere1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/stream_compaction_duration.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
68 changes: 60 additions & 8 deletions src/interactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

#include "intersections.h"

#define epsilon 1e-3f

#define SCHLICK 1
#define HEMISPHERE 0

// CHECKITOUT
/**
* Computes a cosine-weighted random direction in a hemisphere.
Expand All @@ -12,6 +17,15 @@ glm::vec3 calculateRandomDirectionInHemisphere(
glm::vec3 normal, thrust::default_random_engine &rng) {
thrust::uniform_real_distribution<float> u01(0, 1);

#if HEMISPHERE
float s = u01(rng);
float t = u01(rng);

float u = TWO_PI*s;
float v = sqrt(1-t);

return glm::vec3(v*cos(u), sqrt(t), v * sin(u));
#else
float up = sqrt(u01(rng)); // cos(theta)
float over = sqrt(1 - up * up); // sin(theta)
float around = u01(rng) * TWO_PI;
Expand Down Expand Up @@ -39,6 +53,7 @@ glm::vec3 calculateRandomDirectionInHemisphere(
return up * normal
+ cos(around) * over * perpendicularDirection1
+ sin(around) * over * perpendicularDirection2;
#endif
}

/**
Expand Down Expand Up @@ -68,12 +83,49 @@ glm::vec3 calculateRandomDirectionInHemisphere(
*/
__host__ __device__
void scatterRay(
PathSegment & pathSegment,
glm::vec3 intersect,
glm::vec3 normal,
const Material &m,
thrust::default_random_engine &rng) {
// TODO: implement this.
// A basic implementation of pure-diffuse shading will just call the
// calculateRandomDirectionInHemisphere defined above.
PathSegment & pathSegment,
float t,
glm::vec3 normal,
const Material &m,
thrust::default_random_engine &rng) {
// A basic implementation of pure-diffuse shading will just call the
// calculateRandomDirectionInHemisphere defined above.

thrust::uniform_real_distribution<float> u01(0, 1);
glm::vec3 color;
glm::vec3 direction;


pathSegment.color *= m.color;
pathSegment.ray.origin = getPointOnRay(pathSegment.ray, t) + epsilon * normal;


if (m.hasReflective > 0.0f && m.hasRefractive > 0.0f)
{
#if SCHLICK
float R0 = powf(((1.0f - m.indexOfRefraction) / (1.0f + m.indexOfRefraction)), 2);

float specular = R0 + (1 - R0)*powf((1 - glm::dot(normal, pathSegment.ray.direction)),5);
float diffuse = 1.0f - specular;
direction = specular * glm::reflect(pathSegment.ray.direction, normal)
+ diffuse * calculateRandomDirectionInHemisphere(normal, rng);
#else
float diffuse = m.hasRefractive / (m.hasReflective + m.hasRefractive);
float specular = 1 - diffuse;
direction = specular * glm::reflect(pathSegment.ray.direction, normal)
+ diffuse * calculateRandomDirectionInHemisphere(normal, rng);
#endif
}
else if (m.hasReflective > 0.0f)
{
//reflect
direction = glm::reflect(pathSegment.ray.direction, normal);
}
else
{
//diffuse
direction = calculateRandomDirectionInHemisphere(normal, rng);
}

pathSegment.ray.direction = direction;
}
Loading