diff --git a/AA_compare.png b/AA_compare.png new file mode 100755 index 0000000..eabc69e Binary files /dev/null and b/AA_compare.png differ diff --git a/DOF.png b/DOF.png new file mode 100755 index 0000000..1c844a2 Binary files /dev/null and b/DOF.png differ diff --git a/README.md b/README.md index ae6088d..8185151 100644 --- a/README.md +++ b/README.md @@ -3,271 +3,57 @@ 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: - -* 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 - -## RUNNING THE CODE -The main function requires a scene description file (that is provided in data/scenes). -The main function reads in the scene file by an argument as such : -'scene=[sceneFileName]' - -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: +## PROJECT DESCRIPTION +For this project, I implemented a pathtracer on Nvidia GPU by using CUDA so that the rendering process is very fast. +## FEATURES +basic features: * Raycasting from a camera into a scene through a pixel grid * Diffuse surfaces * Perfect specular reflective surfaces -* Cube intersection testing +* Cube&Sphere intersection testing * Sphere surface point sampling -* Stream compaction optimization +* Stream compaction optimization -You are also required to implement at least 2 of the following features: - -* Texture mapping -* Bump mapping +additional features: * Depth of field -* Refraction, i.e. glass -* OBJ Mesh loading and rendering -* Interactive camera +* Fresnel Refraction and Reflection +* Supersampled antialiasing * 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. -Scene files are flat text files that describe all geometry, materials, -lights, cameras, render settings, and animation frames inside of the scene. -Items in the format are delimited by new lines, and comments can be added at -the end of each line preceded with a double-slash. -Materials are defined in the following fashion: +##First version of pathtracer -* MATERIAL (material ID) //material header -* RGB (float r) (float g) (float b) //diffuse color -* SPECX (float specx) //specular exponent -* SPECRGB (float r) (float g) (float b) //specular color -* REFL (bool refl) //reflectivity flag, 0 for - no, 1 for yes -* REFR (bool refr) //refractivity flag, 0 for - no, 1 for yes -* REFRIOR (float ior) //index of refraction - for Fresnel effects -* SCATTER (float scatter) //scatter flag, 0 for - no, 1 for yes -* ABSCOEFF (float r) (float b) (float g) //absorption - coefficient for scattering -* RSCTCOEFF (float rsctcoeff) //reduced scattering - coefficient -* EMITTANCE (float emittance) //the emittance of the - material. Anything >0 makes the material a light source. +When I finished all the basic functions, the pathtracer gave me this wired output: +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/first_result_failed.png) -Cameras are defined in the following fashion: +The problem is my color accumulation. Since I was simply adding the color for each iteration, everything becomes white. Also the emittance of the light is too large (15) that makes almost every pixel white. I fixed this by average color through iterations. And I also add a distance feature to the ray and multiply exp(-Distance) to the final pixel color. -* CAMERA //camera header -* RES (float x) (float y) //resolution -* FOVY (float fovy) //vertical field of - view half-angle. the horizonal angle is calculated from this and the - reslution -* ITERATIONS (float interations) //how many - iterations to refine the image, only relevant for supersampled antialiasing, - depth of field, area lights, and other distributed raytracing applications -* FILE (string filename) //file to output - render to upon completion -* frame (frame number) //start of a frame -* EYE (float x) (float y) (float z) //camera's position in - worldspace -* VIEW (float x) (float y) (float z) //camera's view - direction -* UP (float x) (float y) (float z) //camera's up vector +After doing so, I get this much better result: +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/first_result_success.png) +Also I find that the randseed for BSDF input has a hugh impact for the result. Here are two interesting pictures generated by the same code except different randSeeds which are actually pretty cool! -Objects are defined in the following fashion: -* OBJECT (object ID) //object header -* (cube OR sphere OR mesh) //type of object, can - be either "cube", "sphere", or "mesh". Note that cubes and spheres are unit - sized and centered at the origin. -* material (material ID) //material to - assign this object -* frame (frame number) //start of a frame -* TRANS (float transx) (float transy) (float transz) //translation -* ROTAT (float rotationx) (float rotationy) (float rotationz) //rotation -* SCALE (float scalex) (float scaley) (float scalez) //scale +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/wiredResult_with_randSeed1.png) -An example scene file setting up two frames inside of a Cornell Box can be -found in the scenes/ directory. +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/wiredREsult_with_randSeed2.png) -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. +##Performance analysis for stream compaction +Here's a chart showing the running time for 50 iterations with/without stream compaction: +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/performance_analysis.png) -An example of a mesh object is as follows: +As we can see, stream compaction is extremely useful when max depth becomes larger. While the running time for original method is linear related to the max depth, running time for implementation with stream compaction is not changing too much. This makes sense, since the computation complexity for naive method is linear to the number of depth, while by using stream compaction, I would expect the number of rays that needed to track will decrease exponentially. -OBJECT 0 -mesh tetra.obj -material 0 -frame 0 -TRANS 0 5 -5 -ROTAT 0 90 0 -SCALE .01 10 10 +##Anti-Aliasing +I implemented anti-aliasing by jitting the pixel position when we first generate the ray from camera. The following picture shows the effect with anti-aliasing. Left part is generated with AA while right part is generated without AA. -Check the Google group for some sample .obj files of varying complexity. +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/AA_compare.png) -## 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. +Although it is not very obvious since I only run 500 iteration due to time limit. You can still tell that the edge is a little smoother after using Anti-aliasing. -## 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. +##Motion Blur +I implemented motion blur by hard coded in the cudaRaytraceCore function. By changing the position of the object a little bit during each iteration, you can get a moiton blur like this: -## 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. +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/motion_blur.png) -Be sure to open a pull request and to send Harmony your grade and why you -believe this is the grade you should get. +##DOF +For depth of field, I make the camera position jittering with given radius. +![alt tag](https://raw.githubusercontent.com/jianqiaol/Project3-Pathtracer/master/DOF.png) diff --git a/Thumbs.db b/Thumbs.db new file mode 100755 index 0000000..c02c14e Binary files /dev/null and b/Thumbs.db differ diff --git a/data/scenes/sampleScene.txt b/data/scenes/sampleScene.txt index 6a9f5cc..17249c5 100644 --- a/data/scenes/sampleScene.txt +++ b/data/scenes/sampleScene.txt @@ -1,190 +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 1 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 1 1 -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 +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 1 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 1 1 +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 100 100 + +OBJECT 1 +cube +material 0 +frame 0 +TRANS 0 5 -10 +ROTAT 0 90 0 +SCALE .01 100 100 + +OBJECT 2 +cube +material 0 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .01 100 100 + +OBJECT 3 +cube +material 1 +frame 0 +TRANS -5 5 0 +ROTAT 0 0 0 +SCALE .01 100 100 + +OBJECT 4 +cube +material 2 +frame 0 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 100 100 + +OBJECT 5 +sphere +material 4 +frame 0 +TRANS 0 2 -1 +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 -4 +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/first_result_failed.png b/first_result_failed.png new file mode 100755 index 0000000..56ad8f1 Binary files /dev/null and b/first_result_failed.png differ diff --git a/first_result_success.png b/first_result_success.png new file mode 100755 index 0000000..42c6d9d Binary files /dev/null and b/first_result_success.png differ diff --git a/motion_blur.png b/motion_blur.png new file mode 100755 index 0000000..1e8ef2f Binary files /dev/null and b/motion_blur.png differ diff --git a/performance_analysis.png b/performance_analysis.png new file mode 100644 index 0000000..b0e0e6d Binary files /dev/null and b/performance_analysis.png differ diff --git a/result_with_AA.png b/result_with_AA.png new file mode 100755 index 0000000..24e3348 Binary files /dev/null and b/result_with_AA.png differ diff --git a/src/interactions.h b/src/interactions.h index 7bf6fab..8e69363 100644 --- a/src/interactions.h +++ b/src/interactions.h @@ -40,22 +40,70 @@ __host__ __device__ bool calculateScatterAndAbsorption(ray& r, float& depth, Abs // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ glm::vec3 calculateTransmissionDirection(glm::vec3 normal, glm::vec3 incident, float incidentIOR, float transmittedIOR) { - return glm::vec3(0,0,0); + return glm::vec3(0,0,0); } // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ glm::vec3 calculateReflectionDirection(glm::vec3 normal, glm::vec3 incident) { //nothing fancy here - return glm::vec3(0,0,0); + return glm::normalize(incident-2.0f*glm::dot(incident,normal)*normal); } // TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ Fresnel calculateFresnel(glm::vec3 normal, glm::vec3 incident, float incidentIOR, float transmittedIOR, glm::vec3 reflectionDirection, glm::vec3 transmissionDirection) { - Fresnel fresnel; + Fresnel fresnel; + float n1=incidentIOR; + float n2=transmittedIOR; + + //if n1 or n2 is 0, then only relfection + if(n1<=0.001f ||n2<=0.001f) + { + fresnel.reflectionCoefficient = 1; + fresnel.transmissionCoefficient = 0; + return fresnel; + } + + float ratio=n1/n2; + float cos_theta1=glm::dot(incident,-normal); + float cos_theta2_square=1-ratio*ratio*(1-cos_theta1*cos_theta1); + //check if this is a total internal reflection + if(cos_theta2_square<0) + { + reflectionDirection=calculateReflectionDirection(normal,incident); + fresnel.reflectionCoefficient = 1; + fresnel.transmissionCoefficient = 0; + return fresnel; + } - fresnel.reflectionCoefficient = 1; - fresnel.transmissionCoefficient = 0; - return fresnel; + float cos_theta2=glm::sqrt(cos_theta2_square); + + if(cos_theta1>0.0f) + { + //out-side-in + transmissionDirection=ratio*incident+(ratio*cos_theta1-cos_theta2)*normal; + } + else + { + //in-side-out + transmissionDirection=ratio*incident+(ratio*cos_theta1+cos_theta2)*normal; + } + + //s-polarize light + float Rs=0; + float Rp=0; + if(!epsilonCheck(n1*cos_theta1+n2*cos_theta2,0)) + { + Rs=abs(n1*cos_theta1-n2*cos_theta2)*abs(n1*cos_theta1+n2*cos_theta2); + } + if(!epsilonCheck(n1*cos_theta2+n2*cos_theta1,0)) + { + Rs=abs(n1*cos_theta2-n2*cos_theta1)*abs(n1*cos_theta2+n2*cos_theta1); + } + + fresnel.reflectionCoefficient=(Rs+Rp)*0.5f; + fresnel.transmissionCoefficient=1-fresnel.reflectionCoefficient; + reflectionDirection=calculateReflectionDirection(normal,incident); + return fresnel; } // LOOK: This function demonstrates cosine weighted random direction generation in a sphere! @@ -67,7 +115,8 @@ __host__ __device__ glm::vec3 calculateRandomDirectionInHemisphere(glm::vec3 nor float over = sqrt(1 - up * up); // sin(theta) float around = xi2 * TWO_PI; - // Find a direction that is not the normal based off of whether or not the normal's components are all equal to sqrt(1/3) or whether or not at least one component is less than sqrt(1/3). Learned this trick from Peter Kutz. + // Find a direction that is not the normal based off of whether or not the normal's components are all equal to sqrt(1/3) or whether or not at least one component is less than sqrt(1/3). + //Learned this trick from Peter Kutz. glm::vec3 directionNotNormal; if (abs(normal.x) < SQRT_OF_ONE_THIRD) { @@ -91,16 +140,134 @@ __host__ __device__ glm::vec3 calculateRandomDirectionInHemisphere(glm::vec3 nor // non-cosine (uniform) weighted random direction generation. // This should be much easier than if you had to implement calculateRandomDirectionInHemisphere. __host__ __device__ glm::vec3 getRandomDirectionInSphere(float xi1, float xi2) { - return glm::vec3(0,0,0); + float alpha,beta; + alpha=xi1*2.0f*PI; + beta=xi2*2.0f*PI; + glm::vec3 D; + D=glm::vec3(cos(beta)*cos(alpha),cos(beta)*sin(alpha),sin(beta)); + return D; } +#define THRESHOLD 0.001f // TODO (PARTIALLY OPTIONAL): IMPLEMENT THIS FUNCTION // Returns 0 if diffuse scatter, 1 if reflected, 2 if transmitted. -__host__ __device__ int calculateBSDF(ray& r, glm::vec3 intersect, glm::vec3 normal, glm::vec3 emittedColor, - AbsorptionAndScatteringProperties& currentAbsorptionAndScattering, - glm::vec3& color, glm::vec3& unabsorbedColor, material m){ +__host__ __device__ int calculateBSDF(float randseed, ray& Ray, staticGeom* geoms,int ObjectID,glm::vec3 intersectPoint,glm::vec3 normal,material M) +{ - return 1; + thrust::default_random_engine rng(hash(randseed)); + thrust::uniform_real_distribution u01(0.0f,1.0f); + Fresnel fresnel; + + + float random_shift=0.01f*(float)u01(rng); + + if(M.hasReflective0.5f) + return -1; + } + t1=(-0.5f-ro.x)/rd.x; + t2=(0.5f-ro.x)/rd.x; + if(min(t1,t2)>Tnear) + Tnear=min(t1,t2); + if(max(t1,t2)Tfar||Tfar<0) + return -1; + //check for y-slab + if(rd.y==0.0f) + { + if(ro.y<-0.5f ||ro.y>0.5f) + return -1; + } + t1=(-0.5f-ro.y)/rd.y; + t2=(0.5f-ro.y)/rd.y; + if(min(t1,t2)>Tnear) + Tnear=min(t1,t2); + if(max(t1,t2)Tfar||Tfar<0) + return -1; + //check for z-slab + if(rd.z==0.0f) + { + if(ro.z<-0.5f ||ro.z>0.5f) + return -1; + } + t1=(-0.5f-ro.z)/rd.z; + t2=(0.5f-ro.z)/rd.z; + if(min(t1,t2)>Tnear) + Tnear=min(t1,t2); + if(max(t1,t2)Tfar||Tfar<0) + return -1; + + if(Tnear<0.001f) + Tnear=Tfar; + //return intersection point, normal vector and distance + glm::vec3 IPoint; + glm::vec3 INorm; + IPoint=getPointOnRay(rt,Tnear); + if(abs(IPoint.x-0.5f)<0.01f) + INorm=glm::vec3(1.0,0.0,0.0); + else if(abs(IPoint.x+0.5f)<0.01f) + INorm=glm::vec3(-1.0,0.0,0.0); + else if(abs(IPoint.y-0.5f)<0.01f) + INorm=glm::vec3(0.0,1.0,0.0); + else if(abs(IPoint.y+0.5f)<0.01f) + INorm=glm::vec3(0.0,-1.0,0.0); + else if(abs(IPoint.z-0.5f)<0.01f) + INorm=glm::vec3(0.0,0.0,1.0); + else if(abs(IPoint.z+0.5f)<0.01f) + INorm=glm::vec3(0.0,0.0,-1.0); + + glm::vec3 realItersectionPoint=multiplyMV(box.transform,glm::vec4(IPoint,1.0)); + intersectionPoint=realItersectionPoint; + normal=glm::normalize(multiplyMV(box.transform,glm::vec4(INorm,0.0))); + //return Tnear; + return glm::length(intersectionPoint-r.origin); - return -1; } // LOOK: Here's an intersection test example from a sphere. Now you just need to figure out cube and, optionally, triangle. @@ -177,8 +252,16 @@ __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float random // TODO: IMPLEMENT THIS FUNCTION // Generates a random point on a given sphere __host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float randomSeed){ + thrust::default_random_engine rng(hash(randomSeed)); + thrust::uniform_real_distribution u01(0,TWO_PI); + thrust::uniform_real_distribution u02(0,PI); - return glm::vec3(0,0,0); + float alpha,beta; + alpha=(float)u01(rng); + beta=(float)u02(rng); + glm::vec3 P_sphere(cos(beta)*cos(alpha),cos(beta)*sin(alpha),sin(beta)); + glm::vec3 P_global=multiplyMV(sphere.transform,glm::vec4(P_sphere,1.0f)); + return P_global; } #endif diff --git a/src/main.cpp b/src/main.cpp index b002500..7a4ed41 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,6 +36,7 @@ int main(int argc, char** argv){ if(!loadedScene){ cout << "Error: scene file needed!" << endl; + getchar(); return 0; } @@ -44,6 +45,7 @@ int main(int argc, char** argv){ renderCam = &renderScene->renderCam; width = renderCam->resolution[0]; height = renderCam->resolution[1]; + if(targetFrame >= renderCam->frames){ cout << "Warning: Specified target frame is out of range, defaulting to frame 0." << endl; @@ -52,10 +54,10 @@ int main(int argc, char** argv){ // Initialize CUDA and GL components if (init(argc, argv)) { + // GLFW main loop mainLoop(); } - return 0; } @@ -168,8 +170,8 @@ bool init(int argc, char* argv[]) { return false; } - width = 800; - height = 800; + width = renderCam->resolution.x; + height = renderCam->resolution.y; window = glfwCreateWindow(width, height, "CIS 565 Pathtracer", NULL, NULL); if (!window){ glfwTerminate(); diff --git a/src/raytraceKernel.cu b/src/raytraceKernel.cu index 9c7bc7d..6759431 100644 --- a/src/raytraceKernel.cu +++ b/src/raytraceKernel.cu @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include "sceneStructs.h" #include "glm/glm.hpp" @@ -16,6 +19,14 @@ #include "intersections.h" #include "interactions.h" + +#define MAX_TRAVEL_DIST 9999999.99f +#define ENABLE_AA 1 +#define ENABLE_MOTION_BLUR 0 +#define ENABLE_DOF 1 +#define APERTURE_RADIUS 0.1f +#define FOCALLEN_LENGTH 1.1f + void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); if( cudaSuccess != err) { @@ -24,23 +35,48 @@ void checkCUDAError(const char *msg) { } } -// 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){ - int index = x + (y * resolution.x); - - thrust::default_random_engine rng(hash(index*time)); - thrust::uniform_real_distribution u01(0,1); - - return glm::vec3((float) u01(rng), (float) u01(rng), (float) u01(rng)); -} // 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){ ray r; - r.origin = glm::vec3(0,0,0); - r.direction = glm::vec3(0,0,-1); + r.origin = eye; + glm::vec3 image_x_direction=glm::cross(view,up); + glm::vec3 image_y_direction=-up; + glm::vec3 image_center=eye+view; + float px=float(x); + float py=float(y); + + if(ENABLE_DOF) + { + thrust::default_random_engine rng(hash(time+1.0f)); + thrust::uniform_real_distribution u01(-1.0f,1.0f); + r.origin=r.origin+u01(rng)*image_x_direction*APERTURE_RADIUS; + r.origin=r.origin+u01(rng)*image_y_direction*APERTURE_RADIUS; + image_center=eye+FOCALLEN_LENGTH*view; + } + + + //http://en.wikipedia.org/wiki/Supersampling for Anti Aliasing + if(ENABLE_AA) + { + thrust::default_random_engine rng(hash((time+1.0f)*(px+2.0f)*(py+3.0f))); + thrust::uniform_real_distribution u01(-1.5f,1.5f); + px=px+u01(rng); + py=py+u01(rng); + } + float image_x=((float)px-(float)resolution.x/2)/((float)resolution.x/2); + float image_y=((float)py-(float)resolution.y/2)/((float)resolution.y/2); + + + + + float angle_x=fov.x; + float angle_y=fov.y; + glm::vec3 image_pos=image_center+image_x*glm::length(view)*tan(angle_x)*glm::normalize(image_x_direction)+image_y*glm::length(view)*tan(angle_y)*glm::normalize(image_y_direction); + glm::vec3 ray_direction=glm::normalize(image_pos-eye); + r.direction=ray_direction; + r.travel_dist=0; return r; } @@ -88,37 +124,169 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* } } -// 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){ - int x = (blockIdx.x * blockDim.x) + threadIdx.x; - int y = (blockIdx.y * blockDim.y) + threadIdx.y; + + + + + + +// 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){ int index = x + (y * resolution.x); + + thrust::default_random_engine rng(hash(index*time)); + thrust::uniform_real_distribution u01(0,1); + + return glm::vec3((float) u01(rng), (float) u01(rng), (float) u01(rng)); +} + + + + +__global__ void InitRays(ray* activeRays, 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; + if(x<=resolution.x && y<=resolution.y) + { + ray newRay=raycastFromCameraKernel(resolution,time,x,y,cam.position,cam.view,cam.up,cam.fov*(float)PI/180.0f); + newRay.color=glm::vec3(1.0f); + newRay.is_Active=true; + newRay.index=index; + activeRays[index]=newRay; + } +} + +__global__ void average_image(glm::vec2 resolution,float time,glm::vec3* current_image,glm::vec3* final_image) +{ + int x=blockIdx.x*blockDim.x+threadIdx.x; + int y=blockIdx.y*blockDim.y+threadIdx.y; + int index=x+y*resolution.x; + if(x<=resolution.x && y<=resolution.y) + { + //final_image[index]=current_image[index]/(float)time+final_image[index]*(time-1)/(float)time; + + final_image[index]=current_image[index]/(float)time+final_image[index]*(time-1)/(float)time; + glm::clamp(final_image[index],0.0f,1.0f); + + } - if((x<=resolution.x && y<=resolution.y)){ - colors[index] = generateRandomNumberFromThread(resolution, time, x, y); +} + + + + +// TODO: IMPLEMENT THIS FUNCTION +// Core raytracer kernel +__global__ void raytraceRay(ray* activeRays,int N,int current_depth,glm::vec2 resolution, float time, cameraData cam, glm::vec3* colors, + staticGeom* geoms, int numberOfGeoms, material* materials, int numberOfMaterials){ + int index = blockIdx.x*blockDim.x+threadIdx.x; + + if(index0.0f && d=MAX_TRAVEL_DIST) + { + activeRays[index].is_Active=false; + return; + } + material M=materials[MaterialID]; + activeRays[index].travel_dist+=travelDist; + if(M.emittance>0.001f) + { + colors[activeRays[index].index]=exp(-0.05f*activeRays[index].travel_dist)*M.emittance*M.color*activeRays[index].color; + activeRays[index].is_Active=false; + return; + } + else + { + float randSeed=((float)time+1.0f)*((float)index+2.0f)*((float)current_depth+3.0f); + //int flag; + //flag=calculateBSDF(randSeed, activeRays[index], geoms,ObjectID,intersectionPoint,normal,M); + /*if(flag==0) + { + activeRays[index].color=glm::vec3(1.0f,0.0f,0.0f); + } + else if(flag==1) + { + activeRays[index].color=glm::vec3(0.0f,1.0f,0.0f); + } + else + { + activeRays[index].color=glm::vec3(0.0f,0.0f,1.0f); + }*/ + calculateBSDF(randSeed, activeRays[index], geoms,ObjectID,intersectionPoint,normal,M); + return; + } + + } + else + { + return; + } } } + + +//helper function for stream compact +struct ray_isActive +{ + __host__ __device__ bool operator()(const ray Ray) + { + return !Ray.is_Active; + } +}; + + // 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 - - // 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); - + //send current image to GPU + glm::vec3* current_cudaimage = NULL; + cudaMalloc((void**)¤t_cudaimage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3)); + cudaMemcpy( current_cudaimage, renderCam->image, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyHostToDevice); + + + + //send rays to GPU + ray* activeRays=NULL; + int Num_rays=renderCam->resolution.x*renderCam->resolution.y; + cudaMalloc((void**)&activeRays,Num_rays*sizeof(ray)); + + // package geometry and materials and sent to GPU staticGeom* geomList = new staticGeom[numberOfGeoms]; for(int i=0; iresolution; @@ -144,9 +328,43 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio cam.view = renderCam->views[frame]; cam.up = renderCam->ups[frame]; cam.fov = renderCam->fov; + + + + + + + + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool stream_compact=false; + int traceDepth=10; + // set up crucial magic + int tileSize = 16; + dim3 threadsPerBlock(tileSize, tileSize); + dim3 fullBlocksPerGrid((int)ceil(float(renderCam->resolution.x)/float(tileSize)), (int)ceil(float(renderCam->resolution.y)/float(tileSize))); + + InitRays<<>>(activeRays, renderCam->resolution,(float)iterations,cam); // kernel launches - raytraceRay<<>>(renderCam->resolution, (float)iterations, cam, traceDepth, cudaimage, cudageoms, numberOfGeoms); + int blockSize=64; + for(int i=0;i current_rays(activeRays); + thrust::device_ptr new_rays=thrust::remove_if(current_rays,current_rays+Num_rays,ray_isActive()); + Num_rays=new_rays.get()-current_rays.get(); + //printf("%d\n",Num_rays); + if(Num_rays<1.0f) + break; + } + raytraceRay<<>>(activeRays,Num_rays,i,renderCam->resolution, (float)iterations, cam, current_cudaimage, cudageoms, numberOfGeoms,cudamaterials,numberOfMaterials); + } + + + average_image<<>>(renderCam->resolution,(float)iterations,current_cudaimage,cudaimage); + sendImageToPBO<<>>(PBOpos, renderCam->resolution, cudaimage); @@ -156,6 +374,8 @@ 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 ); + cudaFree(current_cudaimage); + cudaFree(activeRays); delete geomList; // make certain the kernel has completed diff --git a/src/sceneStructs.h b/src/sceneStructs.h index 5e0c853..9f42bc2 100644 --- a/src/sceneStructs.h +++ b/src/sceneStructs.h @@ -16,6 +16,18 @@ enum GEOMTYPE{ SPHERE, CUBE, MESH }; struct ray { glm::vec3 origin; glm::vec3 direction; + glm::vec3 color; + bool is_Active; + int index; + float travel_dist; +}; + +struct rayPool { + ray ray; + glm::vec3 colors; + float coefficient; + int index; + bool isTerminated; }; struct geom { diff --git a/src/utilities.cpp b/src/utilities.cpp index a8e5d90..e657d59 100755 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -72,9 +72,9 @@ 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)); + glm::mat4 rotationMat = glm::rotate(glm::mat4(), rotation.x*(float)PI/180.0f, glm::vec3(1,0,0)); + rotationMat = rotationMat*glm::rotate(glm::mat4(), rotation.y*(float)PI/180.0f, glm::vec3(0,1,0)); + rotationMat = rotationMat*glm::rotate(glm::mat4(), rotation.z*(float)PI/180.0f, 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..a3f40b4 100644 --- a/src/utilities.h +++ b/src/utilities.h @@ -25,6 +25,7 @@ #define ZERO_ABSORPTION_EPSILON 0.00001 #define RAY_BIAS_AMOUNT 0.0002 + 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/Project3-Pathtracer.vcxproj b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj index c45dd79..a493958 100644 --- a/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj +++ b/windows/Project3-Pathtracer/Project3-Pathtracer/Project3-Pathtracer.vcxproj @@ -1,100 +1,106 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - {B7AAC719-5B66-4370-9FD7-8ED6DB66347B} - Project3Pathtracer - - - - Application - true - MultiByte - - - Application - false - true - MultiByte - - - - - - - - - - - - - - - - Level3 - Disabled - $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) - - - true - $(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) - cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) - Console - - - - - Level3 - MaxSpeed - true - true - $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) - - - true - true - true - $(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) - cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) - Console - - - - - - - - - - - - - - - - - - - - - - - - - Document - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + + {B7AAC719-5B66-4370-9FD7-8ED6DB66347B} + Project3Pathtracer + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + + + + Level3 + Disabled + $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) + + + true + $(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) + cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) + Console + + + $(ProjectDir)%(Filename)%(Extension).obj + + + + + Level3 + MaxSpeed + true + true + $(SolutionDir)/../../external/include/;%(AdditionalIncludeDirectories) + + + true + true + true + $(SolutionDir)/../../external/lib/win/GLFW/;$(SolutionDir)/../../external/lib/win/GL/;%(AdditionalLibraryDirectories) + cudart.lib;glew32s.lib;glfw3.lib;opengl32.lib;%(AdditionalDependencies) + Console + + + $(ProjectDir)%(Filename)%(Extension).obj + + + + + + + + + + + + + + + + + + + + + + + + + Document + + + + + + \ No newline at end of file diff --git a/wiredREsult_with_randSeed2.png b/wiredREsult_with_randSeed2.png new file mode 100755 index 0000000..503ca00 Binary files /dev/null and b/wiredREsult_with_randSeed2.png differ diff --git a/wiredResult_with_randSeed1.png b/wiredResult_with_randSeed1.png new file mode 100755 index 0000000..6cd7fd8 Binary files /dev/null and b/wiredResult_with_randSeed1.png differ