diff --git a/.gitignore b/.gitignore index 89942d9..dc26d7a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,8 @@ build .LSOverride # Icon must end with two \r -Icon +Icon + # Thumbnails ._* @@ -558,3 +559,10 @@ xcuserdata *.xccheckout *.moved-aside *.xcuserstate +.vscode/* +renders/* +ebon_hawk/* +scenes/ebon_hawk/* +old_renders/* +oldFinalRenders/* + diff --git a/CMakeLists.txt b/CMakeLists.txt index 62c0e59..036d874 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -86,15 +86,33 @@ set(sources src/utilities.cpp ) +set(imgui + imgui/imconfig.h + imgui/imgui.cpp + imgui/imgui.h + imgui/imgui_draw.cpp + imgui/imgui_internal.h + imgui/imgui_widgets.cpp + imgui/imgui_demo.cpp + imgui/imgui_impl_glfw.cpp + imgui/imgui_impl_glfw.h + imgui/imgui_impl_opengl2.cpp + imgui/imgui_impl_opengl2.h + imgui/imgui_impl_opengl3.cpp + imgui/imgui_impl_opengl3.h + ) + list(SORT headers) list(SORT sources) +list(SORT imgui) source_group(Headers FILES ${headers}) source_group(Sources FILES ${sources}) +source_group(imgui FILES ${imgui}) #add_subdirectory(stream_compaction) # TODO: uncomment if using your stream compaction -cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers}) +cuda_add_executable(${CMAKE_PROJECT_NAME} ${sources} ${headers} ${imgui}) target_link_libraries(${CMAKE_PROJECT_NAME} ${LIBRARIES} #stream_compaction # TODO: uncomment if using your stream compaction diff --git a/INSTRUCTION.md b/INSTRUCTION.md index 9a7ccb1..86909c3 100644 --- a/INSTRUCTION.md +++ b/INSTRUCTION.md @@ -1,9 +1,12 @@ -Proj 3 CUDA Path Tracer - Instructions -======================== +# Proj 3 CUDA Path Tracer - Instructions -This is due **Wednesday October 7th** at 11:59pm. A mid-project submission of the core requirements is due **Tuesday Sept 30th** at 11:59pm. +This is due **Monday October 4th** at 11:59pm. -[Link to "Pathtracing Primer" Slides](https://1drv.ms/p/s!AiLXbdZHgbemhedscBCjlYs-dpL59A) +This project involves a significant bit of running time to generate high-quality images, so be sure to take that into account. You will receive an additional 2 days (due Wednesday, October 6th) for "README and Scene" only updates. However, the standard project requirements for READMEs still apply for the October 4th deadline. You may use these two extra days to improve your images, charts, performance analysis, etc. + +If you plan to use late days on this project (which we recommend), they will apply to the October 4th deadline. Once you have used your extra days and submitted the project, you will recieve the additional 2 days for "README and Scene" updates only. + +[Link to "Pathtracing Primer" Slides](https://1drv.ms/p/s!AiLXbdZHgbemhe02FCjXap5whSuYBQ?e=QxnlpM) **Summary:** @@ -12,6 +15,7 @@ In this project, you'll implement a CUDA-based path tracer capable of rendering The core renderer is left for you to implement. Finally, note that, while this base code is meant to serve as a strong starting point for a CUDA path tracer, you are not required to use it if you don't want to. You may also change any part of the base code as you please. **This is YOUR project.** **Recommendations:** + * Every image you save should automatically get a different filename. Don't delete all of them! For the benefit of your README, keep a bunch of them around so you can pick a few to document your progress at the end. Outtakes are highly appreciated! * Remember to save your debug images - these will make for a great README. * Also remember to save and share your bloopers. Every image has a story to tell and we want to hear about it. @@ -40,8 +44,6 @@ If you are using Visual Studio, you can set this in the `Debugging > Command Arg ## Requirements -**Ask in piazza for clarifications.** - In this project, you are given code for: * Loading and reading the scene description format. @@ -52,13 +54,14 @@ In this project, you are given code for: * Naive ray-scene intersection. * A "fake" shading kernel that colors rays based on the material and intersection properties but does NOT compute a new ray based on the BSDF. -### Part 1 - Core Features +**Ask in piazza for clarifications.** -**You need to complete these features for your mid-project submission on due by Sept, 30**. +### Part 1 - Core Features Follow all the same guidelines for README and Pull Request for your mid-project submission, except that you should create a branch called `mid-project-submission` and open a pull request with that branch. This way you can continue to work on your projects in the master branch. You will need to implement the following features: + * A shading kernel with BSDF evaluation for: * Ideal Diffuse surfaces (using provided cosine-weighted scatter function, see below.) [PBRT 8.3]. * Perfectly specular-reflective (mirrored) surfaces (e.g. using `glm::reflect`). @@ -70,80 +73,73 @@ implement a means of making rays/pathSegments/intersections contiguous in memory * Sort the rays/path segments so that rays/paths interacting with the same material are contiguous in memory before shading. How does this impact performance? Why? * A toggleable option to cache the first bounce intersections for re-use across all subsequent iterations. Provide performance benefit analysis across different max ray depths. -### Part 2 - Advance Features (Required) +### Part 2 - Make Your Pathtracer Unique! -1. 2 of these 3 smaller features: - * Refraction (e.g. glass/water) [PBRT 8.2] with Frensel effects using [Schlick's approximation](https://en.wikipedia.org/wiki/Schlick's_approximation) or more accurate methods [PBRT 8.5]. You can use `glm::refract` for Snell's law. - * Recommended but not required: non-perfect specular surfaces. (See below.) - * Physically-based depth-of-field (by jittering rays within an aperture). [PBRT 6.2.3] - * Stochastic Sampled Antialiasing. See Paul Bourke's [notes](http://paulbourke.net/miscellaneous/aliasing/). Keep in mind how this influences the first-bounce cache in part 1. +The following features are a non-exhaustive list of features you can choose from based on your own interests and motivation. Each feature has an associated score (represented in emoji numbers, eg. :five:). - > Note you may choose to implement the third feature as well for extra credit as noted in Part 3. +**You are required to implement additional features of your choosing from the list below totalling up to minimum 10 score points.** -2. Arbitrary mesh loading and rendering (e.g. glTF 2.0 (preferred) or `obj` files) with -toggleable bounding volume intersection culling - * You can find models online or export them from your favorite 3D modeling application. - With approval, you may use a third-party loading code to bring the data - into C++. - * [tinygltf](https://github.com/syoyo/tinygltf/) is highly recommended for glTF. - * [tinyObj](https://github.com/syoyo/tinyobjloader) is highly recommended for OBJ. - * [obj2gltf](https://github.com/CesiumGS/obj2gltf) can be used to convert - OBJ to glTF files. You can find similar projects for FBX and other - formats. - * You can use the triangle intersection function `glm::intersectRayTriangle`. - * Bounding volume intersection culling: reduce the number of rays that have to - be checked against the entire mesh by first checking rays against a volume - that completely bounds the mesh. For full credit, provide performance analysis - with and without this optimization. - - > Note: This goes great with the Hierarcical Spatial Data Structures extra credit. +An example set of optional features is: -3. [Better hemisphere sampling methods](https://cseweb.ucsd.edu/classes/sp17/cse168-a/CSE168_07_Random.pdf) +* Mesh Loading - :four: points +* Refraction - :two: points +* Anti-aliasing - :two: points +* Final rays post processing - :three: points -### Part 3 - Make Your Pathtracer Unique! +This list is not comprehensive. If you have a particular idea you would like to implement (e.g. acceleration structures, etc.), please post on Piazza. -You are required to choose and implement at least: -* Any 2 Visual Improvements, or -* 1 of Heirarchical Spatial Data Structure or Open Image AI Denoiser. - -This is part of the base project requirements. - -**Extra credit**: implement more features on top of the above required ones, with point value up to +20/100 at the grader's discretion (based on difficulty and coolness). +**Extra credit**: implement more features on top of the above required ones, with point value up to +20/100 at the grader's discretion (based on difficulty and coolness), generally . #### Visual Improvements -* Implement the 3rd feature from Part 2.1. -* Procedural Shapes & Textures. + +* :two: Refraction (e.g. glass/water) [PBRT 8.2] with Frensel effects using [Schlick's approximation](https://en.wikipedia.org/wiki/Schlick's_approximation) or more accurate methods [PBRT 8.5]. You can use `glm::refract` for Snell's law. + * Recommended but not required: non-perfect specular surfaces. (See below.) +* :two: Physically-based depth-of-field (by jittering rays within an aperture). [PBRT 6.2.3] +* :two: Stochastic Sampled Antialiasing. See Paul Bourke's [notes](http://paulbourke.net/miscellaneous/aliasing/). Keep in mind how this influences the first-bounce cache in part 1. +* :four: Procedural Shapes & Textures. * You must generate a minimum of two different complex shapes procedurally. (Not primitives) * You must be able to shade object with a minimum of two different textures -* Texture mapping [PBRT 10.4] and Bump mapping [PBRT 9.3]. +* :five: (:six: if combined with Arbitrary Mesh Loading) Texture mapping [PBRT 10.4] and Bump mapping [PBRT 9.3]. * Implement file-loaded textures AND a basic procedural texture * Provide a performance comparison between the two -* Direct lighting (by taking a final ray directly to a random point on an emissive object acting as a light source). Or more advanced [PBRT 15.1.1]. -* Subsurface scattering [PBRT 5.6.2, 11.6]. -* Some method of defining object motion, and motion blur by averaging samples at different times in the animation. -* Use final rays to apply post-processing shaders. Please post your ideas on Piazza before starting. +* :two: Direct lighting (by taking a final ray directly to a random point on an emissive object acting as a light source). Or more advanced [PBRT 15.1.1]. +* :four: Subsurface scattering [PBRT 5.6.2, 11.6]. +* :three: [Better hemisphere sampling methods](https://cseweb.ucsd.edu/classes/sp17/cse168-a/CSE168_07_Random.pdf) +* :three: Some method of defining object motion, and motion blur by averaging samples at different times in the animation. +* :three: Use final rays to apply post-processing shaders. Please post your ideas on Piazza before starting. + +#### Mesh Improvements + +* :four: Arbitrary mesh loading and rendering (e.g. glTF 2.0 (preferred) or `obj` files) with toggleable bounding volume intersection culling + * You can find models online or export them from your favorite 3D modeling application. With approval, you may use a third-party loading code to bring the data into C++. + * [tinygltf](https://github.com/syoyo/tinygltf/) is highly recommended for glTF. + * [tinyObj](https://github.com/syoyo/tinyobjloader) is highly recommended for OBJ. + * [obj2gltf](https://github.com/CesiumGS/obj2gltf) can be used to convert OBJ to glTF files. You can find similar projects for FBX and other formats. + * You can use the triangle intersection function `glm::intersectRayTriangle`. + * Bounding volume intersection culling: reduce the number of rays that have to be checked against the entire mesh by first checking rays against a volume that completely bounds the mesh. For full credit, provide performance analysis with and without this optimization. + > Note: This goes great with the Hierarcical Spatial Data Structures. #### Performance Improvements -* Work-efficient stream compaction using shared memory across multiple blocks. (See [*GPU Gems 3*, Chapter 39](https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda).) + +* :two: Work-efficient stream compaction using shared memory across multiple blocks. (See [*GPU Gems 3*, Chapter 39](https://developer.nvidia.com/gpugems/gpugems3/part-vi-gpu-computing/chapter-39-parallel-prefix-sum-scan-cuda).) * Note that you will NOT receieve extra credit for this if you implemented shared memory stream compaction as extra credit for Project 2. -* Hierarchical spatial data structures - for better ray/scene intersection testing +* :six: Hierarchical spatial data structures - for better ray/scene intersection testing * Octree recommended - this feature is more about traversal on the GPU than perfect tree structure * CPU-side data structure construction is sufficient - GPU-side construction was a [final project.](https://github.com/jeremynewlin/Accel) * Make sure this is toggleable for performance comparisons * If implemented in conjunction with Arbitrary mesh loading (required for this year), this qualifies as the toggleable bounding volume intersection culling. * See below for more resources -* [Wavefront pathtracing](https://research.nvidia.com/publication/megakernels-considered-harmful-wavefront-path-tracing-gpus): +* :six: [Wavefront pathtracing](https://research.nvidia.com/publication/megakernels-considered-harmful-wavefront-path-tracing-gpus): Group rays by material without a sorting pass. A sane implementation will require considerable refactoring, since every supported material suddenly needs its own kernel. -* [*Open Image AI Denoiser* ](https://github.com/OpenImageDenoise/oidn) Open Image Denoiser is an image denoiser which works by applying a filter on Monte-Carlo-based pathtracer output. The denoiser runs on the CPU and takes in path tracer output from 1spp to beyond. In order to get full credit for this, you must pass in at least one extra buffer along with the [raw "beauty" buffer](https://github.com/OpenImageDenoise/oidn#open-image-denoise-overview). **Ex:** Beauty + Normals. +* :five: [*Open Image AI Denoiser*](https://github.com/OpenImageDenoise/oidn) Open Image Denoiser is an image denoiser which works by applying a filter on Monte-Carlo-based pathtracer output. The denoiser runs on the CPU and takes in path tracer output from 1spp to beyond. In order to get full credit for this, you must pass in at least one extra buffer along with the [raw "beauty" buffer](https://github.com/OpenImageDenoise/oidn#open-image-denoise-overview). **Ex:** Beauty + Normals. * Part of this extra credit is figuring out where the filter should be called, and how you should manage the data for the filter step. * It is important to note that integrating this is not as simple as it may seem at first glance. Library integration, buffer creation, device compatibility, and more are all real problems which will appear, and it may be hard to debug them. Please only try this if you have finished the Part 2 early and would like extra points. While this is difficult, the result would be a significantly faster resolution of the path traced image. -* Re-startable Path tracing: Save some application state (iteration number, samples so far, acceleration structure) so you can start and stop rendering instead of leaving your computer running for hours at end (which will happen in this project) - -**This 'extra features' list is not comprehensive. If you have a particular idea you would like to implement (e.g. acceleration structures, etc.), please post on Piazza.** +* :five: Re-startable Path tracing: Save some application state (iteration number, samples so far, acceleration structure) so you can start and stop rendering instead of leaving your computer running for hours at end (which will happen in this project) +* :five: Switch the project from using CUDA-OpenGL Interop to using CUDA-Vulkan interop (this is a really great one for those of you interested in doing Vulkan). Talk to Janine or Shehzan if you are planning to pursue this. For each extra feature, you must provide the following analysis: -* Overview write-up of the feature +* Overview write-up of the feature along with before/after images. * Performance impact of the feature * If you did something to accelerate the feature, what did you do and why? * Compare your GPU version of the feature to a HYPOTHETICAL CPU version (you don't have to implement it!)? Does it benefit or suffer from being implemented on the GPU? @@ -152,6 +148,7 @@ For each extra feature, you must provide the following analysis: ## Base Code Tour You'll be working in the following files. Look for important parts of the code: + * Search for `CHECKITOUT`. * You'll have to implement parts labeled with `TODO`. (But don't let these constrain you - you have free rein!) @@ -170,7 +167,7 @@ You'll be working in the following files. Look for important parts of the code: ### Generating random numbers -``` +```cpp thrust::default_random_engine rng(hash(index)); thrust::uniform_real_distribution u01(0, 1); float result = u01(rng); @@ -179,7 +176,7 @@ float result = u01(rng); There is a convenience function for generating a random engine using a combination of index, iteration, and depth as the seed: -``` +```cpp thrust::default_random_engine rng = makeSeededRandomEngine(iter, index, path.remainingBounces); ``` @@ -213,16 +210,10 @@ By default, your GPU driver will probably kill a CUDA kernel if it runs for more > The easiest way to disable TDR for Cuda programming, assuming you have the NVIDIA Nsight tools installed, is to open the Nsight Monitor, click on "Nsight Monitor options", and under "General" set "WDDM TDR enabled" to false. This will change the registry setting for you. Close and reboot. Any change to the TDR registry setting won't take effect until you reboot. [Stack Overflow](http://stackoverflow.com/questions/497685/cuda-apps-time-out-fail-after-several-seconds-how-to-work-around-this) -### Notes on GLM - -This project uses GLM for linear algebra. - -On NVIDIA cards pre-Fermi (pre-DX12), you may have issues with mat4-vec4 multiplication. If you have one of these cards, be careful! If you have issues, you might need to grab `cudamat4` and `multiplyMV` from the [Fall 2014 project](https://github.com/CIS565-Fall-2014/Project3-Pathtracer). - -Let us know if you need to do this. - ### Scene File Format +> Note: The Scene File Format and sample scene files are provided as a starting point. You are encouraged to create your own unique scene files, or even modify the scene file format in its entirety. Be sure to document any changes in your readme. + This project uses a custom scene description format. Scene files are flat text files that describe all geometry, materials, lights, cameras, and render settings inside of the scene. Items in the format are delimited by new lines, and comments can be added using C-style `// comments`. Materials are defined in the following fashion: @@ -265,43 +256,33 @@ Two examples are provided in the `scenes/` directory: a single emissive sphere, * 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 path 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, at minimum, result in you receiving an F for the semester. +* You may use third-party 3D models and scenes in your projects. Be sure to provide the right attribution as requested by the creators. ## README Please see: [**TIPS FOR WRITING AN AWESOME README**](https://github.com/pjcozzi/Articles/blob/master/CIS565/GitHubRepo/README.md) * Sell your project. -* Assume the reader has a little knowledge of path tracing - don't go into - detail explaining what it is. Focus on your project. -* Don't talk about it like it's an assignment - don't say what is and isn't - "extra" or "extra credit." Talk about what you accomplished. +* Assume the reader has a little knowledge of path tracing - don't go into detail explaining what it is. Focus on your project. +* Don't talk about it like it's an assignment - don't say what is and isn't "extra" or "extra credit." Talk about what you accomplished. * Use this to document what you've done. -* *DO NOT* leave the README to the last minute! It is a crucial part of the - project, and we will not be able to grade you without a good README. +* *DO NOT* leave the README to the last minute! + * It is a crucial part of the project, and we will not be able to grade you without a good README. + * Generating images will take time. Be sure to account for it! In addition: * 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 be 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 very good to show case this with a - video to show interactivity. If you do so, please include a link! +* You wil not be 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 very good to show case this with a video to show interactivity. If you do so, please include a link! ### Analysis -* Stream compaction helps most after a few bounces. Print and plot the - effects of stream compaction within a single iteration (i.e. the number of - unterminated rays after each bounce) and evaluate the benefits you get from - stream compaction. -* Compare scenes which are open (like the given cornell box) and closed - (i.e. no light can escape the scene). Again, compare the performance effects - of stream compaction! Remember, stream compaction only affects rays which - terminate, so what might you expect? -* For optimizations that target specific kernels, we recommend using - stacked bar graphs to convey total execution time and improvements in - individual kernels. For example: +* Stream compaction helps most after a few bounces. Print and plot the effects of stream compaction within a single iteration (i.e. the number of unterminated rays after each bounce) and evaluate the benefits you get from stream compaction. +* Compare scenes which are open (like the given cornell box) and closed (i.e. no light can escape the scene). Again, compare the performance effects of stream compaction! Remember, stream compaction only affects rays which terminate, so what might you expect? +* For optimizations that target specific kernels, we recommend using stacked bar graphs to convey total execution time and improvements in individual kernels. For example: ![Clearly the Macchiato is optimal.](img/stacked_bar_graph.png) @@ -309,19 +290,21 @@ In addition: ## Submit -If you have modified any of the `CMakeLists.txt` files at all (aside from the -list of `SOURCE_FILES`), mentions it explicity. +If you have modified any of the `CMakeLists.txt` files at all (aside from the list of `SOURCE_FILES`), mentions it explicity. + Beware of any build issues discussed on the Piazza. Open a GitHub pull request so that we can see that you have finished. + The title should be "Project 3: YOUR NAME". + The template of the comment section of your pull request is attached below, you can do some copy and paste: * [Repo Link](https://link-to-your-repo) * (Briefly) Mentions features that you've completed. Especially those bells and whistles you want to highlight - * Feature 0 - * Feature 1 - * ... + * Feature 0 + * Feature 1 + * ... * Feedback on the project itself, if any. ## References @@ -329,3 +312,12 @@ The template of the comment section of your pull request is attached below, you * [PBRT] Physically Based Rendering, Second Edition: From Theory To Implementation. Pharr, Matt and Humphreys, Greg. 2010. * Antialiasing and Raytracing. Chris Cooksey and Paul Bourke, http://paulbourke.net/miscellaneous/aliasing/ * [Sampling notes](http://graphics.ucsd.edu/courses/cse168_s14/) from Steve Rotenberg and Matteo Mannino, University of California, San Diego, CSE168: Rendering Algorithms +* Path Tracer Readme Samples (non-exhaustive list): + * https://github.com/byumjin/Project3-CUDA-Path-Tracer + * https://github.com/lukedan/Project3-CUDA-Path-Tracer + * https://github.com/botforge/CUDA-Path-Tracer + * https://github.com/taylornelms15/Project3-CUDA-Path-Tracer + * https://github.com/emily-vo/cuda-pathtrace + * https://github.com/ascn/toki + * https://github.com/gracelgilbert/Project3-CUDA-Path-Tracer + * https://github.com/vasumahesh1/Project3-CUDA-Path-Tracer \ No newline at end of file diff --git a/README.md b/README.md index 110697c..0b1cbce 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,368 @@ -CUDA Path Tracer +# CUDA Denoiser + +Path Tracer Output | Denoised +-------------|---------- +![](finalRenders2/no_blur.png) | ![](finalRenders2/good_denoise.png) + +**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3** + +* Richard Chen +* Tested on: Windows 11, i7-10875H @ 2.3GHz 16GB, RTX 2060 MAX-Q 6GB (PC) + +## Overview +Path tracing is slow and computationally expensive. Additional passes also provide +diminishing returns with regard to image quality. +This motivates the use of smoothing filters to make images look less noisy. +This can speed up program execution by requiring fewer rendering passes and then +smoothing out the noise from the resultant images. + +A naïve smoother would be to blur neighboring pixels but this approach does not +account for various geometries in a scene and can result in a loss of clarity as +borders between different shapes become more homogenized. + +In this project, I use GPU side geometry buffers (G-Buffers) to store scene relevant data +in order to implement a smoothing filter that better preserves the boundaries +between different geometries. This approach is based off of the paper, +"Edge-Avoiding A-Trous Wavelet Transform for fast Global Illumination Filtering" +by Dammertz, Sewtz, Hanika, and Lensch. The difference is that CUDA is used in +place of GLSL fragment shaders for the computations. + +## Features +* Edge aware A-Trous Smoothing +* G-Buffer Visualization + +## Performance Analysis + +### Qualitative Analysis +* Materials: The filter works best with diffuse materials. +A glass or metal sphere might have neighboring pixels mapping to different parts +of a given scene while maintaining similar position and normal coordinates. +This illustrates that a G-Buffer of first bounce position/normal/color does not +provide sufficient information for the A-Trous filter to avoid reflected edges. +Even in the denoised image, the metal ball's reflections are blurred as to the +filter, they are part of the same shape and thus can be smoothed. +* Lighting: If too much of the image is dark, the filter will darken the image. +It is best to have a well illuminated scene, whether that means bigger lights +or more renders before filtering +* Simpler scenes and those with large diffuse areas are more suitable for a wide +filter and large color weights but more intricate scenes will need more localized smoothing +especially if the scene is supposed to be high frequency from a +signals processing perspective + +Image | Samples | Filter Size | Color | Normal | Position +------|---------|-------------|-------|--------|--------- +![](finalRenders2/wahoo_10_noblur.png) | 10 | N/A | N/A | N/A | N/A +![](finalRenders2/wahoo_10_3_8.866_1.34_0.206.png) | 10 | 3 | 8.866 | 1.34 | 0.206 +![](finalRenders2/wahoo_10_20_8.866_1.34_0.206.png) | 10 | 20 | 8.866 | 1.34 | 0.206 +![](finalRenders2/wahoo_10_100_9.639_0.567_1.082.png) | 10 | 100 | 9.639 | 0.567 | 1.082 +![](finalRenders2/wahoo_100_noblur.png) | 100 | N/A | N/A | N/A | N/A +![](finalRenders2/wahoo_100_100_10_10_10.png) | 100 | 100 | 10 | 10 | 10 + +* For some reason, even with all things set to max, with 100 spp, the filter +smoothing is barely noticeable (side walls are smoother, shadows less pronounced) + +### Quantitative Analysis +The filter operates on the rendered image output, basically post processing the +existing image except it is paired with the G-Buffer of relevant per pixel data. +What this means is that the filtering speed should have no dependence on the +geometries that comprise the scene. For a given resolution, regardless of the +polygon count of the scene or the number of passes taken, the smoothing step +should take a similar amount of time. + +The filter size vs time scaling seems to be linear which is not +expected as the number of iterations should be the log of the filter size but each iteration +reads the same number of pixels. +![](img/filter_timevFilter.png) + +As expected, the time to denoise a scene +is uncoupled from the geometry of the scene itself. Ceiling and Cornell are simple +while wahoo and cow have lots of triangles in the mesh. +![](img/filter_scenevTime.png) + +When the resolution per side doubles, the overall image pixels quadruples. +This chart shows the O(n^2) relationship +![](img/filter_timevRes.png) + +Denoising reduces the iterations needed to get an acceptably smooth result. +However, how large of a reduction is a complicated question. With simple geometry +like cornell ceiling light, 10 iterations is all that is needed especially if +every surface is diffuse. The filter had trouble smoothing over 100 spp mario +while smoothing even glass and metal at 10 spp. It takes much tweaking to find +a good filter configuration however, and there is no good one size fits all solution. +For some more complex scenes especially those involving meshes and textures, +sometimes there seems to be no large differences. For the ebon hawk, at 10 spp, +the filter blended everything together into a rather ugly color still with spots +of noise while at 50spp, I have a similar effect with the wahoo at 100spp: +there is barely any discernable difference, and in this case, the background +streaks change slightly. + +## G-Buffer Views + +Image | Attribute +------|---------- +![](finalRenders2/debug_normals.png) | Surface Normals (absolute valued to be positive), Scaled up to 255 +![](finalRenders2/debug_positions.png) | Positions (absolute valued to be positive), Unscaled +![](finalRenders2/debug_baseColor.png) | Material Color, Scaled up to 255 +![](finalRenders2/cursed_mario.png) | Overflow/wrapparound +![](finalRenders2/filter_hawk.png) | not checking if using texture or base material + +# CUDA Path Tracer ================ +![](finalRenders/ebon_final.png) **University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3** -* (TODO) YOUR NAME HERE -* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab) +* Richard Chen +* Tested on: Windows 11, i7-10875H @ 2.3GHz 16GB, RTX 2060 MAX-Q 6GB (PC) + +## Overview + +Path tracing is a rendering technique where light rays are shot out from the "camera" +into the scene. Whenever it meets a surface, we track how the ray gets attenuated and scattered. +This allows for more accurate rendering at the cost of requiring vast amounts of computation. +Fortunately, since photons do not (ignoring relativity) interact with each other, +this is very parallelizable, a perfect fit for running on a GPU. + +Cornell Box Inspired | Very Fast Shiny Cow +---------------------|------------------ +![](finalRenders/cornell_demo1.png) | ![](finalRenders/hyperspace_cow.png) +
+ + +## Features +
+ +* Diffuse surfaces +Since most surfaces are not microscopically smooth, incoming light can leave in any direction. +![](finalRenders/cornell_dfl.png) +
+ +* Specular reflection +Smooth surfaces reflect light neatly about the surface normal, like a mirror does. +![](finalRenders/cornell_specular.png) +
+ +* Dielectrics with Schlick's Approximation and Snell's Law +Light moves at different speeds through different mediums and this can cause light +to refract and/or reflect. In these examples, glass and air are used with indices of refractions +of 1.5 and 1, respectively. The further the incoming light is from the surface normal, the more likely +it is to reflect. +![](finalRenders/cornell_dielectric.png) +
+ +* Anti Aliasing via Stochastic Sampling +As opposed to classical antialiasing which involves super-sampling an image and is thus very computationally +expensive, stochastic sampling wiggles the outgoing ray directions slightly. This reduces the jagged artifacts +from aliasing at the cost of more noise, but does not involve shooting extra photons per pixel. +Notice how the left edge of the sphere is not nearly as jagged in the anti-aliased version +![](finalRenders/cornell_antialiasing.png) +
+ +* Depth of Field/Defocus Blur +Despite modelling the rays as shooting out from an infinitesimal point, real life cameras have a lens +through which the light passes. Further, the laws of physics also prevent light from being infinitely focused. +With cameras, this means that objects further away from the focal length will be blurrier. In ray tracing, the origin points of the light rays are wiggled in a manner consistent with approximating a lens. +![](finalRenders/defocus_blur.png) +
+ +* Obj Mesh Loading +While cubes and spheres are a great point to start off, one of the great joys in life is +to render Mario T-Posing. Many 3d models are available from the internet, with most of them +being meshes composed of triangles. I used [tinyObj](https://github.com/tinyobjloader/tinyobjloader) to load models that were of the Wavefront OBJ file format. +![](finalRenders/cornell_mario.png) +
+ +* Textures from files +While it is theoretically possible to specify material properties for each shape in a scene, +this can be untenable when working with thousands of shapes, let alone millions. +Instead, it is common to use textures, images where the color encodes useful data. Then, +rather than giving every vertex all of its data, it can associate them with texture coordinates +and look up the corresponding data only when relevant. I focused on textures that encoded +base color, tangent space normal mapping, ambient occlusion/roughness/metallicity, and emissivity. +I also set the background in a few renders to a texture rather than just having it fade to black, lest they be way too dark +![](finalRenders/texture_cow.png) +
+ +* Normal Mapping Texture Adaptation +The normal vector at a location allows for computing reflections, refractions, and more since +knowing it allows one to calculate the angle of incidence. Technically, it is a co-vector but +a consensus has been reached for how the order of vertices in a triangle directs its planar normal. +At its most basic, each triangle contains enough information to calculate its normal. +However, meshes composed of polygons are often used to model smooth objects, so it is common +to associate each vertex with a normal vector. Then, for a point inside a triangle, one can +interpolate between the vertex normals to get a normal for a particular location. +Imagine a brick wall. The mortar crevices could be modelled by adding who knows how many new triangles. +Alternatively, by turning the surface normals into a texture, they can be sampled as needed without weighing +down the system with extra computations. Bump maps and height maps accomplish something very similar, but +normal maps themselves come in two varieties: Object space and Tangent space. Object space maps let one directly +sample the rgb components and associate them with the normal's xyz values. Tangent space normal maps involve +a perspective shift so that the interpolated norm is pointing straight up. This requires some extra computation but is generally preferred due to its flexibility. The change of basis matrix TBN requires the namesake tangent, bitangent, and normal of which the normal is just the triangles planar norm. The other two can be relatively easily computed from the uv/texture coordinates of the vertices. To save on computation, I precompute them when loading in a mesh rather than need to recompute them every time they need to check the normal map. +![](finalRenders/tangent_space_normal_map.png) +
+ +* Physically Based Rendering Texture Adaptation + +Just the base color | With more effects +-------------------------|------------------------- +![](finalRenders/hawk_viewport.png) | ![](finalRenders/preproc_background.png) + +
+Nowadays, many people use metallic/roughness and Albedo instead of diffuse/specular. +I found a mesh (and its accompanying textures) that used this information so I had to +figure out how to adapt to this. Due to vastly different behaviors between dielectrics +and conductors, metallicity the concept is treated almost as a Boolean value, with gradations +encoding how to attenuate the metallic behavior. Physically based rendering tries to use +more physics to enable more realistic rendering. Light is split into refractive and reflective +components and metals will absorb the refractive component whilst dielectrics will scatter both, +with the resultant having both a specular and a diffuse portion. +The roughness also has a varying effect predicated upon metallicity. And lastly there is an +ambient occlusion map that describes how an area might be darker than expected. +This seems to be more tailored towards rasterization as the nature of path tracing means +areas which would be occluded more just will not bounce the light rays back towards light sources. +The theory goes much deeper, having had whole textbooks written about them but just scratching the +surface let me translate the textures and make the model look cool. +
+ +* Background Texture + + Raw Texture | Single Pass | Two Passes + ------------|-------------|-------------- + ![](finalRenders/hawk_nopasses.png) | ![](finalRenders/preproc_background.png) | ![](finalRenders/hawk_darksky.png) + +
+As a Star Wars fan, my thoughts naturally drifted towards making the ship look like it was +in hyperspace. This is also motivated by the fact that with path tracing, I could not think of how +to simulate ambient lighting, and was afraid I would need to sprinkle many small luminescent orbs +around the scene just to be able to see anything. Once, I found a cool background, I was next concerned +with how to map the rectangular texture onto the viewable sphere. By exploiting the symmetry of the hyperspace effect looking like a tunnel, this was made easy but for more complex backgrounds, this +would require more investigation. As it currently stands, for the unit sphere, x^2+y^2+z^2 = 1. +Z is constrained by the x and y values enabling us to map the view direction vector to UV coordinates. +When z = 1, x = 0, y = 0 which maps to uvs of (0.5, 0.5). By extension, this should scoop a unit circle +out of the texture that points would actually map to, with (x, y, z) and (x, y, -z) mapping to the same +uv coordinates ensuring a smooth transition. Then, I rotated the mesh to align with the tunnel direction +and voila, it looks like it is cruising through hyperspace. + +The next issue is that the sky was too bright and too blue, since I was using the bright color for global illumination as well. So I interpolated the texture color between +black and itself based on its brightness, as I wanted the bright streaks to remain but the space between +them to be darker. Then I did it again since it worked well the first time. +
+ + +## Performance Analysis + +![](img/performanceGraph.png) + +* The scene used was a Cornell box with different colored walls, many spheres and cubes that were shiny or glass, and Mario T-Posing menacingly in the back with an emissive texture +* Caching the First Intersection + * The rays start out at a known location and shoot into a screen pixel and then into the scene so it + makes sense to precompute the data on the first intersection for future computations + * Since antialiasing and depth of field are cool effects that add randomness and break this optimization, this optimization is worthless +* Sorting Rays by Material + * When there are multiple materials, checking the rays in order introduces branch divergence since materials will interact with the rays differently. Instead sort the rays by material so that there will be less divergence + * Meshes, which are expensive to check, count as a singular material so this optimization is situationally helpful if the scene in question has many different kinds of materials +* Compact Dead Threads + * If a ray terminates early, remove it from the pool so that there are fewer rays to check + * Especially when the geometry of the scene is very open, this optimization is very beneficial +* Mesh Intersection Test via AABB + * Rather than check collisions against every triangle, associate each mesh with its min and max bounds + for an axis aligned bounding box (AABB) and only check intersection with triangles if it intersects the bounds + * Especially if a mesh fits tightly inside a box, this optimization is very helpful. But if the mesh is irregularly shaped enough that the AABB encompasses the whole scene anyway, it would be less useful. + * The Ebon Hawk model has more than 69,000 triangles and fits relatively neatly into its AABB so this + is extremely useful + + + + +## Debug Views + +Texture | Normal | Depth +--------|--------|------- +![](finalRenders/texture_cube.png) | ![](finalRenders/debug_normal_cube_tilted.png) | ![](finalRenders/debug_depth_cube.png) + +## Headache Inducing Bugs + +Buggy | Fixed | Cause +------|-------|------- +![](finalRenders/ebonhawk_surface_normals.png) | ![](finalRenders/hawk_norm_interp.png) | Bad Normal Interpolation +![](finalRenders/hawk_norm_interp.png) | ![](finalRenders/debug_texture_base_color.png) | Tiling uv coordinates can be negative +![](finalRenders/debug_no_norm_blending.png) | ![](finalRenders/debug_norm_interp_working.png) | The obj did not have normals that were meant to be interpolated +![](finalRenders/debug_cow_normals.png) | ![](finalRenders/debug_cow_normals.png) | I thought the cow would have interpolated normals but it did not so it was not actually a bug. + +Bug | Cause +----|-------- +![](finalRenders/cornell_badrng.png) | Bad RNG Seeding +![](finalRenders/bug_mesh_triangle_shiny.png) | Checking the explicit error condition t == -1 but forgetting to also eliminate the general t < 0 bad case +![](finalRenders/objLoadingCow.png) | Triangle Intersection was wrong + + +## Further Work +* Heavily optimize the performance with a special focus on reducing branch divergence +* Refactoring the code to be more structured and less haphazard +* Changing the option toggles from `#define` macros to Booleans so changing does not require +lengthy recompilation +* Dive deeper into PBR to make everything look cooler like making the coppery parts shinier in a realistic way that is not just sidestepping the material behaviors +* Learn about the Disney BSDF and the GGX equation +* How to interpolate normals from a tangent space normal map + * Refactor with separate position, normal, uv, index, etc. buffers rather than cramming everything into triangle + * use gltf to load instead of obj + * mikktspace algorithm +* Support for multiple mesh importing + +## Other +* Special thanks to lemonaden for creating a free, high quality mesh of the Ebon Hawk https://sketchfab.com/3d-models/ebon-hawk-7f7cd2b43ed64a4ba628b1bb5398d838 +* Ray Tracing in One Weekend +* IQ's list of intersector examples and the Scenes & Ray Intersection slides from UCSD's CSE168 course by Steve Rotenberg that helped me understand how Möller–Trumbore worked +* UT Austin's CS384 slides on normal mapping tangent that explained the theory on how to convert from tangent space normals to object space and https://stackoverflow.com/questions/5255806/how-to-calculate-tangent-and-binormal for explaining the calculations in a way that did not seem like abuse of matrix notation +* https://wallpaperaccess.com/star-wars-hyperspace for the cool hyperspace wallpaper +* Adobe's articles on the PBR Metallic/Roughness workflow that explained the theory behind it +* reddit user u/cowpowered for tips on performing normal interpolation when working with normal maps and tbns + + +```glsl +uniform sampler2D colorMap, normalMap, posMap; +uniform float c_phi, n_phi, p_phi, stepwidth; +uniform float kernel[25]; +uniform vec2 offset[25]; +void main(void) +{ + vec4 sum = vec4(0.0); + vec2 step = vec2(1./512., 1./512.); // resolution + vec4 cval = texture2D(colorMap, gl_TexCoord[0].st); + vec4 nval = texture2D(normalMap, gl_TexCoord[0].st); + vec4 pval = texture2D(posMap, gl_TexCoord[0].st); + float cum_w = 0.0; + for(int i = 0; i < 25; i++) + { + vec2 uv = gl_TexCoord[0].st + offset[i]*step*stepwidth; + vec4 ctmp = texture2D(colorMap, uv); + vec4 t = cval - ctmp; + float dist2 = dot(t,t); + float c_w = min(exp(-(dist2)/c_phi), 1.0); + vec4 ntmp = texture2D(normalMap, uv); + t = nval - ntmp; + dist2 = max(dot(t,t)/(stepwidth*stepwidth),0.0); + float n_w = min(exp(-(dist2)/n_phi), 1.0); + vec4 ptmp = texture2D(posMap, uv); + t = pval - ptmp; + dist2 = dot(t,t); + float p_w = min(exp(-(dist2)/p_phi),1.0); + float weight = c_w * n_w * p_w; + sum += ctmp * weight * kernel[i]; + cum_w += weight*kernel[i]; + } + gl_FragData[0] = sum/cum_w; +} +``` -### (TODO: Your README) + -*DO NOT* leave the README to the last minute! It is a crucial part of the -project, and we will not be able to grade you without a good README. + diff --git a/cmake/CUDAComputesList.cmake b/cmake/CUDAComputesList.cmake index 87629ae..3156a63 100644 --- a/cmake/CUDAComputesList.cmake +++ b/cmake/CUDAComputesList.cmake @@ -60,6 +60,8 @@ IF( CUDA_COMPUTE_20 OR CUDA_COMPUTE_70 OR CUDA_COMPUTE_72 OR CUDA_COMPUTE_75 + OR CUDA_COMPUTE_80 + OR CUDA_COMPUTE_86 ) SET(FALLBACK OFF) ELSE() @@ -70,8 +72,8 @@ LIST(LENGTH COMPUTES_DETECTED_LIST COMPUTES_LEN) IF(${COMPUTES_LEN} EQUAL 0 AND ${FALLBACK}) MESSAGE(STATUS "You can use -DCOMPUTES_DETECTED_LIST=\"AB;XY\" (semicolon separated list of CUDA Compute versions to enable the specified computes") MESSAGE(STATUS "Individual compute versions flags are also available under CMake Advance options") - LIST(APPEND COMPUTES_DETECTED_LIST "30" "50" "60" "70") - MESSAGE(STATUS "No computes detected. Fall back to 30, 50, 60 70") + LIST(APPEND COMPUTES_DETECTED_LIST "30" "50" "60" "70" "80") + MESSAGE(STATUS "No computes detected. Fall back to 30, 50, 60, 70, 80") ENDIF() LIST(LENGTH COMPUTES_DETECTED_LIST COMPUTES_LEN) @@ -90,7 +92,7 @@ MACRO(SET_COMPUTE VERSION) ENDMACRO(SET_COMPUTE) # Iterate over compute versions. Create variables and enable computes if needed -FOREACH(VER 20 30 32 35 37 50 52 53 60 61 62 70 72 75) +FOREACH(VER 20 30 32 35 37 50 52 53 60 61 62 70 72 75 80 86) OPTION(CUDA_COMPUTE_${VER} "CUDA Compute Capability ${VER}" OFF) MARK_AS_ADVANCED(CUDA_COMPUTE_${VER}) IF(${CUDA_COMPUTE_${VER}}) diff --git a/cmake/FindGLFW.cmake b/cmake/FindGLFW.cmake index 014ae83..9cf3786 100644 --- a/cmake/FindGLFW.cmake +++ b/cmake/FindGLFW.cmake @@ -20,57 +20,57 @@ include(FindPackageHandleStandardArgs) if (WIN32) - # Find include files - find_path( - GLFW_INCLUDE_DIR - NAMES GLFW/glfw3.h - PATHS - $ENV{PROGRAMFILES}/include - ${GLFW_ROOT_DIR}/include - DOC "The directory where GLFW/glfw.h resides") + # Find include files + find_path( + GLFW_INCLUDE_DIR + NAMES GLFW/glfw3.h + PATHS + $ENV{PROGRAMFILES}/include + ${GLFW_ROOT_DIR}/include + DOC "The directory where GLFW/glfw.h resides") - # Use glfw3.lib for static library - if (GLFW_USE_STATIC_LIBS) - set(GLFW_LIBRARY_NAME glfw3) - else() - set(GLFW_LIBRARY_NAME glfw3dll) - endif() + # Use glfw3.lib for static library + if (GLFW_USE_STATIC_LIBS) + set(GLFW_LIBRARY_NAME glfw3) + else() + set(GLFW_LIBRARY_NAME glfw3dll) + endif() - # Find library files - find_library( - GLFW_LIBRARY - NAMES ${GLFW_LIBRARY_NAME} - PATHS - $ENV{PROGRAMFILES}/lib - ${GLFW_ROOT_DIR}/lib) + # Find library files + find_library( + GLFW_LIBRARY + NAMES ${GLFW_LIBRARY_NAME} + PATHS + $ENV{PROGRAMFILES}/lib + ${GLFW_ROOT_DIR}/lib) - unset(GLFW_LIBRARY_NAME) + unset(GLFW_LIBRARY_NAME) else() - # Find include files - find_path( - GLFW_INCLUDE_DIR - NAMES GLFW/glfw.h - PATHS - /usr/include - /usr/local/include - /sw/include - /opt/local/include - DOC "The directory where GL/glfw.h resides") + # Find include files + find_path( + GLFW_INCLUDE_DIR + NAMES GLFW/glfw.h + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + DOC "The directory where GL/glfw.h resides") - # Find library files - # Try to use static libraries - find_library( - GLFW_LIBRARY - NAMES glfw3 - PATHS - /usr/lib64 - /usr/lib - /usr/local/lib64 - /usr/local/lib - /sw/lib - /opt/local/lib - ${GLFW_ROOT_DIR}/lib - DOC "The GLFW library") + # Find library files + # Try to use static libraries + find_library( + GLFW_LIBRARY + NAMES glfw3 + PATHS + /usr/lib64 + /usr/lib + /usr/local/lib64 + /usr/local/lib + /sw/lib + /opt/local/lib + ${GLFW_ROOT_DIR}/lib + DOC "The GLFW library") endif() # Handle REQUIRD argument, define *_FOUND variable @@ -78,8 +78,8 @@ find_package_handle_standard_args(GLFW DEFAULT_MSG GLFW_INCLUDE_DIR GLFW_LIBRARY # Define GLFW_LIBRARIES and GLFW_INCLUDE_DIRS if (GLFW_FOUND) - set(GLFW_LIBRARIES ${OPENGL_LIBRARIES} ${GLFW_LIBRARY}) - set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_DIR}) + set(GLFW_LIBRARIES ${OPENGL_LIBRARIES} ${GLFW_LIBRARY}) + set(GLFW_INCLUDE_DIRS ${GLFW_INCLUDE_DIR}) endif() # Hide some variables diff --git a/cmake/FindGLM.cmake b/cmake/FindGLM.cmake index e2d45a8..55086f6 100644 --- a/cmake/FindGLM.cmake +++ b/cmake/FindGLM.cmake @@ -2,12 +2,12 @@ # Find GLM # # Try to find GLM : OpenGL Mathematics. -# This module defines +# This module defines # - GLM_INCLUDE_DIRS # - GLM_FOUND # # The following variables can be set as arguments for the module. -# - GLM_ROOT_DIR : Root library directory of GLM +# - GLM_ROOT_DIR : Root library directory of GLM # # References: # - https://github.com/Groovounet/glm/blob/master/util/FindGLM.cmake @@ -18,26 +18,26 @@ include(FindPackageHandleStandardArgs) if (WIN32) - # Find include files - find_path( - GLM_INCLUDE_DIR - NAMES glm/glm.hpp - PATHS - $ENV{PROGRAMFILES}/include - ${GLM_ROOT_DIR}/include - DOC "The directory where glm/glm.hpp resides") + # Find include files + find_path( + GLM_INCLUDE_DIR + NAMES glm/glm.hpp + PATHS + $ENV{PROGRAMFILES}/include + ${GLM_ROOT_DIR}/include + DOC "The directory where glm/glm.hpp resides") else() - # Find include files - find_path( - GLM_INCLUDE_DIR - NAMES glm/glm.hpp - PATHS - /usr/include - /usr/local/include - /sw/include - /opt/local/include - ${GLM_ROOT_DIR}/include - DOC "The directory where glm/glm.hpp resides") + # Find include files + find_path( + GLM_INCLUDE_DIR + NAMES glm/glm.hpp + PATHS + /usr/include + /usr/local/include + /sw/include + /opt/local/include + ${GLM_ROOT_DIR}/include + DOC "The directory where glm/glm.hpp resides") endif() # Handle REQUIRD argument, define *_FOUND variable @@ -45,7 +45,7 @@ find_package_handle_standard_args(GLM DEFAULT_MSG GLM_INCLUDE_DIR) # Define GLM_INCLUDE_DIRS if (GLM_FOUND) - set(GLM_INCLUDE_DIRS ${GLM_INCLUDE_DIR}) + set(GLM_INCLUDE_DIRS ${GLM_INCLUDE_DIR}) endif() # Hide some variables diff --git a/external/include/GL/Copying.txt b/external/include/GL/Copying.txt deleted file mode 100644 index fc36ad9..0000000 --- a/external/include/GL/Copying.txt +++ /dev/null @@ -1,27 +0,0 @@ - - Freeglut Copyright - ------------------ - - Freeglut code without an explicit copyright is covered by the following - copyright: - - Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies or substantial portions of the Software. - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Pawel W. Olszta shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Pawel W. Olszta. diff --git a/external/include/GL/Readme.txt b/external/include/GL/Readme.txt deleted file mode 100644 index f454169..0000000 --- a/external/include/GL/Readme.txt +++ /dev/null @@ -1,101 +0,0 @@ -freeglut 2.8.1-1.mp for MSVC - -This package contains freeglut import libraries, headers, and Windows DLLs. -These allow 32 and 64 bit GLUT applications to be compiled on Windows using -Microsoft Visual C++. - -For more information on freeglut, visit http://freeglut.sourceforge.net/. - - -Installation - -Create a folder on your PC which is readable by all users, for example -“C:\Program Files\Common Files\MSVC\freeglut\” on a typical Windows system. Copy -the “lib\” and “include\” folders from this zip archive to that location. - -The appropriate freeglut DLL can either be placed in the same folder as your -application, or can be installed in a system-wide folder which appears in your -%PATH% environment variable. Be careful not to mix the 32 bit DLL up with the 64 -bit DLL, as they are not interchangeable. - - -Compiling 32 bit Applications - -To create a 32 bit freeglut application, create a new Win32 C++ project in MSVC. -From the “Win32 Application Wizard”, choose a “Windows application”, check the -“Empty project” box, and submit. - -You’ll now need to configure the compiler and linker settings. Open up the -project properties, and select “All Configurations” (this is necessary to ensure -our changes are applied for both debug and release builds). Open up the -“general” section under “C/C++”, and configure the “include\” folder you created -above as an “Additional Include Directory”. If you have more than one GLUT -package which contains a “glut.h” file, it’s important to ensure that the -freeglut include folder appears above all other GLUT include folders. - -Now open up the “general” section under “Linker”, and configure the “lib\” -folder you created above as an “Additional Library Directory”. A freeglut -application depends on the import libraries “freeglut.lib” and “opengl32.lib”, -which can be configured under the “Input” section. However, it shouldn’t be -necessary to explicitly state these dependencies, since the freeglut headers -handle this for you. Now open the “Advanced” section, and enter “mainCRTStartup” -as the “Entry Point” for your application. This is necessary because GLUT -applications use “main” as the application entry point, not “WinMain”—without it -you’ll get an undefined reference when you try to link your application. - -That’s all of your project properties configured, so you can now add source -files to your project and build the application. If you want your application to -be compatible with GLUT, you should “#include ”. If you want to use -freeglut specific extensions, you should “#include ” instead. - -Don’t forget to either include the freeglut DLL when distributing applications, -or provide your users with some method of obtaining it if they don’t already -have it! - - -Compiling 64 bit Applications - -Building 64 bit applications is almost identical to building 32 bit applications. -When you use the configuration manager to add the x64 platform, it’s easiest to -copy the settings from the Win32 platform. If you do so, it’s then only necessary -to change the “Additional Library Directories” configuration so that it -references the directory containing the 64 bit import library rather -than the 32 bit one. - - -Problems? - -If you have problems using this package (compiler / linker errors etc.), please -check that you have followed all of the steps in this readme file correctly. -Almost all of the problems which are reported with these packages are due to -missing a step or not doing it correctly, for example trying to build a 32 bit -app against the 64 bit import library. If you have followed all of the steps -correctly but your application still fails to build, try building a very simple -but functional program (the example at -http://www.transmissionzero.co.uk/computing/using-glut-with-mingw/ works fine -with MSVC). A lot of people try to build very complex applications after -installing these packages, and often the error is with the application code or -other library dependencies rather than freeglut. - -If you still can’t get it working after trying to compile a simple application, -then please get in touch via http://www.transmissionzero.co.uk/contact/, -providing as much detail as you can. Please don’t complain to the freeglut guys -unless you’re sure it’s a freeglut bug, and have reproduced the issue after -compiling freeglut from the latest SVN version—if that’s still the case, I’m sure -they would appreciate a bug report or a patch. - - -Changelog - -2013–05–11: Release 2.8.1-1.mp - - • First 2.8.1 MSVC release. I’ve built the package using Visual Studio 2012, - and the only change I’ve made is to the DLL version resource—I’ve changed - the description so that my MinGW and MSVC builds are distinguishable from - each other (and other builds) using Windows Explorer. - - -Martin Payne -2013–05–11 - -http://www.transmissionzero.co.uk/ diff --git a/external/include/json.hpp b/external/include/json.hpp new file mode 100644 index 0000000..c9af0be --- /dev/null +++ b/external/include/json.hpp @@ -0,0 +1,20406 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.5.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 5 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + + +#include // random_access_iterator_tag + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template +struct iterator_types {}; + +template +struct iterator_types < + It, + void_t> +{ + using difference_type = typename It::difference_type; + using value_type = typename It::value_type; + using pointer = typename It::pointer; + using reference = typename It::reference; + using iterator_category = typename It::iterator_category; +}; + +// This is required as some compilers implement std::iterator_traits in a way that +// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341. +template +struct iterator_traits +{ +}; + +template +struct iterator_traits < T, enable_if_t < !std::is_pointer::value >> + : iterator_types +{ +}; + +template +struct iterator_traits::value>> +{ + using iterator_category = std::random_access_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; +}; +} +} + +// #include + +// #include + + +#include + +// #include + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template