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: Liang Peng #27

Open
wants to merge 24 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
78 changes: 73 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,79 @@ 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)
* Liang Peng
* Tested on: Windows 10, i7-6700HQ @ 2.6GHz 2.6GHz 8GB, GTX 960M (Personal Laptop)

### (TODO: Your README)
### Feature
* [x] Ray Scattering
* [x] Diffuse
* [x] Refraction
* [x] Specular Reflection
* [x] Glossy Reflection
* [x] Depth of Field
* [x] Stratified Antialiasing
* [x] Performance Analysis

*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.
### Overview
<img src="img/cover_depth8_5000spp.png"><br>
The image is rendered by a path tracer on GPU, with trace depth 8 and 5000 samples per pixel. Features include diffuse, glossy, specular reflection, refraction, depth of field, and stratified antialiasing. The image is produced by averaging the results of all large amount of iterations. In each iteration, the camera will shoot a ray through each pixel and intersect with the scene objects. Based on the material at the intersection point, each ray will change color and be reflected towards certain direction and continue tracing. As a ray reaches it trace depth, its color will be accumulated to compute the final color.

### Ray Scattering
* Lambert Diffuse

Trace Depth 2, SPP 1000 | Trace Depth 8, SPP 1000
--- | ---
<img src="img/lambert_depth2_1000spp.png" width="400"> | <img src="img/lambert_depth8_1000spp.png" width="400">
_observation_ Images rendered with deeper trace level appear darker, which is due to the calculation of ray color. The resulted color is calculated by multiplying the material color of all intersections along the path.

* Refraction

Refraction 1, SPP 1000 | Refraction 2, SPP 5000
--- | ---
<img src="img/refraction_depth8_1000spp.png" width="400"> | <img src="img/refraction2_depth8_1000spp.png" width="400">
_observation_ Since large amount of paths are traced, caustics produced by refraction are free.

* Specular Reflection

Trace Depth 2, SPP 1000 | Trace Depth 8, SPP 1000
--- | ---
<img src="img/mirror_depth2_1000spp.png" width="400"> | <img src="img/mirror_depth8_1000spp.png" width="400">

* Glossy Reflection

Less Glossy Floor, SPP 3000 | Glossier Floor, SPP 3000
--- | ---
<img src="img/glossy_depth8_3000spp.png" width="400"> | <img src="img/glossy2_depth8_3000spp.png" width="400">
_obervation_ For different types of material, glossiness can be adjusted by tuning the specular exponent. Larger exponent produces reflection closer to mirror.

### Depth of Field

Depth of Field, Far Focal | Depth of Field, Near Focal
--- | ---
<img src="img/DoF_depth8_3000spp.png" width="400"> | <img src="img/DoF2_depth8_3000spp.png" width="400">
_obervation_ There are 2 parameters we can play around with in terms of depth of field, lens radius and focal distance. Larger lens radius produces stronger DoF effect. Focal distance affects the distance the virtual camera is focusing on.

### Antialiasing

Antialiasing OFF | Antialiasing ON
--- | ---
<img src="img/aa3_depth8_2000spp.png" width="400"> | <img src="img/aa4_depth8_2000spp.png" width="400">
_obersvation_ By jittering the camera ray within the ray's own pixel and performing large number of iterations, the final color of a pixel is computed by averaging all rays going through the pixel, producing antialiased image.

### Performance Analysis
* Trace Depth

Depth | 1 | 2 | 3
:---:|:---:|:---:|:---:
Time | 38 ms | 70 ms | 93 ms
Image | ![](img/depth1.png) | ![](img/depth2.png) | ![](img/depth3.png)
__Depth__ | __4__ | __5__ | __6__
Time | 110 ms | 120 ms | 140 ms
Image | ![](img/depth4.png) | ![](img/depth5.png) | ![](img/depth6.png)
__Depth__ | __7__ | __8__ | __9__
Tim3 | 148 ms | 156 ms | 160 ms
Image | ![](img/depth7.png) | ![](img/depth8.png) | ![](img/depth9.png)

![](img/time_vs_depth.png)

