diff --git a/README.md b/README.md index ae6088d..608c6f5 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,85 @@ -CIS 565 Project3 : CUDA Pathtracer -=================== - -Fall 2014 - -Due Wed, 10/8 (submit without penalty until Sun, 10/12) - -## INTRODUCTION -In this project, you will implement a CUDA based pathtracer capable of -generating pathtraced rendered images extremely quickly. Building a pathtracer can be viewed as a generalization of building a raytracer, so for those of you who have taken 460/560, the basic concept should not be very new to you. For those of you that have not taken -CIS460/560, raytracing is a technique for generating images by tracing rays of -light through pixels in an image plane out into a scene and following the way -the rays of light bounce and interact with objects in the scene. More -information can be found here: -http://en.wikipedia.org/wiki/Ray_tracing_(graphics). Pathtracing is a generalization of this technique by considering more than just the contribution of direct lighting to a surface. - -Since in this class we are concerned with working in generating actual images -and less so with mundane tasks like file I/O, this project includes basecode -for loading a scene description file format, described below, and various other -things that generally make up the render "harness" that takes care of -everything up to the rendering itself. The core renderer is left for you to -implement. Finally, note that while this basecode is meant to serve as a -strong starting point for a CUDA pathtracer, you are not required to use this -basecode if you wish, and you may also change any part of the basecode -specification as you please, so long as the final rendered result is correct. - -## CONTENTS -The Project3 root directory contains the following subdirectories: +Radium Yang's Pathtracer + +******************** 6000 Iterations, Ray Depth: 8, Depth of Field: focal length 13 ******************* +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/depth%2Brefract%2Bbackreflect%2B6000.bmp) + +##FEATURE LIST +- Basic + * Raycasting + * Diffuse surfaces + * Perfect specular reflective surfaces + * Cube intersection testing + * Sphere surface point sampling + * Stream compaction optimization +- Extra + * Supersampling Anti-Alisasing + * Depth of field + * Refraction + +###Feature Overview +For the Pathtracing Algorithm and basic features' implementations, I mainly followed the raytracing slides in CIS 560 and pathtracing slices in CIS 565. + +Extra Features: +- Depth of field + * I referred to the algorithm posted here: http://ray-tracer-concept.blogspot.com/2011/12/depth-of-field.html + * Find a focal plane before the camera, the new ray direction should come from the image plane to the focal point. -* src/ contains the source code for the project. Both the Windows Visual Studio - solution and the OSX and Linux makefiles reference this folder for all - source; the base source code compiles on Linux, OSX and Windows without - modification. If you are building on OSX, be sure to uncomment lines 4 & 5 of - the CMakeLists.txt in order to make sure CMake builds against clang. -* data/scenes/ contains an example scene description file. -* renders/ contains an example render of the given example scene file. -* windows/ contains a Windows Visual Studio 2010 project and all dependencies - needed for building and running on Windows 7. If you would like to create a - Visual Studio 2012 or 2013 projects, there are static libraries that you can - use for GLFW that are in external/bin/GLFW (Visual Studio 2012 uses msvc110, - and Visual Studio 2013 uses msvc120) -* external/ contains all the header, static libraries and built binaries for - 3rd party libraries (i.e. glm, GLEW, GLFW) that we use for windowing and OpenGL - extensions +- Reflection/ Refraction + * I referred to the algorithm posted here: http://ray-tracer-concept.blogspot.com/2011/12/refraction.html + * Interesting bug... when calculating the accumulated reflective/refractive factor, failed to limit the factor to be required number. + Solution:in reflection, if randomnumber < hasReflective, do reflection; else do diffuse. + in refraction, if randomnumber < refractive, do refraction; else do reflection. + * Example: iterations: 2000, trace depth: 8, hasReflect = 0.3, hasRefract = 0.8 + * Before: + ![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/refr_bug.bmp) + * After: (iterations: 2000, trace depth: 8) + ![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/depth%2Brefract%2Bbackreflect%2B2000.bmp) + +- Stream compaction + * reference: http://wiki.thrust.googlecode.com/hg-history/312700376feeadec0b1a679a259d66ff8512d5b3/html/group__stream__compaction.html#ga517b17ceafe31a9fc70ac5127bd626de + * To accelerate the performance, using thrust to do stream compaction to delete rays which have already been hit to the background or light from the raypool. Thus, after each iteration, the valid rays in the ray pool will be decreased, which will help improve the performance. + +- Supersampling Anti-Alisasing + * When casting the ray, jittered the pixel position on the image plane. (use thrust random number engine) + +## Performance Analysis +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/performance_iterations.JPG) + +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/performance_tracedepth.JPG) + +## Progress Screenshots + +* Step 1: ray intersection + diffuse color + soft shadow (sample 20) test + +///// trace depth: 8 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_2.bmp) + +* Step 2: use ray pool algorithm, diffuse + reflection + specular test + +///// trace depth: 8 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/spec_1.bmp) + +* Step 3: add refraction & depth of field + +///// trace depth: 8 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/depth_refract_1000.bmp) + +* Step 4: set customized scene (reflected walls) + performance tests + +////// Iterations: 4000, trace depth: 2 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth2.bmp) + +////// Iterations: 4000, trace depth: 5 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth5.bmp) + +////// Iterations: 500, trace depth: 8 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/depth%2Brefract%2Bbackreflect%2B500.bmp) + +////// Iterations: 6000, trace depth: 8 ///// +![alt tag](https://github.com/radiumyang/Project3-Pathtracer/blob/master/windows/Project3-Pathtracer/Project3-Pathtracer/depth%2Brefract%2Bbackreflect%2B6000.bmp) + + +=================== ## RUNNING THE CODE The main function requires a scene description file (that is provided in data/scenes). @@ -51,111 +89,6 @@ The main function reads in the scene file by an argument as such : If you are using Visual Studio, you can set this in the Debugging > Command Arguments section in the Project properties. -## REQUIREMENTS -In this project, you are given code for: - -* Loading, reading, and storing the scene scene description format -* Example functions that can run on both the CPU and GPU for generating random - numbers, spherical intersection testing, and surface point sampling on cubes -* A class for handling image operations and saving images -* Working code for CUDA-GL interop - -You will need to implement the following features: - -* Raycasting from a camera into a scene through a pixel grid -* Diffuse surfaces -* Perfect specular reflective surfaces -* Cube intersection testing -* Sphere surface point sampling -* Stream compaction optimization - -You are also required to implement at least 2 of the following features: - -* Texture mapping -* Bump mapping -* Depth of field -* Refraction, i.e. glass -* OBJ Mesh loading and rendering -* Interactive camera -* Motion blur -* Subsurface scattering - -The 'extra features' list is not comprehensive. If you have a particular feature -you would like to implement (e.g. acceleration structures, etc.) please contact us -first! - -For each 'extra feature' you must provide the following analysis : -* overview write up of the feature -* performance impact of the feature -* if you did something to accelerate the feature, why did you do what you did -* compare your GPU version to a CPU version of this feature (you do NOT need to - implement a CPU version) -* how can this feature be further optimized (again, not necessary to implement it, but - should give a roadmap of how to further optimize and why you believe this is the next - step) - -## BASE CODE TOUR -You will be working in three files: raytraceKernel.cu, intersections.h, and -interactions.h. Within these files, areas that you need to complete are marked -with a TODO comment. Areas that are useful to and serve as hints for optional -features are marked with TODO (Optional). Functions that are useful for -reference are marked with the comment LOOK. - -* raytraceKernel.cu contains the core raytracing CUDA kernel. You will need to - complete: - * cudaRaytraceCore() handles kernel launches and memory management; this - function already contains example code for launching kernels, - transferring geometry and cameras from the host to the device, and transferring - image buffers from the host to the device and back. You will have to complete - this function to support passing materials and lights to CUDA. - * raycastFromCameraKernel() is a function that you need to implement. This - function once correctly implemented should handle camera raycasting. - * raytraceRay() is the core raytracing CUDA kernel; all of your pathtracing - logic should be implemented in this CUDA kernel. raytraceRay() should - take in a camera, image buffer, geometry, materials, and lights, and should - trace a ray through the scene and write the resultant color to a pixel in the - image buffer. - -* intersections.h contains functions for geometry intersection testing and - point generation. You will need to complete: - * boxIntersectionTest(), which takes in a box and a ray and performs an - intersection test. This function should work in the same way as - sphereIntersectionTest(). - * getRandomPointOnSphere(), which takes in a sphere and returns a random - point on the surface of the sphere with an even probability distribution. - This function should work in the same way as getRandomPointOnCube(). You can - (although do not necessarily have to) use this to generate points on a sphere - to use a point lights, or can use this for area lighting. - -* interactions.h contains functions for ray-object interactions that define how - rays behave upon hitting materials and objects. You will need to complete: - * getRandomDirectionInSphere(), which generates a random direction in a - sphere with a uniform probability. This function works in a fashion - similar to that of calculateRandomDirectionInHemisphere(), which generates a - random cosine-weighted direction in a hemisphere. - * calculateBSDF(), which takes in an incoming ray, normal, material, and - other information, and returns an outgoing ray. You can either implement - this function for ray-surface interactions, or you can replace it with your own - function(s). - -You will also want to familiarize yourself with: - -* sceneStructs.h, which contains definitions for how geometry, materials, - lights, cameras, and animation frames are stored in the renderer. -* utilities.h, which serves as a kitchen-sink of useful functions - -## NOTES ON GLM -This project uses GLM, the GL Math library, for linear algebra. You need to -know two important points on how GLM is used in this project: - -* In this project, indices in GLM vectors (such as vec3, vec4), are accessed - via swizzling. So, instead of v[0], v.x is used, and instead of v[1], v.y is - used, and so on and so forth. -* GLM Matrix operations work fine on NVIDIA Fermi cards and later, but - pre-Fermi cards do not play nice with GLM matrices. As such, in this project, - GLM matrices are replaced with a custom matrix struct, called a cudaMat4, found - in cudaMat4.h. A custom function for multiplying glm::vec4s and cudaMat4s is - provided as multiplyMV() in intersections.h. ## SCENE FORMAT This project uses a custom scene description format. @@ -219,8 +152,6 @@ Objects are defined in the following fashion: An example scene file setting up two frames inside of a Cornell Box can be found in the scenes/ directory. -For meshes, note that the base code will only read in .obj files. For more -information on the .obj specification see http://en.wikipedia.org/wiki/Wavefront_.obj_file. An example of a mesh object is as follows: @@ -232,42 +163,3 @@ TRANS 0 5 -5 ROTAT 0 90 0 SCALE .01 10 10 -Check the Google group for some sample .obj files of varying complexity. - -## THIRD PARTY CODE POLICY -* Use of any third-party code must be approved by asking on our Google Group. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - -## SELF-GRADING -* On the submission date, email your grade, on a scale of 0 to 100, to Harmony, - harmoli+cis565@seas.upenn.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - -## SUBMISSION -Please change the README to reflect the answers to the questions we have posed -above. Remember: -* this is a renderer, so include images that you've made! -* be sure to back your claims for optimization with numbers and comparisons -* if you reference any other material, please provide a link to it -* you wil not e graded on how fast your path tracer runs, but getting close to - real-time is always nice -* if you have a fast GPU renderer, it is good to show case this with a video to - show interactivity. If you do so, please include a link. - -Be sure to open a pull request and to send Harmony your grade and why you -believe this is the grade you should get. diff --git a/data/scenes/sampleScene.txt b/data/scenes/sampleScene.txt index 6a9f5cc..a3d9a55 100644 --- a/data/scenes/sampleScene.txt +++ b/data/scenes/sampleScene.txt @@ -118,7 +118,7 @@ UP 0 1 0 OBJECT 0 cube -material 0 +material 3 frame 0 TRANS 0 0 0 ROTAT 0 0 90 @@ -126,7 +126,7 @@ SCALE .01 10 10 OBJECT 1 cube -material 0 +material 3 frame 0 TRANS 0 5 -5 ROTAT 0 90 0 @@ -134,7 +134,7 @@ SCALE .01 10 10 OBJECT 2 cube -material 0 +material 3 frame 0 TRANS 0 10 0 ROTAT 0 0 90 @@ -183,7 +183,7 @@ SCALE 3 3 3 OBJECT 8 cube -material 8 +material 3 frame 0 TRANS 0 10 0 ROTAT 0 0 90 diff --git a/src/intersections.h b/src/intersections.h index c9eafb6..e7f0b05 100644 --- a/src/intersections.h +++ b/src/intersections.h @@ -13,6 +13,7 @@ #include "cudaMat4.h" #include "utilities.h" + // Some forward declarations __host__ __device__ glm::vec3 getPointOnRay(ray r, float t); __host__ __device__ glm::vec3 multiplyMV(cudaMat4 m, glm::vec4 v); @@ -69,13 +70,192 @@ __host__ __device__ glm::vec3 getSignOfRay(ray r){ return glm::vec3((int)(inv_direction.x < 0), (int)(inv_direction.y < 0), (int)(inv_direction.z < 0)); } +__host__ __device__ glm::vec3 const& getNearPoint(glm::vec3 const& P0) +{ + glm::vec3* a = new glm::vec3[8]; + glm::vec3* v = new glm::vec3[8]; + a[0] = glm::vec3(0.5, 0.5, 0.5); a[1] = glm::vec3(0.5, 0.5, -0.5); a[2] = glm::vec3(-0.5, 0.5, -0.5); a[3] = glm::vec3(-0.5, 0.5, 0.5); + a[4] = glm::vec3(0.5, -0.5, 0.5); a[5] = glm::vec3(0.5, -0.5, -0.5); a[6] = glm::vec3(-0.5, -0.5, -0.5); a[7] = glm::vec3(-0.5, -0.5, 0.5); + + v[0] = glm::vec3(0.5, 0.5, 0.5) - P0; v[1] = glm::vec3(0.5, 0.5, -0.5)- P0; v[2] = glm::vec3(-0.5, 0.5, -0.5)- P0; v[3] = glm::vec3(-0.5, 0.5, 0.5)- P0; + v[4] = glm::vec3(0.5, -0.5, 0.5)- P0; v[5] = glm::vec3(0.5, -0.5, -0.5)- P0; v[6] = glm::vec3(-0.5, -0.5, -0.5)- P0; v[7] = glm::vec3(-0.5, -0.5, 0.5)- P0; + + float* dis = new float[8]; + for(int i = 0; i<8; i++) + { + dis[i] = glm::dot(v[i], v[i]); + } + + float min = dis[0]; + int minNum = 0; + for(int i = 1; i< 8; i++) + { + if(dis[i] < min) + { + min = dis[i]; + minNum = i; + } + } + return a[minNum]; +} + +__host__ __device__ glm::vec3 const& getFarPoint(glm::vec3 const& P0) +{ + glm::vec3* a = new glm::vec3[8]; + glm::vec3* v = new glm::vec3[8]; + a[0] = glm::vec3(0.5, 0.5, 0.5); a[1] = glm::vec3(0.5, 0.5, -0.5); a[2] = glm::vec3(-0.5, 0.5, -0.5); a[3] = glm::vec3(-0.5, 0.5, 0.5); + a[4] = glm::vec3(0.5, -0.5, 0.5); a[5] = glm::vec3(0.5, -0.5, -0.5); a[6] = glm::vec3(-0.5, -0.5, -0.5); a[7] = glm::vec3(-0.5, -0.5, 0.5); + + v[0] = glm::vec3(0.5, 0.5, 0.5) - P0; v[1] = glm::vec3(0.5, 0.5, -0.5)- P0; v[2] = glm::vec3(-0.5, 0.5, -0.5)- P0; v[3] = glm::vec3(-0.5, 0.5, 0.5)- P0; + v[4] = glm::vec3(0.5, -0.5, 0.5)- P0; v[5] = glm::vec3(0.5, -0.5, -0.5)- P0; v[6] = glm::vec3(-0.5, -0.5, -0.5)- P0; v[7] = glm::vec3(-0.5, -0.5, 0.5)- P0; + + float* dis = new float[8]; + for(int i = 0; i<8; i++) + { + dis[i] = glm::dot(v[i],v[i]); + } + + float max = dis[0]; + int maxNum = 0; + for(int i = 1; i< 8; i++) + { + if(dis[i] > max) + { + max = dis[i]; + maxNum = i; + } + } + return a[maxNum]; +} + // TODO: IMPLEMENT THIS FUNCTION // Cube intersection test, return -1 if no intersection, otherwise, distance to intersection __host__ __device__ float boxIntersectionTest(staticGeom box, ray r, glm::vec3& intersectionPoint, glm::vec3& normal){ + + glm::vec3 P0 = r.origin; + glm::vec3 V0 = r.direction; + glm::vec3 newP0 = multiplyMV(box.inverseTransform, glm::vec4(P0, 1.0f)); + glm::vec3 newV0 = multiplyMV(box.inverseTransform, glm::vec4(V0, 0.0f)); - return -1; + float t1, t2, tnear = -1000000.0f, tfar = 1000000.0f, temp, t; + //glm::vec3 b1 = getNearPoint(newP0); + //glm::vec3 b2 = getFarPoint(newP0); + glm::vec3 b1 = glm::vec3(-0.5f, -0.5f, -0.5f); + glm::vec3 b2 = glm::vec3(0.5f, 0.5f, 0.5f); + + bool intersectFlag = true; + + //x plane +// for(int i =0 ;i < 3; i++) +// { + if(epsilonCheck(abs(newV0.y), 0)) //parallel to xplane + { + if(abs(newP0.y) > 0.5 || epsilonCheck(abs(newP0.y), 0.5)) return -1; + }else //not parallel + { + t1 = (b1.y - newP0.y)/newV0.y; + t2 = (b2.y - newP0.y)/newV0.y; + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + if(t1 > tnear) tnear = t1; + if(t2 < tfar) tfar = t2; + if(tnear > tfar) + { + intersectFlag = false; + return -1; + } + if(tfar < 0) { intersectFlag = false; return -1;} + } + + if(epsilonCheck(abs(newV0.x), 0)) //parallel to xplane + { + if(abs(newP0.x) > 0.5 || epsilonCheck(abs(newP0.x), 0.5)) return -1; + }else //not parallel + { + t1 = (b1.x - newP0.x)/newV0.x; + t2 = (b2.x - newP0.x)/newV0.x; + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + if(t1 > tnear) tnear = t1; + if(t2 < tfar) tfar = t2; + if(tnear > tfar) + { + intersectFlag = false; + return -1; + } + if(tfar < 0) { intersectFlag = false; return -1;} + } +// } + if(epsilonCheck(abs(newV0.z), 0)) //parallel to xplane + { + if(abs(newP0.z) > 0.5 || epsilonCheck(abs(newP0.z), 0.5)) return -1; + }else //not parallel + { + t1 = (b1.z - newP0.z)/newV0.z; + t2 = (b2.z - newP0.z)/newV0.z; + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + if(t1 > tnear) tnear = t1; + if(t2 < tfar) tfar = t2; + if(tnear > tfar) + { + intersectFlag = false; + return -1; + } + if(tfar < 0) { intersectFlag = false; return -1;} + } + + + if(intersectFlag == false) return -1; + else t = tnear; + if( t < 0 || epsilonCheck(t,0)) return -1; + if(!epsilonCheck(t, -1)) + { + //intersection point - local + glm::vec4 intsct = glm::vec4(newP0.x + t*newV0.x, newP0.y + t*newV0.y, newP0.z + t*newV0.z, 1.0f); + //normal - local + glm::vec4 norm = glm::vec4(0,0,0,0); + float nx = abs(intsct.x); + float ny = abs(intsct.y); + float nz = abs(intsct.z); + if (nx > ny) + { + if(nz > nx) norm.z = intsct.z; + else norm.x = intsct.x; + }else + { + if(nz > ny) norm.z = intsct.z; + else norm.y = intsct.y; + } + norm = glm::normalize(norm); + //in world + intersectionPoint = multiplyMV(box.transform, intsct); + normal = multiplyMV(box.transform, norm); + normal = glm::normalize(normal); + + //t = sqrt((intersectionPoint.x - P0.x)*(intersectionPoint.x - P0.x)+(intersectionPoint.y - P0.y)*(intersectionPoint.y - P0.y)+(intersectionPoint.z - P0.z)*(intersectionPoint.z - P0.z))/ sqrt(V0.x*V0.x + V0.y*V0.y + V0.z*V0.z); + t = glm::length(r.origin - intersectionPoint); + } + + return t; + +// return -1; } + + // LOOK: Here's an intersection test example from a sphere. Now you just need to figure out cube and, optionally, triangle. // Sphere intersection test, return -1 if no intersection, otherwise, distance to intersection __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm::vec3& intersectionPoint, glm::vec3& normal){ @@ -178,7 +358,22 @@ __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float random // Generates a random point on a given sphere __host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float randomSeed){ - return glm::vec3(0,0,0); + thrust::default_random_engine rng(hash(randomSeed)); + thrust::uniform_real_distribution u01(-1,1); + thrust::uniform_real_distribution u02(0,TWO_PI); + + float radius = 0.5f; + + float sinx = (float)u01(rng); + float cosx = sqrt(1 - sinx*sinx); + float angley = (float)u02(rng); + + glm::vec3 point = radius*glm::vec3(sinx*cos(angley), sinx*sin(angley), cosx); + + glm::vec3 randPoint = multiplyMV(sphere.transform, glm::vec4(point,1.0f)); + + return randPoint; + // return glm::vec3(0,0,0); } #endif diff --git a/src/main.cpp b/src/main.cpp index b04f03c..ac7bf65 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,7 +89,8 @@ void runCuda(){ // Map OpenGL buffer object for writing from CUDA on a single GPU // No data is moved (Win & Linux). When mapped to CUDA, OpenGL should not use this buffer - + + if(iterations < renderCam->iterations){ uchar4 *dptr=NULL; iterations++; @@ -105,10 +106,13 @@ void runCuda(){ for (int i=0; i < renderScene->materials.size(); i++) { materials[i] = renderScene->materials[i]; } + // execute the kernel cudaRaytraceCore(dptr, renderCam, targetFrame, iterations, materials, renderScene->materials.size(), geoms, renderScene->objects.size() ); + + // unmap buffer object cudaGLUnmapBufferObject(pbo); } else { diff --git a/src/raytraceKernel.cu b/src/raytraceKernel.cu index 9c7bc7d..71d74cd 100644 --- a/src/raytraceKernel.cu +++ b/src/raytraceKernel.cu @@ -16,6 +16,22 @@ #include "intersections.h" #include "interactions.h" +#include +#include +#include +#include +#include + +//////////////// Stream Compaction ////////////// +struct is_ray_dead + { + __host__ __device__ + bool operator()(const ray r) + { + return r.isDead; + } + }; + void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { @@ -24,6 +40,22 @@ void checkCUDAError(const char *msg) { } } +bool nearlyEqual(float a, float b) +{ + const float absA = fabs(a); + const float absB = fabs(b); + const float diff = fabs(a - b); + + if (a == b) { // shortcut + return true; + } else if (a * b == 0) { // a or b or both are zero + // relative error is not meaningful here + return diff < (EPSILON * EPSILON); + } else { // use relative error + return diff / (absA + absB) < EPSILON; + } +} + // LOOK: This function demonstrates how to use thrust for random number generation on the GPU! // Function that generates static. __host__ __device__ glm::vec3 generateRandomNumberFromThread(glm::vec2 resolution, float time, int x, int y){ @@ -37,10 +69,47 @@ __host__ __device__ glm::vec3 generateRandomNumberFromThread(glm::vec2 resolutio // TODO: IMPLEMENT THIS FUNCTION // Function that does the initial raycast from the camera -__host__ __device__ ray raycastFromCameraKernel(glm::vec2 resolution, float time, int x, int y, glm::vec3 eye, glm::vec3 view, glm::vec3 up, glm::vec2 fov){ +__host__ __device__ ray raycastFromCameraKernel(glm::vec2 resolution, float time, int x, int y, glm::vec3 eye, glm::vec3 view, glm::vec3 up, glm::vec2 fov, int index){ ray r; - r.origin = glm::vec3(0,0,0); - r.direction = glm::vec3(0,0,-1); + // r.origin = glm::vec3(0,0,0); + // r.direction = glm::vec3(0,0,-1); + r.origin = eye; + + glm::vec3 E = eye; + glm::vec3 C = view; + glm::vec3 U = up; + + glm::vec3 A = glm::cross(C, U); + glm::vec3 B = glm::cross(A, C); + glm::vec3 M = E + C; + + float tan_phi = tan((float)PI*fov.x/180); + float tan_theta = tan((float)PI*fov.y/180); + glm::vec3 tmp1 = A * glm::length(C) * tan_phi; + glm::vec3 tmp2 = B * glm::length(C) * tan_theta; + glm::vec3 H = tmp1 / glm::length(A); + glm::vec3 V = tmp2 / glm::length(B); + + float r1 = generateRandomNumberFromThread(resolution,time,x,y)[0] - 0.5; + float randx = x + r1; + float randy = y + r1; + float sx = randx / (resolution.x-1); + float sy = randy / (resolution.y-1); + + glm::vec3 P = M + (2.0f*sx - 1) * H + (1 - 2.0f*sy) * V; + r.direction = glm::normalize(P-E); + + //Depth of field + //http://ray-tracer-concept.blogspot.com/2011/12/depth-of-field.html + + //pointAimed is the position of pixel on focal plane in specified ray + float length = 13.0f; + float r2 = generateRandomNumberFromThread(resolution,time,x,y)[0]/2.5; + glm::vec3 pointAimed = r.origin + length * r.direction; + r.origin += glm::vec3(r2,r2,r2); + r.direction = pointAimed - r.origin; + r.direction = glm::normalize(r.direction); + return r; } @@ -88,40 +157,455 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* } } +__device__ ray calcReflectRay(ray Ri, glm::vec3 normal, glm::vec3 interP) +{ + ray Rr; + Rr.origin = interP; + Rr.direction = glm::normalize(Ri.direction) - 2.0f * glm::dot(normal, Ri.direction) * normal; + Rr.direction = glm::normalize(Rr.direction); + Rr.color = Ri.color; + + return Rr; +} + +//http://ray-tracer-concept.blogspot.com/2011/12/refraction.html +__device__ ray calcRefractRay(ray Ri, glm::vec3 normal, glm::vec3 interP, float indexOfRefraction) +{ + ray Rr = calcReflectRay(Ri, normal, interP); + ray Rrr; + Rrr.origin = interP; + + float nr; glm::vec3 tmpnorm = normal; + if(glm::dot(normal, Ri.direction) < 0) + { // going into the sphere + nr = (float)1/indexOfRefraction; + } + else { // going out of sphere + nr = indexOfRefraction; + tmpnorm = -1.0f * normal; + } + float rootContent = sqrtf(1 - nr * nr * (1 - (glm::dot(tmpnorm, -1.0f * Ri.direction)) * glm::dot(tmpnorm, -1.0f * Ri.direction))); + if(rootContent >= EPSILON){ + Rrr.direction = ((nr*glm::dot(tmpnorm, -1.0f * Ri.direction)) - rootContent) * tmpnorm - (-1.0f) *(nr * Ri.direction); + Rrr.direction = glm::normalize(Rrr.direction); + return Rrr; + } +} + +__device__ float rayIntersect(ray Ri, staticGeom* geoms, int numberOfGeoms, int& closestGeo, glm::vec3& interP, glm::vec3& norm) +{ + //return shortest distance, interP, norm, closestGeoID + glm::vec3 tmpnorm = glm::vec3(0,0,0); + float dist = -1; //smallest dist + float intsct = -1; + for(int i = 0; i EPSILON) return false; //hit the light + //if(epsilonCheck(t, -1.0f) || abs(t) < 0.1f) return true; + //else return false; + + float t = -1; float intsct = -1; + float t_light2Obj = glm::length(lightPos - newOrigin); + + for(int i = 0;i 0.01 && t < t_light2Obj) // t!=-1, t not hit itself, not over the maxium length + { + intsct = t; + } + } + } + if(epsilonCheck(intsct, -1)) return true; + else return false; +} + +// add function: recursive raytracing +//__device__ void raytraceRecursive(ray Ri, int rayDepthMax, int rayDepthCur, glm::vec3& color, +// staticGeom* geoms, int numberOfGeoms, material* mats, glm::vec3 pos_cam, int index) +//{ +// if(rayDepthCur == 1) +// { +// // printf("rayDepthMax: %d; curr: %d ", rayDepthMax, rayDepthCur); +// // printf("%d ", index); +// if (index == 381210) +// { +// int test = 0; +// } +// if (index == 383624) +// { +// int test = 0; +// } +// } +// if(rayDepthCur > rayDepthMax) +// { +// color = glm::vec3(BACK_R, BACK_G, BACK_B); +// return; +// } +// ////////////////RAY INTERSECT////////////////////// +// glm::vec3 interP = glm::vec3(0,0,0); +// glm::vec3 norm = glm::vec3(0,0,0); +// +// int closestGeo = -1; +// +// //find the closest geometry //intersection with geometries +// float dist = rayIntersect(Ri, geoms, numberOfGeoms, closestGeo, interP, norm); +// +// /////////////////////COLOR INITIAL//////////////////// +// glm::vec3 colortmp = glm::vec3(0,0,0); +// glm::vec3 color_obj = mats[closestGeo].color; +// glm::vec3 color_light = glm::vec3(0,0,0); +// glm::vec3 color_reflect = glm::vec3(1,1,1); +// glm::vec3 color_refract = glm::vec3(1,1,1); +// glm::vec3 color_ambient = glm::vec3(AMBIENT_R, AMBIENT_G, AMBIENT_B); +// color_ambient *= K_AMBIENT; +// +// glm::vec3 color_diff = glm::vec3(0,0,0); +// glm::vec3 color_spec = glm::vec3(0,0,0); +// +// glm::vec3 color_sum = glm::vec3(0,0,0); +// +// //if didn't hit anything, background color +// if(epsilonCheck(dist, -1.0f) == true) //intsct == -1.0 +// { +// // do nothing, still background color +// colortmp = glm::vec3(BACK_R, BACK_G, BACK_B); +// } +// //hit something +// else +// { +// ////////////////HIT LIGHT//////////////// +// if (mats[closestGeo].emittance>0) +// { +// colortmp = color_obj; +// } +// +// ////////////////HIT GEO////////////////// +// if(epsilonCheck(mats[closestGeo].emittance, 0)) +// { +// //////////////REFLECTION///////////////////// +// ray Rr = calcReflectRay(Ri, norm, interP); //reflect ray +// +// // if it is reflective +// if(mats[closestGeo].hasReflective > EPSILON) +// { +// // printf("isreflective"); +// raytraceRecursive(Rr, rayDepthMax, rayDepthCur+1, color_reflect, geoms, numberOfGeoms,mats, pos_cam, index); +// colortmp = mats[closestGeo].hasReflective * color_reflect; +// } +// colortmp += color_ambient * color_obj; +// +// /////////////Light RAYTRACING & SOFT SHADOW/////////////////// +// for(int gi = 0; gi 0) //is Light +// { +// color_light = mats[gi].color; +// for(int si = 0; si < SAMPLES_SOFT_SHADOW; si++) +// { +// //Random light position; +// glm::vec3 pos_light = getRandomPointOnCube(geoms[gi], hash(si)); +// //calculate light reflect ray +// ray Rlighti; +// Rlighti.origin = pos_light; +// Rlighti.direction = glm::normalize(interP - pos_light); +// ray Rlightr = calcReflectRay(Rlighti, norm, interP); +// +// glm::vec3 localColor = glm::vec3(0,0,0); +// +// ray Rptolight; +// Rptolight.origin = interP; +// Rptolight.direction = glm::normalize(pos_light - interP); +// +// if(ShadowRayUnblocked(Rptolight, pos_light, numberOfGeoms, geoms, mats)) +// { +// /////////NOT IN SHADOW////////// +// // printf("not blocked"); +// if(glm::dot(norm, Rptolight.direction) > 0) +// { +// color_diff = color_obj * glm::dot(norm, Rptolight.direction) * float(K_DIFFUSE) * color_light; +// } +// localColor += color_diff; +// +// ray Rptocam; +// Rptocam.origin = interP; +// Rptocam.direction = glm::normalize(pos_cam - interP); +// +// if(glm::dot(Rlightr.direction, Rptocam.direction) > 0 && mats[closestGeo].specularExponent > 0) +// { +// float temp = pow((float)glm::dot(Rlightr.direction, Rptocam.direction), (float)mats[closestGeo].specularExponent); +// color_spec = color_light * float(K_SPEC) * temp;// * mats[lightIndex[j]].emittance; +// } +// localColor += color_spec; +// } +// color_sum += localColor; +// } +// color_sum *= mats[gi].emittance; +// color_sum /= (float)SAMPLES_SOFT_SHADOW; +// } +// } +// ///////////shadow end/////// +// colortmp += color_sum; +// } +// } +// color = colortmp; +// } + +// test++; + // printf("color , %f, %f, %f", color[0], color[1], color[2]); +// printf("test: %d, index: %d", test, index); + + // TODO: IMPLEMENT THIS FUNCTION // Core raytracer kernel -__global__ void raytraceRay(glm::vec2 resolution, float time, cameraData cam, int rayDepth, glm::vec3* colors, - staticGeom* geoms, int numberOfGeoms){ +__global__ void pathtraceRay(glm::vec2 resolution, float time, cameraData cam, int rayDepthMax, int currDepth, glm::vec3* colors, + staticGeom* geoms, int numberOfGeoms, material* mats, ray* rayPool, glm::vec3* colorAccumulator, int numberOfRays){ - int x = (blockIdx.x * blockDim.x) + threadIdx.x; + /*int x = (blockIdx.x * blockDim.x) + threadIdx.x; int y = (blockIdx.y * blockDim.y) + threadIdx.y; - int index = x + (y * resolution.x); + int index = x + (y * resolution.x);*/ + //1D: + int index = blockDim.x * blockIdx.x + threadIdx.x; + + if(index < numberOfRays) + { + //colors[index] = generateRandomNumberFromThread(resolution, time, x, y); + ray Ri = rayPool[index]; + Ri.origin += 0.001f * Ri.direction; + int index2D = Ri.index2D; + +// glm::vec3 rayColorSum = glm::vec3(0,0,0); +// for (int k = 0; k < SAMPLES_PER_PIXEL; k++) +// { + // glm::vec3 rayColor = glm::vec3(0,0,0); + //raytraceRecursive(Ri, rayDepth, 0, rayColor, geoms,numberOfGeoms,mats, cam.position, index); + + if(currDepth > rayDepthMax) + { + colors[index2D] = (colors[index2D]*(time-1) + colorAccumulator[index2D])/time; + //colors[index2D] = colors[index2D]*0.9f + colorAccumulator[index2D]*0.1f; + return; + } + + ////////////////RAY INTERSECT////////////////////// + glm::vec3 interP = glm::vec3(0,0,0); + glm::vec3 norm = glm::vec3(0,0,0); + int closestGeo = -1; + //find the closest geometry //intersection with geometries + float dist = rayIntersect(Ri, geoms, numberOfGeoms, closestGeo, interP, norm); + // rayPool[index].interP = interP; + // rayPool[index].norm = norm; - if((x<=resolution.x && y<=resolution.y)){ + //if didn't hit anything, background color + if(epsilonCheck(dist, -1.0f) == true) //intsct == -1.0 + { // do nothing, still background color + // colortmp = glm::vec3(BACK_R, BACK_G, BACK_B); + // colors[index2D] = (colors[index2D]*(time-1)+ Ri.color)/time; + colorAccumulator[index2D] *= Ri.k_reflect * glm::vec3(BACK_R, BACK_G, BACK_B); + //kill the ray + rayPool[index].isDead = true; + colors[index2D] = (colors[index2D]*(time-1)+colorAccumulator[index2D])/time; + //colors[index2D] = (colors[index2D]*0.9f+colorAccumulator[index2D]*0.1f); + return; + } + //hit something + else + { + ////////////////HIT LIGHT//////////////// + if (mats[closestGeo].emittance>0) + { + // printf("%f ", Ri.k_spec); + colorAccumulator[index2D] *= (1+Ri.k_spec) * mats[closestGeo].emittance * mats[closestGeo].color; //add specular + // colorAccumulator[index2D] += mats[closestGeo].color; + + rayPool[index].isDead = true; //kill the ray + // colors[index2D] = (colors[index2D]*0.9f+colorAccumulator[index2D]*0.1f); + colors[index2D] = (colors[index2D]*(time-1)+colorAccumulator[index2D])/time; + return; + + } + ////////////////HIT GEO////////////////// + else if(epsilonCheck(mats[closestGeo].emittance, 0)) + { + //random number generation + thrust::default_random_engine rng(hash(time*(currDepth+1))*hash(index2D)); + thrust::uniform_real_distribution u01(0,1); + float r =(float) u01(rng); - colors[index] = generateRandomNumberFromThread(resolution, time, x, y); - } + + ray Rr; + Rr.origin = interP; + if(mats[closestGeo].hasReflective > EPSILON) + { + //////////////REFLECTION///////////////////// + + if(r < mats[closestGeo].hasReflective) + { + //reflect + Rr = calcReflectRay(Ri, norm, interP); + Rr.k_reflect = mats[closestGeo].hasReflective; + } + else + { + //diffuse + //get random direction over hemisphere + Rr.direction = calculateRandomDirectionInHemisphere(norm, (float)u01(rng), (float)u01(rng)); + Rr.direction = glm::normalize(Rr.direction); + //colors[index] += mats[nearestObjIndex].color * mats[nearestObjIndex].hasReflective; + Rr.k_reflect = 1 - mats[closestGeo].hasReflective; + } + } + else if(mats[closestGeo].hasRefractive > EPSILON) + { //////////////Refraction //////////////// + if(r< mats[closestGeo].hasRefractive) + { + Rr = calcRefractRay(Ri, norm, interP, mats[closestGeo].indexOfRefraction); + }else{ + Rr = calcReflectRay(Ri, norm, interP); + } + } + else + { /////diffuse////// + Rr.direction = calculateRandomDirectionInHemisphere(norm, u01(rng), u01(rng)); + Rr.direction = glm::normalize(Rr.direction); + colorAccumulator[index2D] *= mats[closestGeo].color; + // colorAccumulator[index2D] *= K_DIFFUSE; + } + float avgTemp = 0; + for(int gi = 0; gi 0) //is Light + { + + for(int si = 0; si < SAMPLES_SOFT_SHADOW; si++) + { + //Random light position; + glm::vec3 pos_light = getRandomPointOnCube(geoms[gi], hash(si)); + // glm::vec3 pos_light = geoms[gi].translation; + ray Rlighti; + Rlighti.origin = pos_light; + Rlighti.direction = glm::normalize(interP - pos_light); + ray Rlightr = calcReflectRay(Rlighti, norm, interP); + + glm::vec3 localColor = glm::vec3(0,0,0); + + ray Rptolight; + Rptolight.origin = interP; + Rptolight.direction = glm::normalize(pos_light - interP); + + if(ShadowRayUnblocked(Rptolight, pos_light, numberOfGeoms, geoms, mats)) + { + // printf("not blocked"); + ray Rptocam; + Rptocam.origin = interP; + Rptocam.direction = glm::normalize(cam.position - interP); + if(glm::dot(Rlightr.direction, Rptocam.direction) > 0 && mats[closestGeo].specularExponent > 0) + { + // printf("specular"); + float temp = pow((float)glm::dot(Rlightr.direction, Rptocam.direction), (float)mats[closestGeo].specularExponent); + //Rr.k_spec = temp;// * mats[lightIndex[j]].emittance; + avgTemp += temp; + } + } + } + avgTemp /= float(SAMPLES_SOFT_SHADOW); + Rr.k_spec = avgTemp; + } + } + // colortmp += color_ambient * color_obj; + rayPool[index] = Rr; + Rr.origin += 0.001f * Rr.direction; + + + // colortmp += color_sum; + } + } + // rayColorSum += rayColor; +// } +// colors[index2D] = rayColorSum / float(SAMPLES_PER_PIXEL); +// colors[index2D] = colortmp; +// colors[index2D] = (colors[index2D]*(time-1)+colorAccumulator[index2D])/time; + } } +__global__ void rayInitial(ray* rayPool, glm::vec3* colorAccumulator, glm::vec2 resolution, float time, cameraData cam) +{ + int x = (blockIdx.x * blockDim.x) + threadIdx.x; + int y = (blockIdx.y * blockDim.y) + threadIdx.y; + int index = x + (y * resolution.x); + ray Ri = raycastFromCameraKernel(resolution, time, x, y, cam.position, cam.view, cam.up, cam.fov, index); + rayPool[index] = Ri; +// rayPool[index].color = glm::vec3(0,0,0); + rayPool[index].isDead = false; + rayPool[index].index2D = index; + colorAccumulator[index] = glm::vec3(1,1,1); +} // TODO: FINISH THIS FUNCTION // Wrapper for the __global__ call that sets up the kernel calls and does a ton of memory management void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iterations, material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms){ - int traceDepth = 1; //determines how many bounces the raytracer traces - + int traceDepth = DEPTH_TRACE; //determines how many bounces the raytracer traces + // set up crucial magic int tileSize = 8; dim3 threadsPerBlock(tileSize, tileSize); dim3 fullBlocksPerGrid((int)ceil(float(renderCam->resolution.x)/float(tileSize)), (int)ceil(float(renderCam->resolution.y)/float(tileSize))); - - // send image to GPU - glm::vec3* cudaimage = NULL; - cudaMalloc((void**)&cudaimage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3)); - cudaMemcpy( cudaimage, renderCam->image, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyHostToDevice); - + // package geometry and materials and sent to GPU staticGeom* geomList = new staticGeom[numberOfGeoms]; + material* matList = new material[numberOfGeoms]; + for(int i=0; iups[frame]; cam.fov = renderCam->fov; - // kernel launches - raytraceRay<<>>(renderCam->resolution, (float)iterations, cam, traceDepth, cudaimage, cudageoms, numberOfGeoms); + /////////// STEP 1: Construct pool of rays //////////////////// + ////////////STEP 2: Construct accumulator image, initialize black ///////////////// + // package ray + ray* rayPool = NULL; + glm::vec3* colorAccumulator = NULL; + int numberOfRays = (int)cam.resolution.x * (int)cam.resolution.y; + cudaMalloc((void**)&rayPool, numberOfRays*sizeof(ray)); + cudaMalloc((void**)&colorAccumulator, numberOfRays*sizeof(glm::vec3)); + rayInitial<<>>(rayPool, colorAccumulator, renderCam->resolution, (float)iterations, cam); + + + // send image to GPU + glm::vec3* cudaimage = NULL; + cudaMalloc((void**)&cudaimage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3)); + cudaMemcpy( cudaimage, renderCam->image, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyHostToDevice); + + ////////////STEP 3: Launch a kernel to trace ONE bounce //////////////////////////// + int threadsPerBlock_1D_origin = 64; + int blocksPerGrid_1D_origin = (int)ceil(float(numberOfRays)/(float)threadsPerBlock_1D_origin); + int threadsPerBlock_1D = 64; + int blocksPerGrid_1D = (int)ceil(float(numberOfRays)/(float)threadsPerBlock_1D); + for (int currDepth = 0; currDepth < traceDepth; currDepth++) + { + if(numberOfRays == 0) break; + blocksPerGrid_1D = (int)ceil((float)numberOfRays/(float)threadsPerBlock_1D); + pathtraceRay<<>>(renderCam->resolution, (float)iterations, cam, traceDepth, currDepth, + cudaimage, cudageoms, numberOfGeoms, cudamats, rayPool, colorAccumulator, numberOfRays); + /////////////// Stream Compaction /////////////////////// + thrust::device_ptr p_start = thrust::device_pointer_cast(rayPool); + thrust::device_ptr p_end = thrust::remove_if(p_start, p_start+numberOfRays, is_ray_dead()); + numberOfRays = (int)( p_end - p_start); + } + // addShadowColor<<>>((float)iterations, cam, cudaimage, cudageoms, numberOfGeoms, cudamats, rayPool, colorAccumulator, numberOfRays); sendImageToPBO<<>>(PBOpos, renderCam->resolution, cudaimage); // retrieve image from GPU @@ -156,7 +679,13 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio // free up stuff, or else we'll leak memory like a madman cudaFree( cudaimage ); cudaFree( cudageoms ); - delete geomList; + cudaFree( cudamats ); + + cudaFree (rayPool); + cudaFree (colorAccumulator); + + delete[] geomList; + delete[] matList; // make certain the kernel has completed cudaThreadSynchronize(); diff --git a/src/sceneStructs.h b/src/sceneStructs.h index 5e0c853..a71a56c 100644 --- a/src/sceneStructs.h +++ b/src/sceneStructs.h @@ -16,6 +16,20 @@ enum GEOMTYPE{ SPHERE, CUBE, MESH }; struct ray { glm::vec3 origin; glm::vec3 direction; + glm::vec3 color; //add: store the color of the ray + bool isDead; //add: if the ray hit the background or + int index2D; // add: index on the 2D image + float k_reflect; //add: to recursively get final reflective + float k_spec; + + __host__ __device__ ray() //construction + { + color = glm::vec3(0,0,0); + // m_index = 1.0; + isDead = false; + k_reflect = 1.0f; + k_spec = 1.0f; + } }; struct geom { diff --git a/src/utilities.cpp b/src/utilities.cpp index a8e5d90..8069d80 100755 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -72,9 +72,12 @@ void utilityCore::printCudaMat4(cudaMat4 m){ glm::mat4 utilityCore::buildTransformationMatrix(glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale){ glm::mat4 translationMat = glm::translate(glm::mat4(), translation); - glm::mat4 rotationMat = glm::rotate(glm::mat4(), rotation.x, glm::vec3(1,0,0)); - rotationMat = rotationMat*glm::rotate(glm::mat4(), rotation.y, glm::vec3(0,1,0)); - rotationMat = rotationMat*glm::rotate(glm::mat4(), rotation.z, glm::vec3(0,0,1)); + float tx = rotation.x / (float)180 * PI; + float ty = rotation.y / (float)180 * PI; + float tz = rotation.z / (float)180 * PI; + glm::mat4 rotationMat = glm::rotate(glm::mat4(), tx, glm::vec3(1,0,0)); + rotationMat = rotationMat*glm::rotate(glm::mat4(), ty, glm::vec3(0,1,0)); + rotationMat = rotationMat*glm::rotate(glm::mat4(), tz, glm::vec3(0,0,1)); glm::mat4 scaleMat = glm::scale(glm::mat4(), scale); return translationMat*rotationMat*scaleMat; } diff --git a/src/utilities.h b/src/utilities.h index f51598f..ae7e307 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -25,6 +25,23 @@ #define ZERO_ABSORPTION_EPSILON 0.00001 #define RAY_BIAS_AMOUNT 0.0002 +// more definitions +#define BACK_R 0.1 +#define BACK_G 0.1 +#define BACK_B 0.1 + +//#define AMBIENT_R 1.0 +//#define AMBIENT_G 1.0 +//#define AMBIENT_B 1.0 + +#define SAMPLES_PER_PIXEL 50 +#define SAMPLES_SOFT_SHADOW 1 +#define DEPTH_TRACE 8 +//// k +//#define K_AMBIENT 0.2 +//#define K_DIFFUSE 0.6 +//#define K_SPEC 0.5 + namespace utilityCore { extern float clamp(float f, float min, float max); extern bool replaceString(std::string& str, const std::string& from, const std::string& to); diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/2000_depth2.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/2000_depth2.bmp new file mode 100644 index 0000000..179b003 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/2000_depth2.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth2.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth2.bmp new file mode 100644 index 0000000..9a6fe1e Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth2.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth5.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth5.bmp new file mode 100644 index 0000000..653c58b Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/4000_depth5.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/500_8_20.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/500_8_20.bmp new file mode 100644 index 0000000..b7cf3c4 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/500_8_20.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/500_depth2.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/500_depth2.bmp new file mode 100644 index 0000000..29767d6 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/500_depth2.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj index c45dd79..f05f54d 100644 --- a/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj +++ b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj @@ -28,7 +28,7 @@ - + @@ -95,6 +95,6 @@ - + \ No newline at end of file diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+1000.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+1000.bmp new file mode 100644 index 0000000..57717fb Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+1000.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+2000.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+2000.bmp new file mode 100644 index 0000000..6f60ce8 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+2000.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+500.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+500.bmp new file mode 100644 index 0000000..853f9a3 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+500.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+6000.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+6000.bmp new file mode 100644 index 0000000..f529a82 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract+backreflect+6000.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract_0.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract_0.bmp new file mode 100644 index 0000000..dc7914b Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth+refract_0.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth_0.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth_0.bmp new file mode 100644 index 0000000..c2e4d2c Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth_0.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/depth_refract_1000.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/depth_refract_1000.bmp new file mode 100644 index 0000000..321a260 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/depth_refract_1000.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/performance_iterations.JPG b/windows/Project3-Pathtracer/Project3-Pathtracer/performance_iterations.JPG new file mode 100644 index 0000000..ed082fe Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/performance_iterations.JPG differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/performance_tracedepth.JPG b/windows/Project3-Pathtracer/Project3-Pathtracer/performance_tracedepth.JPG new file mode 100644 index 0000000..2ed804d Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/performance_tracedepth.JPG differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/refr_bug.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/refr_bug.bmp new file mode 100644 index 0000000..479f295 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/refr_bug.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene - Copy.txt b/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene - Copy.txt new file mode 100644 index 0000000..e6f2fa3 --- /dev/null +++ b/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene - Copy.txt @@ -0,0 +1,190 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 0.2 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 1 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 0 0 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 15 + +CAMERA +RES 800 800 +FOVY 25 +ITERATIONS 5000 +FILE test.bmp +frame 0 +EYE 0 4.5 12 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 0 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 1 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 2 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 4 +frame 0 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 6 +sphere +material 3 +frame 0 +TRANS 2 5 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +sphere +material 6 +frame 0 +TRANS -2 5 -2 +ROTAT 0 180 0 +SCALE 3 3 3 + + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene.txt b/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene.txt new file mode 100644 index 0000000..5551097 --- /dev/null +++ b/windows/Project3-Pathtracer/Project3-Pathtracer/sampleScene.txt @@ -0,0 +1,198 @@ +MATERIAL 0 //white diffuse +RGB 1 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 3 //yellow glossy +RGB 1 .85 .0 +SPECEX 30 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 4 //white glossy +RGB 0.2 1 1 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0.3 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 5 //glass +RGB 0 0 0 +SPECEX 0 +SPECRGB 1 1 1 +REFL 0 +REFR 0.8 +REFRIOR 2.2 +SCATTER 0 +ABSCOEFF .02 5.1 5.7 +RSCTCOEFF 13 +EMITTANCE 0 + +MATERIAL 6 //pink glossy +RGB 1 .48 .7 +SPECEX 20 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2.6 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 + +MATERIAL 7 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 1 + +MATERIAL 8 //light +RGB 1 1 1 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 12 + + +CAMERA +RES 800 800 +FOVY 25 +ITERATIONS 2000 +FILE test.bmp +frame 0 +EYE 0 4.5 12 +VIEW 0 0 -1 +UP 0 1 0 + +OBJECT 0 +cube +material 4 +frame 0 +TRANS 0 0 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 1 +cube +material 4 +frame 0 +TRANS 0 5 -5 +ROTAT 0 90 0 +SCALE .01 10 10 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 10 10 + +OBJECT 3 +cube +material 1 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 4 +cube +material 2 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 4 +frame 0 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 6 +sphere +material 3 +frame 0 +TRANS 2 5 4.5 +ROTAT 0 180 0 +SCALE 2 2 2 + +OBJECT 7 +sphere +material 6 +frame 0 +TRANS -2 5 -3 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 8 +sphere +material 5 +frame 0 +TRANS -2.5 1 1 +ROTAT 0 180 0 +SCALE 1.7 1.7 1.7 + +OBJECT 9 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 \ No newline at end of file diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/spec_0.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_0.bmp new file mode 100644 index 0000000..6949e54 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_0.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/spec_1.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_1.bmp new file mode 100644 index 0000000..cf22b1a Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_1.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/spec_2.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_2.bmp new file mode 100644 index 0000000..a7eb63e Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/spec_2.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_0.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_0.bmp new file mode 100644 index 0000000..31c4602 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_0.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_1.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_1.bmp new file mode 100644 index 0000000..0f88064 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_1.bmp differ diff --git a/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_2.bmp b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_2.bmp new file mode 100644 index 0000000..dc1e044 Binary files /dev/null and b/windows/Project3-Pathtracer/Project3-Pathtracer/tmp_2.bmp differ