diff --git a/CMakeLists.txt b/CMakeLists.txt
index c473e2c0..176c27ac 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -84,6 +84,9 @@ set(headers
src/ImGui/imstb_rectpack.h
src/ImGui/imstb_textedit.h
src/ImGui/imstb_truetype.h
+
+ external/include/json.hpp
+ external/include/tiny_gltf.h
)
set(sources
diff --git a/README.md b/README.md
index 110697ce..0312992c 100644
--- a/README.md
+++ b/README.md
@@ -3,11 +3,250 @@ CUDA Path Tracer
**University of Pennsylvania, CIS 565: GPU Programming and Architecture, Project 3**
-* (TODO) YOUR NAME HERE
-* Tested on: (TODO) Windows 22, i7-2222 @ 2.22GHz 22GB, GTX 222 222MB (Moore 2222 Lab)
+* Saksham Nagpal
+ * [LinkedIn](https://www.linkedin.com/in/nagpalsaksham/)
+* Tested on: Windows 11 Home, AMD Ryzen 7 6800H Radeon @ 3.2GHz 16GB, NVIDIA GeForce RTX 3050 Ti Laptop GPU 4096MB
-### (TODO: Your README)
+## Summary
+This project is a learning attempt turned into a definitive milestone in my journey of learning CUDA. The aim of making a path tracer using CUDA and C++ is to replicate the behaviour of the graphics pipeline while manually being in-charge of the GPU-side kernel invocations. Using CUDA, I map each of the steps in the graphics pipeline (i.e. vertex shader, rasterization, fragment shader, etc.) into equivalent kernel invocations, thus solidfying both experience with CUDA as well as knowledge of the graphics pipeline. This project also turned out to be a good way of keeping me true to my understanding of the core graphics concepts such as coordinate transformations and barycentric interpolation. By implementing a combination of visually pleasing and computationally accelerating features, I was able to generate some fun renders such as these:
-*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.
+## Representative Outcomes
+_247,963 triangles, 5000 iterations, max 10 bounces per ray_
+
+_Stanford Dragon - 871,306 triangles, 5000 iterations, max 8 bounces per ray_
+
+
+
+
+## Features Implemented
+
+1. [BSDFs - Diffuse, Perfectly Specular, Perfectly Reflective, Imperfect Specular/Diffuse, Refractive](#visual-one)
+3. [Stochastic Sampled Antialiasing](#visual-two)
+4. [Physically-Based Depth of Field](#visual-three)
+5. [Support for loading glTF meshes](#visual-four)
+6. [Texture Mapping for glTF meshes](#visual-four)
+7. [Reinhard operator & Gamma correction](#visual-five)
+8. [First bounce caching](#perf-one)
+9. [Stream Compaction for ray path termination](#perf-two)
+10. [Material Sorting](#perf-three)
+11. [Acceleration Structure - Bounding Volume Heirarchy (BVH)](#perf-four)
+
+## Path Tracer
+
+A path tracer, in summary, is an effort to estimate the **Light Transport Equation (LTE)** for a given scene. The LTE is a methematical representation of how light bounces around in a scene, and how its interactions along the way with various kinds of materials give us varied visual results.
+
+The Light Transport Equation
+--------------
+#### Lo(p, ωo) = Le(p, ωo) + ∫S f(p, ωo, ωi) Li(p, ωi) V(p', p) |dot(ωi, N)| _d_ωi
+
+The [PBRT](https://pbr-book.org/3ed-2018/Light_Transport_I_Surface_Reflection/The_Light_Transport_Equation#) book is an exceptional resource to understand the light transport equation, and I constantly referred it throughout the course of this project.
+
+# Visual Features
+
+ The following features were implemented in this path-tracer to make the renders look more _physically-based_.
+
+
+ ## 1. Bidirectional Distribution Functions (BSDFs)
+
+ BSDF is a function that defines a material in terms of how it scatters rays when light interacts with it. This path tracer implements the requisite BSDFs to support perfectly diffuse, perfectly specular, imeprfect specular/diffuse, and refractive materials.
+
+ |
|
|
|
|
+|:--:|:--:|:--:|:--:|
+| *Diffuse (Lambertian)* | *Partially Diffuse/Specular* | *Perfectly Specular* | *Perfectly Refractive* |
+
+
+## 2. Stochastic Sampled Anti-Aliasing
+
+Ray generation for each pixel, if not perturbed, will be deterministic. This means that the rays generated from the camera in each iteration would hit the same geometry always. This gives visibly jagged _aliased_ edges in the final render. To prevent this, we can select different points on each pixel in each iteartion using [Stratified Sampling](https://pbr-book.org/3ed-2018/Sampling_and_Reconstruction/Stratified_Sampling). This way, each ray originating from the camera is 'jittered' by a small amount, giving the much needed random seed to the path tracer. Since we accumulate pixel colours over iterations, the random jitterling helps averaging out the abrupt jagged edges to smoothly-shaded ones. This feature can be toggled ON/OFF using the preprocessor directive `ANTI_ALIASING` in the `utilities.h` file.
+
+|
|
|
+|:--:|:--:|
+| *Visibly Aliased Edges* | *After Anti-Aliasing* |
+
+
+## 3. Physically-Based Depth of Field
+
+The camera model assumed until now is a _thin-lens model_, that allow light to pass only through a very small aperture to reach the camera film. Real cameras instead have lenses of a finite-sized aperture with a certain _lens radius_ and a _focal plane_. The larger the aperture, i.e. the _lens radius_, the shorter are the exposure times to accurately capture an image. However, such lenses can only focus on the _focal plane_, and any nearer/farther objects appear blurrier. PBRT describes a [thin-lens approximation](https://pbr-book.org/3ed-2018/Camera_Models/Projective_Camera_Models#TheThinLensModelandDepthofField) for such a camera model, which we implement in our path tracer. The concept is fairly straightforward:
+1. Generate a random point on the surface of the disc.
+2. Determine the intersection point on the plane for the ray assuming a pinhole camera model.
+3. The origin of the ray now becomes the randomly generated point on the lens, and its direction is the vector from this new origin towards the point calculated on the film.
+
+Such a simple yet physically accurate implementation allowed us to get the following interesting visual results:
+
+
+
+ Lens Radius = 0.01 |
+ Lens Radius = 0.1 |
+ Lens Radius = 0.6 |
+
+
+  |
+  |
+  |
+
+
+ Focal Length = 6.3, 1000 iterations, trace depth = 8 |
+
+
+A very small lens radius approximates the pin-hole camera, and therefore we get an almost clear render. As we increase the lens radius, more and more light enters the lens surface, and all of it that does not get focused onto the focal plane ends up giving a blurry effect. The above sequence of images shows the results of varying the lens radius while keeping the focal length fixed.
+
+
+
+
+ Focal Length = 4 |
+ Focal Length = 6 |
+ Focal Length = 8 |
+
+
+  |
+  |
+  |
+
+
+ Lens Radius = 0.4, 1000 iterations, trace depth = 8 |
+
+
+
+
+The above sequence of images correctly demonstrate the concept of focal length - this is the distance at which our camera is able to 'focus'. Everything nearer to or further away from the camera gets blurred.
+
+This feature can be toggled ON/OFF using the preprocessor directive `DEPTH_OF_FIELD` in the `utilities.h` file.
+
+
+## 4. Supporting glTF Meshes & Texture Mapping
+
+Given the wide usage of glTF file format in the industry for its ease of defining scenes and animations, I always wanted some experience of working with it. So I took this project as an opportunity to gain some ahnds-on experience with the same. Since this pathtracer is an attempt to replicate the graphics pipeline, there are certain things that I needed to do in the opposite way while working with glTF files, since its format is specifically meant to be handled as-is by the graphics pipeline, which is totally absent here. Such tasks included:
+1. Reading the triangulated mesh's indices from the glTF's buffer view so as to replicate the `Primitive Assembly` step of the graphics pipeline.
+2. Use **Barycentric Interpolation** to interpolate normals for proper shading and UVs for texture sampling.
+
+|
| →|
| →|
| →|
|
+|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
+| *Flat Normals generated by edge cross product* |→| *Barycentric Interpolated Normals* |→| *Loading the model's texture map* |→| *Sampling texture using Barycentric Interpolated UVs* |
+
+
+## 5. Reinhard Operator and Gamma Correction
+
+[Renhard Operator or Tone Mapping](https://expf.wordpress.com/2010/05/04/reinhards_tone_mapping_operator/) is implemented to map the High Dynamic Range (HDR) to a lower range that is capable of being processed by the output devices.
+`Reinhard Operator: color.rgb = color.rgb/(1 + color.rgb)`
+
+[Gamma Correction](https://www.cambridgeincolour.com/tutorials/gamma-correction.htm) defines a relationship between the pixel's numerical value and it's actual luminance so that our eyes can see the colors as they were captured by a digital camera.
+`Gamma Correction: color.rgb = pow(color.rgb, 1/2.2)`
+
+This feature can be toggled ON/OFF using the preprocessor directive `REINHARD_GAMMA` in the `utilities.h` file.
+
+|
|
|
+|:--:|:--:|
+| `REINHARD_GAMMA` OFF | `REINHARD_GAMMA` ON|
+
+
+# Performance Analysis
+
+Here I will document the attempts I made to boost the performance of my pathtracer - my hypothesis on why I thought the change could result in a potential performance improvement, and my actual findings along with supporting metrics.
+
+
+## 1. First Bounce Caching
+
+As a rudimentary optimization, one could try caching the first ray intersections with the scene geometry. The first set of rays generated from the camera per pixel is deterministic, and hence the first intersections would always be the same. Therefore, one can expect a small performance boost from this optimization. Note that this optimization would be invalidated as soon as **Multi-Sampled Anti Aliasing (MSAA)** is implemented, since in that case the first set of generated rays would no longer remain deterministic. This feature can be toggled ON/OFF using the preprocessor directive `FIRST_BOUNCE_CACHED` in the `utilities.h` file, although this feature won't be turned on at all if `ANTI_ALIASING' is turned ON.
+
+### Metrics:
+
+
+
+As expected, caching the first bounce indeed results in a small performance gain. However, this gain becomes less and less significant with increasing trace depth of rays, potentially offset due to more computationally expensive intersections.
+
+
+## 2. Stream Compaction for Ray Path Termination
+
+For each iteartion, we bounce a ray around the scene until it terminates, i.e., either hits a light source or reaches some terminating condition (such as max depth reached, no scene geometry hit, etc.). After each iteartion of scene intersection, if we were to compact the ray paths, then potential performance gains could result due to the following reasons:
+1. **Reducing the number of kernel threads:** Instead of calling the scene intersection kernel always with number of threads equal to the number of pixels in our scene, we could invoke the kernel only with as mnay threads as there are unterminated rays. This should result in less copy-over to and from the device to host, and thus giving us a better memory bandwidth.
+2. **Coalescing Memory:** In our array of rays, each iteration would cause rays at various random indices to get terminated. If we were to compact away the terminated rays and partition our non-terminated rays into contiguous memory, then that should enable warps to retire and be available to the scheduler for more work. Coherent memory should also hasten access times, thereby potentially adding to the performance gain.
+
+This feature can be toggled ON/OFF using the preprocessor directive `STREAM_COMPACTION` in the `utilities.h` file.
+
+### Metrics:
+
+
+
+* **Open Scene:** For the open scene, an actual benefit is seen at higher depth values. This makes sense, since in an open scene there is a high probability for a ray to hit no scene geomtery, and therefore not reach the light source, In such a scenario, removing all the terminated rays at each iteartion would give us a much smaller subset of rays to work with in the next iteration. Since Stream Compaction's performance for our case is memory bound, it makes sense for the offset to occur at higher depths wherein termination of paths actually starts making up for the cost of stream compaction. For our case, looking at the graph we see that stream compaction starts becoming more performant than naive path termination _scene depth = 6_ onwards.
+
+
+
+
+* **Closed Scene:** For a closed scene, there is a much higher probability for rays to reach the light source by bouncing around the scene numerous times. This is corroborated by the grpah, wherein we do not see the number of unterminated rays decreasing with depth count unlike the open scene case. Hence, stream compaction happens to be just an unnecessary overhead in this case, and is never able to offset the naive path termination's performance.
+
+
+## 3. Material Sorting
+
+Another potential candidate for a performance boost is sorting the rays and intersections based on the material indices. Every path segment in a buffer is using one large shading kernel for all BSDF evaluations. Such differences in materials within the kernel will take different amounts of time to complete, making our kernel highly divergent. Therefore, sorting the rays to make paths interacting with the same material contiguous in memory before shading could potentially give us better performance by reducing **Warp Divergence**.
+
+This feature can be toggled ON/OFF using the preprocessor directive `MATERIAL_SORT` in the `utilities.h` file.
+
+### Metrics:
+
+
+
+We see that for our case, at such a small level, material sorting is not really giving us a benefit. In fact, it is actually incurring an extreme overhead. The reason for this could be the small scale and the simplpicity of our scenes, where there is no significant gain that could offset the hit we take from sorting each ray and intersection based on material.
+
+
+## 4. Acceleration Structure - Bounding Volume Heirarchy (BVH)
+
+BVHs are widely used acceleration structures, and I had always wanted to implement one. There are very many versions out there of BVHs, both in terms of implementation as well as traversal. I implemented a very basic version referring to [PBRT](https://pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies).
+
+**Construction**
+1. Assign each geometry(primitive/triangle) its own **Axis-Aligned Bounding Box (AABB)**.
+2. Start with the root node, which is assigned an AABB that is a union of the AABBs of all the primitives in the scene.
+3. At every iteration, determine the axis which has the longest spanning range for all the AABBs' centroids. Split the geometry on that axis, and the two halves are made the two child nodes of the current node.
+4. The above process is repeated until nodes containing single primitives are encounterd, which are then made then leaf nodes of the tree.
+5. Once this tree is constructed, a **linearized version of the tree** is constructed so that it can be stored in an array and sent over to the GPU for traversal.
+
+**Traversal**
+1. On the GPU, a stack-based traversal is sued to determine the ray's intersection with the scene.
+2. The root node is first pushed onto the stack.
+3. When the traversal begins, the stack is popped, and the popped element is checked if it is a leaf node, and if it is, then scene intersection is calculated. If this turns out to be the closest hit yet, we replace the current closest hit parameters with the results from this intersection.
+4. If the popped node is not a leaf, then both its children's AABBs are checked for intersection against the ray. If a child's AABB is intersected by the ray, it is pushed onto the stack.
+
+This feature can be toggled ON/OFF using the preprocessor directive `USE_BVH` in the `utilities.h` file.
+
+### Metrics:
+
+To test the performance of the BVH, I start with a simple scene containg 682 triangles, and then I keep adding instances of the same mesh at every iteration of the test.
+
+|  |  |  |  |  |
+|:--:|:--:|:--:|:--:|:--:|
+| *1st Test: 682 triangles* | *2nd Test: 1364 triangles* | *3rd Test: 2046 triangles* | *4th Test: 2728 triangles* | *5th Test: 4092 triangles* |
+
+The following graph clearly demonstartes the significant FPS boost we receive from using a BVH. Not only do we get a performance gain, but it also offsets the naive performance by more than 2X.
+
+
+
+To compare the FPS trends of the with- and without-BVH cases, I used a logarithmic scale for a better comparison of the trend:
+
+
+
+The log scale clearly shows how well the FPS fall-off is counter-acted by the Bounding Volume Heirarchy. In fact, many of the renders in this project would not even have been possible without implementing an acceleration structure.
+
+
+# Bloopers!
+
+ _* Gentle self-reminder of why we need random sequences. Uniformity is not always great, clearly. *_
+
+
+
+_Wrong ray transformation sent me in the depths of the depths of the...depths...of...depth of field._
+
+
+
+_Sorry Suzanne, I didn't know glTF specified the number of channels for the texture in the model itself!._
+
+
+
+# References
+* [tinygltf](https://github.com/syoyo/tinygltf/) for loading/supporting glTF meshes.
+* [Physicall Based Rendering: From Theory To Implementation](https://pbrt.org/).
+* [Watermelon Fruit Model](https://sketchfab.com/3d-models/watermelon-fruit-f120452f84bf4e979139b106bf9f096c) by [catafest](https://sketchfab.com/catafest) licensed under [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/).
+* [Avocado Model](https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/Avocado) was taken from the Khronos Group glTF sample models repository.
+* [Orange Fruit](https://sketchfab.com/3d-models/orange-fruit-cbdf758f21924c168c1c3da1afed9754) by [polyplant3d](https://sketchfab.com/polyplant3d) licensed under [CC-BY-4.0](http://creativecommons.org/licenses/by/4.0/).
+* [The Utah Teapot](https://skfb.ly/BYQA) by 3D graphics 101 licensed under [Creative Commons Attribution-NonCommercial](http://creativecommons.org/licenses/by-nc/4.0/).
+* [Stanford Bunny Zipper reconstruction)](https://skfb.ly/BSyr) by 3D graphics 101 licensed under [Creative Commons Attribution-NonCommercial](http://creativecommons.org/licenses/by-nc/4.0/).
+* [Alec Jacobson Common 3D Test Models](https://github.com/alecjacobson/common-3d-test-models)
diff --git a/assets/Avocado.bin b/assets/Avocado.bin
new file mode 100644
index 00000000..b98140c9
Binary files /dev/null and b/assets/Avocado.bin differ
diff --git a/assets/Avocado.gltf b/assets/Avocado.gltf
new file mode 100644
index 00000000..55fcd955
--- /dev/null
+++ b/assets/Avocado.gltf
@@ -0,0 +1,155 @@
+{
+ "accessors": [
+ {
+ "bufferView": 0,
+ "componentType": 5126,
+ "count": 406,
+ "type": "VEC2"
+ },
+ {
+ "bufferView": 1,
+ "componentType": 5126,
+ "count": 406,
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 2,
+ "componentType": 5126,
+ "count": 406,
+ "type": "VEC4"
+ },
+ {
+ "bufferView": 3,
+ "componentType": 5126,
+ "count": 406,
+ "type": "VEC3",
+ "max": [
+ 0.02128091,
+ 0.06284806,
+ 0.0138090011
+ ],
+ "min": [
+ -0.02128091,
+ -4.773855E-05,
+ -0.013809
+ ]
+ },
+ {
+ "bufferView": 4,
+ "componentType": 5123,
+ "count": 2046,
+ "type": "SCALAR"
+ }
+ ],
+ "asset": {
+ "generator": "glTF Tools for Unity",
+ "version": "2.0"
+ },
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteLength": 3248
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 3248,
+ "byteLength": 4872
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 8120,
+ "byteLength": 6496
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 14616,
+ "byteLength": 4872
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 19488,
+ "byteLength": 4092
+ }
+ ],
+ "buffers": [
+ {
+ "uri": "Avocado.bin",
+ "byteLength": 23580
+ }
+ ],
+ "images": [
+ {
+ "uri": "Avocado_baseColor.png"
+ },
+ {
+ "uri": "Avocado_roughnessMetallic.png"
+ },
+ {
+ "uri": "Avocado_normal.png"
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "TEXCOORD_0": 0,
+ "NORMAL": 1,
+ "TANGENT": 2,
+ "POSITION": 3
+ },
+ "indices": 4,
+ "material": 0
+ }
+ ],
+ "name": "Avocado"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0
+ },
+ "metallicRoughnessTexture": {
+ "index": 1
+ }
+ },
+ "normalTexture": {
+ "index": 2
+ },
+ "name": "2256_Avocado_d"
+ }
+ ],
+ "nodes": [
+ {
+ "mesh": 0,
+ "rotation": [
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0
+ ],
+ "name": "Avocado"
+ }
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "textures": [
+ {
+ "source": 0
+ },
+ {
+ "source": 1
+ },
+ {
+ "source": 2
+ }
+ ]
+}
\ No newline at end of file
diff --git a/assets/Avocado_baseColor.png b/assets/Avocado_baseColor.png
new file mode 100644
index 00000000..38630edf
Binary files /dev/null and b/assets/Avocado_baseColor.png differ
diff --git a/assets/Avocado_normal.png b/assets/Avocado_normal.png
new file mode 100644
index 00000000..73f90d59
Binary files /dev/null and b/assets/Avocado_normal.png differ
diff --git a/assets/Box.gltf b/assets/Box.gltf
new file mode 100644
index 00000000..7f603f07
--- /dev/null
+++ b/assets/Box.gltf
@@ -0,0 +1,142 @@
+{
+ "asset": {
+ "generator": "COLLADA2GLTF",
+ "version": "2.0"
+ },
+ "scene": 0,
+ "scenes": [
+ {
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ]
+ },
+ {
+ "mesh": 0
+ }
+ ],
+ "meshes": [
+ {
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 2
+ },
+ "indices": 0,
+ "mode": 4,
+ "material": 0
+ }
+ ],
+ "name": "Mesh"
+ }
+ ],
+ "accessors": [
+ {
+ "bufferView": 0,
+ "byteOffset": 0,
+ "componentType": 5123,
+ "count": 36,
+ "max": [
+ 23
+ ],
+ "min": [
+ 0
+ ],
+ "type": "SCALAR"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 0,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "min": [
+ -1.0,
+ -1.0,
+ -1.0
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 288,
+ "componentType": 5126,
+ "count": 24,
+ "max": [
+ 0.5,
+ 0.5,
+ 0.5
+ ],
+ "min": [
+ -0.5,
+ -0.5,
+ -0.5
+ ],
+ "type": "VEC3"
+ }
+ ],
+ "materials": [
+ {
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.800000011920929,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "metallicFactor": 0.0
+ },
+ "name": "Red"
+ }
+ ],
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteOffset": 576,
+ "byteLength": 72,
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteOffset": 0,
+ "byteLength": 576,
+ "byteStride": 12,
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 648,
+ "uri": "Box0.bin"
+ }
+ ]
+}
diff --git a/assets/Box0.bin b/assets/Box0.bin
new file mode 100644
index 00000000..d7798abb
Binary files /dev/null and b/assets/Box0.bin differ
diff --git a/assets/Bunny.bin b/assets/Bunny.bin
new file mode 100644
index 00000000..0386d125
Binary files /dev/null and b/assets/Bunny.bin differ
diff --git a/assets/Bunny.gltf b/assets/Bunny.gltf
new file mode 100644
index 00000000..d14d2919
--- /dev/null
+++ b/assets/Bunny.gltf
@@ -0,0 +1,152 @@
+{
+ "accessors": [
+ {
+ "bufferView": 1,
+ "componentType": 5126,
+ "count": 36218,
+ "max": [
+ 0.06100910156965256,
+ 0.1873210072517395,
+ 0.05879969894886017
+ ],
+ "min": [
+ -0.09468989819288254,
+ 0.03298740088939667,
+ -0.061873599886894226
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "byteOffset": 434616,
+ "componentType": 5126,
+ "count": 36218,
+ "max": [
+ 1.0,
+ 0.9999903440475464,
+ 0.9999992847442627
+ ],
+ "min": [
+ -0.9999505281448364,
+ -0.999995231628418,
+ -0.9999715685844421
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 0,
+ "componentType": 5125,
+ "count": 208353,
+ "type": "SCALAR"
+ }
+ ],
+ "asset": {
+ "extras": {
+ "author": "3D graphics 101 (https://sketchfab.com/3dgraphics)",
+ "license": "CC-BY-NC-4.0 (http://creativecommons.org/licenses/by-nc/4.0/)",
+ "source": "https://sketchfab.com/3d-models/stanford-bunny-zipper-reconstruction-6b197d03ba2447ba83ae94f64b908539",
+ "title": "Stanford Bunny (Zipper reconstruction)"
+ },
+ "generator": "Sketchfab-12.64.0",
+ "version": "2.0"
+ },
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteLength": 833412,
+ "name": "floatBufferViews",
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteLength": 869232,
+ "byteOffset": 833412,
+ "byteStride": 12,
+ "name": "floatBufferViews",
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 1702644,
+ "uri": "Bunny.bin"
+ }
+ ],
+ "materials": [
+ {
+ "doubleSided": true,
+ "name": "Scene_-_Root",
+ "pbrMetallicRoughness": {
+ "baseColorFactor": [
+ 0.5,
+ 0.5,
+ 0.5,
+ 1.0
+ ],
+ "metallicFactor": 0.0,
+ "roughnessFactor": 0.9
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "name": "Object_0",
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 0
+ },
+ "indices": 2,
+ "material": 0,
+ "mode": 4
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 2.220446049250313e-16,
+ 0.0,
+ 0.0,
+ -2.220446049250313e-16,
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "name": "Sketchfab_model"
+ },
+ {
+ "children": [
+ 2
+ ],
+ "name": "Geode"
+ },
+ {
+ "mesh": 0,
+ "name": "Object_2"
+ }
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "name": "Sketchfab_Scene",
+ "nodes": [
+ 0
+ ]
+ }
+ ]
+}
diff --git a/assets/Dragon-20231011T150823Z-001.zip b/assets/Dragon-20231011T150823Z-001.zip
new file mode 100644
index 00000000..b6a46be7
Binary files /dev/null and b/assets/Dragon-20231011T150823Z-001.zip differ
diff --git a/assets/Orange.bin b/assets/Orange.bin
new file mode 100644
index 00000000..e2b8b99a
Binary files /dev/null and b/assets/Orange.bin differ
diff --git a/assets/Orange.gltf b/assets/Orange.gltf
new file mode 100644
index 00000000..1da7a353
--- /dev/null
+++ b/assets/Orange.gltf
@@ -0,0 +1,191 @@
+{
+ "accessors": [
+ {
+ "bufferView": 2,
+ "componentType": 5126,
+ "count": 592,
+ "max": [
+ 13.927929878234863,
+ 13.892550468444824,
+ 7.208002090454102
+ ],
+ "min": [
+ -13.868430137634277,
+ -13.88306999206543,
+ -13.88012981414795
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 7104,
+ "componentType": 5126,
+ "count": 592,
+ "max": [
+ 0.9989652037620544,
+ 0.9990018010139465,
+ 0.9972373843193054
+ ],
+ "min": [
+ -0.9940516352653503,
+ -0.9990112781524658,
+ -0.9989686012268066
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "componentType": 5126,
+ "count": 592,
+ "max": [
+ 0.9950000047683716,
+ 0.9581609964370728
+ ],
+ "min": [
+ 0.004999999888241291,
+ 0.004999995231628418
+ ],
+ "type": "VEC2"
+ },
+ {
+ "bufferView": 0,
+ "componentType": 5125,
+ "count": 2760,
+ "type": "SCALAR"
+ }
+ ],
+ "asset": {
+ "extras": {
+ "author": "polyplant3d (https://sketchfab.com/polyplant3d)",
+ "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
+ "source": "https://sketchfab.com/3d-models/orange-fruit-cbdf758f21924c168c1c3da1afed9754",
+ "title": "orange fruit"
+ },
+ "generator": "Sketchfab-12.68.0",
+ "version": "2.0"
+ },
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteLength": 11040,
+ "name": "floatBufferViews",
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteLength": 4736,
+ "byteOffset": 11040,
+ "byteStride": 8,
+ "name": "floatBufferViews",
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteLength": 14208,
+ "byteOffset": 15776,
+ "byteStride": 12,
+ "name": "floatBufferViews",
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 29984,
+ "uri": "Orange.bin"
+ }
+ ],
+ "images": [
+ {
+ "uri": "orange_halb3DC_null_color_baseColor.jpeg"
+ }
+ ],
+ "materials": [
+ {
+ "doubleSided": true,
+ "name": "orange_halb3DC_null_color",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0
+ },
+ "metallicFactor": 0.0,
+ "roughnessFactor": 0.6
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "name": "Object_0",
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 0,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 0,
+ "mode": 4
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 2.220446049250313e-16,
+ -1.0,
+ 0.0,
+ 0.0,
+ 1.0,
+ 2.220446049250313e-16,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "name": "Sketchfab_model"
+ },
+ {
+ "children": [
+ 2
+ ],
+ "name": "sdsdfs.unity_1.obj.cleaner.gles"
+ },
+ {
+ "mesh": 0,
+ "name": "Object_2"
+ }
+ ],
+ "samplers": [
+ {
+ "magFilter": 9729,
+ "minFilter": 9987,
+ "wrapS": 10497,
+ "wrapT": 10497
+ }
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "name": "Sketchfab_Scene",
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "textures": [
+ {
+ "sampler": 0,
+ "source": 0
+ }
+ ]
+}
diff --git a/assets/Suzanne.bin b/assets/Suzanne.bin
new file mode 100644
index 00000000..60f54db7
Binary files /dev/null and b/assets/Suzanne.bin differ
diff --git a/assets/Suzanne.gltf b/assets/Suzanne.gltf
new file mode 100644
index 00000000..56607849
--- /dev/null
+++ b/assets/Suzanne.gltf
@@ -0,0 +1,193 @@
+{
+ "accessors" : [
+ {
+ "bufferView" : 0,
+ "byteOffset" : 0,
+ "componentType" : 5123,
+ "count" : 11808,
+ "max" : [
+ 11807
+ ],
+ "min" : [
+ 0
+ ],
+ "type" : "SCALAR"
+ },
+ {
+ "bufferView" : 1,
+ "byteOffset" : 0,
+ "componentType" : 5126,
+ "count" : 11808,
+ "max" : [
+ 1.336914,
+ 0.950195,
+ 0.825684
+ ],
+ "min" : [
+ -1.336914,
+ -0.974609,
+ -0.800781
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 2,
+ "byteOffset" : 0,
+ "componentType" : 5126,
+ "count" : 11808,
+ "max" : [
+ 0.996339,
+ 0.999958,
+ 0.999929
+ ],
+ "min" : [
+ -0.996339,
+ -0.985940,
+ -0.999994
+ ],
+ "type" : "VEC3"
+ },
+ {
+ "bufferView" : 3,
+ "byteOffset" : 0,
+ "componentType" : 5126,
+ "count" : 11808,
+ "max" : [
+ 0.998570,
+ 0.999996,
+ 0.999487,
+ 1.000000
+ ],
+ "min" : [
+ -0.999233,
+ -0.999453,
+ -0.999812,
+ 1.000000
+ ],
+ "type" : "VEC4"
+ },
+ {
+ "bufferView" : 4,
+ "byteOffset" : 0,
+ "componentType" : 5126,
+ "count" : 11808,
+ "max" : [
+ 0.999884,
+ 0.884359
+ ],
+ "min" : [
+ 0.000116,
+ 0.000116
+ ],
+ "type" : "VEC2"
+ }
+ ],
+ "asset" : {
+ "generator" : "VKTS glTF 2.0 exporter",
+ "version" : "2.0"
+ },
+ "bufferViews" : [
+ {
+ "buffer" : 0,
+ "byteLength" : 23616,
+ "byteOffset" : 0,
+ "target" : 34963
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 141696,
+ "byteOffset" : 23616,
+ "target" : 34962
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 141696,
+ "byteOffset" : 165312,
+ "target" : 34962
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 188928,
+ "byteOffset" : 307008,
+ "target" : 34962
+ },
+ {
+ "buffer" : 0,
+ "byteLength" : 94464,
+ "byteOffset" : 495936,
+ "target" : 34962
+ }
+ ],
+ "buffers" : [
+ {
+ "byteLength" : 590400,
+ "uri" : "Suzanne.bin"
+ }
+ ],
+ "images" : [
+ {
+ "uri" : "Suzanne_BaseColor.png"
+ },
+ {
+ "uri" : "Suzanne_MetallicRoughness.png"
+ }
+ ],
+ "materials" : [
+ {
+ "name" : "Suzanne",
+ "pbrMetallicRoughness" : {
+ "baseColorTexture" : {
+ "index" : 0
+ },
+ "metallicRoughnessTexture" : {
+ "index" : 1
+ }
+ }
+ }
+ ],
+ "meshes" : [
+ {
+ "name" : "Suzanne",
+ "primitives" : [
+ {
+ "attributes" : {
+ "NORMAL" : 2,
+ "POSITION" : 1,
+ "TANGENT" : 3,
+ "TEXCOORD_0" : 4
+ },
+ "indices" : 0,
+ "material" : 0,
+ "mode" : 4
+ }
+ ]
+ }
+ ],
+ "nodes" : [
+ {
+ "mesh" : 0,
+ "name" : "Suzanne"
+ }
+ ],
+ "samplers" : [
+ {}
+ ],
+ "scene" : 0,
+ "scenes" : [
+ {
+ "nodes" : [
+ 0
+ ]
+ }
+ ],
+ "textures" : [
+ {
+ "sampler" : 0,
+ "source" : 0
+ },
+ {
+ "sampler" : 0,
+ "source" : 1
+ }
+ ]
+}
diff --git a/assets/Suzanne_BaseColor.png b/assets/Suzanne_BaseColor.png
new file mode 100644
index 00000000..1baf37d5
Binary files /dev/null and b/assets/Suzanne_BaseColor.png differ
diff --git a/assets/Watermelon.bin b/assets/Watermelon.bin
new file mode 100644
index 00000000..2ed73c76
Binary files /dev/null and b/assets/Watermelon.bin differ
diff --git a/assets/Watermelon.gltf b/assets/Watermelon.gltf
new file mode 100644
index 00000000..38f4ef0d
--- /dev/null
+++ b/assets/Watermelon.gltf
@@ -0,0 +1,226 @@
+{
+ "accessors": [
+ {
+ "bufferView": 2,
+ "componentType": 5126,
+ "count": 1057,
+ "max": [
+ 0.9999997019767761,
+ -4.371138828673793e-08,
+ 0.9999994039535522
+ ],
+ "min": [
+ -0.9999990463256836,
+ -1.0,
+ -0.9999987483024597
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 2,
+ "byteOffset": 12684,
+ "componentType": 5126,
+ "count": 1057,
+ "max": [
+ 0.9951868653297424,
+ 0.6717398762702942,
+ 0.9951868653297424
+ ],
+ "min": [
+ -0.9951868653297424,
+ -1.0,
+ -0.9951868653297424
+ ],
+ "type": "VEC3"
+ },
+ {
+ "bufferView": 1,
+ "componentType": 5126,
+ "count": 1057,
+ "max": [
+ 0.9996512532234192,
+ 0.9987801909446716
+ ],
+ "min": [
+ 0.016094159334897995,
+ 0.46866166591644287
+ ],
+ "type": "VEC2"
+ },
+ {
+ "bufferView": 0,
+ "componentType": 5125,
+ "count": 5946,
+ "type": "SCALAR"
+ }
+ ],
+ "asset": {
+ "extras": {
+ "author": "catafest (https://sketchfab.com/catafest)",
+ "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
+ "source": "https://sketchfab.com/3d-models/watermelon-fruit-f120452f84bf4e979139b106bf9f096c",
+ "title": "Watermelon fruit"
+ },
+ "generator": "Sketchfab-12.67.0",
+ "version": "2.0"
+ },
+ "bufferViews": [
+ {
+ "buffer": 0,
+ "byteLength": 23784,
+ "name": "floatBufferViews",
+ "target": 34963
+ },
+ {
+ "buffer": 0,
+ "byteLength": 8456,
+ "byteOffset": 23784,
+ "byteStride": 8,
+ "name": "floatBufferViews",
+ "target": 34962
+ },
+ {
+ "buffer": 0,
+ "byteLength": 25368,
+ "byteOffset": 32240,
+ "byteStride": 12,
+ "name": "floatBufferViews",
+ "target": 34962
+ }
+ ],
+ "buffers": [
+ {
+ "byteLength": 57608,
+ "uri": "Watermelon.bin"
+ }
+ ],
+ "extensionsUsed": [
+ "KHR_materials_unlit"
+ ],
+ "images": [
+ {
+ "uri": "watermelon_baseColor.png"
+ }
+ ],
+ "materials": [
+ {
+ "doubleSided": true,
+ "extensions": {
+ "KHR_materials_unlit": {}
+ },
+ "name": "watermelon",
+ "pbrMetallicRoughness": {
+ "baseColorTexture": {
+ "index": 0
+ },
+ "metallicFactor": 0.0
+ }
+ }
+ ],
+ "meshes": [
+ {
+ "name": "Object_0",
+ "primitives": [
+ {
+ "attributes": {
+ "NORMAL": 1,
+ "POSITION": 0,
+ "TEXCOORD_0": 2
+ },
+ "indices": 3,
+ "material": 0,
+ "mode": 4
+ }
+ ]
+ }
+ ],
+ "nodes": [
+ {
+ "children": [
+ 1
+ ],
+ "matrix": [
+ 0.1953413188457489,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 4.337448596863889e-17,
+ -0.1953413188457489,
+ 0.0,
+ 0.0,
+ 0.1953413188457489,
+ 4.337448596863889e-17,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "name": "Sketchfab_model"
+ },
+ {
+ "children": [
+ 2
+ ],
+ "name": "root"
+ },
+ {
+ "children": [
+ 3
+ ],
+ "matrix": [
+ 1.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 2.220446049250313e-16,
+ 1.0,
+ 0.0,
+ 0.0,
+ -1.0,
+ 2.220446049250313e-16,
+ 0.0,
+ 0.0,
+ 0.0,
+ 0.0,
+ 1.0
+ ],
+ "name": "GLTF_SceneRootNode"
+ },
+ {
+ "children": [
+ 4
+ ],
+ "name": "Sphere_0"
+ },
+ {
+ "mesh": 0,
+ "name": "Object_4"
+ }
+ ],
+ "samplers": [
+ {
+ "magFilter": 9729,
+ "minFilter": 9987,
+ "wrapS": 10497,
+ "wrapT": 10497
+ }
+ ],
+ "scene": 0,
+ "scenes": [
+ {
+ "name": "Sketchfab_Scene",
+ "nodes": [
+ 0
+ ]
+ }
+ ],
+ "textures": [
+ {
+ "sampler": 0,
+ "source": 0
+ }
+ ]
+}
diff --git a/assets/default_baseColor.png b/assets/default_baseColor.png
new file mode 100644
index 00000000..50387342
Binary files /dev/null and b/assets/default_baseColor.png differ
diff --git a/assets/dragon.bin b/assets/dragon.bin
new file mode 100644
index 00000000..494daada
Binary files /dev/null and b/assets/dragon.bin differ
diff --git a/assets/dragon.gltf b/assets/dragon.gltf
new file mode 100644
index 00000000..4b2f2714
--- /dev/null
+++ b/assets/dragon.gltf
@@ -0,0 +1,114 @@
+{
+ "asset":{
+ "generator":"Khronos glTF Blender I/O v3.6.27",
+ "version":"2.0"
+ },
+ "scene":0,
+ "scenes":[
+ {
+ "name":"Scene",
+ "nodes":[
+ 0
+ ]
+ }
+ ],
+ "nodes":[
+ {
+ "mesh":0,
+ "name":"dragon",
+ "rotation":[
+ 0.7071068286895752,
+ 0,
+ 0,
+ 0.7071068286895752
+ ]
+ }
+ ],
+ "materials":[
+ {
+ "doubleSided":true,
+ "name":"Default OBJ",
+ "pbrMetallicRoughness":{
+ "baseColorFactor":[
+ 0.800000011920929,
+ 0.800000011920929,
+ 0.800000011920929,
+ 1
+ ],
+ "metallicFactor":0,
+ "roughnessFactor":0.5
+ }
+ }
+ ],
+ "meshes":[
+ {
+ "name":"dragon",
+ "primitives":[
+ {
+ "attributes":{
+ "POSITION":0,
+ "NORMAL":1
+ },
+ "indices":2,
+ "material":0
+ }
+ ]
+ }
+ ],
+ "accessors":[
+ {
+ "bufferView":0,
+ "componentType":5126,
+ "count":439102,
+ "max":[
+ 0.20739500224590302,
+ 0.5277529954910278,
+ 0.2829580008983612
+ ],
+ "min":[
+ -0.239779993891716,
+ -0.47224700450897217,
+ -0.4220220148563385
+ ],
+ "type":"VEC3"
+ },
+ {
+ "bufferView":1,
+ "componentType":5126,
+ "count":439102,
+ "type":"VEC3"
+ },
+ {
+ "bufferView":2,
+ "componentType":5125,
+ "count":2613918,
+ "type":"SCALAR"
+ }
+ ],
+ "bufferViews":[
+ {
+ "buffer":0,
+ "byteLength":5269224,
+ "byteOffset":0,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":5269224,
+ "byteOffset":5269224,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":10455672,
+ "byteOffset":10538448,
+ "target":34963
+ }
+ ],
+ "buffers":[
+ {
+ "byteLength":20994120,
+ "uri":"dragon.bin"
+ }
+ ]
+}
diff --git a/assets/orange_fruit.zip b/assets/orange_fruit.zip
new file mode 100644
index 00000000..52f5713d
Binary files /dev/null and b/assets/orange_fruit.zip differ
diff --git a/assets/orange_halb3DC_null_color_baseColor.jpeg b/assets/orange_halb3DC_null_color_baseColor.jpeg
new file mode 100644
index 00000000..260d5e3d
Binary files /dev/null and b/assets/orange_halb3DC_null_color_baseColor.jpeg differ
diff --git a/assets/stanford_bunny_zipper_reconstruction.zip b/assets/stanford_bunny_zipper_reconstruction.zip
new file mode 100644
index 00000000..94c99bbb
Binary files /dev/null and b/assets/stanford_bunny_zipper_reconstruction.zip differ
diff --git a/assets/teapot.bin b/assets/teapot.bin
new file mode 100644
index 00000000..3286076d
Binary files /dev/null and b/assets/teapot.bin differ
diff --git a/assets/teapot.gltf b/assets/teapot.gltf
new file mode 100644
index 00000000..6b98be9b
--- /dev/null
+++ b/assets/teapot.gltf
@@ -0,0 +1,208 @@
+{
+ "asset":{
+ "generator":"Khronos glTF Blender I/O v3.6.27",
+ "version":"2.0"
+ },
+ "scene":0,
+ "scenes":[
+ {
+ "name":"Scene",
+ "nodes":[
+ 2
+ ]
+ }
+ ],
+ "nodes":[
+ {
+ "mesh":0,
+ "name":"Object_3"
+ },
+ {
+ "children":[
+ 0
+ ],
+ "name":"teapot.obj.cleaner.materialmerger.gles"
+ },
+ {
+ "children":[
+ 1
+ ],
+ "name":"Sketchfab_model",
+ "rotation":[
+ -0.70710688829422,
+ 0,
+ 0,
+ 0.7071066498756409
+ ]
+ }
+ ],
+ "materials":[
+ {
+ "doubleSided":true,
+ "name":"default",
+ "pbrMetallicRoughness":{
+ "metallicFactor":0,
+ "roughnessFactor":0.8999999761581421
+ }
+ },
+ {
+ "doubleSided":true,
+ "name":"Default",
+ "pbrMetallicRoughness":{
+ "metallicFactor":0,
+ "roughnessFactor":0.8999999761581421
+ }
+ }
+ ],
+ "meshes":[
+ {
+ "name":"Object_1",
+ "primitives":[
+ {
+ "attributes":{
+ "POSITION":0,
+ "NORMAL":1,
+ "TEXCOORD_0":2
+ },
+ "indices":3,
+ "material":0
+ },
+ {
+ "attributes":{
+ "POSITION":4,
+ "NORMAL":5,
+ "TEXCOORD_0":6
+ },
+ "indices":7,
+ "material":1
+ }
+ ]
+ }
+ ],
+ "accessors":[
+ {
+ "bufferView":0,
+ "componentType":5126,
+ "count":6534,
+ "max":[
+ 82.29399871826172,
+ 47.9283561706543,
+ 59.87300491333008
+ ],
+ "min":[
+ -71.89253234863281,
+ -47.9283561706543,
+ 0
+ ],
+ "type":"VEC3"
+ },
+ {
+ "bufferView":1,
+ "componentType":5126,
+ "count":6534,
+ "type":"VEC3"
+ },
+ {
+ "bufferView":2,
+ "componentType":5126,
+ "count":6534,
+ "type":"VEC2"
+ },
+ {
+ "bufferView":3,
+ "componentType":5123,
+ "count":36456,
+ "type":"SCALAR"
+ },
+ {
+ "bufferView":4,
+ "componentType":5126,
+ "count":1922,
+ "max":[
+ 33.56470489501953,
+ 33.5647087097168,
+ 79.00656127929688
+ ],
+ "min":[
+ -33.5647087097168,
+ -33.5647087097168,
+ 58.93854904174805
+ ],
+ "type":"VEC3"
+ },
+ {
+ "bufferView":5,
+ "componentType":5126,
+ "count":1922,
+ "type":"VEC3"
+ },
+ {
+ "bufferView":6,
+ "componentType":5126,
+ "count":1922,
+ "type":"VEC2"
+ },
+ {
+ "bufferView":7,
+ "componentType":5123,
+ "count":10656,
+ "type":"SCALAR"
+ }
+ ],
+ "bufferViews":[
+ {
+ "buffer":0,
+ "byteLength":78408,
+ "byteOffset":0,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":78408,
+ "byteOffset":78408,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":52272,
+ "byteOffset":156816,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":72912,
+ "byteOffset":209088,
+ "target":34963
+ },
+ {
+ "buffer":0,
+ "byteLength":23064,
+ "byteOffset":282000,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":23064,
+ "byteOffset":305064,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":15376,
+ "byteOffset":328128,
+ "target":34962
+ },
+ {
+ "buffer":0,
+ "byteLength":21312,
+ "byteOffset":343504,
+ "target":34963
+ }
+ ],
+ "buffers":[
+ {
+ "byteLength":364816,
+ "uri":"teapot.bin"
+ }
+ ]
+}
diff --git a/assets/watermelon_baseColor.png b/assets/watermelon_baseColor.png
new file mode 100644
index 00000000..c24eda31
Binary files /dev/null and b/assets/watermelon_baseColor.png differ
diff --git a/assets/watermelon_fruit.zip b/assets/watermelon_fruit.zip
new file mode 100644
index 00000000..faff2410
Binary files /dev/null and b/assets/watermelon_fruit.zip differ
diff --git a/external/include/json.hpp b/external/include/json.hpp
new file mode 100644
index 00000000..87475ab3
--- /dev/null
+++ b/external/include/json.hpp
@@ -0,0 +1,26753 @@
+/*
+ __ _____ _____ _____
+ __| | __| | | | JSON for Modern C++
+| | |__ | | | | | | version 3.10.4
+|_____|_____|_____|_|___| https://github.com/nlohmann/json
+
+Licensed under the MIT License .
+SPDX-License-Identifier: MIT
+Copyright (c) 2013-2019 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 INCLUDE_NLOHMANN_JSON_HPP_
+#define INCLUDE_NLOHMANN_JSON_HPP_
+
+#define NLOHMANN_JSON_VERSION_MAJOR 3
+#define NLOHMANN_JSON_VERSION_MINOR 10
+#define NLOHMANN_JSON_VERSION_PATCH 4
+
+#include // all_of, find, for_each
+#include // nullptr_t, ptrdiff_t, size_t
+#include // hash, less
+#include // initializer_list
+#ifndef JSON_NO_IO
+ #include // istream, ostream
+#endif // JSON_NO_IO
+#include // random_access_iterator_tag
+#include // unique_ptr
+#include // accumulate
+#include // string, stoi, to_string
+#include // declval, forward, move, pair, swap
+#include // vector
+
+// #include
+
+
+#include
+#include
+
+// #include
+
+
+#include // transform
+#include // array
+#include // forward_list
+#include // inserter, front_inserter, end
+#include