diff --git a/README.md b/README.md index cbc1dce..97d8674 100755 --- a/README.md +++ b/README.md @@ -1,115 +1,139 @@ -------------------------------------------------------------------------------- -CIS565: Project 2: CUDA Pathtracer -------------------------------------------------------------------------------- -Fall 2012 -------------------------------------------------------------------------------- -Due Friday, 10/12/2012 -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- -NOTE: -------------------------------------------------------------------------------- -This project requires an NVIDIA graphics card with CUDA capability! Any card after the Geforce 8xxx series will work. If you do not have an NVIDIA graphics card in the machine you are working on, feel free to use any machine in the SIG Lab or in Moore100 labs. All machines in the SIG Lab and Moore100 are equipped with CUDA capable NVIDIA graphics cards. If this too proves to be a problem, please contact Patrick or Karl as soon as possible. - -------------------------------------------------------------------------------- -INTRODUCTION: -------------------------------------------------------------------------------- -In this project, you will extend your raytracer from Project 1 into a full CUDA based global illumination pathtracer. - -For this project, you may either choose to continue working off of your codebase from Project 1, or you may choose to use the included basecode in this repository. The basecode for Project 2 is the same as the basecode for Project 1, but with some missing components you will need filled in, such as the intersection testing and camera raycasting methods. - -How you choose to extend your raytracer into a pathtracer is a fairly open-ended problem; the supplied basecode is meant to serve as one possible set of guidelines for doing so, but you may choose any approach you want in your actual implementation, including completely scrapping the provided basecode in favor of your own from-scratch solution. - -------------------------------------------------------------------------------- -CONTENTS: -------------------------------------------------------------------------------- -The Project2 root directory contains the following subdirectories: - -* src/ contains the source code for the project. Both the Windows Visual Studio solution and the OSX makefile reference this folder for all source; the base source code compiles on OSX and Windows without modification. -* scenes/ contains an example scene description file. -* renders/ contains two example renders: the raytraced render from Project 1 (GI_no.bmp), and the same scene rendered with global illumination (GI_yes.bmp). -* PROJ1_WIN/ contains a Windows Visual Studio 2010 project and all dependencies needed for building and running on Windows 7. -* PROJ1_OSX/ contains a OSX makefile, run script, and all dependencies needed for building and running on Mac OSX 10.8. - -The Windows and OSX versions of the project build and run exactly the same way as in Project0 and Project1. - -------------------------------------------------------------------------------- -REQUIREMENTS: -------------------------------------------------------------------------------- -In this project, you are given code for: - -* All of the basecode from Project 1, plus: -* Intersection testing code for spheres and cubes -* Code for raycasting from the camera - -You will need to implement the following features. A number of these required features you may have already implemented in Project 1. If you have, you are ahead of the curve and have less work to do! - -* Full global illumination (including soft shadows, color bleeding, etc.) by pathtracing rays through the scene. -* Properly accumulating emittance and colors to generate a final image -* Supersampled antialiasing -* Parallelization by ray instead of by pixel via string compaction (see the Physically-based shading and pathtracing lecture slides from 09/24 if you don't know what this refers to) -* Perfect specular reflection - -You are also required to implement at least two of the following features. Some of these features you may have already implemented in Project 1. If you have, you may NOT resubmit those features and instead must pick two new ones to implement. - -* Additional BRDF models, such as Cook-Torrance, Ward, etc. Each BRDF model may count as a separate feature. -* Texture mapping -* Bump mapping -* Translational motion blur -* Fresnel-based Refraction, i.e. glass -* OBJ Mesh loading and rendering without KD-Tree -* Interactive camera -* Integrate an existing stackless KD-Tree library, such as CUKD (https://github.com/unvirtual/cukd) -* Depth of field - -Alternatively, implementing just one of the following features can satisfy the "pick two" feature requirement, since these are correspondingly more difficult problems: - -* Physically based subsurface scattering and transmission -* Implement and integrate your own stackless KD-Tree from scratch. -* Displacement mapping -* Deformational motion blur - -As yet another alternative, if you have a feature or features you really want to implement that are not on this list, let us know, and we'll probably say yes! - -------------------------------------------------------------------------------- -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. - -------------------------------------------------------------------------------- -BLOG -------------------------------------------------------------------------------- -As mentioned in class, all students should have student blogs detailing progress on projects. If you already have a blog, you can use it; otherwise, please create a blog using www.blogger.com or any other tool, such as www.wordpress.org. Blog posts on your project are due on the SAME DAY as the project, and should include: - -* A brief description of the project and the specific features you implemented. -* A link to your github repo if the code is open source. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx - -------------------------------------------------------------------------------- -THIRD PARTY CODE POLICY -------------------------------------------------------------------------------- -* Use of any third-party code must be approved by asking on Piazza. 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 Karl, yiningli@seas.upenn.edu, 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 -------------------------------------------------------------------------------- -As with the previous project, you should fork this project and work inside of your fork. Upon completion, commit your finished project back to your fork, and make a pull request to the master repository. -You should include a README.md file in the root directory detailing the following - -* A brief description of the project and specific features you implemented -* At least one screenshot of your project running, and at least one screenshot of the final rendered output of your pathtracer -* Instructions for building and running your project if they differ from the base code -* A link to your blog post detailing the project +------------------------------------------------------------------------------- +Assignment Submission +------------------------------------------------------------------------------- +Funtionality implemented: +* Full global illumination (including soft shadows, color bleeding, etc.) by pathtracing rays through the scene. +* Properly accumulating emittance and colors to generate a final image +* Supersampled antialiasing +* Parallelization by ray instead of by pixel via string compaction (see the Physically-based shading and pathtracing lecture slides from 09/24 if you don't know what this refers to) +* Perfect specular reflection + +Additional Features implemented: +* Fresnel-based Refraction, i.e. glass +* Depth of field - implemented it but could not get the effects properly. Hence removed it. + + + +------------------------------------------------------------------------------- +Blog: +------------------------------------------------------------------------------- + http://cudapathtacer.blogspot.com/ + + + + +------------------------------------------------------------------------------- +CIS565: Project 2: CUDA Pathtracer +------------------------------------------------------------------------------- +Fall 2012 +------------------------------------------------------------------------------- +Due Friday, 10/12/2012 +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +NOTE: +------------------------------------------------------------------------------- +This project requires an NVIDIA graphics card with CUDA capability! Any card after the Geforce 8xxx series will work. If you do not have an NVIDIA graphics card in the machine you are working on, feel free to use any machine in the SIG Lab or in Moore100 labs. All machines in the SIG Lab and Moore100 are equipped with CUDA capable NVIDIA graphics cards. If this too proves to be a problem, please contact Patrick or Karl as soon as possible. + +------------------------------------------------------------------------------- +INTRODUCTION: +------------------------------------------------------------------------------- +In this project, you will extend your raytracer from Project 1 into a full CUDA based global illumination pathtracer. + +For this project, you may either choose to continue working off of your codebase from Project 1, or you may choose to use the included basecode in this repository. The basecode for Project 2 is the same as the basecode for Project 1, but with some missing components you will need filled in, such as the intersection testing and camera raycasting methods. + +How you choose to extend your raytracer into a pathtracer is a fairly open-ended problem; the supplied basecode is meant to serve as one possible set of guidelines for doing so, but you may choose any approach you want in your actual implementation, including completely scrapping the provided basecode in favor of your own from-scratch solution. + +------------------------------------------------------------------------------- +CONTENTS: +------------------------------------------------------------------------------- +The Project2 root directory contains the following subdirectories: + +* src/ contains the source code for the project. Both the Windows Visual Studio solution and the OSX makefile reference this folder for all source; the base source code compiles on OSX and Windows without modification. +* scenes/ contains an example scene description file. +* renders/ contains two example renders: the raytraced render from Project 1 (GI_no.bmp), and the same scene rendered with global illumination (GI_yes.bmp). +* PROJ1_WIN/ contains a Windows Visual Studio 2010 project and all dependencies needed for building and running on Windows 7. +* PROJ1_OSX/ contains a OSX makefile, run script, and all dependencies needed for building and running on Mac OSX 10.8. + +The Windows and OSX versions of the project build and run exactly the same way as in Project0 and Project1. + +------------------------------------------------------------------------------- +REQUIREMENTS: +------------------------------------------------------------------------------- +In this project, you are given code for: + +* All of the basecode from Project 1, plus: +* Intersection testing code for spheres and cubes +* Code for raycasting from the camera + +You will need to implement the following features. A number of these required features you may have already implemented in Project 1. If you have, you are ahead of the curve and have less work to do! + +* Full global illumination (including soft shadows, color bleeding, etc.) by pathtracing rays through the scene. +* Properly accumulating emittance and colors to generate a final image +* Supersampled antialiasing +* Parallelization by ray instead of by pixel via string compaction (see the Physically-based shading and pathtracing lecture slides from 09/24 if you don't know what this refers to) +* Perfect specular reflection + +You are also required to implement at least two of the following features. Some of these features you may have already implemented in Project 1. If you have, you may NOT resubmit those features and instead must pick two new ones to implement. + +* Additional BRDF models, such as Cook-Torrance, Ward, etc. Each BRDF model may count as a separate feature. +* Texture mapping +* Bump mapping +* Translational motion blur +* Fresnel-based Refraction, i.e. glass +* OBJ Mesh loading and rendering without KD-Tree +* Interactive camera +* Integrate an existing stackless KD-Tree library, such as CUKD (https://github.com/unvirtual/cukd) +* Depth of field + +Alternatively, implementing just one of the following features can satisfy the "pick two" feature requirement, since these are correspondingly more difficult problems: + +* Physically based subsurface scattering and transmission +* Implement and integrate your own stackless KD-Tree from scratch. +* Displacement mapping +* Deformational motion blur + +As yet another alternative, if you have a feature or features you really want to implement that are not on this list, let us know, and we'll probably say yes! + +------------------------------------------------------------------------------- +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. + +------------------------------------------------------------------------------- +BLOG +------------------------------------------------------------------------------- +As mentioned in class, all students should have student blogs detailing progress on projects. If you already have a blog, you can use it; otherwise, please create a blog using www.blogger.com or any other tool, such as www.wordpress.org. Blog posts on your project are due on the SAME DAY as the project, and should include: + +* A brief description of the project and the specific features you implemented. +* A link to your github repo if the code is open source. +* At least one screenshot of your project running. +* A 30 second or longer video of your project running. To create the video use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx + +------------------------------------------------------------------------------- +THIRD PARTY CODE POLICY +------------------------------------------------------------------------------- +* Use of any third-party code must be approved by asking on Piazza. 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 Karl, yiningli@seas.upenn.edu, 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 +------------------------------------------------------------------------------- +As with the previous project, you should fork this project and work inside of your fork. Upon completion, commit your finished project back to your fork, and make a pull request to the master repository. +You should include a README.md file in the root directory detailing the following + +* A brief description of the project and specific features you implemented +* At least one screenshot of your project running, and at least one screenshot of the final rendered output of your pathtracer +* Instructions for building and running your project if they differ from the base code +* A link to your blog post detailing the project * A list of all third-party code used \ No newline at end of file diff --git a/renders/ScreenShotProjectRunning.png b/renders/ScreenShotProjectRunning.png new file mode 100644 index 0000000..2d34063 Binary files /dev/null and b/renders/ScreenShotProjectRunning.png differ diff --git a/renders/pathtracerRefractionReflection787.png b/renders/pathtracerRefractionReflection787.png new file mode 100644 index 0000000..0486057 Binary files /dev/null and b/renders/pathtracerRefractionReflection787.png differ diff --git a/scenes/sampleScene.txt b/scenes/sampleScene.txt index 936135b..315565a 100755 --- a/scenes/sampleScene.txt +++ b/scenes/sampleScene.txt @@ -1,229 +1,247 @@ -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 renders/sampleScene.bmp -frame 0 -EYE 0 4.5 12 -VIEW 0 0 -1 -UP 0 1 0 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -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 -frame 1 -TRANS 0 10 0 -ROTAT 0 0 90 -SCALE .3 3 3 \ No newline at end of file +MATERIAL 0 //white diffuse +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 0 +TEXTURE 0 +AREALIGHT 0 + +MATERIAL 1 //red diffuse +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 1 0 +RSCTCOEFF 0 +EMITTANCE 0 +TEXTURE 0 +AREALIGHT 0 + +MATERIAL 2 //green diffuse +RGB .15 .48 .09 +SPECEX 0 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 0 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 +TEXTURE 0 +AREALIGHT 0 + +MATERIAL 3 //red glossy +RGB .63 .06 .04 +SPECEX 0 +SPECRGB 1 1 1 +REFL 1 +REFR 1 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 +TEXTURE 0 +AREALIGHT 0 + +MATERIAL 4 //white glossy +RGB 0 0 1 +SPECEX 10 +SPECRGB 0 0 0 +REFL 0 +REFR 0 +REFRIOR 2 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 +TEXTURE 0 +AREALIGHT 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 +TEXTURE 0 +AREALIGHT 0 + +MATERIAL 6 //green glossy +RGB .15 .48 .09 +SPECEX 12 +SPECRGB 1 1 1 +REFL 0 +REFR 0 +REFRIOR 2.3 +SCATTER 0 +ABSCOEFF 0 0 0 +RSCTCOEFF 0 +EMITTANCE 0 +TEXTURE 0 +AREALIGHT 1 + +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 +TEXTURE 0 +AREALIGHT 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 +TEXTURE 0 +AREALIGHT 1 + +CAMERA +RES 800 800 +FOVY 25 +ITERATIONS 10000 +FILE renders/sampleScene.bmp +frame 0 +EYE 0 5 12 +VIEW 0 0 -1 +UP 0 1 0 +frame 1 +EYE 0 4.5 18 +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 +frame 1 +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 +frame 1 +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 +frame 1 +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 +frame 1 +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 +frame 1 +TRANS 5 5 0 +ROTAT 0 0 0 +SCALE .01 10 10 + +OBJECT 5 +sphere +material 2 +frame 0 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 +frame 1 +TRANS 0 2 0 +ROTAT 0 180 0 +SCALE 3 3 3 + +OBJECT 6 +sphere +material 3 +frame 0 +TRANS 2 3 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 +frame 1 +TRANS 2 3 2 +ROTAT 0 180 0 +SCALE 2.5 2.5 2.5 + +OBJECT 7 +sphere +material 4 +frame 0 +TRANS 2 4 -4 +ROTAT 0 180 0 +SCALE 2 2 2 +frame 1 +TRANS 2 4 -4 +ROTAT 0 180 0 +SCALE 2 2 2 + +OBJECT 8 +cube +material 8 +frame 0 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 +frame 1 +TRANS 0 10 0 +ROTAT 0 0 90 +SCALE .3 3 3 diff --git a/src/interactions.h b/src/interactions.h index e18cfff..673c408 100755 --- a/src/interactions.h +++ b/src/interactions.h @@ -29,7 +29,11 @@ __host__ __device__ glm::vec3 calculateRandomDirectionInHemisphere(glm::vec3 nor //TODO (OPTIONAL): IMPLEMENT THIS FUNCTION __host__ __device__ glm::vec3 calculateTransmission(glm::vec3 absorptionCoefficient, float distance) { - return glm::vec3(0,0,0); + + glm::vec3 transmitted; + + return transmitted; + } //TODO (OPTIONAL): IMPLEMENT THIS FUNCTION @@ -40,22 +44,61 @@ __host__ __device__ bool calculateScatterAndAbsorption(ray& r, float& depth, Ab //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); +/* float cosAngle = glm::dot( normal, incident); + float n = incidentIOR / transmittedIOR; + float secondTerm = 1.0f - n * n * (1.0f - cosAngle * cosAngle); + + if (secondTerm >= 0.0f) + { + return (n * incident) - (n * cosAngle + sqrtf( secondTerm )) * normal; + } + + return glm::vec3(0);*/ + + float cosAngle = glm::dot(normal, incident); + + float n = incidentIOR / transmittedIOR; + + float secondTerm = 1 - pow(n, 2) * (1 - pow(cosAngle, 2)); + if (secondTerm < 0) + return glm::vec3(0); + float cosAngle2 = sqrt(secondTerm); + + if (cosAngle > 0) { + return glm::normalize(normal*(n*cosAngle - cosAngle2) + incident*n); + } else { + return glm::normalize(normal*(-n*cosAngle + cosAngle2) + incident*n); + } + + + } //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 incident - 2.0f * glm::dot(normal, incident) * 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; + + if (incidentIOR <= 0 && transmittedIOR <= 0 ) { + fresnel.reflectionCoefficient = 1; + fresnel.transmissionCoefficient = 0; + return fresnel; + }else{ + float cosThetaI = glm::dot(normal, incident); + float sinIncidence = sqrt(1-pow(cosThetaI,2)); + float cosThetaT = sqrt(1-pow(((incidentIOR/transmittedIOR)*sinIncidence),2)); + float RsP = pow( (incidentIOR * cosThetaI - transmittedIOR * cosThetaT) / (incidentIOR * cosThetaI + transmittedIOR * cosThetaT) , 2); + float RpP = pow( (incidentIOR * cosThetaT - transmittedIOR * cosThetaI) / (incidentIOR * cosThetaT + transmittedIOR * cosThetaI) , 2); + fresnel.reflectionCoefficient = (RsP + RpP) / 2.0; + fresnel.transmissionCoefficient = 1 - fresnel.reflectionCoefficient; + return fresnel; + } - fresnel.reflectionCoefficient = 1; - fresnel.transmissionCoefficient = 0; - return fresnel; } //LOOK: This function demonstrates cosine weighted random direction generation in a sphere! @@ -90,7 +133,21 @@ __host__ __device__ glm::vec3 calculateRandomDirectionInHemisphere(glm::vec3 nor //Now that you know how cosine weighted direction generation works, try implementing 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 theta = TWO_PI * xi1; + float phi = acos(2*xi2 -1); + + float x = cos(theta) * sin(phi); + float y = sin(theta) * sin(phi); + float z = cos(phi); + + return glm::vec3(x,y,z); + + + + } //TODO (PARTIALLY OPTIONAL): IMPLEMENT THIS FUNCTION diff --git a/src/intersections.h b/src/intersections.h index 714e918..3650a42 100755 --- a/src/intersections.h +++ b/src/intersections.h @@ -23,7 +23,7 @@ __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm:: __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float randomSeed); //Handy dandy little hashing function that provides seeds for random number generation -__host__ __device__ unsigned int hash(unsigned int a){ +__host__ __device__ unsigned int hashF(unsigned int a){ a = (a+0x7ed55d16) + (a<<12); a = (a^0xc761c23c) ^ (a>>19); a = (a+0x165667b1) + (a<<5); @@ -33,6 +33,8 @@ __host__ __device__ unsigned int hash(unsigned int a){ return a; } + + //Quick and dirty epsilon check __host__ __device__ bool epsilonCheck(float a, float b){ if(fabs(fabs(a)-fabs(b)) tymax) || (tymin > tmax) ){ - return -1; - } - if (tymin > tmin){ - tmin = tymin; - } - if (tymax < tmax){ - tmax = tymax; - } - - if((int)rsign.z==0){ - tzmin = (boxMin.z - r.origin.z) * rInverseDirection.z; - tzmax = (boxMax.z - r.origin.z) * rInverseDirection.z; - }else{ - tzmin = (boxMax.z - r.origin.z) * rInverseDirection.z; - tzmax = (boxMin.z - r.origin.z) * rInverseDirection.z; - } - - if ( (tmin > tzmax) || (tzmin > tmax) ){ - return -1; - } - if (tzmin > tmin){ - tmin = tzmin; - } - if (tzmax < tmax){ - tmax = tzmax; - } - if(tmin<0){ - return -1; - } - - glm::vec3 osintersect = r.origin + tmin*r.direction; - - if(abs(osintersect.x-abs(boxMax.x))<.001){ - currentNormal = glm::vec3(1,0,0); - }else if(abs(osintersect.y-abs(boxMax.y))<.001){ - currentNormal = glm::vec3(0,1,0); - }else if(abs(osintersect.z-abs(boxMax.z))<.001){ - currentNormal = glm::vec3(0,0,1); - }else if(abs(osintersect.x+abs(boxMin.x))<.001){ - currentNormal = glm::vec3(-1,0,0); - }else if(abs(osintersect.y+abs(boxMin.y))<.001){ - currentNormal = glm::vec3(0,-1,0); - }else if(abs(osintersect.z+abs(boxMin.z))<.001){ - currentNormal = glm::vec3(0,0,-1); - } - - intersectionPoint = multiplyMV(box.transform, glm::vec4(osintersect, 1.0)); - - - - normal = multiplyMV(box.transform, glm::vec4(currentNormal,0.0)); - return glm::length(intersectionPoint-ro.origin); + + glm::vec3 ro = multiplyMV(box.inverseTransform, glm::vec4(r.origin,1.0f)); + glm::vec3 rd = glm::normalize(multiplyMV(box.inverseTransform, glm::vec4(r.direction,0.0f))); + + ray rt; rt.origin = ro; rt.direction = rd; + + glm::vec3 bl, bh; + bl = glm::vec3(-0.5, -0.5, -0.5); + bh = glm::vec3(0.5, 0.5, 0.5); + + int coordN=0; // = 0 si X, = 1 si Y, = 2 si Z + int coordF=0; // = 0 si X, = 1 si Y, = 2 si Z + + double tnear, tfar, t1, t2, temp; + tnear = -1000000.0; + tfar = 1000000.0; + float epsilon = 0.001; + if(abs(rd.x) <= epsilon && (ro.x < bl.x || ro.x > bh.x)) + return -1; + + else + { + t1 = (bl.x - ro.x)/rd.x; + t2 = (bh.x - ro.x)/rd.x; + + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + + if(t1 > tnear) + { + coordN = 0; + tnear = t1; + } + + if(t2 < tfar){ + coordF = 0; + tfar = t2; + } + + if(tnear > tfar) + return -1; + + if(tfar < epsilon) + return -1; + } + + if(abs(rd.y) <= epsilon && (ro.y < bl.y || ro.y > bh.y)) + return -1; + + else + { + t1 = (bl.y - ro.y)/rd.y; + t2 = (bh.y - ro.y)/rd.y; + + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + + if(t1 > tnear){ + coordN = 1; + tnear = t1; + } + + if(t2 < tfar){ + coordF = 1; + tfar = t2; + } + + if(tnear > tfar) + return -1; + + if(tfar < epsilon) + return -1; + } + + if(abs(rd.z) <= epsilon && (ro.z < bl.z || ro.z > bh.z)) + return -1; + + else + { + t1 = (bl.z - ro.z)/rd.z; + t2 = (bh.z - ro.z)/rd.z; + + if(t1 > t2) + { + temp = t1; + t1 = t2; + t2 = temp; + } + + if(t1 > tnear){ + coordN = 2; + tnear = t1; + } + + if(t2 < tfar){ + coordF = 2; + tfar = t2; + } + + if(tnear > tfar) + return -1; + + if(tfar < epsilon) + return -1; + } + + if(abs(tnear) < epsilon) + return -1; + float epsilon1= 0.003; + if(tnear < tfar) + { + glm::vec3 point = glm::vec3(ro.x + tnear*rd.x, ro.y + tnear*rd.y, ro.z + tnear*rd.z); + glm::vec4 norm = glm::vec4(0.0,0.0,0.0,0.0); + if(fabs( point.x - 0.5 ) < epsilon1) + norm = glm::vec4(1.0, 0.0, 0.0, 0.0); + + if(fabs( point.x + 0.5 ) < epsilon1) + norm = glm::vec4(-1.0, 0.0, 0.0,0.0); + + if( fabs( point.y - 0.5 ) < epsilon1 ) + norm = glm::vec4(0.0, 1.0, 0.0, 0.0); + + if( fabs( point.y + 0.5 ) < epsilon1 ) + norm = glm::vec4(0.0, -1.0, 0.0, 0.0); + + if(fabs( point.z - 0.5 ) < epsilon1) + norm = glm::vec4(0.0, 0.0, 1.0, 0.0); + + if(fabs( point.z + 0.5 ) < epsilon1) + norm = glm::vec4(0.0, 0.0, -1.0, 0.0); + + normal = glm::normalize(multiplyMV(box.transform, glm::vec4(norm.x,norm.y,norm.z,0.0))); + + glm::vec3 realIntersectionPoint = multiplyMV(box.transform, glm::vec4(getPointOnRay(rt, tnear), 1.0)); + glm::vec3 realOrigin = multiplyMV(box.transform, glm::vec4(0,0,0,1)); + intersectionPoint = realIntersectionPoint; + + return glm::length(r.origin - realIntersectionPoint); + + } + + if(abs(tfar) < epsilon) + return -1; + + if(tfar > epsilon) + { + glm::vec3 point = glm::vec3(ro.x + tfar*rd.x, ro.y + tfar*rd.y, ro.z + tfar*rd.z); + glm::vec4 norm = glm::vec4(0.0,0.0,0.0,0.0); + if(fabs( point.x - 0.5 ) < epsilon1) + norm = glm::vec4(1.0, 0.0, 0.0, 0.0); + + if(fabs( point.x + 0.5 ) < epsilon1) + norm = glm::vec4(-1.0, 0.0, 0.0, 0.0); + + if( fabs( point.y - 0.5 ) < epsilon1 ) + norm = glm::vec4(0.0, 1.0, 0.0, 0.0); + + if( fabs( point.y + 0.5 ) < epsilon1 ) + norm = glm::vec4(0.0, -1.0, 0.0, 0.0); + + if(fabs( point.z - 0.5 ) < epsilon1) + norm = glm::vec4(0.0, 0.0, 1.0, 0.0); + + if(fabs( point.z + 0.5 ) < epsilon1) + norm = glm::vec4(0.0, 0.0, -1.0, 0.0); + + normal = glm::normalize(multiplyMV(box.transform, glm::vec4(norm.x,norm.y,norm.z,0.0))); + glm::vec3 realIntersectionPoint = multiplyMV(box.transform, glm::vec4(getPointOnRay(rt, tfar), 1.0)); + glm::vec3 realOrigin = multiplyMV(box.transform, glm::vec4(0,0,0,1)); + intersectionPoint = realIntersectionPoint; + + + + return glm::length(r.origin - realIntersectionPoint); + } + + + return -1; } //LOOK: Here's an intersection test example from a sphere. Now you just need to figure out cube and, optionally, triangle. @@ -186,12 +288,12 @@ __host__ __device__ float sphereIntersectionTest(staticGeom sphere, ray r, glm: float t2 = firstTerm - squareRoot; float t = 0; - if (t1 < 0 && t2 < 0) { + if (t1 < 0.0 && t2 < 0.0) { return -1; } else if (t1 > 0 && t2 > 0) { - t = min(t1, t2); + t =glm::min(t1, t2); } else { - t = max(t1, t2); + t = glm::max(t1, t2); } glm::vec3 realIntersectionPoint = multiplyMV(sphere.transform, glm::vec4(getPointOnRay(rt, t), 1.0)); @@ -219,7 +321,7 @@ __host__ __device__ glm::vec3 getRadiuses(staticGeom geom){ //Generates a random point on a given cube __host__ __device__ glm::vec3 getRandomPointOnCube(staticGeom cube, float randomSeed){ - thrust::default_random_engine rng(hash(randomSeed)); + thrust::default_random_engine rng(hashF(randomSeed)); thrust::uniform_real_distribution u01(0,1); thrust::uniform_real_distribution u02(-0.5,0.5); @@ -261,11 +363,12 @@ __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){ - float radius=.5f; - thrust::default_random_engine rng(hash(randomSeed)); + float radius=.5f; + thrust::default_random_engine rng(hashF(randomSeed)); thrust::uniform_real_distribution u01(0,1); thrust::uniform_real_distribution u02(-0.5,0.5); @@ -285,4 +388,8 @@ __host__ __device__ glm::vec3 getRandomPointOnSphere(staticGeom sphere, float ra return randPoint; } + + + + #endif \ No newline at end of file diff --git a/src/raytraceKernel.cu b/src/raytraceKernel.cu index d473c89..1e4c926 100755 --- a/src/raytraceKernel.cu +++ b/src/raytraceKernel.cu @@ -4,18 +4,32 @@ // Rob Farber for CUDA-GL interop, from CUDA Supercomputing For The Masses: http://www.drdobbs.com/architecture-and-design/cuda-supercomputing-for-the-masses-part/222600097 // Peter Kutz and Yining Karl Li's GPU Pathtracer: http://gpupathtracer.blogspot.com/ // Yining Karl Li's TAKUA Render, a massively parallel pathtracing renderer: http://www.yiningkarlli.com - +#include +#include +#include +#include +#include #include #include #include #include "sceneStructs.h" #include +#include "glm/glm.hpp" #include "utilities.h" #include "raytraceKernel.h" #include "intersections.h" #include "interactions.h" +#include "EasyBMP.h" #include -#include "glm/glm.hpp" +#include +#include +#include + + + +using namespace std; +#define MAX_DEPTH 100 + void checkCUDAError(const char *msg) { cudaError_t err = cudaGetLastError(); @@ -30,48 +44,73 @@ void checkCUDAError(const char *msg) { __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::default_random_engine rng(hashF(index*time)); thrust::uniform_real_distribution u01(0,1); return glm::vec3((float) u01(rng), (float) u01(rng), (float) u01(rng)); } -//Kernel that does the initial raycast from the camera and caches the result. "First bounce cache, second bounce thrash!" -__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 = x + (y * resolution.x); - - thrust::default_random_engine rng(hash(index*time)); - thrust::uniform_real_distribution u01(0,1); - - //standard camera raycast stuff - glm::vec3 E = eye; - glm::vec3 C = view; - glm::vec3 U = up; - float fovx = fov.x; - float fovy = fov.y; +//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, int index){ + ray r; + + + thrust::default_random_engine rng( hashF(time * index) ); + thrust::uniform_real_distribution u01(-0.5, 0.5); + float jitterX = u01(rng); + float jitterY = u01(rng); + //standard camera raycast stuff + glm::vec3 e = eye; + glm::vec3 C = view; + glm::vec3 U = up; + float fovx = fov.x; + float fovy = fov.y; - float CD = glm::length(C); + float CD = glm::length(C); - glm::vec3 A = glm::cross(C, U); - glm::vec3 B = glm::cross(A, C); - glm::vec3 M = E+C; - glm::vec3 H = (A*float(CD*tan(fovx*(PI/180))))/float(glm::length(A)); - glm::vec3 V = (B*float(CD*tan(-fovy*(PI/180))))/float(glm::length(B)); + glm::vec3 A = glm::cross(C, U); + glm::vec3 B = glm::cross(A, C); + glm::vec3 M = e+C; + glm::vec3 H = (A*float(CD*tan(fovx*(PI/180))))/float(glm::length(A)); + glm::vec3 V = (B*float(CD*tan(-fovy*(PI/180))))/float(glm::length(B)); - float sx = (x)/(resolution.x-1); - float sy = (y)/(resolution.y-1); + float sx = (x+jitterX)/(resolution.x-1); + float sy = (y+jitterY)/(resolution.y-1); - glm::vec3 P = M + (((2*sx)-1)*H) + (((2*sy)-1)*V); - glm::vec3 PmE = P-E; - glm::vec3 R = E + (float(200)*(PmE))/float(glm::length(PmE)); + glm::vec3 P = M + (((2*sx)-1)*H) + (((2*sy)-1)*V); + glm::vec3 PmE = P-e; + glm::vec3 R = e + (float(200)*(PmE))/float(glm::length(PmE)); - glm::vec3 direction = glm::normalize(R); - //major performance cliff at this point, TODO: find out why! - ray r; - r.origin = eye; - r.direction = direction; - return r; + glm::vec3 direction = glm::normalize(R); + r.origin = eye; + r.direction = direction; + + + return r; + + + +} + +__global__ void initiateRays(glm::vec2 resolution, cameraData cam, ray *r,glm::vec3 * colors) +{ + 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) + { + r[index] = raycastFromCameraKernel(cam.resolution, 0.0f, x, y, cam.position, cam.view, cam.up, cam.fov,index); + r[index].colorIndex = index; + r[index].hasStopped = false; + colors[index] = glm::vec3(1); + r[index].color = glm::vec3(1); + r[index].reductionCoeficient = 1.0; + r[index].isRayInside = false; + r[index].IOR = 1.0; + + } +__syncthreads(); } //Kernel that blacks out a given image buffer @@ -118,52 +157,176 @@ __global__ void sendImageToPBO(uchar4* PBOpos, glm::vec2 resolution, glm::vec3* } } +__host__ __device__ int findNearestIntersectionPoint(const staticGeom const *geoms, int numberOfGeoms, const ray &r, glm::vec3 &intersectionPoint, glm::vec3 &normal){ + + float closestIntersectionDistance = 100000.0; + float hitPointDistance = -1; + int currentIndex = -1; + glm::vec3 tempNormal = glm::vec3(0); + glm::vec3 tempIntersectionPoint = glm::vec3(0); + + for(int i = 0; i < numberOfGeoms; i++) + { + if( geoms[i].type == SPHERE ) + { + hitPointDistance = sphereIntersectionTest(geoms[i], r, tempIntersectionPoint, tempNormal); + + }else if(geoms[i].type == CUBE) + { + hitPointDistance = boxIntersectionTest(geoms[i], r, tempIntersectionPoint, tempNormal); + + } + //find the closest intersetion point + if(hitPointDistance > 0.0) + { + if(hitPointDistance < closestIntersectionDistance) + { + closestIntersectionDistance = hitPointDistance; + normal = tempNormal; + intersectionPoint = tempIntersectionPoint; + currentIndex = i; + } + } + }//end geoms for loop + return currentIndex; + +} + //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, material* materials, int numberOfMaterials){ +__global__ void raytraceRay(ray * r, float time, int rayDepth, glm::vec3* colors, staticGeom* geoms, int numberOfGeoms, material* materials, int numberOfMaterials, int numberOfThreads){ - int x = (blockIdx.x * blockDim.x) + threadIdx.x; - int y = (blockIdx.y * blockDim.y) + threadIdx.y; - int index = x + (y * resolution.x); + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + int colorIndex = r[index].colorIndex; - ray r = raycastFromCameraKernel(resolution, time, x, y, cam.position, cam.view, cam.up, cam.fov); - - if((x<=resolution.x && y<=resolution.y)){ - - float MAX_DEPTH = 100000000000000000; - float depth = MAX_DEPTH; - - for(int i=0; i-EPSILON){ - MAX_DEPTH = depth; - colors[index] = materials[geoms[i].materialid].color; - } - } + if(index > numberOfThreads){ + r[index].hasStopped = true; + + return; + } + if( r[index].hasStopped){ + + return; + } + if(rayDepth > MAX_DEPTH && !r[index].hasStopped) + { + colors[colorIndex] = glm::vec3(0.0f, 0.0f, 0.0f); + r[index].hasStopped = true; + return; + } + + + glm::vec3 intersectionPoint = glm::vec3(0); + glm::vec3 normal = glm::vec3(0); + int currentIndex = findNearestIntersectionPoint(geoms,numberOfGeoms,r[index],intersectionPoint,normal); + + //if no object is intersected then color is black + if(currentIndex == -1){ + r[index].hasStopped = true; + colors[colorIndex] *= glm::vec3(0); + return; + } + + if( materials[geoms[currentIndex].materialid].emittance >0){ + r[index].hasStopped = true; + colors[colorIndex] *= materials[geoms[currentIndex].materialid].color * materials[geoms[currentIndex].materialid].emittance; + + }else { + thrust::default_random_engine rng((hashF(time) * hashF(index) * hashF(rayDepth))); + thrust::uniform_real_distribution u01(0,1); + + float incidentIOR =r[index].IOR; + float transmittedIOR = materials[geoms[currentIndex].materialid].indexOfRefraction; + + glm::vec3 reflectionDirection = calculateReflectionDirection(normal, r[index].direction); + glm::vec3 transmissionDirection = calculateTransmissionDirection(normal, r[index].direction, incidentIOR, transmittedIOR); + Fresnel fresnel= calculateFresnel(normal, r[index].direction, incidentIOR, transmittedIOR, reflectionDirection, transmissionDirection); + + + bool reflective = false; + bool refractive = false; + if((materials[geoms[currentIndex].materialid].hasReflective > 0.0)&&(materials[geoms[currentIndex].materialid].hasRefractive > 0.0)){ + if(abs(fresnel.transmissionCoefficient+fresnel.reflectionCoefficient )>1){ + reflective=true; + }else{ + float russianRoulette = (float)u01(rng); + if(russianRoulette<0.5) + reflective=true; + else + refractive=true; + } + }else if(materials[geoms[currentIndex].materialid].hasReflective > 0.0){ + reflective=true; + }else if(materials[geoms[currentIndex].materialid].hasRefractive > 0.0){ + refractive=true; + } + + /********************reflective*******************************************************************************************/ + if ( reflective ) {//reflective + // r[index].reductionCoeficient = calculateFresnel(normal, r[index].direction, incidentIOR, transmittedIOR, reflectionDirection, transmissionDirection).reflectionCoefficient; + // colors[colorIndex] *= materials[geoms[currentIndex].materialid].specularColor;// * r[index].reductionCoeficient; + r[index].origin = intersectionPoint; + r[index].direction = reflectionDirection; + return; + + } + /********************refractive*******************************************************************************************/ + if (refractive) { + float cosAngle = glm::dot( normal, r[index].direction); + float n = incidentIOR / transmittedIOR; + float secondTerm = 1.0f - n * n * (1.0f - cosAngle * cosAngle); + + if (secondTerm >= 0.0f) + { + r[index].direction =( (n * r[index].direction) - (n * cosAngle + sqrtf( secondTerm )) * normal); + }else + r[index].direction = glm::vec3(0); + + r[index].origin = intersectionPoint; + r[index].isRayInside = !r[index].isRayInside; + if(r[index].isRayInside){ + r[index].IOR = materials[geoms[currentIndex].materialid].indexOfRefraction; + }else{ + r[index].IOR = 1.0f; + } + return; + + + } + /********************diffuse*******************************************************************************************/ + if(!reflective && !refractive) {//diffuse + r[index].origin = intersectionPoint; + r[index].direction = glm::normalize(calculateRandomDirectionInHemisphere(normal,(float)u01(rng), (float)u01(rng) )); + colors[colorIndex] *= materials[geoms[currentIndex].materialid].color; + } + + } - //colors[index] = generateRandomNumberFromThread(resolution, time, x, y); - } + + + + //__syncthreads(); + } +//adjust Color +__global__ void adjustColor(glm::vec2 resolution, glm::vec3* colors, glm::vec3* accImage, float iterations) +{ + int x = (blockIdx.x * blockDim.x) + threadIdx.x; + int y = (blockIdx.y * blockDim.y) + threadIdx.y; + int index = x + (y * resolution.x); + colors[index] = (accImage[index] * (iterations - 1.0f) + colors[index]) / (float)iterations; + +} + //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 = MAX_DEPTH; //determines how many bounces the raytracer traces // set up crucial magic int tileSize = 8; @@ -197,6 +360,8 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio cudaMalloc((void**)&cudamaterials, numberOfMaterials*sizeof(material)); cudaMemcpy( cudamaterials, materials, numberOfMaterials*sizeof(material), cudaMemcpyHostToDevice); + + //package camera cameraData cam; cam.resolution = renderCam->resolution; @@ -205,9 +370,38 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio cam.up = renderCam->ups[frame]; cam.fov = renderCam->fov; - //kernel launches - raytraceRay<<>>(renderCam->resolution, (float)iterations, cam, traceDepth, cudaimage, cudageoms, numberOfGeoms, cudamaterials, - numberOfMaterials); + + //package rays to create threads over rays instead of for each pixel + int numberOfRays = (int)cam.resolution.x * (int)cam.resolution.y; + ray *rays = new ray[numberOfRays]; + ray *cudaRays = NULL; + cudaMalloc((void**)&cudaRays, numberOfRays * sizeof(ray)); + cudaMemcpy(cudaRays, rays, numberOfRays * sizeof(ray), cudaMemcpyHostToDevice); + + + //trace the rays first + initiateRays<<>>(renderCam->resolution,cam, cudaRays,cudaimage); + + + unsigned int threadsPerBlockBounce = (int)(tileSize*tileSize); + unsigned int fullBlocksBouncePerGrid = ((unsigned int)ceil(float(numberOfRays)/float(threadsPerBlockBounce))); + + int i = 0; + while (i 0 ){ + + raytraceRay<<>>(cudaRays, (float)iterations, i, cudaimage, cudageoms, numberOfGeoms, cudamaterials, numberOfMaterials, numberOfRays); + thrust::device_ptr in_ray_ptr(cudaRays); + thrust::device_ptr out_ray_ptr = thrust::remove_if(in_ray_ptr, in_ray_ptr + numberOfRays, is_ray_stopped()); + numberOfRays = out_ray_ptr.get() - cudaRays; + fullBlocksBouncePerGrid = (unsigned int)ceil((float)numberOfRays / threadsPerBlockBounce); + i++; + } + + glm::vec3* accImage = NULL; + cudaMalloc((void**)&accImage, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3)); + cudaMemcpy( accImage, renderCam->image, (int)renderCam->resolution.x*(int)renderCam->resolution.y*sizeof(glm::vec3), cudaMemcpyHostToDevice); + + adjustColor<<>>(renderCam->resolution, cudaimage, accImage, (float)iterations); sendImageToPBO<<>>(PBOpos, renderCam->resolution, cudaimage); @@ -218,8 +412,11 @@ void cudaRaytraceCore(uchar4* PBOpos, camera* renderCam, int frame, int iteratio cudaFree( cudaimage ); cudaFree( cudageoms ); cudaFree( cudamaterials ); + cudaFree(cudaRays); + cudaFree( accImage ); + delete [] rays; delete [] geomList; - + // make certain the kernel has completed cudaThreadSynchronize(); diff --git a/src/raytraceKernel.h b/src/raytraceKernel.h index 331e5ce..876fcb6 100755 --- a/src/raytraceKernel.h +++ b/src/raytraceKernel.h @@ -15,6 +15,15 @@ #include "sceneStructs.h" #include + struct is_ray_stopped + { + __host__ __device__ + bool operator()(const ray x) + { + return x.hasStopped; + } + }; + void cudaRaytraceCore(uchar4* pos, camera* renderCam, int frame, int iterations, material* materials, int numberOfMaterials, geom* geoms, int numberOfGeoms); #endif diff --git a/src/scene.cpp b/src/scene.cpp index f0384b2..04035db 100755 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -126,6 +126,8 @@ int scene::loadObject(string objectid){ } objects.push_back(newObject); + + cout << "Loaded " << frameCount << " frames for Object " << objectid << "!" << endl; return 1; @@ -255,6 +257,12 @@ int scene::loadMaterial(string materialid){ }else if(strcmp(tokens[0].c_str(), "EMITTANCE")==0){ newMaterial.emittance = atof(tokens[1].c_str()); + }else if(strcmp(tokens[0].c_str(), "TEXTURE")==0){ + newMaterial.texture = atof(tokens[1].c_str()); + + }else if(strcmp(tokens[0].c_str(), "AREALIGHT")==0){ + newMaterial.areaLight = atof(tokens[1].c_str()); + } } materials.push_back(newMaterial); diff --git a/src/sceneStructs.h b/src/sceneStructs.h index b10f1cf..140e7a6 100755 --- a/src/sceneStructs.h +++ b/src/sceneStructs.h @@ -16,6 +16,14 @@ enum GEOMTYPE{ SPHERE, CUBE, MESH }; struct ray { glm::vec3 origin; glm::vec3 direction; + int colorIndex; + float reductionCoeficient; + float IOR; + bool hasStopped; + bool isRayInside; + glm::vec3 color; + + }; struct geom { @@ -47,6 +55,21 @@ struct cameraData { glm::vec2 fov; }; +struct material{ + glm::vec3 color; + float specularExponent; + glm::vec3 specularColor; + float hasReflective; + float hasRefractive; + float indexOfRefraction; + float hasScatter; + glm::vec3 absorptionCoefficient; + float reducedScatterCoefficient; + float emittance; + float areaLight; + float texture; + +}; struct camera { glm::vec2 resolution; glm::vec3* positions; @@ -60,17 +83,7 @@ struct camera { std::string imageName; }; -struct material{ - glm::vec3 color; - float specularExponent; - glm::vec3 specularColor; - float hasReflective; - float hasRefractive; - float indexOfRefraction; - float hasScatter; - glm::vec3 absorptionCoefficient; - float reducedScatterCoefficient; - float emittance; -}; + + #endif //CUDASTRUCTS_H