_Observation_ Apparently, as trace depth increases, image quality becomes better. Interestingly, time spent on 1 iteration increases with decreasing rate, that is probably due to the fact that as a ray traces deeper, it is more likely to hit nothing or terminated, thus need no more calculation.
Binary file added img/DoF2_depth8_3000spp.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/DoF_depth8_3000spp.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 removed img/REFERENCE_cornell.5000samp.png
Binary file not shown.
Binary file added img/aa2_depth8_2000spp.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/aa3_depth8_2000spp.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/aa4_depth8_2000spp.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/aa_depth8_2000spp.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/cover_depth8_5000spp.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/depth1.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/depth2.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/depth3.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/depth4.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/depth5.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/depth6.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/depth7.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/depth8.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/depth9.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/glossy2_depth8_3000spp.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/glossy_depth8_3000spp.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/lambert_depth2_1000spp.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/lambert_depth8_1000spp.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/mirror_depth2_1000spp.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/mirror_depth8_1000spp.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/refraction2_depth8_1000spp.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/refraction_depth8_1000spp.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/time_vs_depth.png
114 changes: 103 additions & 11 deletions scenes/cornell.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ SPECRGB 0 0 0
REFL 0
REFR 0
REFRIOR 0
EMITTANCE 5
EMITTANCE 10

// Diffuse white
MATERIAL 1
Expand Down Expand Up @@ -38,27 +38,79 @@ REFR 0
REFRIOR 0
EMITTANCE 0

// Specular white
// Specular gold
MATERIAL 4
RGB .98 .98 .98
SPECEX 0
RGB .9 .7 .3
SPECEX 100000
SPECRGB .98 .98 .98
REFL 1
REFR 0
REFRIOR 0
EMITTANCE 0

// Refractive red
MATERIAL 5
RGB .98 .28 .28
SPECEX 5000
SPECRGB .98 .98 .98
REFL 0
REFR 1
REFRIOR 1.5
EMITTANCE 0

// Lambert blue
MATERIAL 6
RGB .28 .28 .98
SPECEX 50000
SPECRGB .98 .98 .98
REFL 0
REFR 0
REFRIOR 1.5
EMITTANCE 0

// Glossy gold
MATERIAL 7
RGB .9 .7 .3
SPECEX 1000
SPECRGB .98 .98 .98
REFL 1
REFR 0
REFRIOR 0
EMITTANCE 0

// Refractive red
MATERIAL 8
RGB .98 .28 .28
SPECEX 5000
SPECRGB .98 .98 .98
REFL 0
REFR 1
REFRIOR 1.8
EMITTANCE 0

// Lambert blue
MATERIAL 9
RGB .28 .28 .98
SPECEX 50000
SPECRGB .98 .98 .98
REFL 0
REFR 0
REFRIOR 1.5
EMITTANCE 0

// Camera
CAMERA
RES 800 800
FOVY 45
ITERATIONS 5000
DEPTH 8
DEPTH 9
FILE cornell
EYE 0.0 5 10.5
EYE 0 5 10.5
LOOKAT 0 5 0
UP 0 1 0

LENSR 0.2
FOCALD 7
AA ON

// Ceiling light
OBJECT 0
Expand Down Expand Up @@ -108,10 +160,50 @@ TRANS 5 5 0
ROTAT 0 0 0
SCALE .01 10 10

// Sphere
// Mirror Cube
OBJECT 6
sphere
cube
material 4
TRANS -1 4 -1
TRANS -3 3 -2
ROTAT 0 30 0
SCALE 2 7 .5

// Transparent cube
OBJECT 7
cube
material 5
TRANS 0 3 -3
ROTAT 0 0 0
SCALE 2 7 .5

// Diffuse cube
OBJECT 8
cube
material 6
TRANS 3 3 -2
ROTAT 0 -30 0
SCALE 2 7 .5

// Mirror sphere
OBJECT 9
sphere
material 7
TRANS -3 1 2
ROTAT 0 0 0
SCALE 2 2 2

// Transparent sphere
OBJECT 10
sphere
material 8
TRANS 0 1 1
ROTAT 0 0 0
SCALE 2 2 2

