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: Fengkai Wu #21

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 38 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,44 @@ 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)
* Fengkai Wu
* Tested on: Windows 7, i7-6700 @ 3.40GHz 16GB, Quadro K620 4095MB (Moore 100C Lab)

### (TODO: Your README)
## Results
![result_img](https://github.com/wufk/Project3-CUDA-Path-Tracer/blob/master/img/final.PNG)

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

1. Shading with BSDF evaluation

2. Path termination using stream compaction

3. Toggeable option to cache first bounce and sort path segments by materials

4. Refraction with frenesel effects using Shilick's approximation

5. Stochastic antialiasing

## Analysis

### Antialiasing

Before:
![nojitter_img](https://github.com/wufk/Project3-CUDA-Path-Tracer/blob/master/img/nonjitter.PNG)

After jittering:
![jitter_img](https://github.com/wufk/Project3-CUDA-Path-Tracer/blob/master/img/jitter.PNG)

By adding a uniform random value to the ray, the aliasing effect is removed. As you can see from the picture, the edges of the cube and the wall is smoothened.

### Sorting materials
![sort_img](https://github.com/wufk/Project3-CUDA-Path-Tracer/blob/master/img/sort.PNG)

The sorting is on ray/path arrays with respect to their materials. It is performed right after computing intersections. However it increase the running time primialy due to this addition operation. Making ray/paths contiguous in memory sorting by material does seem to be a good choice. The reason might due to that each path is independent and the kernel does not access each pixel by material type.

### Caching first bounce

![cache_img](https://github.com/wufk/Project3-CUDA-Path-Tracer/blob/master/img/cache.PNG)

The outcome of the first iteration of the pathtracing is cached in device and reused for the subsequent bouncing. The graph above shows that it indeed increase performance but at a constant rate. Reloading the cache for reuse is also a high cost.

Binary file added img/cache.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/final.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/jitter.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/nonjitter.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.PNG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
54 changes: 53 additions & 1 deletion scenes/cornell.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ REFR 0
REFRIOR 0
EMITTANCE 0

// Transparent white
MATERIAL 5
RGB .7 .6 .6
SPECEX 0
SPECRGB .7 .6 .6
REFL 0
REFR 1.5
REFRIOR 1.4
EMITTANCE 0

// Diffuse red
MATERIAL 6
RGB .1 .5 .9
SPECEX 0
SPECRGB 0 0 0
REFL 0
REFR 0
REFRIOR 0
EMITTANCE 0

// Camera
CAMERA
RES 800 800
Expand Down Expand Up @@ -112,6 +132,38 @@ SCALE .01 10 10
OBJECT 6
sphere
material 4
TRANS -1 4 -1
TRANS -1 1.5 -1
ROTAT 0 0 0
SCALE 3 3 3

// Sphere
OBJECT 7
sphere
material 5
TRANS 3 1.5 -1
ROTAT 0 0 0
SCALE 2 2 2

// right wall light
OBJECT 8
cube
material 0
TRANS 5 5 0
ROTAT 0 0 0
SCALE .3 3 3

// cube
//OBJECT 9
//cube
//material 4
//TRANS 0 1 -2
//ROTAT 0 30 30
//SCALE 2 2 2

// cube
OBJECT 9
cube
material 6
TRANS -3 0 1
ROTAT 30 0 0
SCALE 2 2 2
97 changes: 96 additions & 1 deletion src/interactions.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,69 @@ glm::vec3 calculateRandomDirectionInHemisphere(
+ sin(around) * over * perpendicularDirection2;
}

__host__ __device__ float schlick(float costheta, float n1, float n2)
{
float R0 = (n1 - n2) / (n1 + n2);
R0 *= R0;
return R0 + (1 - R0) * pow((1 - costheta), 5);
}

__host__ __device__ void reflect(
PathSegment & pathSegment,
glm::vec3 intersect,
glm::vec3 &normal,
const Material &m
)
{
pathSegment.ray.direction = glm::reflect(pathSegment.ray.direction, normal);
pathSegment.ray.direction = glm::normalize(pathSegment.ray.direction);
pathSegment.ray.origin = intersect + pathSegment.ray.direction * 0.001f;
pathSegment.color *= m.color;
pathSegment.remainingBounces--;
}

__host__ __device__ void refract(
PathSegment & pathSegment,
glm::vec3 intersect,
glm::vec3 &normal,
const Material &m,
thrust::default_random_engine &rng)
{
float n1, n2;
float cosTheta, eta;
float fresnel;

n1 = 1.0f;
n2 = m.indexOfRefraction;
cosTheta = glm::dot(pathSegment.ray.direction, normal);

if (cosTheta > .0f)
{
normal = -normal;
eta = n2 / n1;
}
else
{
eta = n1 / n2;
}

thrust::uniform_real_distribution<float> u01(0, 1);
fresnel = schlick(fabs(cosTheta), n1, n2);
if (u01(rng) < fresnel)
{
pathSegment.ray.direction = glm::reflect(pathSegment.ray.direction, normal);
pathSegment.color *= m.color;
}
else
{
pathSegment.ray.direction = glm::refract(pathSegment.ray.direction, normal, eta);
}

pathSegment.ray.origin = intersect + pathSegment.ray.direction * 0.001f;
pathSegment.ray.direction = glm::normalize(pathSegment.ray.direction);
pathSegment.remainingBounces--;
}

/**
* Scatter a ray with some probabilities according to the material properties.
* For example, a diffuse surface scatters in a cosine-weighted hemisphere.
Expand Down Expand Up @@ -70,10 +133,42 @@ __host__ __device__
void scatterRay(
PathSegment & pathSegment,
glm::vec3 intersect,
glm::vec3 normal,
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.

if (glm::dot(pathSegment.ray.direction, normal) > 0.0f && m.hasRefractive <= 0.001f)
{
pathSegment.color = glm::vec3(0.0f);
pathSegment.remainingBounces = 0;
return;
}
if (m.hasReflective > 0.0f)
{
reflect(pathSegment, intersect, normal, m);
}
else if (m.hasRefractive > 0.0f)
{
refract(pathSegment, intersect, normal, m, rng);
}
else if (m.emittance > 0.0f)
{
pathSegment.color *= m.color * m.emittance;
pathSegment.remainingBounces = 0;
}
else
{

//PathSegment temp = pathSegment;

pathSegment.ray.direction = calculateRandomDirectionInHemisphere(normal, rng);
pathSegment.ray.direction = glm::normalize(pathSegment.ray.direction);
pathSegment.ray.origin = intersect + pathSegment.ray.direction * 0.001f;
pathSegment.color *= m.color;
pathSegment.remainingBounces--;
}

}
6 changes: 3 additions & 3 deletions src/intersections.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,9 @@ __host__ __device__ float sphereIntersectionTest(Geom sphere, Ray r,

intersectionPoint = multiplyMV(sphere.transform, glm::vec4(objspaceIntersection, 1.f));
normal = glm::normalize(multiplyMV(sphere.invTranspose, glm::vec4(objspaceIntersection, 0.f)));
if (!outside) {
normal = -normal;
}
//if (!outside) {
// normal = -normal;
//}

return glm::length(r.origin - intersectionPoint);
}
17 changes: 17 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ Scene *scene;
RenderState *renderState;
int iteration;

double totalTimeMs = 0.0f;
float iterationTimeMs;
double totalElapsedTimeMs = 0.0;

int width;
int height;

Expand Down Expand Up @@ -134,8 +138,21 @@ void runCuda() {

// execute the kernel
int frame = 0;
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start);

pathtrace(pbo_dptr, frame, iteration);

cudaEventRecord(stop);
cudaEventSynchronize(stop);
cudaEventElapsedTime(&iterationTimeMs, start, stop);
totalElapsedTimeMs += iterationTimeMs;

if (iteration % 50 == 0) {
totalTimeMs = totalElapsedTimeMs;
}
// unmap buffer object
cudaGLUnmapBufferObject(pbo);
} else {
Expand Down
2 changes: 2 additions & 0 deletions src/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ using namespace std;

extern Scene* scene;
extern int iteration;
extern float iterationTimeMs;
extern double totalTimeMs;

extern int width;
extern int height;
Expand Down
Loading