├── .gitignore ├── .vscode └── spellright.dict ├── Cargo.toml ├── LICENSE.txt ├── Readme.md ├── data └── models │ ├── cone.obj │ ├── cube.obj │ ├── cylinder.obj │ ├── d4.obj │ ├── diamond_1.obj │ ├── diamond_2.obj │ ├── diamond_3.obj │ ├── hollow_cube.obj │ ├── ico_sphere.obj │ ├── ico_sphere_1.obj │ ├── sphere.obj │ ├── star.obj │ ├── suzanne.obj │ ├── teapot.obj │ └── torus.obj ├── docs ├── _config.yml ├── _includes │ ├── head-custom-google-analytics.html │ └── head-custom.html ├── _layouts │ └── default.html ├── _sass │ ├── cayman.scss │ ├── jekyll-theme-cayman.scss │ ├── normalize.scss │ ├── rouge-github.scss │ └── variables.scss ├── imgs │ ├── 0 │ │ ├── owl.png │ │ ├── rust_logo.png │ │ └── vulkan_logo.png │ ├── 1 │ │ ├── first_window.png │ │ └── updated_window.png │ ├── 2 │ │ ├── colorful_triangle.png │ │ └── triangle.png │ ├── 3 │ │ ├── coordinates.png │ │ ├── projection_triangle.png │ │ ├── required_trait.png │ │ ├── squished_triangle.png │ │ ├── translated_triangle.png │ │ ├── updated_triangle.png │ │ └── view_triangle.png │ ├── 4 │ │ ├── fixed_depth_triangles.png │ │ └── triangles_with_no_depth.png │ ├── 5 │ │ ├── culled_triangle.png │ │ └── triangle.png │ ├── 6 │ │ ├── ambient_1.png │ │ ├── ambient_2.png │ │ ├── ambient_2b.png │ │ ├── ambient_3.png │ │ ├── error.png │ │ ├── lit_cube.png │ │ ├── rotating_cube.png │ │ └── static_cube.png │ ├── 7 │ │ ├── lit_cube.png │ │ ├── multi_pass_diagram.png │ │ ├── normal_cube.png │ │ ├── review.png │ │ └── unlit_cube.png │ ├── 8 │ │ ├── combined_images.png │ │ ├── cube_lights.png │ │ ├── single_light.png │ │ └── three_lights.png │ ├── 9 │ │ ├── cube.png │ │ ├── export_1.png │ │ ├── export_2.png │ │ ├── suzanne_1.png │ │ ├── suzanne_2.png │ │ └── suzanne_blender.png │ ├── 10 │ │ └── teapot.png │ ├── 11 │ │ ├── blank_window.png │ │ ├── swap.png │ │ ├── teapot.png │ │ └── three.png │ ├── 12 │ │ ├── directional.png │ │ ├── gold_and_rubber.png │ │ ├── lit_cube.png │ │ ├── specular.png │ │ ├── specular_only.png │ │ ├── suzanne_full.png │ │ ├── suzanne_specular_only.png │ │ ├── two_cubes.png │ │ └── two_cubes_full.png │ ├── 13 │ │ ├── NormalMaps.png │ │ ├── diamond.png │ │ ├── noise.png │ │ ├── textured.png │ │ ├── triangle1.png │ │ ├── triangle2.png │ │ ├── untextured.png │ │ └── uv.png │ ├── 14 │ │ ├── 201.png │ │ ├── compressed.png │ │ ├── count.png │ │ ├── marked_texture.png │ │ ├── spacing.png │ │ ├── texture_map.png │ │ └── texture_small.png │ └── 11_5 │ │ ├── illuminated_teapot.png │ │ ├── illuminated_teapot_2.png │ │ ├── sphere_1.png │ │ └── sphere_2.png ├── index.md ├── section_0.md ├── section_1.md ├── section_10.md ├── section_11.md ├── section_11_5.md ├── section_12.md ├── section_13.md ├── section_14.md ├── section_2.md ├── section_3.md ├── section_4.md ├── section_5.md ├── section_6.md ├── section_7.md ├── section_8.md └── section_9.md └── lessons ├── 1. Initialization ├── Cargo.toml └── src │ └── main.rs ├── 10. Uniform Refactoring ├── Cargo.toml └── src │ ├── main.rs │ ├── model.rs │ ├── obj_loader │ ├── face.rs │ ├── loader.rs │ ├── mod.rs │ └── vertex.rs │ └── shaders │ ├── ambient.frag │ ├── ambient.vert │ ├── deferred.frag │ ├── deferred.vert │ ├── directional.frag │ └── directional.vert ├── 11. First Rendering System ├── Cargo.toml └── src │ ├── main.rs │ ├── model.rs │ ├── obj_loader │ ├── face.rs │ ├── loader.rs │ ├── mod.rs │ └── vertex.rs │ └── system │ ├── mod.rs │ ├── shaders │ ├── ambient.frag │ ├── ambient.vert │ ├── deferred.frag │ ├── deferred.vert │ ├── directional.frag │ └── directional.vert │ └── system.rs ├── 11.5. Light Objects ├── Cargo.toml └── src │ ├── main.rs │ ├── model.rs │ ├── obj_loader │ ├── face.rs │ ├── loader.rs │ ├── mod.rs │ └── vertex.rs │ └── system │ ├── mod.rs │ ├── shaders │ ├── ambient.frag │ ├── ambient.vert │ ├── deferred.frag │ ├── deferred.vert │ ├── directional.frag │ ├── directional.vert │ ├── light_obj.frag │ └── light_obj.vert │ └── system.rs ├── 12. Light III ├── Cargo.toml └── src │ ├── main.rs │ ├── model.rs │ ├── obj_loader │ ├── face.rs │ ├── loader.rs │ ├── mod.rs │ └── vertex.rs │ └── system │ ├── mod.rs │ ├── shaders │ ├── ambient.frag │ ├── ambient.vert │ ├── deferred.frag │ ├── deferred.vert │ ├── directional.frag │ ├── directional.vert │ ├── light_obj.frag │ └── light_obj.vert │ └── system.rs ├── 13. Textures ├── Cargo.toml └── src │ ├── main.rs │ └── textures │ ├── compass.png │ └── diamond.png ├── 14. Text ├── Cargo.toml └── src │ ├── main.rs │ ├── monospace.rs │ └── textures │ ├── diamond.png │ └── texture_small.png ├── 2. Triangle ├── Cargo.toml └── src │ └── main.rs ├── 3. Transformations and Uniforms ├── Cargo.toml └── src │ └── main.rs ├── 4. Depth ├── Cargo.toml └── src │ └── main.rs ├── 5. Face and Winding Order ├── Cargo.toml └── src │ └── main.rs ├── 6. Light I ├── Cargo.toml └── src │ └── main.rs ├── 7. Deferred Rendering ├── Cargo.toml └── src │ ├── main.rs │ └── shaders │ ├── deferred.frag │ ├── deferred.vert │ ├── lighting.frag │ └── lighting.vert ├── 8. Light II ├── Cargo.toml └── src │ ├── main.rs │ └── shaders │ ├── ambient.frag │ ├── ambient.vert │ ├── deferred.frag │ ├── deferred.vert │ ├── directional.frag │ └── directional.vert └── 9. Model Loading ├── Cargo.toml └── src ├── main.rs ├── model.rs ├── obj_loader ├── face.rs ├── loader.rs ├── mod.rs └── vertex.rs └── shaders ├── ambient.frag ├── ambient.vert ├── deferred.frag ├── deferred.vert ├── directional.frag └── directional.vert /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | .idea 4 | *.iml 5 | Cargo.lock 6 | **/**/target 7 | **/**/Cargo.lock -------------------------------------------------------------------------------- /.vscode/spellright.dict: -------------------------------------------------------------------------------- 1 | Vulkano 2 | Vulkan 3 | shader 4 | shaders 5 | normals 6 | obj 7 | renderable 8 | renderpass 9 | subpasses 10 | subpass 11 | gotcha 12 | mvp 13 | opengl 14 | Cargo.toml 15 | nalgebra-glm 16 | swapchain 17 | destructuring 18 | enum 19 | swapchains 20 | suzanne 21 | io 22 | png 23 | api 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "lessons/1. Initialization", 4 | "lessons/2. Triangle", 5 | "lessons/3. Transformations and Uniforms", 6 | "lessons/4. Depth", 7 | "lessons/5. Face and Winding Order", 8 | "lessons/6. Light I", 9 | "lessons/7. Deferred Rendering", 10 | "lessons/8. Light II", 11 | "lessons/9. Model Loading", 12 | "lessons/10. Uniform Refactoring", 13 | "lessons/11. First Rendering System", 14 | "lessons/11.5. Light Objects", 15 | "lessons/12. Light III", 16 | "lessons/13. Textures", 17 | "lessons/14. Text", 18 | ] 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 taidaesal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Vulkano Tutorial 2 | 3 | A repo for a tutorial series on Vulkan programming using the Vulkano Rust crate. The lessons go from initial project setup to toy rendering systems. Based on example code provided by the Vulkano project contributors. 4 | 5 | See the website [here](https://taidaesal.github.io/vulkano_tutorial/) 6 | 7 | Status of the project: 8 | - Current Vulkano version: [![Crates.io](https://img.shields.io/crates/v/vulkano.svg)](https://crates.io/crates/vulkano) 9 | - Current tutorial version: `0.32.0` 10 | 11 | All code is provided under the [MIT License](http://opensource.org/licenses/MIT) and includes samples taken from official Vulkano examples. All text and images are licensed under the [Creative Commons Attribution](https://creativecommons.org/licenses/by/4.0/) license (CC BY 4.0) 12 | -------------------------------------------------------------------------------- /data/models/cone.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Cone 4 | v 0.000000 1.000000 1.000000 5 | v 0.195090 1.000000 0.980785 6 | v 0.382683 1.000000 0.923880 7 | v 0.555570 1.000000 0.831470 8 | v 0.707107 1.000000 0.707107 9 | v 0.831470 1.000000 0.555570 10 | v 0.923880 1.000000 0.382683 11 | v 0.980785 1.000000 0.195090 12 | v 1.000000 1.000000 0.000000 13 | v 0.980785 1.000000 -0.195090 14 | v 0.923880 1.000000 -0.382683 15 | v 0.831470 1.000000 -0.555570 16 | v 0.707107 1.000000 -0.707107 17 | v 0.555570 1.000000 -0.831470 18 | v 0.382683 1.000000 -0.923880 19 | v 0.195090 1.000000 -0.980785 20 | v -0.000000 1.000000 -1.000000 21 | v -0.195091 1.000000 -0.980785 22 | v -0.382684 1.000000 -0.923879 23 | v -0.555571 1.000000 -0.831469 24 | v -0.707107 1.000000 -0.707106 25 | v -0.831470 1.000000 -0.555570 26 | v -0.923880 1.000000 -0.382683 27 | v 0.000000 -1.000000 0.000000 28 | v -0.980785 1.000000 -0.195089 29 | v -1.000000 1.000000 0.000001 30 | v -0.980785 1.000000 0.195091 31 | v -0.923879 1.000000 0.382684 32 | v -0.831469 1.000000 0.555571 33 | v -0.707106 1.000000 0.707108 34 | v -0.555569 1.000000 0.831470 35 | v -0.382682 1.000000 0.923880 36 | v -0.195089 1.000000 0.980786 37 | vt 0.250000 0.490000 38 | vt 0.250000 0.250000 39 | vt 0.296822 0.485388 40 | vt 0.341844 0.471731 41 | vt 0.383337 0.449553 42 | vt 0.419706 0.419706 43 | vt 0.449553 0.383337 44 | vt 0.471731 0.341844 45 | vt 0.485388 0.296822 46 | vt 0.490000 0.250000 47 | vt 0.485388 0.203178 48 | vt 0.471731 0.158156 49 | vt 0.449553 0.116663 50 | vt 0.419706 0.080294 51 | vt 0.383337 0.050447 52 | vt 0.341844 0.028269 53 | vt 0.296822 0.014612 54 | vt 0.250000 0.010000 55 | vt 0.203178 0.014612 56 | vt 0.158156 0.028269 57 | vt 0.116663 0.050447 58 | vt 0.080294 0.080294 59 | vt 0.050447 0.116663 60 | vt 0.028269 0.158156 61 | vt 0.014611 0.203179 62 | vt 0.010000 0.250000 63 | vt 0.014612 0.296822 64 | vt 0.028269 0.341844 65 | vt 0.050447 0.383337 66 | vt 0.080295 0.419706 67 | vt 0.116663 0.449553 68 | vt 0.158156 0.471731 69 | vt 0.203179 0.485389 70 | vt 0.985388 0.296822 71 | vt 0.796822 0.014612 72 | vt 0.514611 0.203179 73 | vt 0.703179 0.485389 74 | vt 0.750000 0.490000 75 | vt 0.796822 0.485388 76 | vt 0.841844 0.471731 77 | vt 0.883337 0.449553 78 | vt 0.919706 0.419706 79 | vt 0.949553 0.383337 80 | vt 0.971731 0.341844 81 | vt 0.990000 0.250000 82 | vt 0.985388 0.203178 83 | vt 0.971731 0.158156 84 | vt 0.949553 0.116663 85 | vt 0.919706 0.080294 86 | vt 0.883337 0.050447 87 | vt 0.841844 0.028269 88 | vt 0.750000 0.010000 89 | vt 0.703178 0.014612 90 | vt 0.658156 0.028269 91 | vt 0.616663 0.050447 92 | vt 0.580294 0.080294 93 | vt 0.550447 0.116663 94 | vt 0.528269 0.158156 95 | vt 0.510000 0.250000 96 | vt 0.514612 0.296822 97 | vt 0.528269 0.341844 98 | vt 0.550447 0.383337 99 | vt 0.580295 0.419706 100 | vt 0.616663 0.449553 101 | vt 0.658156 0.471731 102 | vn 0.0878 -0.4455 0.8910 103 | vn 0.2599 -0.4455 0.8567 104 | vn 0.4220 -0.4455 0.7896 105 | vn 0.5680 -0.4455 0.6921 106 | vn 0.6921 -0.4455 0.5680 107 | vn 0.7896 -0.4455 0.4220 108 | vn 0.8567 -0.4455 0.2599 109 | vn 0.8910 -0.4455 0.0878 110 | vn 0.8910 -0.4455 -0.0878 111 | vn 0.8567 -0.4455 -0.2599 112 | vn 0.7896 -0.4455 -0.4220 113 | vn 0.6921 -0.4455 -0.5680 114 | vn 0.5680 -0.4455 -0.6921 115 | vn 0.4220 -0.4455 -0.7896 116 | vn 0.2599 -0.4455 -0.8567 117 | vn 0.0878 -0.4455 -0.8910 118 | vn -0.0878 -0.4455 -0.8910 119 | vn -0.2599 -0.4455 -0.8567 120 | vn -0.4220 -0.4455 -0.7896 121 | vn -0.5680 -0.4455 -0.6921 122 | vn -0.6921 -0.4455 -0.5680 123 | vn -0.7896 -0.4455 -0.4220 124 | vn -0.8567 -0.4455 -0.2599 125 | vn -0.8910 -0.4455 -0.0878 126 | vn -0.8910 -0.4455 0.0878 127 | vn -0.8567 -0.4455 0.2599 128 | vn -0.7896 -0.4455 0.4220 129 | vn -0.6921 -0.4455 0.5680 130 | vn -0.5680 -0.4455 0.6921 131 | vn -0.4220 -0.4455 0.7896 132 | vn -0.2599 -0.4455 0.8567 133 | vn -0.0878 -0.4455 0.8910 134 | vn 0.0000 1.0000 0.0000 135 | s off 136 | f 1/1/1 24/2/1 2/3/1 137 | f 2/3/2 24/2/2 3/4/2 138 | f 3/4/3 24/2/3 4/5/3 139 | f 4/5/4 24/2/4 5/6/4 140 | f 5/6/5 24/2/5 6/7/5 141 | f 6/7/6 24/2/6 7/8/6 142 | f 7/8/7 24/2/7 8/9/7 143 | f 8/9/8 24/2/8 9/10/8 144 | f 9/10/9 24/2/9 10/11/9 145 | f 10/11/10 24/2/10 11/12/10 146 | f 11/12/11 24/2/11 12/13/11 147 | f 12/13/12 24/2/12 13/14/12 148 | f 13/14/13 24/2/13 14/15/13 149 | f 14/15/14 24/2/14 15/16/14 150 | f 15/16/15 24/2/15 16/17/15 151 | f 16/17/16 24/2/16 17/18/16 152 | f 17/18/17 24/2/17 18/19/17 153 | f 18/19/18 24/2/18 19/20/18 154 | f 19/20/19 24/2/19 20/21/19 155 | f 20/21/20 24/2/20 21/22/20 156 | f 21/22/21 24/2/21 22/23/21 157 | f 22/23/22 24/2/22 23/24/22 158 | f 23/24/23 24/2/23 25/25/23 159 | f 25/25/24 24/2/24 26/26/24 160 | f 26/26/25 24/2/25 27/27/25 161 | f 27/27/26 24/2/26 28/28/26 162 | f 28/28/27 24/2/27 29/29/27 163 | f 29/29/28 24/2/28 30/30/28 164 | f 30/30/29 24/2/29 31/31/29 165 | f 31/31/30 24/2/30 32/32/30 166 | f 32/32/31 24/2/31 33/33/31 167 | f 33/33/32 24/2/32 1/1/32 168 | f 8/34/33 16/35/33 25/36/33 169 | f 33/37/33 1/38/33 2/39/33 170 | f 2/39/33 3/40/33 4/41/33 171 | f 4/41/33 5/42/33 6/43/33 172 | f 6/43/33 7/44/33 4/41/33 173 | f 7/44/33 8/34/33 4/41/33 174 | f 8/34/33 9/45/33 10/46/33 175 | f 10/46/33 11/47/33 8/34/33 176 | f 11/47/33 12/48/33 8/34/33 177 | f 12/48/33 13/49/33 16/35/33 178 | f 13/49/33 14/50/33 16/35/33 179 | f 14/50/33 15/51/33 16/35/33 180 | f 16/35/33 17/52/33 18/53/33 181 | f 18/53/33 19/54/33 20/55/33 182 | f 20/55/33 21/56/33 22/57/33 183 | f 22/57/33 23/58/33 25/36/33 184 | f 25/36/33 26/59/33 27/60/33 185 | f 27/60/33 28/61/33 29/62/33 186 | f 29/62/33 30/63/33 33/37/33 187 | f 30/63/33 31/64/33 33/37/33 188 | f 31/64/33 32/65/33 33/37/33 189 | f 33/37/33 2/39/33 4/41/33 190 | f 16/35/33 18/53/33 25/36/33 191 | f 18/53/33 20/55/33 25/36/33 192 | f 20/55/33 22/57/33 25/36/33 193 | f 25/36/33 27/60/33 33/37/33 194 | f 27/60/33 29/62/33 33/37/33 195 | f 33/37/33 4/41/33 8/34/33 196 | f 8/34/33 12/48/33 16/35/33 197 | f 33/37/33 8/34/33 25/36/33 198 | -------------------------------------------------------------------------------- /data/models/cube.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Cube_Cube.001 4 | v -1.000000 1.000000 -1.000000 5 | v -1.000000 -1.000000 -1.000000 6 | v -1.000000 1.000000 1.000000 7 | v -1.000000 -1.000000 1.000000 8 | v 1.000000 1.000000 -1.000000 9 | v 1.000000 -1.000000 -1.000000 10 | v 1.000000 1.000000 1.000000 11 | v 1.000000 -1.000000 1.000000 12 | vt 0.625000 0.000000 13 | vt 0.375000 0.250000 14 | vt 0.375000 0.000000 15 | vt 0.625000 0.250000 16 | vt 0.375000 0.500000 17 | vt 0.625000 0.500000 18 | vt 0.375000 0.750000 19 | vt 0.625000 0.750000 20 | vt 0.375000 1.000000 21 | vt 0.125000 0.750000 22 | vt 0.125000 0.500000 23 | vt 0.875000 0.500000 24 | vt 0.625000 1.000000 25 | vt 0.875000 0.750000 26 | vn -1.0000 0.0000 0.0000 27 | vn 0.0000 0.0000 1.0000 28 | vn 1.0000 0.0000 0.0000 29 | vn 0.0000 0.0000 -1.0000 30 | vn 0.0000 1.0000 0.0000 31 | vn 0.0000 -1.0000 0.0000 32 | s off 33 | f 2/1/1 3/2/1 1/3/1 34 | f 4/4/2 7/5/2 3/2/2 35 | f 8/6/3 5/7/3 7/5/3 36 | f 6/8/4 1/9/4 5/7/4 37 | f 7/5/5 1/10/5 3/11/5 38 | f 4/12/6 6/8/6 8/6/6 39 | f 2/1/1 4/4/1 3/2/1 40 | f 4/4/2 8/6/2 7/5/2 41 | f 8/6/3 6/8/3 5/7/3 42 | f 6/8/4 2/13/4 1/9/4 43 | f 7/5/5 5/7/5 1/10/5 44 | f 4/12/6 2/14/6 6/8/6 45 | -------------------------------------------------------------------------------- /data/models/d4.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o GD_mesh 4 | v 0.000000 -1.000000 0.000000 5 | v -0.000000 0.333333 -0.942809 6 | v 0.816497 0.333333 0.471405 7 | v -0.816497 0.333333 0.471405 8 | vn -0.8165 0.3333 0.4714 9 | vn 0.0000 0.3333 -0.9428 10 | vn 0.8165 0.3333 0.4714 11 | vn 0.0000 -1.0000 0.0000 12 | s off 13 | f 1//1 3//1 2//1 14 | f 1//2 4//2 3//2 15 | f 1//3 2//3 4//3 16 | f 2//4 3//4 4//4 17 | -------------------------------------------------------------------------------- /data/models/diamond_2.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Diamond 4 | v 0.000000 -0.350000 0.000000 5 | v 0.000000 0.800000 0.000000 6 | v 0.600000 -0.350000 0.000000 7 | v 1.000000 0.000000 0.000000 8 | v 0.588471 -0.350000 -0.117054 9 | v 0.980785 0.000000 -0.195090 10 | v 0.554328 -0.350000 -0.229610 11 | v 0.923880 0.000000 -0.382683 12 | v 0.498882 -0.350000 -0.333342 13 | v 0.831470 0.000000 -0.555570 14 | v 0.424264 -0.350000 -0.424264 15 | v 0.707107 0.000000 -0.707107 16 | v 0.333342 -0.350000 -0.498882 17 | v 0.555570 0.000000 -0.831470 18 | v 0.229610 -0.350000 -0.554328 19 | v 0.382684 0.000000 -0.923879 20 | v 0.117054 -0.350000 -0.588471 21 | v 0.195090 0.000000 -0.980785 22 | v 0.000000 -0.350000 -0.600000 23 | v 0.000000 0.000000 -1.000000 24 | v -0.117054 -0.350000 -0.588471 25 | v -0.195090 0.000000 -0.980785 26 | v -0.229610 -0.350000 -0.554328 27 | v -0.382684 0.000000 -0.923880 28 | v -0.333342 -0.350000 -0.498882 29 | v -0.555570 0.000000 -0.831470 30 | v -0.424264 -0.350000 -0.424264 31 | v -0.707107 0.000000 -0.707107 32 | v -0.498882 -0.350000 -0.333342 33 | v -0.831469 0.000000 -0.555570 34 | v -0.554328 -0.350000 -0.229610 35 | v -0.923879 0.000000 -0.382683 36 | v -0.588471 -0.350000 -0.117054 37 | v -0.980785 0.000000 -0.195090 38 | v -0.600000 -0.350000 -0.000000 39 | v -1.000000 0.000000 -0.000000 40 | v -0.588471 -0.350000 0.117054 41 | v -0.980785 0.000000 0.195090 42 | v -0.554328 -0.350000 0.229610 43 | v -0.923880 0.000000 0.382683 44 | v -0.498882 -0.350000 0.333342 45 | v -0.831469 0.000000 0.555570 46 | v -0.424264 -0.350000 0.424264 47 | v -0.707107 0.000000 0.707107 48 | v -0.333342 -0.350000 0.498882 49 | v -0.555571 0.000000 0.831469 50 | v -0.229610 -0.350000 0.554328 51 | v -0.382684 0.000000 0.923880 52 | v -0.117054 -0.350000 0.588471 53 | v -0.195091 0.000000 0.980785 54 | v 0.000000 -0.350000 0.600000 55 | v 0.000000 0.000000 1.000000 56 | v 0.117054 -0.350000 0.588471 57 | v 0.195090 0.000000 0.980785 58 | v 0.229610 -0.350000 0.554328 59 | v 0.382684 0.000000 0.923879 60 | v 0.333342 -0.350000 0.498882 61 | v 0.555570 0.000000 0.831470 62 | v 0.424264 -0.350000 0.424264 63 | v 0.707106 0.000000 0.707107 64 | v 0.498882 -0.350000 0.333342 65 | v 0.831470 0.000000 0.555570 66 | v 0.554328 -0.350000 0.229610 67 | v 0.923879 0.000000 0.382684 68 | v 0.588471 -0.350000 0.117054 69 | v 0.980785 0.000000 0.195090 70 | vn 0.6235 0.7794 0.0614 71 | vn 0.6235 0.7794 -0.0614 72 | vn 0.5996 0.7794 -0.1819 73 | vn 0.5526 0.7794 -0.2953 74 | vn 0.4843 0.7794 -0.3975 75 | vn 0.3975 0.7794 -0.4843 76 | vn 0.2953 0.7794 -0.5526 77 | vn 0.1819 0.7794 -0.5996 78 | vn 0.0614 0.7794 -0.6235 79 | vn -0.0614 0.7794 -0.6235 80 | vn -0.1819 0.7794 -0.5996 81 | vn -0.2953 0.7794 -0.5526 82 | vn -0.3975 0.7794 -0.4843 83 | vn -0.4843 0.7794 -0.3975 84 | vn -0.5526 0.7794 -0.2953 85 | vn -0.5996 0.7794 -0.1819 86 | vn -0.6235 0.7794 -0.0614 87 | vn -0.6235 0.7794 0.0614 88 | vn -0.5996 0.7794 0.1819 89 | vn -0.5526 0.7794 0.2953 90 | vn -0.4843 0.7794 0.3975 91 | vn -0.3975 0.7794 0.4843 92 | vn -0.2953 0.7794 0.5526 93 | vn -0.1819 0.7794 0.5996 94 | vn -0.0614 0.7794 0.6235 95 | vn 0.0614 0.7794 0.6235 96 | vn 0.1819 0.7794 0.5996 97 | vn 0.2953 0.7794 0.5526 98 | vn 0.3975 0.7794 0.4843 99 | vn 0.4843 0.7794 0.3975 100 | vn 0.5526 0.7794 0.2953 101 | vn 0.5996 0.7794 0.1819 102 | vn 0.6571 -0.7510 0.0647 103 | vn 0.6571 -0.7510 -0.0647 104 | vn 0.6319 -0.7510 -0.1917 105 | vn 0.5823 -0.7510 -0.3113 106 | vn 0.5104 -0.7510 -0.4189 107 | vn 0.4189 -0.7510 -0.5104 108 | vn 0.3113 -0.7510 -0.5823 109 | vn 0.1917 -0.7510 -0.6319 110 | vn 0.0647 -0.7510 -0.6571 111 | vn -0.0647 -0.7510 -0.6571 112 | vn -0.1917 -0.7510 -0.6319 113 | vn -0.3113 -0.7510 -0.5823 114 | vn -0.4189 -0.7510 -0.5104 115 | vn -0.5104 -0.7510 -0.4189 116 | vn -0.5823 -0.7510 -0.3113 117 | vn -0.6319 -0.7510 -0.1917 118 | vn -0.6571 -0.7510 -0.0647 119 | vn -0.6571 -0.7510 0.0647 120 | vn -0.6319 -0.7510 0.1917 121 | vn -0.5823 -0.7510 0.3113 122 | vn -0.5104 -0.7510 0.4189 123 | vn -0.4189 -0.7510 0.5104 124 | vn -0.3113 -0.7510 0.5823 125 | vn -0.1917 -0.7510 0.6319 126 | vn -0.0647 -0.7510 0.6571 127 | vn 0.0647 -0.7510 0.6571 128 | vn 0.1917 -0.7510 0.6319 129 | vn 0.3113 -0.7510 0.5823 130 | vn 0.4189 -0.7510 0.5104 131 | vn 0.5104 -0.7510 0.4189 132 | vn 0.5823 -0.7510 0.3113 133 | vn 0.6319 -0.7510 0.1917 134 | vn 0.0000 -1.0000 0.0000 135 | s off 136 | f 4//1 2//1 66//1 137 | f 2//2 4//2 6//2 138 | f 2//3 6//3 8//3 139 | f 2//4 8//4 10//4 140 | f 2//5 10//5 12//5 141 | f 2//6 12//6 14//6 142 | f 2//7 14//7 16//7 143 | f 2//8 16//8 18//8 144 | f 2//9 18//9 20//9 145 | f 2//10 20//10 22//10 146 | f 2//11 22//11 24//11 147 | f 2//12 24//12 26//12 148 | f 2//13 26//13 28//13 149 | f 2//14 28//14 30//14 150 | f 2//15 30//15 32//15 151 | f 2//16 32//16 34//16 152 | f 2//17 34//17 36//17 153 | f 2//18 36//18 38//18 154 | f 2//19 38//19 40//19 155 | f 2//20 40//20 42//20 156 | f 2//21 42//21 44//21 157 | f 2//22 44//22 46//22 158 | f 2//23 46//23 48//23 159 | f 2//24 48//24 50//24 160 | f 2//25 50//25 52//25 161 | f 2//26 52//26 54//26 162 | f 2//27 54//27 56//27 163 | f 2//28 56//28 58//28 164 | f 2//29 58//29 60//29 165 | f 2//30 60//30 62//30 166 | f 2//31 62//31 64//31 167 | f 2//32 64//32 66//32 168 | f 4//33 65//33 3//33 169 | f 3//34 6//34 4//34 170 | f 5//35 8//35 6//35 171 | f 8//36 9//36 10//36 172 | f 9//37 12//37 10//37 173 | f 12//38 13//38 14//38 174 | f 13//39 16//39 14//39 175 | f 16//40 17//40 18//40 176 | f 18//41 19//41 20//41 177 | f 20//42 21//42 22//42 178 | f 21//43 24//43 22//43 179 | f 23//44 26//44 24//44 180 | f 25//45 28//45 26//45 181 | f 27//46 30//46 28//46 182 | f 29//47 32//47 30//47 183 | f 31//48 34//48 32//48 184 | f 34//49 35//49 36//49 185 | f 35//50 38//50 36//50 186 | f 37//51 40//51 38//51 187 | f 40//52 41//52 42//52 188 | f 41//53 44//53 42//53 189 | f 43//54 46//54 44//54 190 | f 45//55 48//55 46//55 191 | f 48//56 49//56 50//56 192 | f 49//57 52//57 50//57 193 | f 51//58 54//58 52//58 194 | f 53//59 56//59 54//59 195 | f 56//60 57//60 58//60 196 | f 57//61 60//61 58//61 197 | f 60//62 61//62 62//62 198 | f 61//63 64//63 62//63 199 | f 63//64 66//64 64//64 200 | f 1//65 3//65 65//65 201 | f 3//65 1//65 5//65 202 | f 5//65 1//65 7//65 203 | f 7//65 1//65 9//65 204 | f 9//65 1//65 11//65 205 | f 11//65 1//65 13//65 206 | f 13//65 1//65 15//65 207 | f 15//65 1//65 17//65 208 | f 17//65 1//65 19//65 209 | f 19//65 1//65 21//65 210 | f 21//65 1//65 23//65 211 | f 23//65 1//65 25//65 212 | f 25//65 1//65 27//65 213 | f 27//65 1//65 29//65 214 | f 29//65 1//65 31//65 215 | f 31//65 1//65 33//65 216 | f 33//65 1//65 35//65 217 | f 35//65 1//65 37//65 218 | f 37//65 1//65 39//65 219 | f 39//65 1//65 41//65 220 | f 41//65 1//65 43//65 221 | f 43//65 1//65 45//65 222 | f 45//65 1//65 47//65 223 | f 47//65 1//65 49//65 224 | f 49//65 1//65 51//65 225 | f 51//65 1//65 53//65 226 | f 53//65 1//65 55//65 227 | f 55//65 1//65 57//65 228 | f 57//65 1//65 59//65 229 | f 59//65 1//65 61//65 230 | f 61//65 1//65 63//65 231 | f 63//65 1//65 65//65 232 | f 4//33 66//33 65//33 233 | f 3//34 5//34 6//34 234 | f 5//35 7//35 8//35 235 | f 8//36 7//36 9//36 236 | f 9//37 11//37 12//37 237 | f 12//38 11//38 13//38 238 | f 13//39 15//39 16//39 239 | f 16//40 15//40 17//40 240 | f 18//41 17//41 19//41 241 | f 20//42 19//42 21//42 242 | f 21//43 23//43 24//43 243 | f 23//44 25//44 26//44 244 | f 25//45 27//45 28//45 245 | f 27//46 29//46 30//46 246 | f 29//47 31//47 32//47 247 | f 31//48 33//48 34//48 248 | f 34//49 33//49 35//49 249 | f 35//50 37//50 38//50 250 | f 37//51 39//51 40//51 251 | f 40//52 39//52 41//52 252 | f 41//53 43//53 44//53 253 | f 43//54 45//54 46//54 254 | f 45//55 47//55 48//55 255 | f 48//56 47//56 49//56 256 | f 49//57 51//57 52//57 257 | f 51//58 53//58 54//58 258 | f 53//59 55//59 56//59 259 | f 56//60 55//60 57//60 260 | f 57//61 59//61 60//61 261 | f 60//62 59//62 61//62 262 | f 61//63 63//63 64//63 263 | f 63//64 65//64 66//64 264 | -------------------------------------------------------------------------------- /data/models/diamond_3.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Gem 4 | v 0.000000 0.800000 0.000000 5 | v 0.000000 -0.350000 0.000000 6 | v 0.000000 0.400000 0.541196 7 | v 0.382683 0.000000 0.923880 8 | v 0.000000 -0.175000 0.865914 9 | v 0.229610 -0.350000 0.554328 10 | v 0.382683 0.400000 0.382683 11 | v 0.923880 0.000000 0.382683 12 | v 0.612293 -0.175000 0.612293 13 | v 0.554328 -0.350000 0.229610 14 | v 0.541196 0.400000 0.000000 15 | v 0.923880 0.000000 -0.382683 16 | v 0.865914 -0.175000 0.000000 17 | v 0.554328 -0.350000 -0.229610 18 | v 0.382683 0.400000 -0.382683 19 | v 0.382683 0.000000 -0.923880 20 | v 0.612293 -0.175000 -0.612293 21 | v 0.229610 -0.350000 -0.554328 22 | v 0.000000 0.400000 -0.541196 23 | v -0.382683 0.000000 -0.923880 24 | v 0.000000 -0.175000 -0.865914 25 | v -0.229610 -0.350000 -0.554328 26 | v -0.382683 0.400000 -0.382683 27 | v -0.923880 0.000000 -0.382683 28 | v -0.612293 -0.175000 -0.612293 29 | v -0.554328 -0.350000 -0.229610 30 | v -0.541196 0.400000 -0.000000 31 | v -0.923880 0.000000 0.382683 32 | v -0.865914 -0.175000 -0.000000 33 | v -0.554328 -0.350000 0.229610 34 | v -0.382683 0.400000 0.382683 35 | v -0.382683 0.000000 0.923880 36 | v -0.612293 -0.175000 0.612293 37 | v -0.229610 -0.350000 0.554328 38 | vn 0.2391 0.7809 0.5771 39 | vn 0.5109 0.6913 0.5109 40 | vn 0.6712 -0.3144 0.6712 41 | vn 0.2520 -0.7526 0.6084 42 | vn 0.3463 -0.8719 0.3463 43 | vn 0.5771 0.7809 0.2391 44 | vn 0.7226 0.6913 0.0000 45 | vn 0.9493 -0.3144 0.0000 46 | vn 0.6084 -0.7526 0.2520 47 | vn 0.4897 -0.8719 0.0000 48 | vn 0.5771 0.7809 -0.2391 49 | vn 0.5109 0.6913 -0.5109 50 | vn 0.6712 -0.3144 -0.6712 51 | vn 0.6084 -0.7526 -0.2520 52 | vn 0.3463 -0.8719 -0.3463 53 | vn 0.2391 0.7809 -0.5771 54 | vn 0.0000 0.6913 -0.7226 55 | vn 0.0000 -0.3144 -0.9493 56 | vn 0.2520 -0.7526 -0.6084 57 | vn 0.0000 -0.8719 -0.4897 58 | vn -0.2391 0.7809 -0.5771 59 | vn -0.5109 0.6913 -0.5109 60 | vn -0.6712 -0.3144 -0.6712 61 | vn -0.2520 -0.7526 -0.6084 62 | vn -0.3463 -0.8719 -0.3463 63 | vn -0.5771 0.7809 -0.2391 64 | vn -0.7226 0.6913 0.0000 65 | vn -0.9493 -0.3144 0.0000 66 | vn -0.6084 -0.7526 -0.2520 67 | vn -0.4897 -0.8719 0.0000 68 | vn -0.5771 0.7809 0.2391 69 | vn -0.5109 0.6913 0.5109 70 | vn -0.6712 -0.3144 0.6712 71 | vn -0.6084 -0.7526 0.2520 72 | vn -0.3463 -0.8719 0.3463 73 | vn -0.2391 0.7809 0.5771 74 | vn 0.0000 0.6913 0.7226 75 | vn 0.0000 -0.3144 0.9493 76 | vn -0.2520 -0.7526 0.6084 77 | vn 0.0000 -0.8719 0.4897 78 | vn 0.0000 1.0000 0.0000 79 | s off 80 | f 7//1 3//1 4//1 81 | f 7//2 4//2 8//2 82 | f 8//3 4//3 9//3 83 | f 4//4 6//4 9//4 84 | f 9//5 6//5 10//5 85 | f 11//6 7//6 8//6 86 | f 11//7 8//7 12//7 87 | f 12//8 8//8 13//8 88 | f 8//9 10//9 13//9 89 | f 13//10 10//10 14//10 90 | f 15//11 11//11 12//11 91 | f 15//12 12//12 16//12 92 | f 16//13 12//13 17//13 93 | f 12//14 14//14 17//14 94 | f 17//15 14//15 18//15 95 | f 19//16 15//16 16//16 96 | f 19//17 16//17 20//17 97 | f 20//18 16//18 21//18 98 | f 16//19 18//19 21//19 99 | f 21//20 18//20 22//20 100 | f 23//21 19//21 20//21 101 | f 23//22 20//22 24//22 102 | f 24//23 20//23 25//23 103 | f 20//24 22//24 25//24 104 | f 25//25 22//25 26//25 105 | f 27//26 23//26 24//26 106 | f 27//27 24//27 28//27 107 | f 28//28 24//28 29//28 108 | f 24//29 26//29 29//29 109 | f 29//30 26//30 30//30 110 | f 31//31 27//31 28//31 111 | f 31//32 28//32 32//32 112 | f 32//33 28//33 33//33 113 | f 28//34 30//34 33//34 114 | f 33//35 30//35 34//35 115 | f 3//36 31//36 32//36 116 | f 3//37 32//37 4//37 117 | f 4//38 32//38 5//38 118 | f 32//39 34//39 5//39 119 | f 5//40 34//40 6//40 120 | f 6//41 2//41 34//41 121 | f 2//41 6//41 10//41 122 | f 2//41 10//41 14//41 123 | f 2//41 14//41 18//41 124 | f 2//41 18//41 22//41 125 | f 2//41 22//41 26//41 126 | f 2//41 26//41 30//41 127 | f 2//41 30//41 34//41 128 | f 7//1 1//1 3//1 129 | f 4//4 5//4 6//4 130 | f 11//6 1//6 7//6 131 | f 8//9 9//9 10//9 132 | f 15//11 1//11 11//11 133 | f 12//14 13//14 14//14 134 | f 19//16 1//16 15//16 135 | f 16//19 17//19 18//19 136 | f 23//21 1//21 19//21 137 | f 20//24 21//24 22//24 138 | f 27//26 1//26 23//26 139 | f 24//29 25//29 26//29 140 | f 31//31 1//31 27//31 141 | f 28//34 29//34 30//34 142 | f 3//36 1//36 31//36 143 | f 32//39 33//39 34//39 144 | -------------------------------------------------------------------------------- /data/models/ico_sphere.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Icosphere 4 | v 0.000000 1.000000 0.000000 5 | v 0.723607 0.447220 -0.525725 6 | v -0.276388 0.447220 -0.850649 7 | v -0.894426 0.447216 0.000000 8 | v -0.276388 0.447220 0.850649 9 | v 0.723607 0.447220 0.525725 10 | v 0.276388 -0.447220 -0.850649 11 | v -0.723607 -0.447220 -0.525725 12 | v -0.723607 -0.447220 0.525725 13 | v 0.276388 -0.447220 0.850649 14 | v 0.894426 -0.447216 0.000000 15 | v 0.000000 -1.000000 0.000000 16 | v -0.162456 0.850654 -0.499995 17 | v 0.425323 0.850654 -0.309011 18 | v 0.262869 0.525738 -0.809012 19 | v 0.850648 0.525736 0.000000 20 | v 0.425323 0.850654 0.309011 21 | v -0.525730 0.850652 0.000000 22 | v -0.688189 0.525736 -0.499997 23 | v -0.162456 0.850654 0.499995 24 | v -0.688189 0.525736 0.499997 25 | v 0.262869 0.525738 0.809012 26 | v 0.951058 0.000000 -0.309013 27 | v 0.951058 0.000000 0.309013 28 | v 0.000000 0.000000 -1.000000 29 | v 0.587786 0.000000 -0.809017 30 | v -0.951058 0.000000 -0.309013 31 | v -0.587786 0.000000 -0.809017 32 | v -0.587786 0.000000 0.809017 33 | v -0.951058 0.000000 0.309013 34 | v 0.587786 0.000000 0.809017 35 | v 0.000000 0.000000 1.000000 36 | v 0.688189 -0.525736 -0.499997 37 | v -0.262869 -0.525738 -0.809012 38 | v -0.850648 -0.525736 0.000000 39 | v -0.262869 -0.525738 0.809012 40 | v 0.688189 -0.525736 0.499997 41 | v 0.162456 -0.850654 -0.499995 42 | v 0.525730 -0.850652 0.000000 43 | v -0.425323 -0.850654 -0.309011 44 | v -0.425323 -0.850654 0.309011 45 | v 0.162456 -0.850654 0.499995 46 | vt 0.818181 0.000000 47 | vt 0.772726 0.078731 48 | vt 0.863635 0.078731 49 | vt 0.727272 0.157461 50 | vt 0.681818 0.078731 51 | vt 0.636363 0.157461 52 | vt 0.090909 0.000000 53 | vt 0.045454 0.078731 54 | vt 0.136363 0.078731 55 | vt 0.272727 0.000000 56 | vt 0.227273 0.078731 57 | vt 0.318182 0.078731 58 | vt 0.454545 0.000000 59 | vt 0.409090 0.078731 60 | vt 0.500000 0.078731 61 | vt 0.681818 0.236191 62 | vt 0.909090 0.157461 63 | vt 0.818181 0.157461 64 | vt 0.863635 0.236191 65 | vt 0.181818 0.157461 66 | vt 0.090909 0.157461 67 | vt 0.136363 0.236191 68 | vt 0.363636 0.157461 69 | vt 0.272727 0.157461 70 | vt 0.318182 0.236191 71 | vt 0.545454 0.157461 72 | vt 0.454545 0.157461 73 | vt 0.500000 0.236191 74 | vt 0.772726 0.236191 75 | vt 0.954545 0.236191 76 | vt 0.227273 0.236191 77 | vt 0.409090 0.236191 78 | vt 0.590909 0.236191 79 | vt 0.818181 0.314921 80 | vt 0.727272 0.314921 81 | vt 0.772726 0.393651 82 | vt 1.000000 0.314921 83 | vt 0.909091 0.314921 84 | vt 0.954545 0.393651 85 | vt 0.272727 0.314921 86 | vt 0.181818 0.314921 87 | vt 0.227273 0.393651 88 | vt 0.454545 0.314921 89 | vt 0.363636 0.314921 90 | vt 0.409090 0.393651 91 | vt 0.636363 0.314921 92 | vt 0.545454 0.314921 93 | vt 0.590909 0.393651 94 | vt 0.500000 0.393651 95 | vt 0.545454 0.472382 96 | vt 0.318182 0.393651 97 | vt 0.363636 0.472382 98 | vt 0.136363 0.393651 99 | vt 0.181818 0.472382 100 | vt 0.090909 0.314921 101 | vt 0.863635 0.393651 102 | vt 0.909090 0.472382 103 | vt 0.681818 0.393651 104 | vt 0.727272 0.472382 105 | vt 0.045454 0.236191 106 | vt 0.000000 0.157461 107 | vt 0.590909 0.078731 108 | vt 0.636363 0.000000 109 | vn 0.1024 0.9435 -0.3151 110 | vn 0.7002 0.6617 -0.2680 111 | vn -0.2680 0.9435 -0.1947 112 | vn -0.2680 0.9435 0.1947 113 | vn 0.1024 0.9435 0.3151 114 | vn 0.9050 0.3304 -0.2680 115 | vn 0.0247 0.3304 -0.9435 116 | vn -0.8897 0.3304 -0.3151 117 | vn -0.5746 0.3304 0.7488 118 | vn 0.5346 0.3304 0.7779 119 | vn 0.8026 0.1256 -0.5831 120 | vn -0.3066 0.1256 -0.9435 121 | vn -0.9921 0.1256 0.0000 122 | vn -0.3066 0.1256 0.9435 123 | vn 0.8026 0.1256 0.5831 124 | vn 0.4089 -0.6617 -0.6284 125 | vn -0.4713 -0.6617 -0.5831 126 | vn -0.7002 -0.6617 0.2680 127 | vn 0.0385 -0.6617 0.7488 128 | vn 0.7240 -0.6617 0.1947 129 | vn 0.2680 -0.9435 0.1947 130 | vn 0.4911 -0.7947 0.3568 131 | vn 0.4089 -0.6617 0.6284 132 | vn -0.1024 -0.9435 0.3151 133 | vn -0.1876 -0.7947 0.5773 134 | vn -0.4713 -0.6617 0.5831 135 | vn -0.3313 -0.9435 0.0000 136 | vn -0.6071 -0.7947 0.0000 137 | vn -0.7002 -0.6617 -0.2680 138 | vn -0.1024 -0.9435 -0.3151 139 | vn -0.1876 -0.7947 -0.5773 140 | vn 0.0385 -0.6617 -0.7488 141 | vn 0.2680 -0.9435 -0.1947 142 | vn 0.4911 -0.7947 -0.3568 143 | vn 0.7240 -0.6617 -0.1947 144 | vn 0.8897 -0.3304 0.3151 145 | vn 0.7947 -0.1876 0.5773 146 | vn 0.5746 -0.3304 0.7488 147 | vn -0.0247 -0.3304 0.9435 148 | vn -0.3035 -0.1876 0.9342 149 | vn -0.5346 -0.3304 0.7779 150 | vn -0.9050 -0.3304 0.2680 151 | vn -0.9822 -0.1876 0.0000 152 | vn -0.9050 -0.3304 -0.2680 153 | vn -0.5346 -0.3304 -0.7779 154 | vn -0.3035 -0.1876 -0.9342 155 | vn -0.0247 -0.3304 -0.9435 156 | vn 0.5746 -0.3304 -0.7488 157 | vn 0.7947 -0.1876 -0.5773 158 | vn 0.8897 -0.3304 -0.3151 159 | vn 0.3066 -0.1256 0.9435 160 | vn 0.3035 0.1876 0.9342 161 | vn 0.0247 0.3304 0.9435 162 | vn -0.8026 -0.1256 0.5831 163 | vn -0.7947 0.1876 0.5773 164 | vn -0.8897 0.3304 0.3151 165 | vn -0.8026 -0.1256 -0.5831 166 | vn -0.7947 0.1876 -0.5773 167 | vn -0.5746 0.3304 -0.7488 168 | vn 0.3066 -0.1256 -0.9435 169 | vn 0.3035 0.1876 -0.9342 170 | vn 0.5346 0.3304 -0.7779 171 | vn 0.9921 -0.1256 0.0000 172 | vn 0.9822 0.1876 0.0000 173 | vn 0.9050 0.3304 0.2680 174 | vn 0.4713 0.6617 0.5831 175 | vn 0.1876 0.7947 0.5773 176 | vn -0.0385 0.6617 0.7488 177 | vn -0.4089 0.6617 0.6284 178 | vn -0.4911 0.7947 0.3568 179 | vn -0.7240 0.6617 0.1947 180 | vn -0.7240 0.6617 -0.1947 181 | vn -0.4911 0.7947 -0.3568 182 | vn -0.4089 0.6617 -0.6284 183 | vn 0.7002 0.6617 0.2680 184 | vn 0.6071 0.7947 0.0000 185 | vn 0.3313 0.9435 0.0000 186 | vn -0.0385 0.6617 -0.7488 187 | vn 0.1876 0.7947 -0.5773 188 | vn 0.4713 0.6617 -0.5831 189 | s off 190 | f 1/1/1 14/2/1 13/3/1 191 | f 2/4/2 14/5/2 16/6/2 192 | f 1/7/3 13/8/3 18/9/3 193 | f 1/10/4 18/11/4 20/12/4 194 | f 1/13/5 20/14/5 17/15/5 195 | f 2/4/6 16/6/6 23/16/6 196 | f 3/17/7 15/18/7 25/19/7 197 | f 4/20/8 19/21/8 27/22/8 198 | f 5/23/9 21/24/9 29/25/9 199 | f 6/26/10 22/27/10 31/28/10 200 | f 2/4/11 23/16/11 26/29/11 201 | f 3/17/12 25/19/12 28/30/12 202 | f 4/20/13 27/22/13 30/31/13 203 | f 5/23/14 29/25/14 32/32/14 204 | f 6/26/15 31/28/15 24/33/15 205 | f 7/34/16 33/35/16 38/36/16 206 | f 8/37/17 34/38/17 40/39/17 207 | f 9/40/18 35/41/18 41/42/18 208 | f 10/43/19 36/44/19 42/45/19 209 | f 11/46/20 37/47/20 39/48/20 210 | f 39/48/21 42/49/21 12/50/21 211 | f 39/48/22 37/47/22 42/49/22 212 | f 37/47/23 10/43/23 42/49/23 213 | f 42/45/24 41/51/24 12/52/24 214 | f 42/45/25 36/44/25 41/51/25 215 | f 36/44/26 9/40/26 41/51/26 216 | f 41/42/27 40/53/27 12/54/27 217 | f 41/42/28 35/41/28 40/53/28 218 | f 35/41/29 8/55/29 40/53/29 219 | f 40/39/30 38/56/30 12/57/30 220 | f 40/39/31 34/38/31 38/56/31 221 | f 34/38/32 7/34/32 38/56/32 222 | f 38/36/33 39/58/33 12/59/33 223 | f 38/36/34 33/35/34 39/58/34 224 | f 33/35/35 11/46/35 39/58/35 225 | f 24/33/36 37/47/36 11/46/36 226 | f 24/33/37 31/28/37 37/47/37 227 | f 31/28/38 10/43/38 37/47/38 228 | f 32/32/39 36/44/39 10/43/39 229 | f 32/32/40 29/25/40 36/44/40 230 | f 29/25/41 9/40/41 36/44/41 231 | f 30/31/42 35/41/42 9/40/42 232 | f 30/31/43 27/22/43 35/41/43 233 | f 27/22/44 8/55/44 35/41/44 234 | f 28/30/45 34/38/45 8/37/45 235 | f 28/30/46 25/19/46 34/38/46 236 | f 25/19/47 7/34/47 34/38/47 237 | f 26/29/48 33/35/48 7/34/48 238 | f 26/29/49 23/16/49 33/35/49 239 | f 23/16/50 11/46/50 33/35/50 240 | f 31/28/51 32/32/51 10/43/51 241 | f 31/28/52 22/27/52 32/32/52 242 | f 22/27/53 5/23/53 32/32/53 243 | f 29/25/54 30/31/54 9/40/54 244 | f 29/25/55 21/24/55 30/31/55 245 | f 21/24/56 4/20/56 30/31/56 246 | f 27/22/57 28/60/57 8/55/57 247 | f 27/22/58 19/21/58 28/60/58 248 | f 19/21/59 3/61/59 28/60/59 249 | f 25/19/60 26/29/60 7/34/60 250 | f 25/19/61 15/18/61 26/29/61 251 | f 15/18/62 2/4/62 26/29/62 252 | f 23/16/63 24/33/63 11/46/63 253 | f 23/16/64 16/6/64 24/33/64 254 | f 16/6/65 6/26/65 24/33/65 255 | f 17/15/66 22/27/66 6/26/66 256 | f 17/15/67 20/14/67 22/27/67 257 | f 20/14/68 5/23/68 22/27/68 258 | f 20/12/69 21/24/69 5/23/69 259 | f 20/12/70 18/11/70 21/24/70 260 | f 18/11/71 4/20/71 21/24/71 261 | f 18/9/72 19/21/72 4/20/72 262 | f 18/9/73 13/8/73 19/21/73 263 | f 13/8/74 3/61/74 19/21/74 264 | f 16/6/75 17/62/75 6/26/75 265 | f 16/6/76 14/5/76 17/62/76 266 | f 14/5/77 1/63/77 17/62/77 267 | f 13/3/78 15/18/78 3/17/78 268 | f 13/3/79 14/2/79 15/18/79 269 | f 14/2/80 2/4/80 15/18/80 270 | -------------------------------------------------------------------------------- /data/models/star.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.81 (sub 16) OBJ File: '' 2 | # www.blender.org 3 | o Star 4 | v 0.000000 -0.250000 0.000000 5 | v 0.000000 0.250000 0.000000 6 | v 0.500000 -0.250000 0.000000 7 | v 0.500000 0.250000 0.000000 8 | v 0.809017 -0.250000 0.587785 9 | v 0.809017 0.250000 0.587785 10 | v 0.154509 -0.250000 0.475528 11 | v 0.154509 0.250000 0.475528 12 | v -0.309017 -0.250000 0.951057 13 | v -0.309017 0.250000 0.951057 14 | v -0.404509 -0.250000 0.293893 15 | v -0.404509 0.250000 0.293893 16 | v -1.000000 -0.250000 0.000000 17 | v -1.000000 0.250000 0.000000 18 | v -0.404509 -0.250000 -0.293893 19 | v -0.404509 0.250000 -0.293893 20 | v -0.309017 -0.250000 -0.951057 21 | v -0.309017 0.250000 -0.951057 22 | v 0.154509 -0.250000 -0.475528 23 | v 0.154509 0.250000 -0.475528 24 | v 0.809017 -0.250000 -0.587786 25 | v 0.809017 0.250000 -0.587786 26 | vn 0.0000 -1.0000 0.0000 27 | vn 0.8851 0.0000 0.4653 28 | vn 0.8851 0.0000 -0.4653 29 | vn -0.1690 0.0000 0.9856 30 | vn 0.7161 0.0000 0.6980 31 | vn -0.9896 0.0000 0.1438 32 | vn -0.4426 0.0000 0.8967 33 | vn -0.4426 0.0000 -0.8967 34 | vn -0.9896 0.0000 -0.1438 35 | vn 0.7161 0.0000 -0.6980 36 | vn -0.1690 0.0000 -0.9856 37 | vn 0.0000 1.0000 0.0000 38 | s off 39 | f 3//1 1//1 21//1 40 | f 1//1 3//1 5//1 41 | f 1//1 5//1 7//1 42 | f 1//1 7//1 9//1 43 | f 1//1 9//1 11//1 44 | f 1//1 11//1 13//1 45 | f 1//1 13//1 15//1 46 | f 1//1 15//1 17//1 47 | f 1//1 17//1 19//1 48 | f 1//1 19//1 21//1 49 | f 3//2 22//2 4//2 50 | f 4//3 5//3 3//3 51 | f 6//4 7//4 5//4 52 | f 8//5 9//5 7//5 53 | f 10//6 11//6 9//6 54 | f 12//7 13//7 11//7 55 | f 14//8 15//8 13//8 56 | f 16//9 17//9 15//9 57 | f 18//10 19//10 17//10 58 | f 20//11 21//11 19//11 59 | f 2//12 4//12 22//12 60 | f 4//12 2//12 6//12 61 | f 6//12 2//12 8//12 62 | f 8//12 2//12 10//12 63 | f 10//12 2//12 12//12 64 | f 12//12 2//12 14//12 65 | f 14//12 2//12 16//12 66 | f 16//12 2//12 18//12 67 | f 18//12 2//12 20//12 68 | f 20//12 2//12 22//12 69 | f 3//2 21//2 22//2 70 | f 4//3 6//3 5//3 71 | f 6//4 8//4 7//4 72 | f 8//5 10//5 9//5 73 | f 10//6 12//6 11//6 74 | f 12//7 14//7 13//7 75 | f 14//8 16//8 15//8 76 | f 16//9 18//9 17//9 77 | f 18//10 20//10 19//10 78 | f 20//11 22//11 21//11 79 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman 2 | title: Vulkano Tutorial 3 | 4 | defaults: 5 | - 6 | scope: 7 | path: "" 8 | values: 9 | home: True 10 | -------------------------------------------------------------------------------- /docs/_includes/head-custom-google-analytics.html: -------------------------------------------------------------------------------- 1 | {% if site.google_analytics %} 2 | 10 | {% endif %} 11 | -------------------------------------------------------------------------------- /docs/_includes/head-custom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head-custom-google-analytics.html %} 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {% seo %} 7 | 8 | 9 | 10 | 11 | 12 | 13 | {% include head-custom.html %} 14 | 15 | 16 | Skip to the content. 17 | 18 | 27 | 28 |
29 | {{ content }} 30 | 31 | 32 | {% if page.back_link %} 33 | Previous Lesson 34 | {% endif %} 35 | {% if page.home %} 36 | Home 37 | {% endif %} 38 | {% if page.next_link %} 39 | Next Lesson 40 | {% endif %} 41 | 42 | 48 |
49 | 50 | 51 | -------------------------------------------------------------------------------- /docs/_sass/cayman.scss: -------------------------------------------------------------------------------- 1 | // Placeholder file. If your site uses 2 | // @import "{{ site.theme }}"; 3 | // Then using this theme with jekyll-remote-theme will work fine. 4 | @import "jekyll-theme-cayman"; 5 | -------------------------------------------------------------------------------- /docs/_sass/jekyll-theme-cayman.scss: -------------------------------------------------------------------------------- 1 | @import "normalize"; 2 | @import "rouge-github"; 3 | @import "variables"; 4 | @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700&display=swap'); 5 | 6 | @mixin large { 7 | @media screen and (min-width: #{$large-breakpoint}) { 8 | @content; 9 | } 10 | } 11 | 12 | @mixin medium { 13 | @media screen and (min-width: #{$medium-breakpoint}) and (max-width: #{$large-breakpoint}) { 14 | @content; 15 | } 16 | } 17 | 18 | @mixin small { 19 | @media screen and (max-width: #{$medium-breakpoint}) { 20 | @content; 21 | } 22 | } 23 | 24 | * { 25 | box-sizing: border-box; 26 | } 27 | 28 | body { 29 | padding: 0; 30 | margin: 0; 31 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; 32 | font-size: 16px; 33 | line-height: 1.5; 34 | color: $body-text-color; 35 | } 36 | 37 | #skip-to-content { 38 | height: 1px; 39 | width: 1px; 40 | position: absolute; 41 | overflow: hidden; 42 | top: -10px; 43 | 44 | &:focus { 45 | position: fixed; 46 | top: 10px; 47 | left: 10px; 48 | height: auto; 49 | width: auto; 50 | background: invert($body-link-color); 51 | outline: thick solid invert($body-link-color); 52 | } 53 | } 54 | 55 | a { 56 | color: $body-link-color; 57 | text-decoration: none; 58 | 59 | &:hover { 60 | text-decoration: underline; 61 | } 62 | } 63 | 64 | .btn { 65 | display: inline-block; 66 | margin-bottom: 1rem; 67 | color: rgba(255, 255, 255, 0.7); 68 | background-color: rgba(255, 255, 255, 0.08); 69 | border-color: rgba(255, 255, 255, 0.2); 70 | border-style: solid; 71 | border-width: 1px; 72 | border-radius: 0.3rem; 73 | transition: color 0.2s, background-color 0.2s, border-color 0.2s; 74 | 75 | &:hover { 76 | color: rgba(255, 255, 255, 0.8); 77 | text-decoration: none; 78 | background-color: rgba(255, 255, 255, 0.2); 79 | border-color: rgba(255, 255, 255, 0.3); 80 | } 81 | 82 | + .btn { 83 | margin-left: 1rem; 84 | } 85 | 86 | @include large { 87 | padding: 0.75rem 1rem; 88 | } 89 | 90 | @include medium { 91 | padding: 0.6rem 0.9rem; 92 | font-size: 0.9rem; 93 | } 94 | 95 | @include small { 96 | display: block; 97 | width: 100%; 98 | padding: 0.75rem; 99 | font-size: 0.9rem; 100 | 101 | + .btn { 102 | margin-top: 1rem; 103 | margin-left: 0; 104 | } 105 | } 106 | } 107 | 108 | .link-bar { 109 | display: inline-block; 110 | text-align: center; 111 | .nav-btn { 112 | display: inline-block; 113 | margin-bottom: 1rem; 114 | color: rgba(255, 255, 255, 0.7); 115 | background-color: $header-bg-color; 116 | border-color: rgba(255, 255, 255, 0.2); 117 | border-style: solid; 118 | border-width: 1px; 119 | border-radius: 0.3rem; 120 | transition: color 0.2s, background-color 0.2s, border-color 0.2s; 121 | 122 | &:hover { 123 | color: rgba(255, 255, 255, 0.8); 124 | text-decoration: none; 125 | background-color: #0d4d2d; 126 | border-color: rgba(255, 255, 255, 0.3); 127 | } 128 | 129 | + .nav-btn { 130 | margin-left: 1rem; 131 | } 132 | 133 | @include large { 134 | padding: 0.75rem 1rem; 135 | } 136 | 137 | @include medium { 138 | padding: 0.6rem 0.9rem; 139 | font-size: 0.9rem; 140 | } 141 | 142 | @include small { 143 | display: block; 144 | width: 100%; 145 | padding: 0.75rem; 146 | font-size: 0.9rem; 147 | 148 | + .btn { 149 | margin-top: 1rem; 150 | margin-left: 0; 151 | } 152 | } 153 | } 154 | } 155 | 156 | .page-header { 157 | color: $header-heading-color; 158 | text-align: center; 159 | background-color: $header-bg-color; 160 | background-image: linear-gradient(120deg, $header-bg-color-secondary, $header-bg-color); 161 | 162 | @include large { 163 | padding: 5rem 6rem; 164 | } 165 | 166 | @include medium { 167 | padding: 3rem 4rem; 168 | } 169 | 170 | @include small { 171 | padding: 2rem 1rem; 172 | } 173 | } 174 | 175 | .project-name { 176 | margin-top: 0; 177 | margin-bottom: 0.1rem; 178 | 179 | @include large { 180 | font-size: 3.25rem; 181 | } 182 | 183 | @include medium { 184 | font-size: 2.25rem; 185 | } 186 | 187 | @include small { 188 | font-size: 1.75rem; 189 | } 190 | } 191 | 192 | .project-tagline { 193 | margin-bottom: 2rem; 194 | font-weight: normal; 195 | opacity: 0.7; 196 | 197 | @include large { 198 | font-size: 1.25rem; 199 | } 200 | 201 | @include medium { 202 | font-size: 1.15rem; 203 | } 204 | 205 | @include small { 206 | font-size: 1rem; 207 | } 208 | } 209 | 210 | .main-content { 211 | word-wrap: break-word; 212 | 213 | :first-child { 214 | margin-top: 0; 215 | } 216 | 217 | @include large { 218 | max-width: 64rem; 219 | padding: 2rem 6rem; 220 | margin: 0 auto; 221 | font-size: 1.1rem; 222 | } 223 | 224 | @include medium { 225 | padding: 2rem 4rem; 226 | font-size: 1.1rem; 227 | } 228 | 229 | @include small { 230 | padding: 2rem 1rem; 231 | font-size: 1rem; 232 | } 233 | 234 | kbd { 235 | background-color: #fafbfc; 236 | border: 1px solid #c6cbd1; 237 | border-bottom-color: #959da5; 238 | border-radius: 3px; 239 | box-shadow: inset 0 -1px 0 #959da5; 240 | color: #444d56; 241 | display: inline-block; 242 | font-size: 11px; 243 | line-height: 10px; 244 | padding: 3px 5px; 245 | vertical-align: middle; 246 | } 247 | 248 | img { 249 | max-width: 100%; 250 | } 251 | 252 | h1, 253 | h2, 254 | h3, 255 | h4, 256 | h5, 257 | h6 { 258 | margin-top: 2rem; 259 | margin-bottom: 1rem; 260 | font-weight: normal; 261 | color: $section-headings-color; 262 | } 263 | 264 | p { 265 | margin-bottom: 1em; 266 | } 267 | 268 | code { 269 | padding: 2px 4px; 270 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; 271 | font-size: 0.9rem; 272 | color: $code-text-color; 273 | background-color: $code-bg-color; 274 | border-radius: 0.3rem; 275 | } 276 | 277 | pre { 278 | padding: 0.8rem; 279 | margin-top: 0; 280 | margin-bottom: 1rem; 281 | font: 1rem Consolas, "Liberation Mono", Menlo, Courier, monospace; 282 | color: $code-text-color; 283 | word-wrap: normal; 284 | background-color: $code-bg-color; 285 | border: solid 1px $border-color; 286 | border-radius: 0.3rem; 287 | 288 | > code { 289 | padding: 0; 290 | margin: 0; 291 | font-size: 0.9rem; 292 | color: $code-text-color; 293 | word-break: normal; 294 | white-space: pre; 295 | background: transparent; 296 | border: 0; 297 | } 298 | } 299 | 300 | .highlight { 301 | margin-bottom: 1rem; 302 | 303 | pre { 304 | margin-bottom: 0; 305 | word-break: normal; 306 | } 307 | } 308 | 309 | .highlight pre, 310 | pre { 311 | padding: 0.8rem; 312 | overflow: auto; 313 | font-size: 0.9rem; 314 | line-height: 1.45; 315 | border-radius: 0.3rem; 316 | -webkit-overflow-scrolling: touch; 317 | } 318 | 319 | pre code, 320 | pre tt { 321 | display: inline; 322 | max-width: initial; 323 | padding: 0; 324 | margin: 0; 325 | overflow: initial; 326 | line-height: inherit; 327 | word-wrap: normal; 328 | background-color: transparent; 329 | border: 0; 330 | 331 | &:before, 332 | &:after { 333 | content: normal; 334 | } 335 | } 336 | 337 | ul, 338 | ol { 339 | margin-top: 0; 340 | } 341 | 342 | blockquote { 343 | padding: 0 1rem; 344 | margin-left: 0; 345 | color: $blockquote-text-color; 346 | border-left: 0.3rem solid $border-color; 347 | 348 | > :first-child { 349 | margin-top: 0; 350 | } 351 | 352 | > :last-child { 353 | margin-bottom: 0; 354 | } 355 | } 356 | 357 | table { 358 | display: block; 359 | width: 100%; 360 | overflow: auto; 361 | word-break: normal; 362 | word-break: keep-all; // For Firefox to horizontally scroll wider tables. 363 | -webkit-overflow-scrolling: touch; 364 | 365 | th { 366 | font-weight: bold; 367 | } 368 | 369 | th, 370 | td { 371 | padding: 0.5rem 1rem; 372 | border: 1px solid $table-border-color; 373 | } 374 | } 375 | 376 | dl { 377 | padding: 0; 378 | 379 | dt { 380 | padding: 0; 381 | margin-top: 1rem; 382 | font-size: 1rem; 383 | font-weight: bold; 384 | } 385 | 386 | dd { 387 | padding: 0; 388 | margin-bottom: 1rem; 389 | } 390 | } 391 | 392 | hr { 393 | height: 2px; 394 | padding: 0; 395 | margin: 1rem 0; 396 | background-color: $hr-border-color; 397 | border: 0; 398 | } 399 | } 400 | 401 | .site-footer { 402 | padding-top: 2rem; 403 | margin-top: 2rem; 404 | border-top: solid 1px $hr-border-color; 405 | 406 | @include large { 407 | font-size: 1rem; 408 | } 409 | 410 | @include medium { 411 | font-size: 1rem; 412 | } 413 | 414 | @include small { 415 | font-size: 0.9rem; 416 | } 417 | } 418 | 419 | .site-footer-owner { 420 | display: block; 421 | font-weight: bold; 422 | } 423 | 424 | .site-footer-credits { 425 | color: $blockquote-text-color; 426 | } 427 | -------------------------------------------------------------------------------- /docs/_sass/rouge-github.scss: -------------------------------------------------------------------------------- 1 | .highlight table td { padding: 5px; } 2 | .highlight table pre { margin: 0; } 3 | .highlight .cm { 4 | color: #999988; 5 | font-style: italic; 6 | } 7 | .highlight .cp { 8 | color: #999999; 9 | font-weight: bold; 10 | } 11 | .highlight .c1 { 12 | color: #999988; 13 | font-style: italic; 14 | } 15 | .highlight .cs { 16 | color: #999999; 17 | font-weight: bold; 18 | font-style: italic; 19 | } 20 | .highlight .c, .highlight .cd { 21 | color: #999988; 22 | font-style: italic; 23 | } 24 | .highlight .err { 25 | color: #a61717; 26 | background-color: #e3d2d2; 27 | } 28 | .highlight .gd { 29 | color: #000000; 30 | background-color: #ffdddd; 31 | } 32 | .highlight .ge { 33 | color: #000000; 34 | font-style: italic; 35 | } 36 | .highlight .gr { 37 | color: #aa0000; 38 | } 39 | .highlight .gh { 40 | color: #999999; 41 | } 42 | .highlight .gi { 43 | color: #000000; 44 | background-color: #ddffdd; 45 | } 46 | .highlight .go { 47 | color: #888888; 48 | } 49 | .highlight .gp { 50 | color: #555555; 51 | } 52 | .highlight .gs { 53 | font-weight: bold; 54 | } 55 | .highlight .gu { 56 | color: #aaaaaa; 57 | } 58 | .highlight .gt { 59 | color: #aa0000; 60 | } 61 | .highlight .kc { 62 | color: #000000; 63 | font-weight: bold; 64 | } 65 | .highlight .kd { 66 | color: #000000; 67 | font-weight: bold; 68 | } 69 | .highlight .kn { 70 | color: #000000; 71 | font-weight: bold; 72 | } 73 | .highlight .kp { 74 | color: #000000; 75 | font-weight: bold; 76 | } 77 | .highlight .kr { 78 | color: #000000; 79 | font-weight: bold; 80 | } 81 | .highlight .kt { 82 | color: #445588; 83 | font-weight: bold; 84 | } 85 | .highlight .k, .highlight .kv { 86 | color: #000000; 87 | font-weight: bold; 88 | } 89 | .highlight .mf { 90 | color: #009999; 91 | } 92 | .highlight .mh { 93 | color: #009999; 94 | } 95 | .highlight .il { 96 | color: #009999; 97 | } 98 | .highlight .mi { 99 | color: #009999; 100 | } 101 | .highlight .mo { 102 | color: #009999; 103 | } 104 | .highlight .m, .highlight .mb, .highlight .mx { 105 | color: #009999; 106 | } 107 | .highlight .sb { 108 | color: #d14; 109 | } 110 | .highlight .sc { 111 | color: #d14; 112 | } 113 | .highlight .sd { 114 | color: #d14; 115 | } 116 | .highlight .s2 { 117 | color: #d14; 118 | } 119 | .highlight .se { 120 | color: #d14; 121 | } 122 | .highlight .sh { 123 | color: #d14; 124 | } 125 | .highlight .si { 126 | color: #d14; 127 | } 128 | .highlight .sx { 129 | color: #d14; 130 | } 131 | .highlight .sr { 132 | color: #009926; 133 | } 134 | .highlight .s1 { 135 | color: #d14; 136 | } 137 | .highlight .ss { 138 | color: #990073; 139 | } 140 | .highlight .s { 141 | color: #d14; 142 | } 143 | .highlight .na { 144 | color: #008080; 145 | } 146 | .highlight .bp { 147 | color: #999999; 148 | } 149 | .highlight .nb { 150 | color: #0086B3; 151 | } 152 | .highlight .nc { 153 | color: #445588; 154 | font-weight: bold; 155 | } 156 | .highlight .no { 157 | color: #008080; 158 | } 159 | .highlight .nd { 160 | color: #3c5d5d; 161 | font-weight: bold; 162 | } 163 | .highlight .ni { 164 | color: #800080; 165 | } 166 | .highlight .ne { 167 | color: #990000; 168 | font-weight: bold; 169 | } 170 | .highlight .nf { 171 | color: #990000; 172 | font-weight: bold; 173 | } 174 | .highlight .nl { 175 | color: #990000; 176 | font-weight: bold; 177 | } 178 | .highlight .nn { 179 | color: #555555; 180 | } 181 | .highlight .nt { 182 | color: #000080; 183 | } 184 | .highlight .vc { 185 | color: #008080; 186 | } 187 | .highlight .vg { 188 | color: #008080; 189 | } 190 | .highlight .vi { 191 | color: #008080; 192 | } 193 | .highlight .nv { 194 | color: #008080; 195 | } 196 | .highlight .ow { 197 | color: #000000; 198 | font-weight: bold; 199 | } 200 | .highlight .o { 201 | color: #000000; 202 | font-weight: bold; 203 | } 204 | .highlight .w { 205 | color: #bbbbbb; 206 | } 207 | .highlight { 208 | background-color: #f8f8f8; 209 | } 210 | -------------------------------------------------------------------------------- /docs/_sass/variables.scss: -------------------------------------------------------------------------------- 1 | // Breakpoints 2 | $large-breakpoint: 64em !default; 3 | $medium-breakpoint: 42em !default; 4 | 5 | // Headers 6 | $header-heading-color: #fff !default; 7 | $header-bg-color: #159957 !default; 8 | $header-bg-color-secondary: #155799 !default; 9 | 10 | // Text 11 | $section-headings-color: #159957 !default; 12 | $body-text-color: #606c71 !default; 13 | $body-link-color: #1e6bb8 !default; 14 | $blockquote-text-color: #819198 !default; 15 | 16 | // Code 17 | $code-bg-color: #f3f6fa !default; 18 | $code-text-color: #567482 !default; 19 | 20 | // Borders 21 | $border-color: #dce6f0 !default; 22 | $table-border-color: #e9ebec !default; 23 | $hr-border-color: #eff0f1 !default; 24 | -------------------------------------------------------------------------------- /docs/imgs/0/owl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/0/owl.png -------------------------------------------------------------------------------- /docs/imgs/0/rust_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/0/rust_logo.png -------------------------------------------------------------------------------- /docs/imgs/0/vulkan_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/0/vulkan_logo.png -------------------------------------------------------------------------------- /docs/imgs/1/first_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/1/first_window.png -------------------------------------------------------------------------------- /docs/imgs/1/updated_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/1/updated_window.png -------------------------------------------------------------------------------- /docs/imgs/10/teapot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/10/teapot.png -------------------------------------------------------------------------------- /docs/imgs/11/blank_window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11/blank_window.png -------------------------------------------------------------------------------- /docs/imgs/11/swap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11/swap.png -------------------------------------------------------------------------------- /docs/imgs/11/teapot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11/teapot.png -------------------------------------------------------------------------------- /docs/imgs/11/three.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11/three.png -------------------------------------------------------------------------------- /docs/imgs/11_5/illuminated_teapot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11_5/illuminated_teapot.png -------------------------------------------------------------------------------- /docs/imgs/11_5/illuminated_teapot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11_5/illuminated_teapot_2.png -------------------------------------------------------------------------------- /docs/imgs/11_5/sphere_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11_5/sphere_1.png -------------------------------------------------------------------------------- /docs/imgs/11_5/sphere_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/11_5/sphere_2.png -------------------------------------------------------------------------------- /docs/imgs/12/directional.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/directional.png -------------------------------------------------------------------------------- /docs/imgs/12/gold_and_rubber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/gold_and_rubber.png -------------------------------------------------------------------------------- /docs/imgs/12/lit_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/lit_cube.png -------------------------------------------------------------------------------- /docs/imgs/12/specular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/specular.png -------------------------------------------------------------------------------- /docs/imgs/12/specular_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/specular_only.png -------------------------------------------------------------------------------- /docs/imgs/12/suzanne_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/suzanne_full.png -------------------------------------------------------------------------------- /docs/imgs/12/suzanne_specular_only.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/suzanne_specular_only.png -------------------------------------------------------------------------------- /docs/imgs/12/two_cubes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/two_cubes.png -------------------------------------------------------------------------------- /docs/imgs/12/two_cubes_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/12/two_cubes_full.png -------------------------------------------------------------------------------- /docs/imgs/13/NormalMaps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/NormalMaps.png -------------------------------------------------------------------------------- /docs/imgs/13/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/diamond.png -------------------------------------------------------------------------------- /docs/imgs/13/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/noise.png -------------------------------------------------------------------------------- /docs/imgs/13/textured.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/textured.png -------------------------------------------------------------------------------- /docs/imgs/13/triangle1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/triangle1.png -------------------------------------------------------------------------------- /docs/imgs/13/triangle2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/triangle2.png -------------------------------------------------------------------------------- /docs/imgs/13/untextured.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/untextured.png -------------------------------------------------------------------------------- /docs/imgs/13/uv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/13/uv.png -------------------------------------------------------------------------------- /docs/imgs/14/201.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/201.png -------------------------------------------------------------------------------- /docs/imgs/14/compressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/compressed.png -------------------------------------------------------------------------------- /docs/imgs/14/count.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/count.png -------------------------------------------------------------------------------- /docs/imgs/14/marked_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/marked_texture.png -------------------------------------------------------------------------------- /docs/imgs/14/spacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/spacing.png -------------------------------------------------------------------------------- /docs/imgs/14/texture_map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/texture_map.png -------------------------------------------------------------------------------- /docs/imgs/14/texture_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/14/texture_small.png -------------------------------------------------------------------------------- /docs/imgs/2/colorful_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/2/colorful_triangle.png -------------------------------------------------------------------------------- /docs/imgs/2/triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/2/triangle.png -------------------------------------------------------------------------------- /docs/imgs/3/coordinates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/coordinates.png -------------------------------------------------------------------------------- /docs/imgs/3/projection_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/projection_triangle.png -------------------------------------------------------------------------------- /docs/imgs/3/required_trait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/required_trait.png -------------------------------------------------------------------------------- /docs/imgs/3/squished_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/squished_triangle.png -------------------------------------------------------------------------------- /docs/imgs/3/translated_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/translated_triangle.png -------------------------------------------------------------------------------- /docs/imgs/3/updated_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/updated_triangle.png -------------------------------------------------------------------------------- /docs/imgs/3/view_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/3/view_triangle.png -------------------------------------------------------------------------------- /docs/imgs/4/fixed_depth_triangles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/4/fixed_depth_triangles.png -------------------------------------------------------------------------------- /docs/imgs/4/triangles_with_no_depth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/4/triangles_with_no_depth.png -------------------------------------------------------------------------------- /docs/imgs/5/culled_triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/5/culled_triangle.png -------------------------------------------------------------------------------- /docs/imgs/5/triangle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/5/triangle.png -------------------------------------------------------------------------------- /docs/imgs/6/ambient_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/ambient_1.png -------------------------------------------------------------------------------- /docs/imgs/6/ambient_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/ambient_2.png -------------------------------------------------------------------------------- /docs/imgs/6/ambient_2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/ambient_2b.png -------------------------------------------------------------------------------- /docs/imgs/6/ambient_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/ambient_3.png -------------------------------------------------------------------------------- /docs/imgs/6/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/error.png -------------------------------------------------------------------------------- /docs/imgs/6/lit_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/lit_cube.png -------------------------------------------------------------------------------- /docs/imgs/6/rotating_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/rotating_cube.png -------------------------------------------------------------------------------- /docs/imgs/6/static_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/6/static_cube.png -------------------------------------------------------------------------------- /docs/imgs/7/lit_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/7/lit_cube.png -------------------------------------------------------------------------------- /docs/imgs/7/multi_pass_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/7/multi_pass_diagram.png -------------------------------------------------------------------------------- /docs/imgs/7/normal_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/7/normal_cube.png -------------------------------------------------------------------------------- /docs/imgs/7/review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/7/review.png -------------------------------------------------------------------------------- /docs/imgs/7/unlit_cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/7/unlit_cube.png -------------------------------------------------------------------------------- /docs/imgs/8/combined_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/8/combined_images.png -------------------------------------------------------------------------------- /docs/imgs/8/cube_lights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/8/cube_lights.png -------------------------------------------------------------------------------- /docs/imgs/8/single_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/8/single_light.png -------------------------------------------------------------------------------- /docs/imgs/8/three_lights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/8/three_lights.png -------------------------------------------------------------------------------- /docs/imgs/9/cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/cube.png -------------------------------------------------------------------------------- /docs/imgs/9/export_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/export_1.png -------------------------------------------------------------------------------- /docs/imgs/9/export_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/export_2.png -------------------------------------------------------------------------------- /docs/imgs/9/suzanne_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/suzanne_1.png -------------------------------------------------------------------------------- /docs/imgs/9/suzanne_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/suzanne_2.png -------------------------------------------------------------------------------- /docs/imgs/9/suzanne_blender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/docs/imgs/9/suzanne_blender.png -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: False 3 | --- 4 | 5 | # Vulkano Tutorial 6 | 7 | This site is intended to serve as a tutorial for using Vulkan in Rust via the Vulkano crate. This mostly documents my own experiments with learning graphical programming but I’m writing it down here in case others might find it useful. The Vulkano crate is in active development and so regularly experiences breaking changes. I will try to keep the examples updated but this is a hobby project. 8 | 9 | Note: All code is provided under the [MIT License](http://opensource.org/licenses/MIT) and includes samples taken from official Vulkano examples. All text and images are licensed under the [Creative Commons Attribution](https://creativecommons.org/licenses/by/4.0/) license (CC BY 4.0) 10 | 11 | 12 | ## Requirements 13 | 14 | The following needs to be present on your computer if you want to follow along: 15 | 16 | 1: [Rust](https://www.rust-lang.org/) version 1.56.1 or later 17 | 18 | 2: A computer that supports Vulkan. You can check your hardware at the vendor's website. 19 | - [NVIDIA](https://developer.nvidia.com/vulkan-driver), [AMD](https://www.amd.com/en/technologies/vulkan), [Intel](https://www.intel.com/content/www/us/en/support/articles/000005524/graphics.html) 20 | 21 | 3: A working install of a shader pipeline as outlined in the [main Vulkano documentation](https://github.com/vulkano-rs/vulkano) 22 | 23 | ## Running the Lessons 24 | 25 | This tutorial series uses Cargo's [Workspaces](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html) feature to group multiple projects into a single repo. To run cargo on a single project you can pass in the `-p` flag followed by the name of the project. 26 | 27 | All the lessons in this series are independent projects and are named `lesson_{tutorial_number}`. For example, to run the first lesson navigate to the root `vulkano_tutorial` directory and run `cargo run -p lesson_1`. 28 | 29 | ## Contents 30 | 31 | ### 0. Introduction 32 | Provides a brief overview of some Vulkan considerations as well as a couple of notes on Rust. 33 | 34 | [Introduction to Vulkan](./section_0.md) 35 | 36 | ### 1. Our first window 37 | 38 | For our initial project, we will open a black window. This terminally-boring example is actually much longer and more important than you might expect. It will introduce most of the critical aspects shared by any Vulkan program. 39 | 40 | [First Window](./section_1.md) 41 | 42 | ### 2. Rendering a triangle 43 | 44 | With our first project we learned how to set up and use a Vulkan program. Now in this lesson we learn how to render things to the screen. This will involve writing our first shaders as well as passing information to them. 45 | 46 | [Triangle](./section_2.md) 47 | 48 | ### 3. Transformations 49 | 50 | After getting your first triangle on the screen the obvious question becomes "great, so how do I make it do things?" For that we will need to learn to apply *transformations* via `Uniform` data, which will be the other main way we feed data to our shaders in addition to the vertex data we learned about in the last lesson. 51 | 52 | [Transformations](./section_3.md) 53 | 54 | ### 4. Depth 55 | 56 | A shorter lesson that shows how to enable depth-testing in Vulkan. This is a necessity for the more complicated scenes we'll be creating in later lessons. 57 | 58 | [Depth](./section_4.md) 59 | 60 | ### 5. Winding order 61 | 62 | This lesson is a short one but it talks about a very important subject for rendering more complicated scenes: winding order and how you can use it to lower the amount of work your graphics hardware has to do. 63 | 64 | [Winding Order](./section_5.md) 65 | 66 | ### 6. Light I 67 | 68 | And in the sixth lesson the programmer said "let there be light" and lo, there was light! 69 | 70 | [Light](./section_6.md) 71 | 72 | ### 7. Multi-pass rendering 73 | 74 | Now that we're starting to get into more advanced features we're going to need to increase the power of our rendering system. We will accomplish this by introducing multiple rendering passes into the equation. 75 | 76 | [Multi-pass rendering](./section_7.md) 77 | 78 | ### 8. Light II 79 | 80 | Now that we've got our deferred rendering system set up, let's look at how you can use it to add more than one directional light to our scene. 81 | 82 | [Multiple Lights](./section_8.md) 83 | 84 | ### 9. Models 85 | 86 | Now that we've set up a working lighting system let's take a step back and look at something else that would be important to any graphics application: how to load models from a file. 87 | 88 | [Loading Models](./section_9.md) 89 | 90 | ### 10. New Uniforms 91 | 92 | After a couple of longer lessons, let's take a short break to refactor our normals code as well as set the stage for multiple models. 93 | 94 | [Normal Uniform](./section_10.md) 95 | 96 | ### 11. Render System I 97 | 98 | We're ready now to take our first stab at making a real rendering system. We won't introduce any new concepts in this lesson, just wrap up what we already know in a way that lets us input models to render as well as directional light sources. Think of this as a draft version of the more advanced system we'll make in a few lessons. 99 | 100 | [Render System](./section_11.md) 101 | 102 | #### 11.5 Light Objects 103 | 104 | Let's take a bit of a break from "big picture" topics and implement a small feature that will give us the option to visually display where our light sources are in our scene. 105 | 106 | [Light Objects](./section_11_5.md) 107 | 108 | ### 12. Light III 109 | 110 | We're almost ready to move on to "advanced" topics, but first we have to revisit light one more time to complete our lighting model. This time we'll be adding "shininess." 111 | 112 | [Specular Reflection](./section_12.md) 113 | 114 | ### 13. Textures 115 | 116 | A brief look at textures and a discussion of their uses. 117 | 118 | [Textures](./section_13.md) 119 | 120 | ### 14. Text 121 | 122 | A look at how to use textures to display a timer to the user. 123 | 124 | [Text](./section_14.md) 125 | -------------------------------------------------------------------------------- /docs/section_4.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Depth 4 | back_link: "./section_3.html" 5 | next_link: "./section_5.html" 6 | --- 7 | 8 | # Depth 9 | 10 | We're four lessons into this thing but we've been cheating the whole time. We have been talking about models in 3-dimensional space and how to transform them and such. However, we have actually been silently ignoring the third dimension entirely. What do I mean by that? Let's look at an example. 11 | 12 | ## Example 13 | 14 | Let's change our code so we have two triangles with one being white, and the other black. For the sake of this example we'll get rid of the translation/rotation code from last time and replace the model matrix with the simple identity matrix. 15 | 16 | ```rust 17 | let vertices = [ 18 | Vertex { 19 | position: [-0.5, 0.5, -0.5], 20 | color: [0.0, 0.0, 0.0], 21 | }, 22 | Vertex { 23 | position: [0.5, 0.5, -0.5], 24 | color: [0.0, 0.0, 0.0], 25 | }, 26 | Vertex { 27 | position: [0.0, -0.5, -0.5], 28 | color: [0.0, 0.0, 0.0], 29 | }, 30 | Vertex { 31 | position: [-0.5, -0.5, -0.6], 32 | color: [1.0, 1.0, 1.0], 33 | }, 34 | Vertex { 35 | position: [0.5, -0.5, -0.6], 36 | color: [1.0, 1.0, 1.0], 37 | }, 38 | Vertex { 39 | position: [0.0, 0.5, -0.6], 40 | color: [1.0, 1.0, 1.0], 41 | }, 42 | ]; 43 | ``` 44 | 45 | Pretty simple; we have two triangles, one behind the other. The one in front is black and the one in back is in white. Let's run the code and see what happens. 46 | 47 | ![two triangles with the one that should be behind the other actually rendered in front of it](./imgs/4/triangles_with_no_depth.png) 48 | 49 | That...doesn't look right. The white triangle is supposed to be behind the black one but it's the other way around, what's going on? What we're lacking is *depth testing*, the mechanism where vulkan checks what depth each vertex is at. In other words, with depth testing enabled our graphics hardware will be able to draw back-to-front with the furthest away vertices being drawn first. Right now, the vertices are being drawn in the order they are received, which is why we currently have this problem. 50 | 51 | Luckily for us, Vulkan makes it very easy to turn on depth testing. Let's take a look at that now. 52 | 53 | #### Render Pass 54 | 55 | We do depth testing through something called a *depth_stencil*. The way this works is that it's another render attachment (data buffer) that we attach to the render pass we want depth testing for. It might sound like it might be a bit difficult but it's actually pretty simple. Let's look at what our new render pass declaration looks like. 56 | 57 | ```rust 58 | let render_pass = vulkano::single_pass_renderpass!( 59 | device.clone(), 60 | attachments: { 61 | color: { 62 | load: Clear, 63 | store: Store, 64 | format: swapchain.format(), 65 | samples: 1, 66 | }, 67 | depth: { 68 | load: Clear, 69 | store: DontCare, 70 | format: Format::D16_UNORM, 71 | samples: 1, 72 | } 73 | }, 74 | pass: { 75 | color: [color], 76 | depth_stencil: {depth} 77 | } 78 | ).unwrap(); 79 | ``` 80 | 81 | As you can see, our `depth` attachment looks a lot like our `color` attachment. There are, however, two things to take note of. First, our `store` value is `DontCare`. This means that our graphics driver can do what it wants with the data, including destroying it if it wishes. This is because this attachment is used within the rendering process by the driver and we're not interested in retrieving it later. The second thing is that our `format` is *not* the same format as our swapchain. This is because is serves as a *stencil* rather than a full-on render target. So we only need a format which can store the depth information. 82 | 83 | Also, just like `color` we could have called `depth` anything but it's most idiomatic to name our depth attachment after its function. It's not a big problem when you only have two attachments in a single render pass but more complicated workflows will have a lot more to keep track of. Giving everything sensible names will save yourself a lot of annoyance down the line. 84 | 85 | #### Graphics pipeline 86 | 87 | Our render pass tells Vulkan *what* is available but to tell Vulkan *how to use it* we need to update our pipeline declaration. Thankfully, this is even easier than updating our render pass. 88 | 89 | ```rust 90 | let pipeline = GraphicsPipeline::start() 91 | .vertex_input_state(BuffersDefinition::new().vertex::()) 92 | .vertex_shader(vs.entry_point("main").unwrap(), ()) 93 | .input_assembly_state(InputAssemblyState::new()) 94 | .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant()) 95 | .fragment_shader(fs.entry_point("main").unwrap(), ()) 96 | .depth_stencil_state(DepthStencilState::simple_depth_test()) 97 | .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) 98 | .build(device.clone()) 99 | .unwrap(); 100 | ``` 101 | 102 | our only new line is `.depth_stencil_state(DepthStencilState::simple_depth_test())` and it instructs Vulkan to use our attached depth stencil. Like with `input_assembly_state` there are more complex things we could do but for now the simplest option is all we need. 103 | 104 | #### Framebuffer 105 | 106 | We have a new framebuffer attachment declared in our renderpass so we need to make sure to add it to our framebuffer declarations as well. 107 | 108 | ```rust 109 | let dimensions = images[0].dimensions().width_height(); 110 | viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32]; 111 | let depth_buffer = ImageView::new_default( 112 | AttachmentImage::transient(allocator, dimensions, Format::D16_UNORM).unwrap(), 113 | ) 114 | .unwrap(); 115 | 116 | images 117 | .iter() 118 | .map(|image| { 119 | let view = ImageView::new_default(image.clone()).unwrap(); 120 | Framebuffer::new( 121 | render_pass.clone(), 122 | FramebufferCreateInfo { 123 | attachments: vec![view, depth_buffer.clone()], 124 | ..Default::default() 125 | }, 126 | ) 127 | .unwrap() 128 | }) 129 | .collect::>() 130 | ``` 131 | 132 | Our call to `AttachmentImage::transient` is how we create the actual buffer that will be used in the framebuffer attachment. Since we don't care what happens to it once we're done, it can be a transient image. 133 | 134 | Also, since this is being taken care of in our `window_size_dependent_setup` helper function, we'll need to expand the parameter list to pass in a `StandardMemoryAllocator`, needed to create the attachment image. 135 | 136 | ```rust 137 | fn window_size_dependent_setup( 138 | allocator: &StandardMemoryAllocator, 139 | images: &[Arc], 140 | render_pass: Arc, 141 | viewport: &mut Viewport, 142 | ) -> Vec> { 143 | // .... 144 | } 145 | ``` 146 | 147 | #### Clear colors 148 | 149 | The last thing we need to do is set the clear colors. This is an easy thing to miss but important. Each framebuffer attachment we use needs to have its own clear color. 150 | 151 | ```rust 152 | let clear_values = vec![Some([0.0, 0.68, 1.0, 1.0].into()), Some(1.0.into())]; 153 | ``` 154 | 155 | Two things to notice here: 156 | - because our depth buffer is in a format that takes a single value per vertex rather than an array we can get away with using `1.0` as the clear value rather than a color vector 157 | - the clear values **must** be listed in the same order as the buffer attachments. This is an easy thing to get wrong, so just keep it in mind. 158 | 159 | #### Running our new code 160 | 161 | Re-run our code and you should see that everything is now in the expected order with the black triangle in front of the white one. 162 | 163 | ![two triangles showing correct depth ordering](./imgs/4/fixed_depth_triangles.png) 164 | 165 | Not the most exciting image, I know, but now that we have depth sorted out we are ready to start moving on to more complicated scenes. 166 | 167 | In this lesson you also got your first taste of using multiple attachments, something which will be very useful in future lessons. 168 | 169 | [lesson source code](https://github.com/taidaesal/vulkano_tutorial/tree/gh-pages/lessons/4.%20Depth) 170 | -------------------------------------------------------------------------------- /docs/section_5.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Face-Culling 4 | back_link: "./section_4.html" 5 | next_link: "./section_6.html" 6 | --- 7 | 8 | # Winding Order and Face Culling 9 | 10 | Much like depth testing, up until now we've been overlooking a concept that's fundamental to getting complicated scenes to work: winding order. What's that you might ask? It's nothing more complicated than the order in which we specify a triangle's vertices. Consider the following diagram: 11 | 12 | ![a picture of a triangle with the three vertices labeled from A to C](./imgs/5/triangle.png) 13 | 14 | A triangle is defined by three vertices and, up until now, we've been listing them in whatever order we please; however, Vulkan would very much *like* to care about that order for reasons we'll touch on in a second. 15 | 16 | Winding order can be either clockwise or counter-clockwise. A clockwise winding for the triangle above would be `A -> B -> C` whereas a counter-clockwise winding would be `A -> C -> B`. Conceptually it isn't very difficult but it can easily trip you up if you don't pay attention to it. 17 | 18 | Okay, that's great and all but why should we care? What winding lets us do is figure out which triangles are facing away from us due to a neat math trick. If a triangle has clockwise winding when it's facing us, if we turn it around it will appear to us to have a counter-clockwise winding instead. This lets Vulkan silently cull (or drop) these vertices which aren't facing us. A complicated scene might have hundreds of thousands or even millions of triangles in its raw data, but around half of those will be facing away from us and invisible to the user at any given time. By using face winding we can halve the amount of rendering our graphics hardware needs to do. It's an inexpensive trick, but one which frees up *a lot* of graphics hardware capability to use for things we care about. 19 | 20 | ## Example 21 | 22 | Okay, a simple example is below. Let's use the same code as we did for our depth testing but modify it a little bit. Let's set it so that the black triangle uses counter-clockwise winding while the white triangle uses clockwise winding. 23 | ```rust 24 | let vertices = [ 25 | Vertex { 26 | position: [-0.5, 0.5, -0.5], 27 | color: [0.0, 0.0, 0.0], 28 | }, 29 | Vertex { 30 | position: [0.5, 0.5, -0.5], 31 | color: [0.0, 0.0, 0.0], 32 | }, 33 | Vertex { 34 | position: [0.0, -0.5, -0.5], 35 | color: [0.0, 0.0, 0.0], 36 | }, 37 | Vertex { 38 | position: [-0.5, -0.5, -0.6], 39 | color: [1.0, 1.0, 1.0], 40 | }, 41 | Vertex { 42 | position: [0.5, -0.5, -0.6], 43 | color: [1.0, 1.0, 1.0], 44 | }, 45 | Vertex { 46 | position: [0.0, 0.5, -0.6], 47 | color: [1.0, 1.0, 1.0], 48 | }, 49 | ]; 50 | ``` 51 | 52 | If you run your code now you'll see that both triangles show up, exactly as in the last lesson. Let's change that now. 53 | 54 | #### Pipeline 55 | 56 | To tell Vulkan we want to enable face-culling we need to add some commands to our Pipeline. 57 | 58 | ```rust 59 | let pipeline = GraphicsPipeline::start() 60 | .vertex_input_state(BuffersDefinition::new().vertex::()) 61 | .vertex_shader(vs.entry_point("main").unwrap(), ()) 62 | .input_assembly_state(InputAssemblyState::new()) 63 | .viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant()) 64 | .fragment_shader(fs.entry_point("main").unwrap(), ()) 65 | .depth_stencil_state(DepthStencilState::simple_depth_test()) 66 | .rasterization_state(RasterizationState::new().cull_mode(CullMode::Back)) 67 | .render_pass(Subpass::from(render_pass.clone(), 0).unwrap()) 68 | .build(device.clone()) 69 | .unwrap(); 70 | ``` 71 | 72 | `.rasterization_state` lets us change a number of settings including depth clamping, whether we want to fill in our polygons, and, most importantly for us right now, if we want to use face-culling. By default, the `RasterizationState` does not have culling enabled, so we turn it on with `.cull_mode(CullMode::Back)`. We can cull everything in front as well if we wish, as well as change the winding order. The default winding order is counter-clockwise. You can change this by adding `.front_face(FrontFace::Clockwise)` after `.cull_mode(..)` 73 | 74 | Run the code and we should see the white triangle has disappeared, exactly as expected. 75 | 76 | ![an image showing that only the triangle with the correct winding remains](./imgs/5/culled_triangle.png) 77 | 78 | As with depth testing, we will be leaving this feature on for all future lessons. 79 | 80 | [lesson source code](https://github.com/taidaesal/vulkano_tutorial/tree/gh-pages/lessons/5.%20Face%20and%20Winding%20Order) 81 | -------------------------------------------------------------------------------- /lessons/1. Initialization/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_1" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | vulkano = "0.32.3" 9 | vulkano-shaders = "0.32.0" 10 | vulkano-win = "0.32.0" 11 | winit = "0.27.3" 12 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_10" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/model.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::obj_loader::{Loader, NormalVertex}; 7 | 8 | use nalgebra_glm::{identity, inverse_transpose, rotate_normalized_axis, translate, TMat4, TVec3}; 9 | use std::cell::Cell; 10 | 11 | /// Holds our data for a renderable model, including the model matrix data 12 | /// 13 | /// Note: When building an instance of `Model` the loader will assume that 14 | /// the input obj file is in clockwise winding order. If it is already in 15 | /// counter-clockwise winding order, call `.invert_winding_order(false)` 16 | /// when building the `Model`. 17 | pub struct Model { 18 | data: Vec, 19 | translation: TMat4, 20 | rotation: TMat4, 21 | 22 | // We might call multiple translation/rotation calls 23 | // in between asking for the model matrix. This lets us 24 | // only recreate the model matrices when needed. 25 | // Use a Cell with the interior mutability pattern, 26 | // so that it can be modified by methods that don't take &mut self 27 | cache: Cell>, 28 | } 29 | 30 | #[derive(Copy, Clone)] 31 | struct ModelMatrices { 32 | model: TMat4, 33 | normals: TMat4, 34 | } 35 | 36 | pub struct ModelBuilder { 37 | file_name: String, 38 | custom_color: [f32; 3], 39 | invert: bool, 40 | } 41 | 42 | impl ModelBuilder { 43 | fn new(file: String) -> ModelBuilder { 44 | ModelBuilder { 45 | file_name: file, 46 | custom_color: [1.0, 0.35, 0.137], 47 | invert: true, 48 | } 49 | } 50 | 51 | pub fn build(self) -> Model { 52 | let loader = Loader::new(self.file_name.as_str(), self.custom_color, self.invert); 53 | Model { 54 | data: loader.as_normal_vertices(), 55 | translation: identity(), 56 | rotation: identity(), 57 | cache: Cell::new(None), 58 | } 59 | } 60 | 61 | pub fn color(mut self, new_color: [f32; 3]) -> ModelBuilder { 62 | self.custom_color = new_color; 63 | self 64 | } 65 | 66 | pub fn file(mut self, file: String) -> ModelBuilder { 67 | self.file_name = file; 68 | self 69 | } 70 | 71 | pub fn invert_winding_order(mut self, invert: bool) -> ModelBuilder { 72 | self.invert = invert; 73 | self 74 | } 75 | } 76 | 77 | impl Model { 78 | pub fn new(file_name: &str) -> ModelBuilder { 79 | ModelBuilder::new(file_name.into()) 80 | } 81 | 82 | pub fn data(&self) -> Vec { 83 | self.data.clone() 84 | } 85 | 86 | pub fn model_matrices(&self) -> (TMat4, TMat4) { 87 | if let Some(cache) = self.cache.get() { 88 | return (cache.model, cache.normals); 89 | } 90 | 91 | // recalculate matrices 92 | let model = self.translation * self.rotation; 93 | let normals = inverse_transpose(model); 94 | 95 | self.cache.set(Some(ModelMatrices { model, normals })); 96 | 97 | (model, normals) 98 | } 99 | 100 | pub fn rotate(&mut self, radians: f32, v: TVec3) { 101 | self.rotation = rotate_normalized_axis(&self.rotation, radians, &v); 102 | self.cache.set(None); 103 | } 104 | 105 | pub fn translate(&mut self, v: TVec3) { 106 | self.translation = translate(&self.translation, &v); 107 | self.cache.set(None); 108 | } 109 | 110 | /// Return the model's rotation to 0 111 | pub fn zero_rotation(&mut self) { 112 | self.rotation = identity(); 113 | self.cache.set(None); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/obj_loader/face.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use std::fmt; 6 | 7 | pub struct RawFace { 8 | pub verts: [usize; 3], 9 | pub norms: Option<[usize; 3]>, 10 | pub text: Option<[usize; 3]>, 11 | } 12 | 13 | impl RawFace { 14 | // call with invert = true if the models are using a clockwise winding order 15 | // 16 | // Blender files are a common example 17 | pub fn new(raw_arg: &str, invert: bool) -> RawFace { 18 | let arguments: Vec<&str> = raw_arg.split_whitespace().collect(); 19 | RawFace { 20 | verts: RawFace::parse(arguments.clone(), 0, invert).unwrap(), 21 | norms: RawFace::parse(arguments.clone(), 2, invert), 22 | text: RawFace::parse(arguments.clone(), 1, invert), 23 | } 24 | } 25 | 26 | fn parse(inpt: Vec<&str>, index: usize, invert: bool) -> Option<[usize; 3]> { 27 | let f1: Vec<&str> = inpt.get(0).unwrap().split("/").collect(); 28 | let f2: Vec<&str> = inpt.get(1).unwrap().split("/").collect(); 29 | let f3: Vec<&str> = inpt.get(2).unwrap().split("/").collect(); 30 | let a1 = f1.get(index).unwrap().clone(); 31 | let a2 = f2.get(index).unwrap().clone(); 32 | let a3 = f3.get(index).unwrap().clone(); 33 | match a1 { 34 | "" => None, 35 | _ => { 36 | let p1: usize = a1.parse().unwrap(); 37 | let (p2, p3): (usize, usize) = if invert { 38 | (a3.parse().unwrap(), a2.parse().unwrap()) 39 | } else { 40 | (a2.parse().unwrap(), a3.parse().unwrap()) 41 | }; 42 | Some([p1 - 1, p2 - 1, p3 - 1]) // .obj files aren't 0-index 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl fmt::Display for RawFace { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | let verts = format!("{}/{}/{}", self.verts[0], self.verts[1], self.verts[2]); 51 | let normals = match self.norms { 52 | None => "None".to_string(), 53 | Some(x) => { 54 | format!("{}/{}/{}", x[0], x[1], x[2]) 55 | } 56 | }; 57 | let textures = match self.text { 58 | None => "None".to_string(), 59 | Some(x) => { 60 | format!("{}/{}/{}", x[0], x[1], x[2]) 61 | } 62 | }; 63 | write!( 64 | f, 65 | "Face:\n\tVertices: {}\n\tNormals: {}\n\tTextures: {}", 66 | verts, normals, textures 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/obj_loader/loader.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::face::RawFace; 7 | use super::vertex::RawVertex; 8 | use super::NormalVertex; 9 | 10 | use std::fs::File; 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub struct Loader { 14 | color: [f32; 3], 15 | verts: Vec, 16 | norms: Vec, 17 | text: Vec, 18 | faces: Vec, 19 | invert_winding_order: bool, 20 | } 21 | 22 | impl Loader { 23 | pub fn new(file_name: &str, custom_color: [f32; 3], invert_winding_order: bool) -> Loader { 24 | let color = custom_color; 25 | let input = File::open(file_name).unwrap(); 26 | let buffered = BufReader::new(input); 27 | let mut verts: Vec = Vec::new(); 28 | let mut norms: Vec = Vec::new(); 29 | let mut text: Vec = Vec::new(); 30 | let mut faces: Vec = Vec::new(); 31 | for raw_line in buffered.lines() { 32 | let line = raw_line.unwrap(); 33 | if line.len() > 2 { 34 | match line.split_at(2) { 35 | ("v ", x) => { 36 | verts.push(RawVertex::new(x)); 37 | } 38 | ("vn", x) => { 39 | norms.push(RawVertex::new(x)); 40 | } 41 | ("vt", x) => { 42 | text.push(RawVertex::new(x)); 43 | } 44 | ("f ", x) => { 45 | faces.push(RawFace::new(x, invert_winding_order)); 46 | } 47 | (_, _) => {} 48 | }; 49 | } 50 | } 51 | Loader { 52 | color, 53 | verts, 54 | norms, 55 | text, 56 | faces, 57 | invert_winding_order, 58 | } 59 | } 60 | 61 | pub fn as_normal_vertices(&self) -> Vec { 62 | let mut ret: Vec = Vec::new(); 63 | for face in &self.faces { 64 | let verts = face.verts; 65 | let normals = face.norms.unwrap(); 66 | ret.push(NormalVertex { 67 | position: self.verts.get(verts[0]).unwrap().vals, 68 | normal: self.norms.get(normals[0]).unwrap().vals, 69 | color: self.color, 70 | }); 71 | ret.push(NormalVertex { 72 | position: self.verts.get(verts[1]).unwrap().vals, 73 | normal: self.norms.get(normals[1]).unwrap().vals, 74 | color: self.color, 75 | }); 76 | ret.push(NormalVertex { 77 | position: self.verts.get(verts[2]).unwrap().vals, 78 | normal: self.norms.get(normals[2]).unwrap().vals, 79 | color: self.color, 80 | }); 81 | } 82 | ret 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/obj_loader/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod face; 6 | mod loader; 7 | mod vertex; 8 | pub use self::loader::Loader; 9 | use bytemuck::{Pod, Zeroable}; 10 | 11 | use std::fmt; 12 | 13 | /// A vertex type intended to be used to provide dummy rendering 14 | /// data for rendering passes that do not require geometry data. 15 | /// This is due to a quirk of the Vulkan API in that *all* 16 | /// render passes require some sort of input. 17 | #[repr(C)] 18 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 19 | pub struct DummyVertex { 20 | /// A regular position vector with the z-value shaved off for space. 21 | /// This assumes the shaders will take a `vec2` and transform it as 22 | /// needed. 23 | pub position: [f32; 2], 24 | } 25 | 26 | impl DummyVertex { 27 | /// Creates an array of `DummyVertex` values. 28 | /// 29 | /// This is intended to compliment the use of this data type for passing to 30 | /// deferred rendering passes that do not actually require geometry input. 31 | /// This list will draw a square across the entire rendering area. This will 32 | /// cause the fragment shaders to execute on all pixels in the rendering 33 | /// area. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```glsl 38 | /// #version 450 39 | /// 40 | ///layout(location = 0) in vec2 position; 41 | /// 42 | ///void main() { 43 | /// gl_Position = vec4(position, 0.0, 1.0); 44 | ///} 45 | /// ``` 46 | pub fn list() -> [DummyVertex; 6] { 47 | [ 48 | DummyVertex { 49 | position: [-1.0, -1.0], 50 | }, 51 | DummyVertex { 52 | position: [-1.0, 1.0], 53 | }, 54 | DummyVertex { 55 | position: [1.0, 1.0], 56 | }, 57 | DummyVertex { 58 | position: [-1.0, -1.0], 59 | }, 60 | DummyVertex { 61 | position: [1.0, 1.0], 62 | }, 63 | DummyVertex { 64 | position: [1.0, -1.0], 65 | }, 66 | ] 67 | } 68 | } 69 | 70 | /// A structure for the vertex information used in earlier lessons 71 | #[repr(C)] 72 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 73 | pub struct ColoredVertex { 74 | pub position: [f32; 3], 75 | pub color: [f32; 3], 76 | } 77 | 78 | /// A structure used for the vertex information starting 79 | /// from our lesson on lighting 80 | #[repr(C)] 81 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 82 | pub struct NormalVertex { 83 | pub position: [f32; 3], 84 | pub normal: [f32; 3], 85 | pub color: [f32; 3], 86 | } 87 | 88 | impl fmt::Display for DummyVertex { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | let pos = format!("[{:.6}, {:.6}]", self.position[0], self.position[1]); 91 | write!(f, "DummyVertex {{ position: {} }}", pos) 92 | } 93 | } 94 | 95 | impl fmt::Display for ColoredVertex { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | let pos = format!( 98 | "[{:.6}, {:.6}, {:.6}]", 99 | self.position[0], self.position[1], self.position[2] 100 | ); 101 | let color = format!( 102 | "[{:.6}, {:.6}, {:.6}]", 103 | self.color[0], self.color[1], self.color[2] 104 | ); 105 | write!(f, "ColoredVertex {{ position: {}, color: {} }}", pos, color) 106 | } 107 | } 108 | 109 | impl fmt::Display for NormalVertex { 110 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 111 | let pos = format!( 112 | "[{:.6}, {:.6}, {:.6}]", 113 | self.position[0], self.position[1], self.position[2] 114 | ); 115 | let color = format!( 116 | "[{:.6}, {:.6}, {:.6}]", 117 | self.color[0], self.color[1], self.color[2] 118 | ); 119 | let norms = format!( 120 | "[{:.6}, {:.6}, {:.6}]", 121 | self.normal[0], self.normal[1], self.normal[2] 122 | ); 123 | write!( 124 | f, 125 | "NormalVertex {{ position: {}, normal: {}, color: {} }}", 126 | pos, norms, color 127 | ) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/obj_loader/vertex.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | pub struct RawVertex { 6 | pub vals: [f32; 3], 7 | } 8 | 9 | impl RawVertex { 10 | pub fn new(inpt: &str) -> RawVertex { 11 | let items = inpt.split_whitespace(); 12 | let mut content: Vec = Vec::new(); 13 | for item in items { 14 | content.push(item.parse().unwrap()); 15 | } 16 | if content.len() == 2 { 17 | content.push(0.0); 18 | } 19 | RawVertex { 20 | vals: [ 21 | *content.get(0).unwrap(), 22 | *content.get(1).unwrap(), 23 | *content.get(2).unwrap(), 24 | ], 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | 5 | layout(set = 0, binding = 1) uniform Ambient_Data { 6 | vec3 color; 7 | float intensity; 8 | } ambient; 9 | 10 | layout(location = 0) out vec4 f_color; 11 | 12 | void main() { 13 | vec3 ambient_color = ambient.intensity * ambient.color; 14 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 15 | f_color = vec4(combined_color, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | layout(location = 0) in vec3 in_color; 3 | layout(location = 1) in vec3 in_normal; 4 | 5 | layout(location = 0) out vec4 f_color; 6 | layout(location = 1) out vec3 f_normal; 7 | 8 | void main() { 9 | f_color = vec4(in_color, 1.0); 10 | f_normal = in_normal; 11 | } -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform VP_Data { 11 | mat4 view; 12 | mat4 projection; 13 | } vp_uniforms; 14 | 15 | layout(set = 1, binding = 0) uniform Model_Data { 16 | mat4 model; 17 | mat4 normals; 18 | } model; 19 | 20 | void main() { 21 | gl_Position = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 22 | out_color = color; 23 | out_normal = mat3(model.normals) * normal; 24 | } -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 5 | 6 | layout(set = 0, binding = 2) uniform Directional_Light_Data { 7 | vec4 position; 8 | vec3 color; 9 | } directional; 10 | 11 | layout(location = 0) out vec4 f_color; 12 | 13 | void main() { 14 | vec3 light_direction = normalize(directional.position.xyz + subpassLoad(u_normals).xyz); 15 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 16 | vec3 directional_color = directional_intensity * directional.color; 17 | vec3 combined_color = directional_color * subpassLoad(u_color).rgb; 18 | f_color = vec4(combined_color, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /lessons/10. Uniform Refactoring/src/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/11. First Rendering System/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_11" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod model; 6 | mod obj_loader; 7 | mod system; 8 | 9 | use model::Model; 10 | use system::DirectionalLight; 11 | use system::System; 12 | 13 | use vulkano::sync; 14 | use vulkano::sync::GpuFuture; 15 | 16 | use winit::event::{Event, WindowEvent}; 17 | use winit::event_loop::{ControlFlow, EventLoop}; 18 | 19 | use nalgebra_glm::{look_at, pi, vec3}; 20 | 21 | use std::time::Instant; 22 | 23 | fn main() { 24 | let event_loop = EventLoop::new(); 25 | let mut system = System::new(&event_loop); 26 | 27 | system.set_view(&look_at( 28 | &vec3(0.0, 0.0, 0.1), 29 | &vec3(0.0, 0.0, 0.0), 30 | &vec3(0.0, 1.0, 0.0), 31 | )); 32 | 33 | let mut teapot = Model::new("data/models/teapot.obj").build(); 34 | teapot.translate(vec3(-5.0, 2.0, -8.0)); 35 | 36 | let mut suzanne = Model::new("data/models/suzanne.obj").build(); 37 | suzanne.translate(vec3(5.0, 2.0, -6.0)); 38 | 39 | let mut torus = Model::new("data/models/torus.obj").build(); 40 | torus.translate(vec3(0.0, -2.0, -5.0)); 41 | 42 | let directional_light_r = DirectionalLight::new([-4.0, -4.0, 0.0, -2.0], [1.0, 0.0, 0.0]); 43 | let directional_light_g = DirectionalLight::new([4.0, -4.0, 0.0, -2.0], [0.0, 1.0, 0.0]); 44 | let directional_light_b = DirectionalLight::new([0.0, 4.0, 0.0, -2.0], [0.0, 0.0, 1.0]); 45 | 46 | let rotation_start = Instant::now(); 47 | 48 | let mut previous_frame_end = 49 | Some(Box::new(sync::now(system.device.clone())) as Box); 50 | 51 | event_loop.run(move |event, _, control_flow| match event { 52 | Event::WindowEvent { 53 | event: WindowEvent::CloseRequested, 54 | .. 55 | } => { 56 | *control_flow = ControlFlow::Exit; 57 | } 58 | Event::WindowEvent { 59 | event: WindowEvent::Resized(_), 60 | .. 61 | } => { 62 | system.recreate_swapchain(); 63 | } 64 | Event::RedrawEventsCleared => { 65 | previous_frame_end 66 | .as_mut() 67 | .take() 68 | .unwrap() 69 | .cleanup_finished(); 70 | 71 | let elapsed = rotation_start.elapsed().as_secs() as f64 72 | + rotation_start.elapsed().subsec_nanos() as f64 / 1_000_000_000.0; 73 | let elapsed_as_radians = elapsed * pi::() / 180.0; 74 | 75 | teapot.zero_rotation(); 76 | teapot.rotate(elapsed_as_radians as f32 * 50.0, vec3(0.0, 0.0, 1.0)); 77 | teapot.rotate(elapsed_as_radians as f32 * 30.0, vec3(0.0, 1.0, 0.0)); 78 | teapot.rotate(elapsed_as_radians as f32 * 20.0, vec3(1.0, 0.0, 0.0)); 79 | 80 | suzanne.zero_rotation(); 81 | suzanne.rotate(elapsed_as_radians as f32 * 25.0, vec3(0.0, 0.0, 1.0)); 82 | suzanne.rotate(elapsed_as_radians as f32 * 10.0, vec3(0.0, 1.0, 0.0)); 83 | suzanne.rotate(elapsed_as_radians as f32 * 60.0, vec3(1.0, 0.0, 0.0)); 84 | 85 | torus.zero_rotation(); 86 | torus.rotate(elapsed_as_radians as f32 * 5.0, vec3(0.0, 0.0, 1.0)); 87 | torus.rotate(elapsed_as_radians as f32 * 45.0, vec3(0.0, 1.0, 0.0)); 88 | torus.rotate(elapsed_as_radians as f32 * 12.0, vec3(1.0, 0.0, 0.0)); 89 | 90 | system.start(); 91 | system.geometry(&teapot); 92 | system.geometry(&suzanne); 93 | system.geometry(&torus); 94 | system.ambient(); 95 | system.directional(&directional_light_r); 96 | system.directional(&directional_light_g); 97 | system.directional(&directional_light_b); 98 | system.finish(&mut previous_frame_end); 99 | } 100 | _ => (), 101 | }); 102 | } 103 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/model.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::obj_loader::{Loader, NormalVertex}; 7 | 8 | use nalgebra_glm::{identity, inverse_transpose, rotate_normalized_axis, translate, TMat4, TVec3}; 9 | use std::cell::Cell; 10 | 11 | /// Holds our data for a renderable model, including the model matrix data 12 | /// 13 | /// Note: When building an instance of `Model` the loader will assume that 14 | /// the input obj file is in clockwise winding order. If it is already in 15 | /// counter-clockwise winding order, call `.invert_winding_order(false)` 16 | /// when building the `Model`. 17 | pub struct Model { 18 | data: Vec, 19 | translation: TMat4, 20 | rotation: TMat4, 21 | 22 | // We might call multiple translation/rotation calls 23 | // in between asking for the model matrix. This lets us 24 | // only recreate the model matrices when needed. 25 | // Use a Cell with the interior mutability pattern, 26 | // so that it can be modified by methods that don't take &mut self 27 | cache: Cell>, 28 | } 29 | 30 | #[derive(Copy, Clone)] 31 | struct ModelMatrices { 32 | model: TMat4, 33 | normals: TMat4, 34 | } 35 | 36 | pub struct ModelBuilder { 37 | file_name: String, 38 | custom_color: [f32; 3], 39 | invert: bool, 40 | } 41 | 42 | impl ModelBuilder { 43 | fn new(file: String) -> ModelBuilder { 44 | ModelBuilder { 45 | file_name: file, 46 | custom_color: [1.0, 0.35, 0.137], 47 | invert: true, 48 | } 49 | } 50 | 51 | pub fn build(self) -> Model { 52 | let loader = Loader::new(self.file_name.as_str(), self.custom_color, self.invert); 53 | Model { 54 | data: loader.as_normal_vertices(), 55 | translation: identity(), 56 | rotation: identity(), 57 | cache: Cell::new(None), 58 | } 59 | } 60 | 61 | pub fn color(mut self, new_color: [f32; 3]) -> ModelBuilder { 62 | self.custom_color = new_color; 63 | self 64 | } 65 | 66 | pub fn file(mut self, file: String) -> ModelBuilder { 67 | self.file_name = file; 68 | self 69 | } 70 | 71 | pub fn invert_winding_order(mut self, invert: bool) -> ModelBuilder { 72 | self.invert = invert; 73 | self 74 | } 75 | } 76 | 77 | impl Model { 78 | pub fn new(file_name: &str) -> ModelBuilder { 79 | ModelBuilder::new(file_name.into()) 80 | } 81 | 82 | pub fn data(&self) -> Vec { 83 | self.data.clone() 84 | } 85 | 86 | pub fn model_matrices(&self) -> (TMat4, TMat4) { 87 | if let Some(cache) = self.cache.get() { 88 | return (cache.model, cache.normals); 89 | } 90 | 91 | // recalculate matrices 92 | let model = self.translation * self.rotation; 93 | let normals = inverse_transpose(model); 94 | 95 | self.cache.set(Some(ModelMatrices { model, normals })); 96 | 97 | (model, normals) 98 | } 99 | 100 | pub fn rotate(&mut self, radians: f32, v: TVec3) { 101 | self.rotation = rotate_normalized_axis(&self.rotation, radians, &v); 102 | self.cache.set(None); 103 | } 104 | 105 | pub fn translate(&mut self, v: TVec3) { 106 | self.translation = translate(&self.translation, &v); 107 | self.cache.set(None); 108 | } 109 | 110 | /// Return the model's rotation to 0 111 | pub fn zero_rotation(&mut self) { 112 | self.rotation = identity(); 113 | self.cache.set(None); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/obj_loader/face.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use std::fmt; 6 | 7 | pub struct RawFace { 8 | pub verts: [usize; 3], 9 | pub norms: Option<[usize; 3]>, 10 | pub text: Option<[usize; 3]>, 11 | } 12 | 13 | impl RawFace { 14 | // call with invert = true if the models are using a clockwise winding order 15 | // 16 | // Blender files are a common example 17 | pub fn new(raw_arg: &str, invert: bool) -> RawFace { 18 | let arguments: Vec<&str> = raw_arg.split_whitespace().collect(); 19 | RawFace { 20 | verts: RawFace::parse(arguments.clone(), 0, invert).unwrap(), 21 | norms: RawFace::parse(arguments.clone(), 2, invert), 22 | text: RawFace::parse(arguments.clone(), 1, invert), 23 | } 24 | } 25 | 26 | fn parse(inpt: Vec<&str>, index: usize, invert: bool) -> Option<[usize; 3]> { 27 | let f1: Vec<&str> = inpt.get(0).unwrap().split("/").collect(); 28 | let f2: Vec<&str> = inpt.get(1).unwrap().split("/").collect(); 29 | let f3: Vec<&str> = inpt.get(2).unwrap().split("/").collect(); 30 | let a1 = f1.get(index).unwrap().clone(); 31 | let a2 = f2.get(index).unwrap().clone(); 32 | let a3 = f3.get(index).unwrap().clone(); 33 | match a1 { 34 | "" => None, 35 | _ => { 36 | let p1: usize = a1.parse().unwrap(); 37 | let (p2, p3): (usize, usize) = if invert { 38 | (a3.parse().unwrap(), a2.parse().unwrap()) 39 | } else { 40 | (a2.parse().unwrap(), a3.parse().unwrap()) 41 | }; 42 | Some([p1 - 1, p2 - 1, p3 - 1]) // .obj files aren't 0-index 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl fmt::Display for RawFace { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | let verts = format!("{}/{}/{}", self.verts[0], self.verts[1], self.verts[2]); 51 | let normals = match self.norms { 52 | None => "None".to_string(), 53 | Some(x) => { 54 | format!("{}/{}/{}", x[0], x[1], x[2]) 55 | } 56 | }; 57 | let textures = match self.text { 58 | None => "None".to_string(), 59 | Some(x) => { 60 | format!("{}/{}/{}", x[0], x[1], x[2]) 61 | } 62 | }; 63 | write!( 64 | f, 65 | "Face:\n\tVertices: {}\n\tNormals: {}\n\tTextures: {}", 66 | verts, normals, textures 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/obj_loader/loader.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::face::RawFace; 7 | use super::vertex::RawVertex; 8 | use super::NormalVertex; 9 | 10 | use std::fs::File; 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub struct Loader { 14 | color: [f32; 3], 15 | verts: Vec, 16 | norms: Vec, 17 | text: Vec, 18 | faces: Vec, 19 | invert_winding_order: bool, 20 | } 21 | 22 | impl Loader { 23 | pub fn new(file_name: &str, custom_color: [f32; 3], invert_winding_order: bool) -> Loader { 24 | let color = custom_color; 25 | let input = File::open(file_name).unwrap(); 26 | let buffered = BufReader::new(input); 27 | let mut verts: Vec = Vec::new(); 28 | let mut norms: Vec = Vec::new(); 29 | let mut text: Vec = Vec::new(); 30 | let mut faces: Vec = Vec::new(); 31 | for raw_line in buffered.lines() { 32 | let line = raw_line.unwrap(); 33 | if line.len() > 2 { 34 | match line.split_at(2) { 35 | ("v ", x) => { 36 | verts.push(RawVertex::new(x)); 37 | } 38 | ("vn", x) => { 39 | norms.push(RawVertex::new(x)); 40 | } 41 | ("vt", x) => { 42 | text.push(RawVertex::new(x)); 43 | } 44 | ("f ", x) => { 45 | faces.push(RawFace::new(x, invert_winding_order)); 46 | } 47 | (_, _) => {} 48 | }; 49 | } 50 | } 51 | Loader { 52 | color, 53 | verts, 54 | norms, 55 | text, 56 | faces, 57 | invert_winding_order, 58 | } 59 | } 60 | 61 | pub fn as_normal_vertices(&self) -> Vec { 62 | let mut ret: Vec = Vec::new(); 63 | for face in &self.faces { 64 | let verts = face.verts; 65 | let normals = face.norms.unwrap(); 66 | ret.push(NormalVertex { 67 | position: self.verts.get(verts[0]).unwrap().vals, 68 | normal: self.norms.get(normals[0]).unwrap().vals, 69 | color: self.color, 70 | }); 71 | ret.push(NormalVertex { 72 | position: self.verts.get(verts[1]).unwrap().vals, 73 | normal: self.norms.get(normals[1]).unwrap().vals, 74 | color: self.color, 75 | }); 76 | ret.push(NormalVertex { 77 | position: self.verts.get(verts[2]).unwrap().vals, 78 | normal: self.norms.get(normals[2]).unwrap().vals, 79 | color: self.color, 80 | }); 81 | } 82 | ret 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/obj_loader/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod face; 6 | mod loader; 7 | mod vertex; 8 | pub use self::loader::Loader; 9 | use bytemuck::{Pod, Zeroable}; 10 | 11 | use std::fmt; 12 | 13 | /// A vertex type intended to be used to provide dummy rendering 14 | /// data for rendering passes that do not require geometry data. 15 | /// This is due to a quirk of the Vulkan API in that *all* 16 | /// render passes require some sort of input. 17 | #[repr(C)] 18 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 19 | pub struct DummyVertex { 20 | /// A regular position vector with the z-value shaved off for space. 21 | /// This assumes the shaders will take a `vec2` and transform it as 22 | /// needed. 23 | pub position: [f32; 2], 24 | } 25 | 26 | impl DummyVertex { 27 | /// Creates an array of `DummyVertex` values. 28 | /// 29 | /// This is intended to compliment the use of this data type for passing to 30 | /// deferred rendering passes that do not actually require geometry input. 31 | /// This list will draw a square across the entire rendering area. This will 32 | /// cause the fragment shaders to execute on all pixels in the rendering 33 | /// area. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```glsl 38 | /// #version 450 39 | /// 40 | ///layout(location = 0) in vec2 position; 41 | /// 42 | ///void main() { 43 | /// gl_Position = vec4(position, 0.0, 1.0); 44 | ///} 45 | /// ``` 46 | pub fn list() -> [DummyVertex; 6] { 47 | [ 48 | DummyVertex { 49 | position: [-1.0, -1.0], 50 | }, 51 | DummyVertex { 52 | position: [-1.0, 1.0], 53 | }, 54 | DummyVertex { 55 | position: [1.0, 1.0], 56 | }, 57 | DummyVertex { 58 | position: [-1.0, -1.0], 59 | }, 60 | DummyVertex { 61 | position: [1.0, 1.0], 62 | }, 63 | DummyVertex { 64 | position: [1.0, -1.0], 65 | }, 66 | ] 67 | } 68 | } 69 | 70 | /// A structure for the vertex information used in earlier lessons 71 | #[repr(C)] 72 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 73 | pub struct ColoredVertex { 74 | pub position: [f32; 3], 75 | pub color: [f32; 3], 76 | } 77 | 78 | /// A structure used for the vertex information starting 79 | /// from our lesson on lighting 80 | #[repr(C)] 81 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 82 | pub struct NormalVertex { 83 | pub position: [f32; 3], 84 | pub normal: [f32; 3], 85 | pub color: [f32; 3], 86 | } 87 | 88 | impl fmt::Display for DummyVertex { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | let pos = format!("[{:.6}, {:.6}]", self.position[0], self.position[1]); 91 | write!(f, "DummyVertex {{ position: {} }}", pos) 92 | } 93 | } 94 | 95 | impl fmt::Display for ColoredVertex { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | let pos = format!( 98 | "[{:.6}, {:.6}, {:.6}]", 99 | self.position[0], self.position[1], self.position[2] 100 | ); 101 | let color = format!( 102 | "[{:.6}, {:.6}, {:.6}]", 103 | self.color[0], self.color[1], self.color[2] 104 | ); 105 | write!(f, "ColoredVertex {{ position: {}, color: {} }}", pos, color) 106 | } 107 | } 108 | 109 | impl fmt::Display for NormalVertex { 110 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 111 | let pos = format!( 112 | "[{:.6}, {:.6}, {:.6}]", 113 | self.position[0], self.position[1], self.position[2] 114 | ); 115 | let color = format!( 116 | "[{:.6}, {:.6}, {:.6}]", 117 | self.color[0], self.color[1], self.color[2] 118 | ); 119 | let norms = format!( 120 | "[{:.6}, {:.6}, {:.6}]", 121 | self.normal[0], self.normal[1], self.normal[2] 122 | ); 123 | write!( 124 | f, 125 | "NormalVertex {{ position: {}, normal: {}, color: {} }}", 126 | pos, norms, color 127 | ) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/obj_loader/vertex.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | pub struct RawVertex { 6 | pub vals: [f32; 3], 7 | } 8 | 9 | impl RawVertex { 10 | pub fn new(inpt: &str) -> RawVertex { 11 | let items = inpt.split_whitespace(); 12 | let mut content: Vec = Vec::new(); 13 | for item in items { 14 | content.push(item.parse().unwrap()); 15 | } 16 | if content.len() == 2 { 17 | content.push(0.0); 18 | } 19 | RawVertex { 20 | vals: [ 21 | *content.get(0).unwrap(), 22 | *content.get(1).unwrap(), 23 | *content.get(2).unwrap(), 24 | ], 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod system; 6 | 7 | pub use system::System; 8 | 9 | #[derive(Default, Debug, Clone)] 10 | pub struct DirectionalLight { 11 | position: [f32; 4], 12 | color: [f32; 3], 13 | } 14 | 15 | impl DirectionalLight { 16 | pub fn new(position: [f32; 4], color: [f32; 3]) -> DirectionalLight { 17 | DirectionalLight { position, color } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | 5 | layout(set = 0, binding = 1) uniform Ambient_Data { 6 | vec3 color; 7 | float intensity; 8 | } ambient; 9 | 10 | layout(location = 0) out vec4 f_color; 11 | 12 | void main() { 13 | vec3 ambient_color = ambient.intensity * ambient.color; 14 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 15 | f_color = vec4(combined_color, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | layout(location = 0) in vec3 in_color; 3 | layout(location = 1) in vec3 in_normal; 4 | 5 | layout(location = 0) out vec4 f_color; 6 | layout(location = 1) out vec3 f_normal; 7 | 8 | void main() { 9 | f_color = vec4(in_color, 1.0); 10 | f_normal = in_normal; 11 | } -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform VP_Data { 11 | mat4 view; 12 | mat4 projection; 13 | } vp_uniforms; 14 | 15 | layout(set = 1, binding = 0) uniform Model_Data { 16 | mat4 model; 17 | mat4 normals; 18 | } model; 19 | 20 | void main() { 21 | gl_Position = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 22 | out_color = color; 23 | out_normal = mat3(model.normals) * normal; 24 | } -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 5 | 6 | layout(set = 0, binding = 2) uniform Directional_Light_Data { 7 | vec4 position; 8 | vec3 color; 9 | } directional; 10 | 11 | layout(location = 0) out vec4 f_color; 12 | 13 | void main() { 14 | vec3 light_direction = normalize(directional.position.xyz + subpassLoad(u_normals).xyz); 15 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 16 | vec3 directional_color = directional_intensity * directional.color; 17 | vec3 combined_color = directional_color * subpassLoad(u_color).rgb; 18 | f_color = vec4(combined_color, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /lessons/11. First Rendering System/src/system/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_11_5" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod model; 6 | mod obj_loader; 7 | mod system; 8 | 9 | use model::Model; 10 | use system::DirectionalLight; 11 | use system::System; 12 | 13 | use vulkano::sync; 14 | use vulkano::sync::GpuFuture; 15 | 16 | use winit::event::{Event, WindowEvent}; 17 | use winit::event_loop::{ControlFlow, EventLoop}; 18 | 19 | use nalgebra_glm::{look_at, pi, vec3}; 20 | 21 | use std::time::Instant; 22 | 23 | fn main() { 24 | let event_loop = EventLoop::new(); 25 | let mut system = System::new(&event_loop); 26 | 27 | system.set_view(&look_at( 28 | &vec3(0.0, 0.0, 0.1), 29 | &vec3(0.0, 0.0, 0.0), 30 | &vec3(0.0, 1.0, 0.0), 31 | )); 32 | 33 | let mut sphere = Model::new("data/models/ico_sphere_1.obj").build(); 34 | sphere.translate(vec3(0.0, 0.0, -3.0)); 35 | 36 | let rotation_start = Instant::now(); 37 | 38 | let mut previous_frame_end = 39 | Some(Box::new(sync::now(system.device.clone())) as Box); 40 | 41 | event_loop.run(move |event, _, control_flow| match event { 42 | Event::WindowEvent { 43 | event: WindowEvent::CloseRequested, 44 | .. 45 | } => { 46 | *control_flow = ControlFlow::Exit; 47 | } 48 | Event::WindowEvent { 49 | event: WindowEvent::Resized(_), 50 | .. 51 | } => { 52 | system.recreate_swapchain(); 53 | } 54 | Event::RedrawEventsCleared => { 55 | previous_frame_end 56 | .as_mut() 57 | .take() 58 | .unwrap() 59 | .cleanup_finished(); 60 | 61 | let elapsed = rotation_start.elapsed().as_secs() as f32 62 | + rotation_start.elapsed().subsec_nanos() as f32 / 1_000_000_000.0; 63 | let elapsed_as_radians = elapsed * 30.0 * (pi::() / 180.0); 64 | 65 | let x: f32 = 2.0 * elapsed_as_radians.cos(); 66 | let z: f32 = -3.0 + (2.0 * elapsed_as_radians.sin()); 67 | 68 | let directional_light = DirectionalLight::new([x, 0.0, z, 1.0], [1.0, 1.0, 1.0]); 69 | 70 | system.start(); 71 | system.geometry(&sphere); 72 | system.ambient(); 73 | system.directional(&directional_light); 74 | system.light_object(&directional_light); 75 | system.finish(&mut previous_frame_end); 76 | } 77 | _ => (), 78 | }); 79 | } 80 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/model.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::obj_loader::{ColoredVertex, Loader, NormalVertex}; 7 | 8 | use nalgebra_glm::{ 9 | identity, inverse_transpose, rotate_normalized_axis, scale, translate, vec3, TMat4, TVec3, 10 | }; 11 | use std::cell::Cell; 12 | 13 | /// Holds our data for a renderable model, including the model matrix data 14 | /// 15 | /// Note: When building an instance of `Model` the loader will assume that 16 | /// the input obj file is in clockwise winding order. If it is already in 17 | /// counter-clockwise winding order, call `.invert_winding_order(false)` 18 | /// when building the `Model`. 19 | pub struct Model { 20 | data: Vec, 21 | translation: TMat4, 22 | rotation: TMat4, 23 | uniform_scale: f32, 24 | 25 | // We might call multiple translation/rotation calls 26 | // in between asking for the model matrix. This lets us 27 | // only recreate the model matrices when needed. 28 | // Use a Cell with the interior mutability pattern, 29 | // so that it can be modified by methods that don't take &mut self 30 | cache: Cell>, 31 | } 32 | 33 | #[derive(Copy, Clone)] 34 | struct ModelMatrices { 35 | model: TMat4, 36 | normals: TMat4, 37 | } 38 | 39 | pub struct ModelBuilder { 40 | file_name: String, 41 | custom_color: [f32; 3], 42 | invert: bool, 43 | scale_factor: f32, 44 | } 45 | 46 | impl ModelBuilder { 47 | fn new(file: String) -> ModelBuilder { 48 | ModelBuilder { 49 | file_name: file, 50 | custom_color: [1.0, 0.35, 0.137], 51 | invert: true, 52 | scale_factor: 1.0, 53 | } 54 | } 55 | 56 | pub fn build(self) -> Model { 57 | let loader = Loader::new(self.file_name.as_str(), self.custom_color, self.invert); 58 | Model { 59 | data: loader.as_normal_vertices(), 60 | translation: identity(), 61 | rotation: identity(), 62 | uniform_scale: self.scale_factor, 63 | cache: Cell::new(None), 64 | } 65 | } 66 | 67 | pub fn color(mut self, new_color: [f32; 3]) -> ModelBuilder { 68 | self.custom_color = new_color; 69 | self 70 | } 71 | 72 | pub fn file(mut self, file: String) -> ModelBuilder { 73 | self.file_name = file; 74 | self 75 | } 76 | 77 | pub fn invert_winding_order(mut self, invert: bool) -> ModelBuilder { 78 | self.invert = invert; 79 | self 80 | } 81 | 82 | pub fn uniform_scale_factor(mut self, scale: f32) -> ModelBuilder { 83 | self.scale_factor = scale; 84 | self 85 | } 86 | } 87 | 88 | impl Model { 89 | pub fn new(file_name: &str) -> ModelBuilder { 90 | ModelBuilder::new(file_name.into()) 91 | } 92 | 93 | pub fn color_data(&self) -> Vec { 94 | let mut ret: Vec = Vec::new(); 95 | for v in &self.data { 96 | ret.push(ColoredVertex { 97 | position: v.position, 98 | color: v.color, 99 | }); 100 | } 101 | ret 102 | } 103 | 104 | pub fn data(&self) -> Vec { 105 | self.data.clone() 106 | } 107 | 108 | pub fn model_matrices(&self) -> (TMat4, TMat4) { 109 | if let Some(cache) = self.cache.get() { 110 | return (cache.model, cache.normals); 111 | } 112 | 113 | // recalculate matrices 114 | let model = self.translation * self.rotation; 115 | let model = scale(&model, &vec3(self.uniform_scale, self.uniform_scale, self.uniform_scale)); 116 | let normals = inverse_transpose(model); 117 | 118 | self.cache.set(Some(ModelMatrices { model, normals })); 119 | 120 | (model, normals) 121 | } 122 | 123 | pub fn rotate(&mut self, radians: f32, v: TVec3) { 124 | self.rotation = rotate_normalized_axis(&self.rotation, radians, &v); 125 | self.cache.set(None); 126 | } 127 | 128 | pub fn translate(&mut self, v: TVec3) { 129 | self.translation = translate(&self.translation, &v); 130 | self.cache.set(None); 131 | } 132 | 133 | /// Return the model's rotation to 0 134 | pub fn zero_rotation(&mut self) { 135 | self.rotation = identity(); 136 | self.cache.set(None); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/obj_loader/face.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use std::fmt; 6 | 7 | pub struct RawFace { 8 | pub verts: [usize; 3], 9 | pub norms: Option<[usize; 3]>, 10 | pub text: Option<[usize; 3]>, 11 | } 12 | 13 | impl RawFace { 14 | // call with invert = true if the models are using a clockwise winding order 15 | // 16 | // Blender files are a common example 17 | pub fn new(raw_arg: &str, invert: bool) -> RawFace { 18 | let arguments: Vec<&str> = raw_arg.split_whitespace().collect(); 19 | RawFace { 20 | verts: RawFace::parse(arguments.clone(), 0, invert).unwrap(), 21 | norms: RawFace::parse(arguments.clone(), 2, invert), 22 | text: RawFace::parse(arguments.clone(), 1, invert), 23 | } 24 | } 25 | 26 | fn parse(inpt: Vec<&str>, index: usize, invert: bool) -> Option<[usize; 3]> { 27 | let f1: Vec<&str> = inpt.get(0).unwrap().split("/").collect(); 28 | let f2: Vec<&str> = inpt.get(1).unwrap().split("/").collect(); 29 | let f3: Vec<&str> = inpt.get(2).unwrap().split("/").collect(); 30 | let a1 = f1.get(index).unwrap().clone(); 31 | let a2 = f2.get(index).unwrap().clone(); 32 | let a3 = f3.get(index).unwrap().clone(); 33 | match a1 { 34 | "" => None, 35 | _ => { 36 | let p1: usize = a1.parse().unwrap(); 37 | let (p2, p3): (usize, usize) = if invert { 38 | (a3.parse().unwrap(), a2.parse().unwrap()) 39 | } else { 40 | (a2.parse().unwrap(), a3.parse().unwrap()) 41 | }; 42 | Some([p1 - 1, p2 - 1, p3 - 1]) // .obj files aren't 0-index 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl fmt::Display for RawFace { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | let verts = format!("{}/{}/{}", self.verts[0], self.verts[1], self.verts[2]); 51 | let normals = match self.norms { 52 | None => "None".to_string(), 53 | Some(x) => { 54 | format!("{}/{}/{}", x[0], x[1], x[2]) 55 | } 56 | }; 57 | let textures = match self.text { 58 | None => "None".to_string(), 59 | Some(x) => { 60 | format!("{}/{}/{}", x[0], x[1], x[2]) 61 | } 62 | }; 63 | write!( 64 | f, 65 | "Face:\n\tVertices: {}\n\tNormals: {}\n\tTextures: {}", 66 | verts, normals, textures 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/obj_loader/loader.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::face::RawFace; 7 | use super::vertex::RawVertex; 8 | use super::NormalVertex; 9 | 10 | use std::fs::File; 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub struct Loader { 14 | color: [f32; 3], 15 | verts: Vec, 16 | norms: Vec, 17 | text: Vec, 18 | faces: Vec, 19 | invert_winding_order: bool, 20 | } 21 | 22 | impl Loader { 23 | pub fn new(file_name: &str, custom_color: [f32; 3], invert_winding_order: bool) -> Loader { 24 | let color = custom_color; 25 | let input = File::open(file_name).unwrap(); 26 | let buffered = BufReader::new(input); 27 | let mut verts: Vec = Vec::new(); 28 | let mut norms: Vec = Vec::new(); 29 | let mut text: Vec = Vec::new(); 30 | let mut faces: Vec = Vec::new(); 31 | for raw_line in buffered.lines() { 32 | let line = raw_line.unwrap(); 33 | if line.len() > 2 { 34 | match line.split_at(2) { 35 | ("v ", x) => { 36 | verts.push(RawVertex::new(x)); 37 | } 38 | ("vn", x) => { 39 | norms.push(RawVertex::new(x)); 40 | } 41 | ("vt", x) => { 42 | text.push(RawVertex::new(x)); 43 | } 44 | ("f ", x) => { 45 | faces.push(RawFace::new(x, invert_winding_order)); 46 | } 47 | (_, _) => {} 48 | }; 49 | } 50 | } 51 | Loader { 52 | color, 53 | verts, 54 | norms, 55 | text, 56 | faces, 57 | invert_winding_order, 58 | } 59 | } 60 | 61 | pub fn as_normal_vertices(&self) -> Vec { 62 | let mut ret: Vec = Vec::new(); 63 | for face in &self.faces { 64 | let verts = face.verts; 65 | let normals = face.norms.unwrap(); 66 | ret.push(NormalVertex { 67 | position: self.verts.get(verts[0]).unwrap().vals, 68 | normal: self.norms.get(normals[0]).unwrap().vals, 69 | color: self.color, 70 | }); 71 | ret.push(NormalVertex { 72 | position: self.verts.get(verts[1]).unwrap().vals, 73 | normal: self.norms.get(normals[1]).unwrap().vals, 74 | color: self.color, 75 | }); 76 | ret.push(NormalVertex { 77 | position: self.verts.get(verts[2]).unwrap().vals, 78 | normal: self.norms.get(normals[2]).unwrap().vals, 79 | color: self.color, 80 | }); 81 | } 82 | ret 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/obj_loader/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod face; 6 | mod loader; 7 | mod vertex; 8 | pub use self::loader::Loader; 9 | use bytemuck::{Pod, Zeroable}; 10 | 11 | use std::fmt; 12 | 13 | /// A vertex type intended to be used to provide dummy rendering 14 | /// data for rendering passes that do not require geometry data. 15 | /// This is due to a quirk of the Vulkan API in that *all* 16 | /// render passes require some sort of input. 17 | #[repr(C)] 18 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 19 | pub struct DummyVertex { 20 | /// A regular position vector with the z-value shaved off for space. 21 | /// This assumes the shaders will take a `vec2` and transform it as 22 | /// needed. 23 | pub position: [f32; 2], 24 | } 25 | 26 | impl DummyVertex { 27 | /// Creates an array of `DummyVertex` values. 28 | /// 29 | /// This is intended to compliment the use of this data type for passing to 30 | /// deferred rendering passes that do not actually require geometry input. 31 | /// This list will draw a square across the entire rendering area. This will 32 | /// cause the fragment shaders to execute on all pixels in the rendering 33 | /// area. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```glsl 38 | /// #version 450 39 | /// 40 | ///layout(location = 0) in vec2 position; 41 | /// 42 | ///void main() { 43 | /// gl_Position = vec4(position, 0.0, 1.0); 44 | ///} 45 | /// ``` 46 | pub fn list() -> [DummyVertex; 6] { 47 | [ 48 | DummyVertex { 49 | position: [-1.0, -1.0], 50 | }, 51 | DummyVertex { 52 | position: [-1.0, 1.0], 53 | }, 54 | DummyVertex { 55 | position: [1.0, 1.0], 56 | }, 57 | DummyVertex { 58 | position: [-1.0, -1.0], 59 | }, 60 | DummyVertex { 61 | position: [1.0, 1.0], 62 | }, 63 | DummyVertex { 64 | position: [1.0, -1.0], 65 | }, 66 | ] 67 | } 68 | } 69 | 70 | /// A structure for the vertex information used in earlier lessons 71 | #[repr(C)] 72 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 73 | pub struct ColoredVertex { 74 | pub position: [f32; 3], 75 | pub color: [f32; 3], 76 | } 77 | 78 | /// A structure used for the vertex information starting 79 | /// from our lesson on lighting 80 | #[repr(C)] 81 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 82 | pub struct NormalVertex { 83 | pub position: [f32; 3], 84 | pub normal: [f32; 3], 85 | pub color: [f32; 3], 86 | } 87 | 88 | impl fmt::Display for DummyVertex { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | let pos = format!("[{:.6}, {:.6}]", self.position[0], self.position[1]); 91 | write!(f, "DummyVertex {{ position: {} }}", pos) 92 | } 93 | } 94 | 95 | impl fmt::Display for ColoredVertex { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | let pos = format!( 98 | "[{:.6}, {:.6}, {:.6}]", 99 | self.position[0], self.position[1], self.position[2] 100 | ); 101 | let color = format!( 102 | "[{:.6}, {:.6}, {:.6}]", 103 | self.color[0], self.color[1], self.color[2] 104 | ); 105 | write!(f, "ColoredVertex {{ position: {}, color: {} }}", pos, color) 106 | } 107 | } 108 | 109 | impl fmt::Display for NormalVertex { 110 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 111 | let pos = format!( 112 | "[{:.6}, {:.6}, {:.6}]", 113 | self.position[0], self.position[1], self.position[2] 114 | ); 115 | let color = format!( 116 | "[{:.6}, {:.6}, {:.6}]", 117 | self.color[0], self.color[1], self.color[2] 118 | ); 119 | let norms = format!( 120 | "[{:.6}, {:.6}, {:.6}]", 121 | self.normal[0], self.normal[1], self.normal[2] 122 | ); 123 | write!( 124 | f, 125 | "NormalVertex {{ position: {}, normal: {}, color: {} }}", 126 | pos, norms, color 127 | ) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/obj_loader/vertex.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | pub struct RawVertex { 6 | pub vals: [f32; 3], 7 | } 8 | 9 | impl RawVertex { 10 | pub fn new(inpt: &str) -> RawVertex { 11 | let items = inpt.split_whitespace(); 12 | let mut content: Vec = Vec::new(); 13 | for item in items { 14 | content.push(item.parse().unwrap()); 15 | } 16 | if content.len() == 2 { 17 | content.push(0.0); 18 | } 19 | RawVertex { 20 | vals: [ 21 | *content.get(0).unwrap(), 22 | *content.get(1).unwrap(), 23 | *content.get(2).unwrap(), 24 | ], 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod system; 6 | 7 | use nalgebra_glm::{vec3, TVec3}; 8 | pub use system::System; 9 | 10 | #[derive(Default, Debug, Clone)] 11 | pub struct DirectionalLight { 12 | position: [f32; 4], 13 | color: [f32; 3], 14 | } 15 | 16 | impl DirectionalLight { 17 | pub fn new(position: [f32; 4], color: [f32; 3]) -> DirectionalLight { 18 | DirectionalLight { position, color } 19 | } 20 | 21 | pub fn get_position(&self) -> TVec3 { 22 | vec3(self.position[0], self.position[1], self.position[2]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | 5 | layout(set = 0, binding = 1) uniform Ambient_Data { 6 | vec3 color; 7 | float intensity; 8 | } ambient; 9 | 10 | layout(location = 0) out vec4 f_color; 11 | 12 | void main() { 13 | vec3 ambient_color = ambient.intensity * ambient.color; 14 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 15 | f_color = vec4(combined_color, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | layout(location = 0) in vec3 in_color; 3 | layout(location = 1) in vec3 in_normal; 4 | 5 | layout(location = 0) out vec4 f_color; 6 | layout(location = 1) out vec3 f_normal; 7 | 8 | void main() { 9 | f_color = vec4(in_color, 1.0); 10 | f_normal = in_normal; 11 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform VP_Data { 11 | mat4 view; 12 | mat4 projection; 13 | } vp_uniforms; 14 | 15 | layout(set = 1, binding = 0) uniform Model_Data { 16 | mat4 model; 17 | mat4 normals; 18 | } model; 19 | 20 | void main() { 21 | gl_Position = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 22 | out_color = color; 23 | out_normal = mat3(model.normals) * normal; 24 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 5 | 6 | layout(set = 0, binding = 2) uniform Directional_Light_Data { 7 | vec4 position; 8 | vec3 color; 9 | } directional; 10 | 11 | layout(location = 0) out vec4 f_color; 12 | 13 | void main() { 14 | vec3 light_direction = normalize(directional.position.xyz + subpassLoad(u_normals).xyz); 15 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 16 | vec3 directional_color = directional_intensity * directional.color; 17 | vec3 combined_color = directional_color * subpassLoad(u_color).rgb; 18 | f_color = vec4(combined_color, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/light_obj.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | layout(location = 0) in vec3 in_color; 3 | 4 | layout(location = 0) out vec4 f_color; 5 | 6 | void main() { 7 | f_color = vec4(in_color, 1.0); 8 | } -------------------------------------------------------------------------------- /lessons/11.5. Light Objects/src/system/shaders/light_obj.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 color; 5 | 6 | layout(location = 0) out vec3 out_color; 7 | 8 | layout(set = 0, binding = 0) uniform VP_Data { 9 | mat4 view; 10 | mat4 projection; 11 | } vp_uniforms; 12 | 13 | layout(set = 1, binding = 0) uniform Model_Data { 14 | mat4 model; 15 | mat4 normals; 16 | } model; 17 | 18 | void main() { 19 | gl_Position = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 20 | out_color = color; 21 | } -------------------------------------------------------------------------------- /lessons/12. Light III/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_12" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/main.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod model; 6 | mod obj_loader; 7 | mod system; 8 | 9 | use model::Model; 10 | use system::DirectionalLight; 11 | use system::System; 12 | 13 | use vulkano::sync; 14 | use vulkano::sync::GpuFuture; 15 | 16 | use winit::event::{Event, WindowEvent}; 17 | use winit::event_loop::{ControlFlow, EventLoop}; 18 | 19 | use nalgebra_glm::{look_at, pi, vec3}; 20 | 21 | use std::time::Instant; 22 | 23 | fn main() { 24 | let event_loop = EventLoop::new(); 25 | let mut system = System::new(&event_loop); 26 | 27 | system.set_view(&look_at( 28 | &vec3(0.0, 0.0, 0.1), 29 | &vec3(0.0, 0.0, 0.0), 30 | &vec3(0.0, 1.0, 0.0), 31 | )); 32 | 33 | let mut cube1 = Model::new("data/models/cube.obj") 34 | .specular(0.5, 12.0) 35 | .build(); 36 | cube1.translate(vec3(1.1, 0.0, -4.0)); 37 | 38 | let mut cube2 = Model::new("data/models/cube.obj") 39 | .specular(0.5, 128.0) 40 | .build(); 41 | cube2.translate(vec3(-1.1, 0.0, -4.0)); 42 | 43 | let rotation_start = Instant::now(); 44 | 45 | let mut previous_frame_end = 46 | Some(Box::new(sync::now(system.device.clone())) as Box); 47 | 48 | event_loop.run(move |event, _, control_flow| match event { 49 | Event::WindowEvent { 50 | event: WindowEvent::CloseRequested, 51 | .. 52 | } => { 53 | *control_flow = ControlFlow::Exit; 54 | } 55 | Event::WindowEvent { 56 | event: WindowEvent::Resized(_), 57 | .. 58 | } => { 59 | system.recreate_swapchain(); 60 | } 61 | Event::RedrawEventsCleared => { 62 | previous_frame_end 63 | .as_mut() 64 | .take() 65 | .unwrap() 66 | .cleanup_finished(); 67 | 68 | let elapsed = rotation_start.elapsed().as_secs() as f32 69 | + rotation_start.elapsed().subsec_nanos() as f32 / 1_000_000_000.0; 70 | let elapsed_as_radians = elapsed * 30.0 * (pi::() / 180.0); 71 | 72 | let x: f32 = 3.0 * elapsed_as_radians.cos(); 73 | let z: f32 = -2.0 + (3.0 * elapsed_as_radians.sin()); 74 | 75 | let directional_light = DirectionalLight::new([x, 0.0, z, 1.0], [1.0, 1.0, 1.0]); 76 | 77 | system.start(); 78 | system.geometry(&cube1); 79 | system.geometry(&cube2); 80 | system.ambient(); 81 | system.directional(&directional_light); 82 | system.light_object(&directional_light); 83 | system.finish(&mut previous_frame_end); 84 | } 85 | _ => (), 86 | }); 87 | } 88 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/model.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::obj_loader::{ColoredVertex, Loader, NormalVertex}; 7 | 8 | use nalgebra_glm::{ 9 | identity, inverse_transpose, rotate_normalized_axis, scale, translate, vec3, TMat4, TVec3, 10 | }; 11 | use std::cell::Cell; 12 | 13 | /// Holds our data for a renderable model, including the model matrix data 14 | /// 15 | /// Note: When building an instance of `Model` the loader will assume that 16 | /// the input obj file is in clockwise winding order. If it is already in 17 | /// counter-clockwise winding order, call `.invert_winding_order(false)` 18 | /// when building the `Model`. 19 | pub struct Model { 20 | data: Vec, 21 | translation: TMat4, 22 | rotation: TMat4, 23 | uniform_scale: f32, 24 | specular_intensity: f32, 25 | shininess: f32, 26 | 27 | // We might call multiple translation/rotation calls 28 | // in between asking for the model matrix. This lets us 29 | // only recreate the model matrices when needed. 30 | // Use a Cell with the interior mutability pattern, 31 | // so that it can be modified by methods that don't take &mut self 32 | cache: Cell>, 33 | } 34 | 35 | #[derive(Copy, Clone)] 36 | struct ModelMatrices { 37 | model: TMat4, 38 | normals: TMat4, 39 | } 40 | 41 | pub struct ModelBuilder { 42 | file_name: String, 43 | custom_color: [f32; 3], 44 | invert: bool, 45 | scale_factor: f32, 46 | specular_intensity: f32, 47 | shininess: f32, 48 | } 49 | 50 | impl ModelBuilder { 51 | fn new(file: String) -> ModelBuilder { 52 | ModelBuilder { 53 | file_name: file, 54 | custom_color: [1.0, 0.35, 0.137], 55 | invert: true, 56 | scale_factor: 1.0, 57 | specular_intensity: 0.5, 58 | shininess: 32.0, 59 | } 60 | } 61 | 62 | pub fn build(self) -> Model { 63 | let loader = Loader::new(self.file_name.as_str(), self.custom_color, self.invert); 64 | Model { 65 | data: loader.as_normal_vertices(), 66 | translation: identity(), 67 | rotation: identity(), 68 | uniform_scale: self.scale_factor, 69 | specular_intensity: self.specular_intensity, 70 | shininess: self.shininess, 71 | cache: Cell::new(None), 72 | } 73 | } 74 | 75 | pub fn color(mut self, new_color: [f32; 3]) -> ModelBuilder { 76 | self.custom_color = new_color; 77 | self 78 | } 79 | 80 | pub fn file(mut self, file: String) -> ModelBuilder { 81 | self.file_name = file; 82 | self 83 | } 84 | 85 | pub fn invert_winding_order(mut self, invert: bool) -> ModelBuilder { 86 | self.invert = invert; 87 | self 88 | } 89 | 90 | pub fn specular(mut self, specular_intensity: f32, shininess: f32) -> ModelBuilder { 91 | self.specular_intensity = specular_intensity; 92 | self.shininess = shininess; 93 | self 94 | } 95 | 96 | pub fn uniform_scale_factor(mut self, scale: f32) -> ModelBuilder { 97 | self.scale_factor = scale; 98 | self 99 | } 100 | } 101 | 102 | impl Model { 103 | pub fn new(file_name: &str) -> ModelBuilder { 104 | ModelBuilder::new(file_name.into()) 105 | } 106 | 107 | pub fn color_data(&self) -> Vec { 108 | let mut ret: Vec = Vec::new(); 109 | for v in &self.data { 110 | ret.push(ColoredVertex { 111 | position: v.position, 112 | color: v.color, 113 | }); 114 | } 115 | ret 116 | } 117 | 118 | pub fn data(&self) -> Vec { 119 | self.data.clone() 120 | } 121 | 122 | pub fn specular(&self) -> (f32, f32) { 123 | (self.specular_intensity, self.shininess) 124 | } 125 | 126 | pub fn model_matrices(&self) -> (TMat4, TMat4) { 127 | if let Some(cache) = self.cache.get() { 128 | return (cache.model, cache.normals); 129 | } 130 | 131 | // recalculate matrices 132 | let model = self.translation * self.rotation; 133 | let model = scale(&model, &vec3(self.uniform_scale, self.uniform_scale, self.uniform_scale)); 134 | let normals = inverse_transpose(model); 135 | 136 | self.cache.set(Some(ModelMatrices { model, normals })); 137 | 138 | (model, normals) 139 | } 140 | 141 | pub fn rotate(&mut self, radians: f32, v: TVec3) { 142 | self.rotation = rotate_normalized_axis(&self.rotation, radians, &v); 143 | self.cache.set(None); 144 | } 145 | 146 | pub fn translate(&mut self, v: TVec3) { 147 | self.translation = translate(&self.translation, &v); 148 | self.cache.set(None); 149 | } 150 | 151 | /// Return the model's rotation to 0 152 | pub fn zero_rotation(&mut self) { 153 | self.rotation = identity(); 154 | self.cache.set(None); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/obj_loader/face.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use std::fmt; 6 | 7 | pub struct RawFace { 8 | pub verts: [usize; 3], 9 | pub norms: Option<[usize; 3]>, 10 | pub text: Option<[usize; 3]>, 11 | } 12 | 13 | impl RawFace { 14 | // call with invert = true if the models are using a clockwise winding order 15 | // 16 | // Blender files are a common example 17 | pub fn new(raw_arg: &str, invert: bool) -> RawFace { 18 | let arguments: Vec<&str> = raw_arg.split_whitespace().collect(); 19 | RawFace { 20 | verts: RawFace::parse(arguments.clone(), 0, invert).unwrap(), 21 | norms: RawFace::parse(arguments.clone(), 2, invert), 22 | text: RawFace::parse(arguments.clone(), 1, invert), 23 | } 24 | } 25 | 26 | fn parse(inpt: Vec<&str>, index: usize, invert: bool) -> Option<[usize; 3]> { 27 | let f1: Vec<&str> = inpt.get(0).unwrap().split("/").collect(); 28 | let f2: Vec<&str> = inpt.get(1).unwrap().split("/").collect(); 29 | let f3: Vec<&str> = inpt.get(2).unwrap().split("/").collect(); 30 | let a1 = f1.get(index).unwrap().clone(); 31 | let a2 = f2.get(index).unwrap().clone(); 32 | let a3 = f3.get(index).unwrap().clone(); 33 | match a1 { 34 | "" => None, 35 | _ => { 36 | let p1: usize = a1.parse().unwrap(); 37 | let (p2, p3): (usize, usize) = if invert { 38 | (a3.parse().unwrap(), a2.parse().unwrap()) 39 | } else { 40 | (a2.parse().unwrap(), a3.parse().unwrap()) 41 | }; 42 | Some([p1 - 1, p2 - 1, p3 - 1]) // .obj files aren't 0-index 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl fmt::Display for RawFace { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | let verts = format!("{}/{}/{}", self.verts[0], self.verts[1], self.verts[2]); 51 | let normals = match self.norms { 52 | None => "None".to_string(), 53 | Some(x) => { 54 | format!("{}/{}/{}", x[0], x[1], x[2]) 55 | } 56 | }; 57 | let textures = match self.text { 58 | None => "None".to_string(), 59 | Some(x) => { 60 | format!("{}/{}/{}", x[0], x[1], x[2]) 61 | } 62 | }; 63 | write!( 64 | f, 65 | "Face:\n\tVertices: {}\n\tNormals: {}\n\tTextures: {}", 66 | verts, normals, textures 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/obj_loader/loader.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::face::RawFace; 7 | use super::vertex::RawVertex; 8 | use super::NormalVertex; 9 | 10 | use std::fs::File; 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub struct Loader { 14 | color: [f32; 3], 15 | verts: Vec, 16 | norms: Vec, 17 | text: Vec, 18 | faces: Vec, 19 | invert_winding_order: bool, 20 | } 21 | 22 | impl Loader { 23 | pub fn new(file_name: &str, custom_color: [f32; 3], invert_winding_order: bool) -> Loader { 24 | let color = custom_color; 25 | let input = File::open(file_name).unwrap(); 26 | let buffered = BufReader::new(input); 27 | let mut verts: Vec = Vec::new(); 28 | let mut norms: Vec = Vec::new(); 29 | let mut text: Vec = Vec::new(); 30 | let mut faces: Vec = Vec::new(); 31 | for raw_line in buffered.lines() { 32 | let line = raw_line.unwrap(); 33 | if line.len() > 2 { 34 | match line.split_at(2) { 35 | ("v ", x) => { 36 | verts.push(RawVertex::new(x)); 37 | } 38 | ("vn", x) => { 39 | norms.push(RawVertex::new(x)); 40 | } 41 | ("vt", x) => { 42 | text.push(RawVertex::new(x)); 43 | } 44 | ("f ", x) => { 45 | faces.push(RawFace::new(x, invert_winding_order)); 46 | } 47 | (_, _) => {} 48 | }; 49 | } 50 | } 51 | Loader { 52 | color, 53 | verts, 54 | norms, 55 | text, 56 | faces, 57 | invert_winding_order, 58 | } 59 | } 60 | 61 | pub fn as_normal_vertices(&self) -> Vec { 62 | let mut ret: Vec = Vec::new(); 63 | for face in &self.faces { 64 | let verts = face.verts; 65 | let normals = face.norms.unwrap(); 66 | ret.push(NormalVertex { 67 | position: self.verts.get(verts[0]).unwrap().vals, 68 | normal: self.norms.get(normals[0]).unwrap().vals, 69 | color: self.color, 70 | }); 71 | ret.push(NormalVertex { 72 | position: self.verts.get(verts[1]).unwrap().vals, 73 | normal: self.norms.get(normals[1]).unwrap().vals, 74 | color: self.color, 75 | }); 76 | ret.push(NormalVertex { 77 | position: self.verts.get(verts[2]).unwrap().vals, 78 | normal: self.norms.get(normals[2]).unwrap().vals, 79 | color: self.color, 80 | }); 81 | } 82 | ret 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/obj_loader/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod face; 6 | mod loader; 7 | mod vertex; 8 | pub use self::loader::Loader; 9 | use bytemuck::{Pod, Zeroable}; 10 | 11 | use std::fmt; 12 | 13 | /// A vertex type intended to be used to provide dummy rendering 14 | /// data for rendering passes that do not require geometry data. 15 | /// This is due to a quirk of the Vulkan API in that *all* 16 | /// render passes require some sort of input. 17 | #[repr(C)] 18 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 19 | pub struct DummyVertex { 20 | /// A regular position vector with the z-value shaved off for space. 21 | /// This assumes the shaders will take a `vec2` and transform it as 22 | /// needed. 23 | pub position: [f32; 2], 24 | } 25 | 26 | impl DummyVertex { 27 | /// Creates an array of `DummyVertex` values. 28 | /// 29 | /// This is intended to compliment the use of this data type for passing to 30 | /// deferred rendering passes that do not actually require geometry input. 31 | /// This list will draw a square across the entire rendering area. This will 32 | /// cause the fragment shaders to execute on all pixels in the rendering 33 | /// area. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```glsl 38 | /// #version 450 39 | /// 40 | ///layout(location = 0) in vec2 position; 41 | /// 42 | ///void main() { 43 | /// gl_Position = vec4(position, 0.0, 1.0); 44 | ///} 45 | /// ``` 46 | pub fn list() -> [DummyVertex; 6] { 47 | [ 48 | DummyVertex { 49 | position: [-1.0, -1.0], 50 | }, 51 | DummyVertex { 52 | position: [-1.0, 1.0], 53 | }, 54 | DummyVertex { 55 | position: [1.0, 1.0], 56 | }, 57 | DummyVertex { 58 | position: [-1.0, -1.0], 59 | }, 60 | DummyVertex { 61 | position: [1.0, 1.0], 62 | }, 63 | DummyVertex { 64 | position: [1.0, -1.0], 65 | }, 66 | ] 67 | } 68 | } 69 | 70 | /// A structure for the vertex information used in earlier lessons 71 | #[repr(C)] 72 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 73 | pub struct ColoredVertex { 74 | pub position: [f32; 3], 75 | pub color: [f32; 3], 76 | } 77 | 78 | /// A structure used for the vertex information starting 79 | /// from our lesson on lighting 80 | #[repr(C)] 81 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 82 | pub struct NormalVertex { 83 | pub position: [f32; 3], 84 | pub normal: [f32; 3], 85 | pub color: [f32; 3], 86 | } 87 | 88 | impl fmt::Display for DummyVertex { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | let pos = format!("[{:.6}, {:.6}]", self.position[0], self.position[1]); 91 | write!(f, "DummyVertex {{ position: {} }}", pos) 92 | } 93 | } 94 | 95 | impl fmt::Display for ColoredVertex { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | let pos = format!( 98 | "[{:.6}, {:.6}, {:.6}]", 99 | self.position[0], self.position[1], self.position[2] 100 | ); 101 | let color = format!( 102 | "[{:.6}, {:.6}, {:.6}]", 103 | self.color[0], self.color[1], self.color[2] 104 | ); 105 | write!(f, "ColoredVertex {{ position: {}, color: {} }}", pos, color) 106 | } 107 | } 108 | 109 | impl fmt::Display for NormalVertex { 110 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 111 | let pos = format!( 112 | "[{:.6}, {:.6}, {:.6}]", 113 | self.position[0], self.position[1], self.position[2] 114 | ); 115 | let color = format!( 116 | "[{:.6}, {:.6}, {:.6}]", 117 | self.color[0], self.color[1], self.color[2] 118 | ); 119 | let norms = format!( 120 | "[{:.6}, {:.6}, {:.6}]", 121 | self.normal[0], self.normal[1], self.normal[2] 122 | ); 123 | write!( 124 | f, 125 | "NormalVertex {{ position: {}, normal: {}, color: {} }}", 126 | pos, norms, color 127 | ) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/obj_loader/vertex.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | pub struct RawVertex { 6 | pub vals: [f32; 3], 7 | } 8 | 9 | impl RawVertex { 10 | pub fn new(inpt: &str) -> RawVertex { 11 | let items = inpt.split_whitespace(); 12 | let mut content: Vec = Vec::new(); 13 | for item in items { 14 | content.push(item.parse().unwrap()); 15 | } 16 | if content.len() == 2 { 17 | content.push(0.0); 18 | } 19 | RawVertex { 20 | vals: [ 21 | *content.get(0).unwrap(), 22 | *content.get(1).unwrap(), 23 | *content.get(2).unwrap(), 24 | ], 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod system; 6 | 7 | use nalgebra_glm::{vec3, TVec3}; 8 | pub use system::System; 9 | 10 | #[derive(Default, Debug, Clone)] 11 | pub struct DirectionalLight { 12 | position: [f32; 4], 13 | color: [f32; 3], 14 | } 15 | 16 | impl DirectionalLight { 17 | pub fn new(position: [f32; 4], color: [f32; 3]) -> DirectionalLight { 18 | DirectionalLight { position, color } 19 | } 20 | 21 | pub fn get_position(&self) -> TVec3 { 22 | vec3(self.position[0], self.position[1], self.position[2]) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | 5 | layout(set = 0, binding = 1) uniform Ambient_Data { 6 | vec3 color; 7 | float intensity; 8 | } ambient; 9 | 10 | layout(location = 0) out vec4 f_color; 11 | 12 | void main() { 13 | vec3 ambient_color = ambient.intensity * ambient.color; 14 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 15 | f_color = vec4(combined_color, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 in_color; 4 | layout(location = 1) in vec3 in_normal; 5 | layout(location = 2) in vec4 in_location; 6 | 7 | layout(set = 1, binding = 1) uniform Specular_Data { 8 | float intensity; 9 | float shininess; 10 | } specular; 11 | 12 | layout(location = 0) out vec4 f_color; 13 | layout(location = 1) out vec3 f_normal; 14 | layout(location = 2) out vec4 f_location; 15 | layout(location = 3) out vec2 f_specular; 16 | 17 | void main() { 18 | f_color = vec4(in_color, 1.0); 19 | f_normal = in_normal; 20 | f_location = in_location; 21 | f_specular = vec2(specular.intensity, specular.shininess); 22 | } 23 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | layout(location = 2) out vec4 out_location; 10 | 11 | layout(set = 0, binding = 0) uniform VP_Data { 12 | mat4 view; 13 | mat4 projection; 14 | } vp_uniforms; 15 | 16 | layout(set = 1, binding = 0) uniform Model_Data { 17 | mat4 model; 18 | mat4 normals; 19 | } model; 20 | 21 | void main() { 22 | vec4 frag_pos = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 23 | gl_Position = frag_pos; 24 | out_color = color; 25 | out_normal = mat3(model.normals) * normal; 26 | out_location = frag_pos; 27 | } -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 5 | layout(input_attachment_index = 2, set = 0, binding = 2) uniform subpassInput u_frag_location; 6 | layout(input_attachment_index = 3, set = 0, binding = 3) uniform subpassInput u_specular; 7 | 8 | layout(set = 0, binding = 4) uniform Directional_Light_Data { 9 | vec4 position; 10 | vec3 color; 11 | } directional; 12 | 13 | layout(set = 0, binding = 5) uniform Camera_Data { 14 | vec3 position; 15 | } camera; 16 | 17 | layout(location = 0) out vec4 f_color; 18 | 19 | void main() { 20 | vec3 normal = subpassLoad(u_normals).xyz; 21 | float specular_intensity = subpassLoad(u_specular).x; 22 | float specular_shininess = subpassLoad(u_specular).y; 23 | vec3 view_dir = -normalize(camera.position - subpassLoad(u_frag_location).xyz); 24 | vec3 light_direction = normalize(directional.position.xyz + normal); 25 | vec3 reflect_dir = reflect(-light_direction, normal); 26 | float spec = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess); 27 | vec3 specular = specular_intensity * spec * directional.color; 28 | float directional_intensity = max(dot(normal, light_direction), 0.0); 29 | vec3 directional_color = directional_intensity * directional.color; 30 | vec3 combined_color = (specular + directional_color) * subpassLoad(u_color).rgb; 31 | f_color = vec4(combined_color, 1.0); 32 | } 33 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/light_obj.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 in_color; 4 | 5 | layout(location = 0) out vec4 f_color; 6 | 7 | void main() { 8 | f_color = vec4(in_color, 1.0); 9 | } 10 | -------------------------------------------------------------------------------- /lessons/12. Light III/src/system/shaders/light_obj.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 color; 5 | 6 | layout(location = 0) out vec3 out_color; 7 | 8 | layout(set = 0, binding = 0) uniform VP_Data { 9 | mat4 view; 10 | mat4 projection; 11 | } vp_uniforms; 12 | 13 | layout(set = 1, binding = 0) uniform Model_Data { 14 | mat4 model; 15 | mat4 normals; 16 | } model; 17 | 18 | void main() { 19 | gl_Position = vp_uniforms.projection * vp_uniforms.view * model.model * vec4(position, 1.0); 20 | out_color = color; 21 | } -------------------------------------------------------------------------------- /lessons/13. Textures/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_13" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | png = "0.17.7" 11 | vulkano = "0.32.3" 12 | vulkano-shaders = "0.32.0" 13 | vulkano-win = "0.32.0" 14 | winit = "0.27.3" 15 | -------------------------------------------------------------------------------- /lessons/13. Textures/src/textures/compass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/lessons/13. Textures/src/textures/compass.png -------------------------------------------------------------------------------- /lessons/13. Textures/src/textures/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/lessons/13. Textures/src/textures/diamond.png -------------------------------------------------------------------------------- /lessons/14. Text/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_14" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | png = "0.17.7" 11 | vulkano = "0.32.3" 12 | vulkano-shaders = "0.32.0" 13 | vulkano-win = "0.32.0" 14 | winit = "0.27.3" 15 | -------------------------------------------------------------------------------- /lessons/14. Text/src/monospace.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use png; 6 | 7 | use std::io::Cursor; 8 | 9 | pub struct Monospace { 10 | input_width: usize, 11 | texture_data: Vec, 12 | } 13 | 14 | impl Monospace { 15 | pub fn new() -> Monospace { 16 | let png_bytes = include_bytes!("./textures/texture_small.png").to_vec(); 17 | let cursor = Cursor::new(png_bytes); 18 | let decoder = png::Decoder::new(cursor); 19 | let mut reader = decoder.read_info().unwrap(); 20 | let info = reader.info(); 21 | let width = info.width; 22 | let height = info.height; 23 | let mut image_data = Vec::new(); 24 | let depth: u32 = match info.bit_depth { 25 | png::BitDepth::One => 1, 26 | png::BitDepth::Two => 2, 27 | png::BitDepth::Four => 4, 28 | png::BitDepth::Eight => 8, 29 | png::BitDepth::Sixteen => 16, 30 | }; 31 | image_data.resize((width * height * depth) as usize, 0); 32 | reader.next_frame(&mut image_data).unwrap(); 33 | 34 | Monospace { 35 | input_width: width as usize, 36 | texture_data: image_data, 37 | } 38 | } 39 | 40 | pub fn text(&self, value: &str) -> (Vec, u32, u32) { 41 | let chars = value.chars(); 42 | let length = value.len(); 43 | let height = 64; 44 | let width = length * 64; 45 | let mut ret: Vec = Vec::new(); 46 | ret.resize(height * width * 4, 0); // each pixel has four components 47 | for (i, ch) in chars.enumerate() { 48 | let val = ch.to_digit(10).unwrap() as usize; 49 | let source_index = val * 64; // The pixel index of the left pixel column 50 | let target_index = i * 64; 51 | for row in 0..64 { 52 | let source_row_offset = row * self.input_width * 4; 53 | let target_row_offset = row * width * 4; 54 | for col in 0..64 { 55 | let source_col_offset = (source_index + col) * 4; 56 | let target_col_offset = (target_index + col) * 4; 57 | for ii in 0..4 { 58 | ret[target_row_offset + target_col_offset + ii] = 59 | self.texture_data[source_row_offset + source_col_offset + ii]; 60 | } 61 | } 62 | } 63 | } 64 | (ret, 64, (length * 64) as u32) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /lessons/14. Text/src/textures/diamond.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/lessons/14. Text/src/textures/diamond.png -------------------------------------------------------------------------------- /lessons/14. Text/src/textures/texture_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taidaesal/vulkano_tutorial/a2c4fe562b1acf8b56b6c0e56e2073ee129d279e/lessons/14. Text/src/textures/texture_small.png -------------------------------------------------------------------------------- /lessons/2. Triangle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_2" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | vulkano = "0.32.3" 10 | vulkano-shaders = "0.32.0" 11 | vulkano-win = "0.32.0" 12 | winit = "0.27.3" 13 | -------------------------------------------------------------------------------- /lessons/3. Transformations and Uniforms/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_3" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/4. Depth/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_4" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/5. Face and Winding Order/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_5" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/6. Light I/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_6" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/7. Deferred Rendering/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_7" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/7. Deferred Rendering/src/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 in_color; 4 | layout(location = 1) in vec3 in_normal; 5 | 6 | layout(location = 0) out vec4 f_color; 7 | layout(location = 1) out vec3 f_normal; 8 | 9 | void main() { 10 | f_color = vec4(in_color, 1.0); 11 | f_normal = in_normal; 12 | } 13 | -------------------------------------------------------------------------------- /lessons/7. Deferred Rendering/src/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform MVP_Data { 11 | mat4 model; 12 | mat4 view; 13 | mat4 projection; 14 | } uniforms; 15 | 16 | void main() { 17 | mat4 worldview = uniforms.view * uniforms.model; 18 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 19 | out_color = color; 20 | out_normal = mat3(uniforms.model) * normal; 21 | } -------------------------------------------------------------------------------- /lessons/7. Deferred Rendering/src/shaders/lighting.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 frag_pos; 4 | 5 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 6 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 7 | 8 | layout(set = 0, binding = 3) uniform Ambient_Data { 9 | vec3 color; 10 | float intensity; 11 | } ambient; 12 | 13 | layout(set = 0, binding = 4) uniform Directional_Light_Data { 14 | vec4 position; 15 | vec3 color; 16 | } directional; 17 | 18 | layout(location = 0) out vec4 f_color; 19 | 20 | void main() { 21 | vec3 ambient_color = ambient.intensity * ambient.color; 22 | vec3 light_direction = normalize(directional.position.xyz - frag_pos); 23 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 24 | vec3 directional_color = directional_intensity * directional.color; 25 | vec3 combined_color = (ambient_color + directional_color) * subpassLoad(u_color).rgb; 26 | f_color = vec4(combined_color, 1.0); 27 | } 28 | -------------------------------------------------------------------------------- /lessons/7. Deferred Rendering/src/shaders/lighting.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | 5 | layout(set = 0, binding = 2) uniform MVP_Data { 6 | mat4 model; 7 | mat4 view; 8 | mat4 projection; 9 | } uniforms; 10 | 11 | layout(location = 0) out vec3 frag_pos; 12 | 13 | void main() { 14 | mat4 worldview = uniforms.view * uniforms.model; 15 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 16 | frag_pos = vec3(uniforms.model * vec4(position, 1.0)); 17 | } -------------------------------------------------------------------------------- /lessons/8. Light II/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_8" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 frag_pos; 4 | 5 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 6 | 7 | layout(set = 0, binding = 2) uniform Ambient_Data { 8 | vec3 color; 9 | float intensity; 10 | } ambient; 11 | 12 | layout(location = 0) out vec4 f_color; 13 | 14 | void main() { 15 | vec3 ambient_color = ambient.intensity * ambient.color; 16 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 17 | f_color = vec4(combined_color, 1.0); 18 | } 19 | -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | 5 | layout(set = 0, binding = 1) uniform MVP_Data { 6 | mat4 model; 7 | mat4 view; 8 | mat4 projection; 9 | } uniforms; 10 | 11 | layout(location = 0) out vec3 frag_pos; 12 | 13 | void main() { 14 | mat4 worldview = uniforms.view * uniforms.model; 15 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 16 | frag_pos = vec3(uniforms.model * vec4(position, 1.0)); 17 | } -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 in_color; 4 | layout(location = 1) in vec3 in_normal; 5 | 6 | layout(location = 0) out vec4 f_color; 7 | layout(location = 1) out vec3 f_normal; 8 | 9 | void main() { 10 | f_color = vec4(in_color, 1.0); 11 | f_normal = in_normal; 12 | } 13 | -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform MVP_Data { 11 | mat4 model; 12 | mat4 view; 13 | mat4 projection; 14 | } uniforms; 15 | 16 | void main() { 17 | mat4 worldview = uniforms.view * uniforms.model; 18 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 19 | out_color = color; 20 | out_normal = mat3(uniforms.model) * normal; 21 | } -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 frag_pos; 4 | 5 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 6 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 7 | 8 | layout(set = 0, binding = 3) uniform Directional_Light_Data { 9 | vec4 position; 10 | vec3 color; 11 | } directional; 12 | 13 | layout(location = 0) out vec4 f_color; 14 | 15 | void main() { 16 | vec3 light_direction = normalize(directional.position.xyz + subpassLoad(u_normals).xyz); 17 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 18 | vec3 directional_color = directional_intensity * directional.color; 19 | vec3 combined_color = directional_color * subpassLoad(u_color).rgb; 20 | f_color = vec4(combined_color, 1.0); 21 | } 22 | -------------------------------------------------------------------------------- /lessons/8. Light II/src/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | 5 | layout(set = 0, binding = 2) uniform MVP_Data { 6 | mat4 model; 7 | mat4 view; 8 | mat4 projection; 9 | } uniforms; 10 | 11 | layout(location = 0) out vec3 frag_pos; 12 | 13 | void main() { 14 | mat4 worldview = uniforms.view * uniforms.model; 15 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 16 | frag_pos = vec3(uniforms.model * vec4(position, 1.0)); 17 | } -------------------------------------------------------------------------------- /lessons/9. Model Loading/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lesson_9" 3 | version = "0.32.0" 4 | authors = ["taidaesal"] 5 | edition = "2021" 6 | 7 | [dependencies] 8 | bytemuck = { version = "1.12.1", features = ["derive", "extern_crate_std", "min_const_generics"] } 9 | nalgebra-glm = "0.17.0" 10 | vulkano = "0.32.3" 11 | vulkano-shaders = "0.32.0" 12 | vulkano-win = "0.32.0" 13 | winit = "0.27.3" 14 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/model.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::obj_loader::{Loader, NormalVertex}; 7 | 8 | use nalgebra_glm::{identity, rotate_normalized_axis, translate, TMat4, TVec3}; 9 | use std::cell::Cell; 10 | 11 | /// Holds our data for a renderable model, including the model matrix data 12 | /// 13 | /// Note: When building an instance of `Model` the loader will assume that 14 | /// the input obj file is in clockwise winding order. If it is already in 15 | /// counter-clockwise winding order, call `.invert_winding_order(false)` 16 | /// when building the `Model`. 17 | pub struct Model { 18 | data: Vec, 19 | translation: TMat4, 20 | rotation: TMat4, 21 | 22 | // We might call multiple translation/rotation calls 23 | // in between asking for the model matrix. This lets us 24 | // only recreate the model matrices when needed. 25 | // Use a Cell with the interior mutability pattern, 26 | // so that it can be modified by methods that don't take &mut self 27 | cache: Cell>, 28 | } 29 | 30 | #[derive(Copy, Clone)] 31 | struct ModelMatrices { 32 | model: TMat4, 33 | } 34 | 35 | pub struct ModelBuilder { 36 | file_name: String, 37 | custom_color: [f32; 3], 38 | invert: bool, 39 | } 40 | 41 | impl ModelBuilder { 42 | fn new(file: String) -> ModelBuilder { 43 | ModelBuilder { 44 | file_name: file, 45 | custom_color: [1.0, 0.35, 0.137], 46 | invert: true, 47 | } 48 | } 49 | 50 | pub fn build(self) -> Model { 51 | let loader = Loader::new(self.file_name.as_str(), self.custom_color, self.invert); 52 | Model { 53 | data: loader.as_normal_vertices(), 54 | translation: identity(), 55 | rotation: identity(), 56 | cache: Cell::new(None), 57 | } 58 | } 59 | 60 | pub fn color(mut self, new_color: [f32; 3]) -> ModelBuilder { 61 | self.custom_color = new_color; 62 | self 63 | } 64 | 65 | pub fn file(mut self, file: String) -> ModelBuilder { 66 | self.file_name = file; 67 | self 68 | } 69 | 70 | pub fn invert_winding_order(mut self, invert: bool) -> ModelBuilder { 71 | self.invert = invert; 72 | self 73 | } 74 | } 75 | 76 | impl Model { 77 | pub fn new(file_name: &str) -> ModelBuilder { 78 | ModelBuilder::new(file_name.into()) 79 | } 80 | 81 | pub fn data(&self) -> Vec { 82 | self.data.clone() 83 | } 84 | 85 | pub fn model_matrix(&self) -> TMat4 { 86 | if let Some(cache) = self.cache.get() { 87 | return cache.model; 88 | } 89 | 90 | // recalculate matrix 91 | let model = self.translation * self.rotation; 92 | 93 | self.cache.set(Some(ModelMatrices { model })); 94 | 95 | model 96 | } 97 | 98 | pub fn rotate(&mut self, radians: f32, v: TVec3) { 99 | self.rotation = rotate_normalized_axis(&self.rotation, radians, &v); 100 | self.cache.set(None); 101 | } 102 | 103 | pub fn translate(&mut self, v: TVec3) { 104 | self.translation = translate(&self.translation, &v); 105 | self.cache.set(None); 106 | } 107 | 108 | /// Return the model's rotation to 0 109 | pub fn zero_rotation(&mut self) { 110 | self.rotation = identity(); 111 | self.cache.set(None); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/obj_loader/face.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | use std::fmt; 6 | 7 | pub struct RawFace { 8 | pub verts: [usize; 3], 9 | pub norms: Option<[usize; 3]>, 10 | pub text: Option<[usize; 3]>, 11 | } 12 | 13 | impl RawFace { 14 | // call with invert = true if the models are using a clockwise winding order 15 | // 16 | // Blender files are a common example 17 | pub fn new(raw_arg: &str, invert: bool) -> RawFace { 18 | let arguments: Vec<&str> = raw_arg.split_whitespace().collect(); 19 | RawFace { 20 | verts: RawFace::parse(arguments.clone(), 0, invert).unwrap(), 21 | norms: RawFace::parse(arguments.clone(), 2, invert), 22 | text: RawFace::parse(arguments.clone(), 1, invert), 23 | } 24 | } 25 | 26 | fn parse(inpt: Vec<&str>, index: usize, invert: bool) -> Option<[usize; 3]> { 27 | let f1: Vec<&str> = inpt.get(0).unwrap().split("/").collect(); 28 | let f2: Vec<&str> = inpt.get(1).unwrap().split("/").collect(); 29 | let f3: Vec<&str> = inpt.get(2).unwrap().split("/").collect(); 30 | let a1 = f1.get(index).unwrap().clone(); 31 | let a2 = f2.get(index).unwrap().clone(); 32 | let a3 = f3.get(index).unwrap().clone(); 33 | match a1 { 34 | "" => None, 35 | _ => { 36 | let p1: usize = a1.parse().unwrap(); 37 | let (p2, p3): (usize, usize) = if invert { 38 | (a3.parse().unwrap(), a2.parse().unwrap()) 39 | } else { 40 | (a2.parse().unwrap(), a3.parse().unwrap()) 41 | }; 42 | Some([p1 - 1, p2 - 1, p3 - 1]) // .obj files aren't 0-index 43 | } 44 | } 45 | } 46 | } 47 | 48 | impl fmt::Display for RawFace { 49 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 50 | let verts = format!("{}/{}/{}", self.verts[0], self.verts[1], self.verts[2]); 51 | let normals = match self.norms { 52 | None => "None".to_string(), 53 | Some(x) => { 54 | format!("{}/{}/{}", x[0], x[1], x[2]) 55 | } 56 | }; 57 | let textures = match self.text { 58 | None => "None".to_string(), 59 | Some(x) => { 60 | format!("{}/{}/{}", x[0], x[1], x[2]) 61 | } 62 | }; 63 | write!( 64 | f, 65 | "Face:\n\tVertices: {}\n\tNormals: {}\n\tTextures: {}", 66 | verts, normals, textures 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/obj_loader/loader.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | #![allow(dead_code)] 6 | use super::face::RawFace; 7 | use super::vertex::RawVertex; 8 | use super::NormalVertex; 9 | 10 | use std::fs::File; 11 | use std::io::{BufRead, BufReader}; 12 | 13 | pub struct Loader { 14 | color: [f32; 3], 15 | verts: Vec, 16 | norms: Vec, 17 | text: Vec, 18 | faces: Vec, 19 | invert_winding_order: bool, 20 | } 21 | 22 | impl Loader { 23 | pub fn new(file_name: &str, custom_color: [f32; 3], invert_winding_order: bool) -> Loader { 24 | let color = custom_color; 25 | let input = File::open(file_name).unwrap(); 26 | let buffered = BufReader::new(input); 27 | let mut verts: Vec = Vec::new(); 28 | let mut norms: Vec = Vec::new(); 29 | let mut text: Vec = Vec::new(); 30 | let mut faces: Vec = Vec::new(); 31 | for raw_line in buffered.lines() { 32 | let line = raw_line.unwrap(); 33 | if line.len() > 2 { 34 | match line.split_at(2) { 35 | ("v ", x) => { 36 | verts.push(RawVertex::new(x)); 37 | } 38 | ("vn", x) => { 39 | norms.push(RawVertex::new(x)); 40 | } 41 | ("vt", x) => { 42 | text.push(RawVertex::new(x)); 43 | } 44 | ("f ", x) => { 45 | faces.push(RawFace::new(x, invert_winding_order)); 46 | } 47 | (_, _) => {} 48 | }; 49 | } 50 | } 51 | Loader { 52 | color, 53 | verts, 54 | norms, 55 | text, 56 | faces, 57 | invert_winding_order, 58 | } 59 | } 60 | 61 | pub fn as_normal_vertices(&self) -> Vec { 62 | let mut ret: Vec = Vec::new(); 63 | for face in &self.faces { 64 | let verts = face.verts; 65 | let normals = face.norms.unwrap(); 66 | ret.push(NormalVertex { 67 | position: self.verts.get(verts[0]).unwrap().vals, 68 | normal: self.norms.get(normals[0]).unwrap().vals, 69 | color: self.color, 70 | }); 71 | ret.push(NormalVertex { 72 | position: self.verts.get(verts[1]).unwrap().vals, 73 | normal: self.norms.get(normals[1]).unwrap().vals, 74 | color: self.color, 75 | }); 76 | ret.push(NormalVertex { 77 | position: self.verts.get(verts[2]).unwrap().vals, 78 | normal: self.norms.get(normals[2]).unwrap().vals, 79 | color: self.color, 80 | }); 81 | } 82 | ret 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/obj_loader/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | mod face; 6 | mod loader; 7 | mod vertex; 8 | pub use self::loader::Loader; 9 | use bytemuck::{Pod, Zeroable}; 10 | 11 | use std::fmt; 12 | 13 | /// A vertex type intended to be used to provide dummy rendering 14 | /// data for rendering passes that do not require geometry data. 15 | /// This is due to a quirk of the Vulkan API in that *all* 16 | /// render passes require some sort of input. 17 | #[repr(C)] 18 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 19 | pub struct DummyVertex { 20 | /// A regular position vector with the z-value shaved off for space. 21 | /// This assumes the shaders will take a `vec2` and transform it as 22 | /// needed. 23 | pub position: [f32; 2], 24 | } 25 | 26 | impl DummyVertex { 27 | /// Creates an array of `DummyVertex` values. 28 | /// 29 | /// This is intended to compliment the use of this data type for passing to 30 | /// deferred rendering passes that do not actually require geometry input. 31 | /// This list will draw a square across the entire rendering area. This will 32 | /// cause the fragment shaders to execute on all pixels in the rendering 33 | /// area. 34 | /// 35 | /// # Example 36 | /// 37 | /// ```glsl 38 | /// #version 450 39 | /// 40 | ///layout(location = 0) in vec2 position; 41 | /// 42 | ///void main() { 43 | /// gl_Position = vec4(position, 0.0, 1.0); 44 | ///} 45 | /// ``` 46 | pub fn list() -> [DummyVertex; 6] { 47 | [ 48 | DummyVertex { 49 | position: [-1.0, -1.0], 50 | }, 51 | DummyVertex { 52 | position: [-1.0, 1.0], 53 | }, 54 | DummyVertex { 55 | position: [1.0, 1.0], 56 | }, 57 | DummyVertex { 58 | position: [-1.0, -1.0], 59 | }, 60 | DummyVertex { 61 | position: [1.0, 1.0], 62 | }, 63 | DummyVertex { 64 | position: [1.0, -1.0], 65 | }, 66 | ] 67 | } 68 | } 69 | 70 | /// A structure for the vertex information used in earlier lessons 71 | #[repr(C)] 72 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 73 | pub struct ColoredVertex { 74 | pub position: [f32; 3], 75 | pub color: [f32; 3], 76 | } 77 | 78 | /// A structure used for the vertex information starting 79 | /// from our lesson on lighting 80 | #[repr(C)] 81 | #[derive(Clone, Copy, Debug, Default, Zeroable, Pod)] 82 | pub struct NormalVertex { 83 | pub position: [f32; 3], 84 | pub normal: [f32; 3], 85 | pub color: [f32; 3], 86 | } 87 | 88 | impl fmt::Display for DummyVertex { 89 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 90 | let pos = format!("[{:.6}, {:.6}]", self.position[0], self.position[1]); 91 | write!(f, "DummyVertex {{ position: {} }}", pos) 92 | } 93 | } 94 | 95 | impl fmt::Display for ColoredVertex { 96 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 97 | let pos = format!( 98 | "[{:.6}, {:.6}, {:.6}]", 99 | self.position[0], self.position[1], self.position[2] 100 | ); 101 | let color = format!( 102 | "[{:.6}, {:.6}, {:.6}]", 103 | self.color[0], self.color[1], self.color[2] 104 | ); 105 | write!(f, "ColoredVertex {{ position: {}, color: {} }}", pos, color) 106 | } 107 | } 108 | 109 | impl fmt::Display for NormalVertex { 110 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 111 | let pos = format!( 112 | "[{:.6}, {:.6}, {:.6}]", 113 | self.position[0], self.position[1], self.position[2] 114 | ); 115 | let color = format!( 116 | "[{:.6}, {:.6}, {:.6}]", 117 | self.color[0], self.color[1], self.color[2] 118 | ); 119 | let norms = format!( 120 | "[{:.6}, {:.6}, {:.6}]", 121 | self.normal[0], self.normal[1], self.normal[2] 122 | ); 123 | write!( 124 | f, 125 | "NormalVertex {{ position: {}, normal: {}, color: {} }}", 126 | pos, norms, color 127 | ) 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/obj_loader/vertex.rs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2022 taidaesal 2 | // Licensed under the MIT license 3 | // 4 | 5 | pub struct RawVertex { 6 | pub vals: [f32; 3], 7 | } 8 | 9 | impl RawVertex { 10 | pub fn new(inpt: &str) -> RawVertex { 11 | let items = inpt.split_whitespace(); 12 | let mut content: Vec = Vec::new(); 13 | for item in items { 14 | content.push(item.parse().unwrap()); 15 | } 16 | if content.len() == 2 { 17 | content.push(0.0); 18 | } 19 | RawVertex { 20 | vals: [ 21 | *content.get(0).unwrap(), 22 | *content.get(1).unwrap(), 23 | *content.get(2).unwrap(), 24 | ], 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/ambient.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | 5 | layout(set = 0, binding = 1) uniform Ambient_Data { 6 | vec3 color; 7 | float intensity; 8 | } ambient; 9 | 10 | layout(location = 0) out vec4 f_color; 11 | 12 | void main() { 13 | vec3 ambient_color = ambient.intensity * ambient.color; 14 | vec3 combined_color = ambient_color * subpassLoad(u_color).rgb; 15 | f_color = vec4(combined_color, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/ambient.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/deferred.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | layout(location = 0) in vec3 in_color; 3 | layout(location = 1) in vec3 in_normal; 4 | 5 | layout(location = 0) out vec4 f_color; 6 | layout(location = 1) out vec3 f_normal; 7 | 8 | void main() { 9 | f_color = vec4(in_color, 1.0); 10 | f_normal = in_normal; 11 | } -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/deferred.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec3 position; 4 | layout(location = 1) in vec3 normal; 5 | layout(location = 2) in vec3 color; 6 | 7 | layout(location = 0) out vec3 out_color; 8 | layout(location = 1) out vec3 out_normal; 9 | 10 | layout(set = 0, binding = 0) uniform MVP_Data { 11 | mat4 model; 12 | mat4 view; 13 | mat4 projection; 14 | } uniforms; 15 | 16 | void main() { 17 | mat4 worldview = uniforms.view * uniforms.model; 18 | gl_Position = uniforms.projection * worldview * vec4(position, 1.0); 19 | out_color = color; 20 | out_normal = mat3(uniforms.model) * normal; 21 | } -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/directional.frag: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput u_color; 4 | layout(input_attachment_index = 1, set = 0, binding = 1) uniform subpassInput u_normals; 5 | 6 | layout(set = 0, binding = 2) uniform Directional_Light_Data { 7 | vec4 position; 8 | vec3 color; 9 | } directional; 10 | 11 | layout(location = 0) out vec4 f_color; 12 | 13 | void main() { 14 | vec3 light_direction = normalize(directional.position.xyz + subpassLoad(u_normals).xyz); 15 | float directional_intensity = max(dot(normalize(subpassLoad(u_normals).rgb), light_direction), 0.0); 16 | vec3 directional_color = directional_intensity * directional.color; 17 | vec3 combined_color = directional_color * subpassLoad(u_color).rgb; 18 | f_color = vec4(combined_color, 1.0); 19 | } 20 | -------------------------------------------------------------------------------- /lessons/9. Model Loading/src/shaders/directional.vert: -------------------------------------------------------------------------------- 1 | #version 450 2 | 3 | layout(location = 0) in vec2 position; 4 | 5 | void main() { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | } --------------------------------------------------------------------------------