// Diffuse sphere
OBJECT 11
sphere
material 9
TRANS 3 1 2
ROTAT 0 0 0
SCALE 3 3 3
SCALE 2 2 2
64 changes: 54 additions & 10 deletions src/interactions.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "intersections.h"
#include <glm/gtx/rotate_vector.hpp>

// CHECKITOUT
/**
Expand Down Expand Up @@ -36,9 +37,9 @@ glm::vec3 calculateRandomDirectionInHemisphere(
glm::vec3 perpendicularDirection2 =
glm::normalize(glm::cross(normal, perpendicularDirection1));

return up * normal
return glm::normalize(up * normal
+ cos(around) * over * perpendicularDirection1
+ sin(around) * over * perpendicularDirection2;
+ sin(around) * over * perpendicularDirection2);
}

/**
Expand All @@ -47,11 +48,11 @@ glm::vec3 calculateRandomDirectionInHemisphere(
* 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
Expand All @@ -67,13 +68,56 @@ glm::vec3 calculateRandomDirectionInHemisphere(
* 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) {
void scatterRay(PathSegment &path, const ShadeableIntersection &intersection,
const Material &material, thrust::default_random_engine &rng) {

// TODO: implement this.
// A basic implementation of pure-diffuse shading will just call the
// calculateRandomDirectionInHemisphere defined above.

const Ray &ray = path.ray;
Ray newRay = path.ray;
thrust::uniform_real_distribution<float> u01(0, 1);

if (material.hasReflective > 0.f) {
// specular reflection
float theta = acos(pow(u01(rng), 1.f / (material.specular.exponent + 1.f)));
float phi = TWO_PI * u01(rng);
glm::vec3 mirror = glm::normalize(glm::reflect(ray.direction,
intersection.surfaceNormal));
glm::vec3 up = {0.f, 0.f, 1.f};
glm::vec3 axis = glm::normalize(glm::cross(up, mirror));
float angle = acos(glm::dot(up, mirror));

newRay.direction = glm::vec3(cos(phi) * sin(theta),
sin(phi) * sin(theta), cos(theta));
newRay.direction = glm::normalize(
glm::rotate(newRay.direction, angle, axis));
} else if(material.hasRefractive > 0.f) {
// refraction
float cosine = glm::dot(intersection.surfaceNormal, ray.direction);

if (glm::abs(cosine) < 1e-2f) {
newRay.direction = ray.direction;
} else if (cosine < 0.f) {
newRay.direction = glm::refract(ray.direction,
intersection.surfaceNormal, 1.f / material.indexOfRefraction);
} else {
newRay.direction = glm::refract(ray.direction,
-intersection.surfaceNormal, material.indexOfRefraction);
}
// total reflection
if (glm::length(newRay.direction) < 1e-3f){
newRay.direction = glm::reflect(ray.direction,
-intersection.surfaceNormal);
}
} else {
// lambert reflection
newRay.direction = calculateRandomDirectionInHemisphere(
intersection.surfaceNormal, rng);
}

newRay.origin = ray.origin + ray.direction * intersection.t
+ newRay.direction * 1e-3f;
path.ray = newRay;
}
10 changes: 6 additions & 4 deletions src/intersections.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ __host__ __device__ glm::vec3 multiplyMV(glm::mat4 m, glm::vec4 v) {
*/
__host__ __device__ float boxIntersectionTest(Geom box, Ray r,
glm::vec3 &intersectionPoint, glm::vec3 &normal, bool &outside) {

Ray q;
q.origin = multiplyMV(box.inverseTransform, glm::vec4(r.origin , 1.0f));
q.origin = multiplyMV(box.inverseTransform, glm::vec4(r.origin, 1.0f));
q.direction = glm::normalize(multiplyMV(box.inverseTransform, glm::vec4(r.direction, 0.0f)));

float tmin = -1e38f;
float tmax = 1e38f;
glm::vec3 tmin_n;
glm::vec3 tmax_n;

for (int xyz = 0; xyz < 3; ++xyz) {
float qdxyz = q.direction[xyz];
/*if (glm::abs(qdxyz) > 0.00001f)*/ {
Expand Down Expand Up @@ -136,9 +138,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);
}
Loading