├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── build.rs ├── preview.png ├── res ├── turkey.mtl └── turkey.obj └── src ├── camera.rs ├── camera_controller.rs ├── color.rs ├── depth_pass.rs ├── depth_pass.wgsl ├── light.rs ├── light.wgsl ├── main.rs ├── model.rs ├── rendering.rs ├── rendering ├── gpu_resources.rs ├── render_utils.rs ├── vertex_desc.rs └── vertex_instance.rs ├── shader.wgsl ├── texture.rs ├── voxel_tools.rs └── voxel_tools ├── chunk.rs ├── chunks.rs ├── direction.rs ├── mesh_builder.rs ├── quad.rs ├── rendering.rs ├── rendering ├── voxel.wgsl ├── voxel_pipeline.rs ├── voxel_rendering.rs └── voxel_vertex.rs └── voxel.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "teal_mountain" 3 | version = "0.1.0" 4 | authors = ["TanTanDev "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | image = "0.23" 11 | winit = "0.24" 12 | cgmath = "0.18" 13 | env_logger = "0.7" 14 | log = "0.4" 15 | futures = "0.3" 16 | bytemuck = {version = "1.4", features = ["derive"]} 17 | anyhow = "1.0" 18 | tobj = "3.0.0" 19 | rand = "0.8.3" 20 | lazy_static = "1.4.0" 21 | noise = "0.7.0" 22 | 23 | # pooling library 24 | lifeguard = "0.6.1" 25 | generational-arena = "0.2.8" 26 | 27 | 28 | [dependencies.wgpu] 29 | version = "0.8.1" 30 | #features = ["vulkan-portability"] 31 | 32 | 33 | [build-dependencies] 34 | shaderc = "0.7" 35 | anyhow = "1.0" 36 | fs_extra = "1.1" 37 | glob = "0.3" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 TanTanDev 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # first_voxel_engine 2 | This is my first ever voxel engine written for Rust, using [wgpu-rs](https://github.com/gfx-rs/wgpu-rs) as rendering backend. 3 | 4 | I will not accept pull requests as I want people watching my video about creating this (here: https://youtu.be/96ht7rd3Y5I) 5 | 6 | to have easy access to the source code at this projects initial state. 7 | 8 | so what is the initial state? 9 | Working endless voxel generation, but not optimized! 10 | Only one form of world generation is provided, endless grass cave one. 11 | ![preview](preview.png) 12 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use anyhow::*; 2 | use std::path::PathBuf; 3 | 4 | use fs_extra::copy_items; 5 | use fs_extra::dir::CopyOptions; 6 | use std::env; 7 | 8 | // copy resource folder to OUT_DIR 9 | fn copy_res() -> Result<()> { 10 | // This tells cargo to rerun this script if something in /res/ changes. 11 | println!("cargo:rerun-if-changed=res/*"); 12 | 13 | let out_dir = env::var("OUT_DIR")?; 14 | let out_dir = PathBuf::from(out_dir); 15 | let out_dir = out_dir 16 | .parent() 17 | .unwrap() 18 | .parent() 19 | .unwrap() 20 | .parent() 21 | .unwrap(); 22 | println!("out dir: {:?}", out_dir); 23 | let mut copy_options = CopyOptions::new(); 24 | copy_options.overwrite = true; 25 | let mut paths_to_copy = Vec::new(); 26 | paths_to_copy.push("res/"); 27 | copy_items(&paths_to_copy, out_dir, ©_options)?; 28 | Ok(()) 29 | } 30 | 31 | fn main() -> Result<()> { 32 | copy_res()?; 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TanTanDev/first_voxel_engine/1cb19a85fdba285e478eb97819dc762753c6c5e9/preview.png -------------------------------------------------------------------------------- /res/turkey.mtl: -------------------------------------------------------------------------------- 1 | # Created by Kenney (www.kenney.nl) 2 | 3 | newmtl brownDark 4 | Kd 0.6392157 0.3882353 0.2784314 5 | 6 | newmtl brownLight 7 | Kd 0.9764706 0.772549 0.5490196 8 | 9 | -------------------------------------------------------------------------------- /res/turkey.obj: -------------------------------------------------------------------------------- 1 | # Created by Kenney (www.kenney.nl) 2 | 3 | mtllib turkey.mtl 4 | 5 | g turkey 6 | 7 | v -0.08542026 0.02454943 -0.2064808 8 | v 0.2021332 0.02454943 -0.2064808 9 | v -0.1253459 0.1158994 -0.256321 10 | v 0.2343771 0.09454031 -0.2446675 11 | v 0.2248685 0.1158994 -0.256321 12 | v 0.381105 0.1268945 -0.1031329 13 | v 0.381105 0.1389945 -0.1281605 14 | v 0.4092309 0.1101891 -0.07680026 15 | v 0.4388129 0.1047187 -0.07413182 16 | v 0.3893485 0.2084327 0.2169776 17 | v 0.3797456 0.2202994 0.2009406 18 | v 0.4176896 0.141188 0.1904434 19 | v 0.4130881 0.141188 0.1697239 20 | v 0.4130881 0.141188 -0.1697239 21 | v 0.3797456 0.2202994 -0.2009406 22 | v 0.4176896 0.141188 -0.1904434 23 | v 0.3893485 0.2084327 -0.2169776 24 | v 0.244217 0.2202994 0.256321 25 | v 0.3440694 0.2202994 0.1628349 26 | v 0.2798933 0.2202994 0.2944267 27 | v 0.2438244 0.0739433 -0.2316611 28 | v 0.3977586 0.0739433 -0.0875411 29 | v 0.244217 0.06207659 -0.256321 30 | v 0.4253161 0.06207658 -0.0867681 31 | v 0.2108745 0.141188 0.2875377 32 | v 0.2154832 0.141188 0.2581953 33 | v 0.2174851 0.1459379 0.256321 34 | v 0.2465508 0.141188 0.3256434 35 | v 0.2798933 0.06207659 0.2944267 36 | v 0.244217 0.06207659 0.256321 37 | v 0.3044739 0.0739433 0.2964408 38 | v 0.2761328 0.141188 0.322975 39 | v 0.244217 0.2202994 -0.256321 40 | v 0.2798933 0.2202994 -0.2944267 41 | v 0.3440694 0.2202994 -0.1628349 42 | v 0.3774119 0.141188 -0.1316181 43 | v 0.381105 0.1389945 0.1281605 44 | v 0.3774119 0.141188 0.1316181 45 | v 0.381105 0.2202994 0.1281605 46 | v 0.4388129 0.1047187 0.07413182 47 | v 0.4744892 0.1047187 0.1122375 48 | v 0.4584082 0.0739433 0.1523208 49 | v 0.4698805 0.1101891 0.14158 50 | v 0.3044739 0.2084327 0.2964408 51 | v 0.381105 0.2202994 -0.1281605 52 | v 0.2798933 0.06207659 -0.2944267 53 | v 0.4609924 0.06207659 -0.1248738 54 | v 0.3044739 0.0739433 -0.2964408 55 | v 0.4584082 0.0739433 -0.1523208 56 | v 0.3618379 0.09028035 -0.1211717 57 | v 0.2369389 0.09028035 -0.2381075 58 | v 0.381105 0.1158994 -0.1031329 59 | v 0.2465508 0.141188 -0.3256435 60 | v 0.2761328 0.141188 -0.322975 61 | v 0.3044739 0.2084327 -0.2964408 62 | v 0.2174851 0.1364381 -0.256321 63 | v 0.2154832 0.141188 -0.2581953 64 | v 0.2108745 0.141188 -0.2875377 65 | v 0.3124041 0.02454943 -0.1032404 66 | v 0.4609924 0.06207659 0.1248738 67 | v 0.4253161 0.06207659 0.08676808 68 | v 0.3618378 0.09028035 0.1211717 69 | v 0.381105 0.1158994 0.1031329 70 | v 0.3124041 0.02454943 0.1032404 71 | v 0.3977586 0.0739433 0.08754108 72 | v 0.4092309 0.1101891 0.07680025 73 | v 0.2438244 0.0739433 0.2316611 74 | v 0.2369389 0.09028035 0.2381075 75 | v 0.381105 0.1268945 0.1031329 76 | v -0.1506606 0.3116494 -2.712427E-09 77 | v -0.05405466 0.3116494 -0.1673263 78 | v -0.05405466 0.3116494 0.1673263 79 | v 0.1690722 0.3116494 0.1673263 80 | v 0.1690722 0.3116494 -0.1673263 81 | v 0.2584327 0.3116494 0.08366317 82 | v 0.2584327 0.3116494 -0.08366317 83 | v 0.2174851 0.1364381 0.256321 84 | v 0.2248685 0.1158994 0.256321 85 | v 0.2343771 0.09454031 0.2446675 86 | v -0.1253459 0.2202994 -0.256321 87 | v 0.2174851 0.1459379 -0.256321 88 | v 0.4744892 0.1047187 -0.1122375 89 | v 0.4698805 0.1101891 -0.14158 90 | v -0.2733329 0.2202994 -2.712429E-09 91 | v -0.1253459 0.1158994 0.256321 92 | v -0.08542026 0.02454943 0.2064808 93 | v -0.2733329 0.1158994 -2.712429E-09 94 | v -0.204632 0.02454943 -2.712426E-09 95 | v -0.1253459 0.2202994 0.256321 96 | v 0.2021332 0.02454943 0.2064808 97 | 98 | vn 0 -0.4789478 -0.8778434 99 | vn 0.1262062 0.8931039 0.4317841 100 | vn 0.8742052 0.4450533 -0.1941465 101 | vn 0.8742052 0.4450533 0.1941465 102 | vn 0 1 0 103 | vn -0.37228 -0.8386278 0.3976315 104 | vn -0.9309278 0.3346553 -0.146217 105 | vn -0.6321939 -0.5 0.5918875 106 | vn 0.08465976 -0.3346553 0.93853 107 | vn 0.6321939 0.5 0.5918875 108 | vn 0.6834528 0 0.7299947 109 | vn 0.2903916 0.9174723 -0.2718772 110 | vn -0.1316462 -0.243115 0.9610226 111 | vn 0.6834529 0 -0.7299946 112 | vn 0.37228 -0.8386278 -0.3976316 113 | vn -0.6834528 0 0.7299947 114 | vn 0.08465976 0.3346553 -0.93853 115 | vn 0 -1 0 116 | vn -0.9309278 -0.3346553 0.146217 117 | vn 0.5564498 -0.5806205 -0.5943429 118 | vn 0.08465976 -0.3346552 -0.93853 119 | vn 0.6697499 -0.3977996 -0.6270491 120 | vn 0.7992081 -0.6010544 0 121 | vn -0.1316461 -0.2431149 -0.9610226 122 | vn 0.37228 0.8386278 -0.3976315 123 | vn 0.9502806 -0.2431149 0.1945812 124 | vn -0.6834528 0 -0.7299947 125 | vn -0.6321939 -0.5 -0.5918875 126 | vn 0.6321939 0.5 -0.5918875 127 | vn -0.9309278 -0.3346553 -0.146217 128 | vn 0 0 -1 129 | vn 0.37228 0.8386278 0.3976316 130 | vn -0.37228 -0.8386278 -0.3976316 131 | vn 0.37228 -0.8386278 0.3976315 132 | vn 0.9502806 -0.2431149 -0.1945812 133 | vn 0.1262062 0.8931039 -0.4317839 134 | vn -0.6321939 0.5 -0.5918875 135 | vn -0.5646324 0.758235 -0.3259906 136 | vn 0.5972588 0.8020486 0 137 | vn -0.7256804 -0.545757 0.4189717 138 | vn -0.8660254 0 0.5 139 | vn 0.08465976 0.3346552 0.93853 140 | vn 0.4221174 0.786473 -0.4508627 141 | vn -0.7256804 -0.545757 -0.4189717 142 | vn -0.5646324 0.758235 0.3259906 143 | vn 0.4391511 0.8931039 -0.09752817 144 | vn 0 0 1 145 | vn 0 0.6978123 -0.7162808 146 | vn 0.2903916 0.9174723 0.2718773 147 | vn -0.8660254 0 -0.5 148 | vn 0.6834528 0 -0.7299947 149 | vn 0 -0.4789478 0.8778434 150 | vn 0.6697499 -0.3977996 0.6270491 151 | vn -0.6321939 0.5 0.5918875 152 | vn 0.4391511 0.8931039 0.0975282 153 | vn -0.9309278 0.3346553 0.146217 154 | vn 0 0.6978123 0.7162808 155 | vn 1 0 0 156 | vn 0.4221174 0.786473 0.4508627 157 | vn 0.5564498 -0.5806205 0.5943429 158 | 159 | vt 3.363002 4.741893 160 | vt -7.958001 4.741893 161 | vt 4.934879 8.838817 162 | vt -9.227447 7.880889 163 | vt -8.85309 8.838817 164 | vt 15.54069 1.968605 165 | vt 15.81713 3.027569 166 | vt 16.31268 0.5065768 167 | vt 17.40108 0.02781816 168 | vt -11.66253 1.512937 169 | vt -10.9642 2.034647 170 | vt -10.88462 -1.443419 171 | vt -10.04902 -1.443419 172 | vt 10.04902 -1.443419 173 | vt 10.9642 2.034648 174 | vt 10.88463 -1.443419 175 | vt 11.66253 1.512938 176 | vt 9.614844 -10.09138 177 | vt 13.54604 -6.410821 178 | vt 11.01942 -11.5916 179 | vt 14.95062 -7.911046 180 | vt 0.7740568 -9.499812 181 | vt 9.076041 -9.499812 182 | vt 0.1218028 -10.35751 183 | vt 9.888843 -10.35751 184 | vt 9.895087 8.570612 185 | vt 8.725711 8.570612 186 | vt 8.477285 11.87581 187 | vt 8.640585 8.769057 188 | vt 15.99306 5.652087 189 | vt 15.99306 2.05563 190 | vt 13.93794 5.652087 191 | vt 13.93794 2.05563 192 | vt 9.933472 6.49785 193 | vt 8.51567 9.803049 194 | vt 10.89018 6.99363 195 | vt 9.685046 9.803049 196 | vt 9.614844 10.09138 197 | vt 11.01942 11.5916 198 | vt 13.54604 6.410821 199 | vt 14.95062 7.911047 200 | vt 13.93794 1.161239 201 | vt 13.93794 4.757696 202 | vt 15.99306 1.161239 203 | vt 15.99306 4.757696 204 | vt 7.504447 5.472224 205 | vt 7.305271 5.558583 206 | vt 7.504447 8.673206 207 | vt 5.507042 8.673206 208 | vt -13.93794 -4.491182 209 | vt -13.93794 -4.708275 210 | vt -15.99306 -4.491182 211 | vt -13.93794 -8.100534 212 | vt -15.99306 -8.100534 213 | vt 16.12618 0.9953283 214 | vt 15.04714 1.476972 215 | vt 16.72015 2.726079 216 | vt 15.55202 2.948111 217 | vt 0.7740573 2.911154 218 | vt -0.7544369 5.558583 219 | vt 9.076041 2.911154 220 | vt 9.694763 4.338154 221 | vt 6.880005 5.558583 222 | vt 0.7740572 8.206013 223 | vt 5.351511 8.206013 224 | vt -7.504447 5.472224 225 | vt -7.504447 8.673206 226 | vt -7.30527 5.558583 227 | vt -5.507042 8.673205 228 | vt -0.1218033 14.74346 229 | vt -9.888844 14.74346 230 | vt -0.7740573 15.60116 231 | vt -9.076041 15.60116 232 | vt 0.774057 2.911153 233 | vt 7.138763 3.554344 234 | vt 9.076041 2.911153 235 | vt 9.694763 4.338154 236 | vt 0.4027105 3.554344 237 | vt 8.177878 4.562969 238 | vt 8.177878 4.995848 239 | vt -8.51567 0.6731084 240 | vt -9.685046 0.6731084 241 | vt -9.933472 3.978307 242 | vt -10.89018 3.482527 243 | vt -9.614844 10.09138 244 | vt -16.74473 3.416067 245 | vt -11.01942 11.5916 246 | vt -18.14931 4.916292 247 | vt -8.640586 1.707099 248 | vt -8.595482 0.849013 249 | vt -8.725711 1.905545 250 | vt -8.477285 -1.399653 251 | vt -9.895088 1.905545 252 | vt -8.084155 -0.04335056 253 | vt -7.813365 -0.2213272 254 | vt -7.520579 -0.9038734 255 | vt -6.200526 7.390404 256 | vt -0.4027105 10.56888 257 | vt -0.2533965 7.390404 258 | vt -0.1525718 10.77487 259 | vt -7.138763 10.56888 260 | vt -9.933472 6.49785 261 | vt -10.89018 6.99363 262 | vt -8.51567 9.803048 263 | vt -9.685046 9.803048 264 | vt -15.99306 6.176044 265 | vt -15.99306 8.005879 266 | vt -13.93794 6.176044 267 | vt -13.93794 8.005879 268 | vt -4.770538 11.40303 269 | vt -4.060351 12.66506 270 | vt -4.064583 8.165038 271 | vt 4.064583 8.165038 272 | vt 4.060351 12.66506 273 | vt 4.770538 11.40303 274 | vt -16.12618 0.9953288 275 | vt -16.72015 2.72608 276 | vt -15.04714 1.476973 277 | vt -15.55202 2.948111 278 | vt -0.1218028 -8.687892 279 | vt -0.7740568 -9.545592 280 | vt -5.507042 -8.687892 281 | vt -5.35151 -9.545592 282 | vt -2.254648 7.41472 283 | vt -1.749773 8.885859 284 | vt -1.175613 6.933076 285 | vt -0.5816422 8.663827 286 | vt -0.7740573 2.911154 287 | vt -9.076041 2.911154 288 | vt -0.4027109 3.554344 289 | vt -7.138763 3.554344 290 | vt -9.694763 4.338154 291 | vt -8.177879 4.56297 292 | vt -8.177879 4.995848 293 | vt -5.931519 1.067885E-07 294 | vt -2.128136 6.587652 295 | vt -2.128136 -6.587652 296 | vt 6.656385 -6.587652 297 | vt 6.656385 6.587652 298 | vt 10.17451 -3.293826 299 | vt 10.17451 3.293826 300 | vt -13.93794 2.05563 301 | vt -15.99306 2.05563 302 | vt -13.93794 5.652087 303 | vt -15.99306 5.652087 304 | vt -15.99306 4.757695 305 | vt -13.93794 4.757695 306 | vt -15.99306 1.161239 307 | vt -13.93794 1.161239 308 | vt 0.7544369 5.558583 309 | vt 0.6464704 5.37158 310 | vt 0.6464704 5.745586 311 | vt 9.895087 1.905545 312 | vt 8.477285 -1.399653 313 | vt 8.725711 1.905545 314 | vt 8.595482 0.8490131 315 | vt 8.640585 1.7071 316 | vt 8.084154 -0.0433505 317 | vt 7.520578 -0.9038733 318 | vt 7.813365 -0.2213273 319 | vt -8.85309 4.56297 320 | vt -8.562407 5.371579 321 | vt 4.934879 4.56297 322 | vt 4.934879 8.673206 323 | vt -8.562407 5.745586 324 | vt -9.614843 8.673206 325 | vt 0.1218035 -8.687891 326 | vt 5.507043 -8.687891 327 | vt 0.7740575 -9.545591 328 | vt 5.351511 -9.545591 329 | vt -0.7740575 -9.499811 330 | vt -0.1218035 -10.35751 331 | vt -9.076041 -9.499811 332 | vt -9.888844 -10.35751 333 | vt 0.1218031 14.74346 334 | vt 0.774057 15.60116 335 | vt 9.888844 14.74346 336 | vt 9.076041 15.60116 337 | vt 0.5816424 8.663827 338 | vt 1.749773 8.885859 339 | vt 1.175614 6.933076 340 | vt 2.254648 7.41472 341 | vt -15.81713 3.027568 342 | vt -15.54069 1.968603 343 | vt -17.40108 0.027817 344 | vt -16.31268 0.5065757 345 | vt -13.93794 7.572118 346 | vt -13.93794 3.975662 347 | vt -15.99306 7.572118 348 | vt -15.99306 3.975662 349 | vt -0.6464705 5.371579 350 | vt -0.754437 5.558583 351 | vt -0.6464705 5.745586 352 | vt 5.380569 -1.411543 353 | vt -6.271951 -1.411543 354 | vt 2.965759 4.104653 355 | vt -4.641006 4.104653 356 | vt -3.293826 -0.8322908 357 | vt 3.293826 -0.8322908 358 | vt -5.045689 -6.853896 359 | vt 5.045689 -6.853896 360 | vt 6.27195 8.909649 361 | vt 5.358563 4.617645 362 | vt -5.380569 8.909649 363 | vt -4.028189 4.617645 364 | vt 6.27195 8.673206 365 | vt 6.27195 4.56297 366 | vt -5.380569 8.673206 367 | vt -5.380569 4.56297 368 | vt 8.51567 0.6731089 369 | vt 9.933472 3.978307 370 | vt 9.685046 0.6731089 371 | vt 10.89018 3.482528 372 | vt -0.3567764 0.2180146 373 | vt -0.1218031 -5.605031 374 | vt -5.176166 0.2180146 375 | vt -5.507042 -5.605031 376 | vt -7.504447 -5.605031 377 | vt 8.056378 1.067884E-07 378 | vt 3.363002 -8.129166 379 | vt 3.363002 8.129166 380 | vt -7.958001 8.129166 381 | vt -7.958001 -8.129166 382 | vt -12.29937 -4.064583 383 | vt -12.29937 4.064583 384 | vt 4.028189 4.617645 385 | vt -5.358563 4.617645 386 | vt 5.380569 8.909649 387 | vt -6.271951 8.909649 388 | vt -5.380569 -1.411543 389 | vt -2.96576 4.104654 390 | vt 6.27195 -1.411543 391 | vt 4.641006 4.104654 392 | vt -10.04902 -10.38502 393 | vt -8.363698 -13.57674 394 | vt -10.88462 -10.38502 395 | vt -9.452099 -13.09798 396 | vt 8.85309 4.56297 397 | vt -4.934879 4.56297 398 | vt 8.562407 5.37158 399 | vt -4.934879 8.673206 400 | vt 8.562407 5.745586 401 | vt 9.614843 8.673206 402 | vt 4.934879 -0.8294376 403 | vt -9.614843 -0.8294376 404 | vt 2.128136 4.191578 405 | vt -6.656385 4.191578 406 | vt -9.614843 -10.09138 407 | vt -11.01942 -11.5916 408 | vt -16.74473 -3.416066 409 | vt -18.14931 -4.916292 410 | vt 13.93795 -4.491181 411 | vt 15.99306 -4.491181 412 | vt 13.93795 -4.708273 413 | vt 13.93795 -8.100533 414 | vt 15.99306 -8.100533 415 | vt 5.380569 8.673206 416 | vt 5.380569 4.56297 417 | vt -6.271951 8.673206 418 | vt -6.271951 4.56297 419 | vt -9.076041 2.911153 420 | vt -9.694763 4.338154 421 | vt -0.774057 2.911153 422 | vt 0.754437 5.558583 423 | vt -6.880004 5.558583 424 | vt -5.351511 8.206012 425 | vt -0.7740571 8.206012 426 | vt 7.958001 4.741893 427 | vt -3.363002 4.741893 428 | vt 9.227447 7.880888 429 | vt -4.934879 8.838817 430 | vt 8.85309 8.838817 431 | vt 13.93794 8.005879 432 | vt 15.99306 8.005879 433 | vt 13.93794 6.176044 434 | vt 15.99306 6.176044 435 | vt 15.99306 3.975662 436 | vt 13.93794 3.975662 437 | vt 15.99306 7.572118 438 | vt 13.93794 7.572118 439 | vt 10.04902 -10.38502 440 | vt 10.88463 -10.38502 441 | vt 8.3637 -13.57674 442 | vt 9.452101 -13.09798 443 | vt -8.477285 11.87581 444 | vt -8.640585 8.769057 445 | vt -9.895088 8.570612 446 | vt -8.725711 8.570612 447 | vt 9.614843 -0.8294375 448 | vt -4.934879 -0.8294375 449 | vt 6.656385 4.191578 450 | vt -2.128136 4.191578 451 | vt -4.060351 4.56297 452 | vt 4.060351 4.995848 453 | vt 4.060351 4.56297 454 | vt 5.045689 8.673206 455 | vt -4.060351 4.995848 456 | vt -5.045689 5.472224 457 | vt -5.045689 8.673206 458 | vt 5.045689 5.472224 459 | vt 0.3567765 0.2180147 460 | vt 5.176167 0.2180147 461 | vt 0.1218032 -5.605031 462 | vt 5.507042 -5.605031 463 | vt 7.504447 -5.605031 464 | vt 6.200526 7.390404 465 | vt 0.2533967 7.390404 466 | vt 7.138763 10.56888 467 | vt 0.4027109 10.56888 468 | vt 0.1525719 10.77487 469 | 470 | usemtl brownDark 471 | 472 | f 3/3/1 2/2/1 1/1/1 473 | f 2/2/1 3/3/1 4/4/1 474 | f 4/4/1 3/3/1 5/5/1 475 | f 8/8/2 7/7/2 6/6/2 476 | f 7/7/2 8/8/2 9/9/2 477 | f 12/12/3 11/11/3 10/10/3 478 | f 11/11/3 12/12/3 13/13/3 479 | f 16/16/4 15/15/4 14/14/4 480 | f 15/15/4 16/16/4 17/17/4 481 | f 20/20/5 19/19/5 18/18/5 482 | f 19/19/5 20/20/5 11/21/5 483 | f 23/24/6 22/23/6 21/22/6 484 | f 22/23/6 23/24/6 24/25/6 485 | f 18/28/7 26/27/7 25/26/7 486 | f 26/27/7 18/28/7 27/29/7 487 | f 25/32/8 29/31/8 28/30/8 488 | f 29/31/8 25/32/8 30/33/8 489 | f 31/36/9 28/35/9 29/34/9 490 | f 28/35/9 31/36/9 32/37/9 491 | f 35/40/5 34/39/5 33/38/5 492 | f 34/39/5 35/40/5 15/41/5 493 | f 14/44/10 35/43/10 36/42/10 494 | f 35/43/10 14/44/10 15/45/10 495 | f 39/48/11 38/47/11 37/46/11 496 | f 38/47/11 39/48/11 19/49/11 497 | f 13/52/12 37/51/12 38/50/12 498 | f 37/51/12 13/52/12 40/53/12 499 | f 40/53/12 13/52/12 41/54/12 500 | f 9/57/13 22/56/13 24/55/13 501 | f 22/56/13 9/57/13 8/58/13 502 | f 42/61/11 32/60/11 31/59/11 503 | f 32/60/11 42/61/11 43/62/11 504 | f 32/60/11 43/62/11 12/63/11 505 | f 32/60/11 12/63/11 44/64/11 506 | f 44/64/11 12/63/11 10/65/11 507 | f 36/68/14 45/67/14 7/66/14 508 | f 45/67/14 36/68/14 35/69/14 509 | f 48/72/15 47/71/15 46/70/15 510 | f 47/71/15 48/72/15 49/73/15 511 | f 22/76/16 50/75/16 21/74/16 512 | f 50/75/16 22/76/16 8/77/16 513 | f 21/74/16 50/75/16 51/78/16 514 | f 50/75/16 8/77/16 52/79/16 515 | f 52/79/16 8/77/16 6/80/16 516 | f 34/83/17 54/82/17 53/81/17 517 | f 54/82/17 34/83/17 55/84/17 518 | f 46/87/18 24/86/18 23/85/18 519 | f 24/86/18 46/87/18 47/88/18 520 | f 57/91/19 5/90/19 56/89/19 521 | f 5/90/19 57/91/19 23/92/19 522 | f 23/92/19 57/91/19 58/93/19 523 | f 23/92/19 4/94/19 5/90/19 524 | f 23/92/19 51/95/19 4/94/19 525 | f 51/95/19 23/92/19 21/96/19 526 | f 2/99/20 51/98/20 59/97/20 527 | f 51/98/20 2/99/20 4/100/20 528 | f 50/101/20 59/97/20 51/98/20 529 | f 53/104/21 48/103/21 46/102/21 530 | f 48/103/21 53/104/21 54/105/21 531 | f 61/108/22 41/107/22 60/106/22 532 | f 41/107/22 61/108/22 40/109/22 533 | f 64/112/23 63/111/23 62/110/23 534 | f 63/111/23 64/112/23 59/113/23 535 | f 63/111/23 59/113/23 52/114/23 536 | f 52/114/23 59/113/23 50/115/23 537 | f 65/118/24 40/117/24 61/116/24 538 | f 40/117/24 65/118/24 66/119/24 539 | f 15/122/25 55/121/25 34/120/25 540 | f 55/121/25 15/122/25 17/123/25 541 | f 60/126/26 43/125/26 42/124/26 542 | f 43/125/26 60/126/26 41/127/26 543 | f 68/130/27 65/129/27 67/128/27 544 | f 65/129/27 68/130/27 62/131/27 545 | f 65/129/27 62/131/27 66/132/27 546 | f 66/132/27 62/131/27 63/133/27 547 | f 66/132/27 63/133/27 69/134/27 548 | f 72/137/5 71/136/5 70/135/5 549 | f 71/136/5 72/137/5 73/138/5 550 | f 71/136/5 73/138/5 74/139/5 551 | f 74/139/5 73/138/5 75/140/5 552 | f 74/139/5 75/140/5 76/141/5 553 | f 58/144/28 46/143/28 23/142/28 554 | f 46/143/28 58/144/28 53/145/28 555 | f 13/148/29 19/147/29 11/146/29 556 | f 19/147/29 13/148/29 38/149/29 557 | f 27/152/27 77/151/27 26/150/27 558 | f 26/155/30 30/154/30 25/153/30 559 | f 30/154/30 26/155/30 78/156/30 560 | f 78/156/30 26/155/30 77/157/30 561 | f 30/154/30 78/156/30 79/158/30 562 | f 30/154/30 79/158/30 67/159/30 563 | f 67/159/30 79/158/30 68/160/30 564 | f 3/163/31 56/162/31 5/161/31 565 | f 56/162/31 3/163/31 80/164/31 566 | f 56/162/31 80/164/31 81/165/31 567 | f 81/165/31 80/164/31 33/166/31 568 | f 44/169/32 11/168/32 20/167/32 569 | f 11/168/32 44/169/32 10/170/32 570 | f 65/173/33 30/172/33 67/171/33 571 | f 30/172/33 65/173/33 61/174/33 572 | f 60/177/34 31/176/34 29/175/34 573 | f 31/176/34 60/177/34 42/178/34 574 | f 47/181/35 83/180/35 82/179/35 575 | f 83/180/35 47/181/35 49/182/35 576 | f 40/185/36 69/184/36 37/183/36 577 | f 69/184/36 40/185/36 66/186/36 578 | f 34/189/37 58/188/37 33/187/37 579 | f 58/188/37 34/189/37 53/190/37 580 | f 81/193/16 57/192/16 56/191/16 581 | f 70/196/38 80/195/38 84/194/38 582 | f 80/195/38 70/196/38 71/197/38 583 | f 39/200/39 76/199/39 75/198/39 584 | f 76/199/39 39/200/39 45/201/39 585 | f 87/204/40 86/203/40 85/202/40 586 | f 86/203/40 87/204/40 88/205/40 587 | f 84/208/41 85/207/41 89/206/41 588 | f 85/207/41 84/208/41 87/209/41 589 | f 32/212/42 20/211/42 28/210/42 590 | f 20/211/42 32/212/42 44/213/42 591 | f 76/216/43 33/215/43 74/214/43 592 | f 33/215/43 76/216/43 35/217/43 593 | f 35/217/43 76/216/43 45/218/43 594 | f 1/221/18 86/220/18 88/219/18 595 | f 86/220/18 1/221/18 2/222/18 596 | f 86/220/18 2/222/18 90/223/18 597 | f 90/223/18 2/222/18 64/224/18 598 | f 64/224/18 2/222/18 59/225/18 599 | f 87/228/44 1/227/44 88/226/44 600 | f 1/227/44 87/228/44 3/229/44 601 | f 89/232/45 70/231/45 84/230/45 602 | f 70/231/45 89/232/45 72/233/45 603 | f 12/236/46 41/235/46 13/234/46 604 | f 41/235/46 12/236/46 43/237/46 605 | f 77/240/47 85/239/47 78/238/47 606 | f 85/239/47 77/240/47 89/241/47 607 | f 89/241/47 77/240/47 27/242/47 608 | f 89/241/47 27/242/47 18/243/47 609 | f 71/246/48 33/245/48 80/244/48 610 | f 33/245/48 71/246/48 74/247/48 611 | f 61/250/18 29/249/18 30/248/18 612 | f 29/249/18 61/250/18 60/251/18 613 | f 7/254/49 14/253/49 36/252/49 614 | f 14/253/49 7/254/49 9/255/49 615 | f 14/253/49 9/255/49 82/256/49 616 | f 80/259/50 87/258/50 84/257/50 617 | f 87/258/50 80/259/50 3/260/50 618 | f 48/263/51 83/262/51 49/261/51 619 | f 83/262/51 48/263/51 54/264/51 620 | f 83/262/51 54/264/51 16/265/51 621 | f 16/265/51 54/264/51 17/266/51 622 | f 17/266/51 54/264/51 55/267/51 623 | f 79/270/52 86/269/52 90/268/52 624 | f 86/269/52 79/270/52 85/271/52 625 | f 85/271/52 79/270/52 78/272/52 626 | f 24/275/53 82/274/53 9/273/53 627 | f 82/274/53 24/275/53 47/276/53 628 | f 20/279/54 25/278/54 28/277/54 629 | f 25/278/54 20/279/54 18/280/54 630 | f 82/283/55 16/282/55 14/281/55 631 | f 16/282/55 82/283/55 83/284/55 632 | f 58/287/56 81/286/56 33/285/56 633 | f 81/286/56 58/287/56 57/288/56 634 | f 73/291/57 89/290/57 18/289/57 635 | f 89/290/57 73/291/57 72/292/57 636 | f 52/295/58 6/294/58 63/293/58 637 | f 45/296/58 63/293/58 6/294/58 638 | f 45/296/58 69/297/58 63/293/58 639 | f 45/296/58 37/298/58 69/297/58 640 | f 37/298/58 45/296/58 39/299/58 641 | f 45/296/58 6/294/58 7/300/58 642 | f 18/303/59 75/302/59 73/301/59 643 | f 75/302/59 18/303/59 19/304/59 644 | f 75/302/59 19/304/59 39/305/59 645 | f 62/308/60 90/307/60 64/306/60 646 | f 90/307/60 62/308/60 68/309/60 647 | f 79/310/60 90/307/60 68/309/60 648 | 649 | g leg 650 | 651 | v 0.02018873 -4.22995E-18 -0.2804412 652 | v 0.1534428 0.1379548 -0.3161466 653 | v -0.0003234446 0.04343766 -0.3120238 654 | v 0.1022155 0.1495938 -0.3394991 655 | v -0.1385343 0.05049495 -0.1446901 656 | v -0.1629215 0.1447198 -0.1381555 657 | v -0.09854957 0.08229352 -0.1183251 658 | v -0.1360815 0.2273056 -0.1082685 659 | v -0.1873087 0.2389446 -0.131621 660 | v 0.06468366 0.2946059 -0.3294424 661 | v 0.1046684 0.3264045 -0.3030775 662 | v -0.07538723 0.3334618 -0.2919106 663 | v -0.07736001 0.3768994 -0.2543031 664 | v -0.1206817 0.307922 -0.1494737 665 | v -0.143987 0.307922 -0.2364505 666 | v -0.05405466 0.3768994 -0.1673263 667 | v 0.04349409 1.341783E-09 -0.1934644 668 | v 0.1767482 0.1379548 -0.2291698 669 | v -0.1862269 0.1447198 -0.2251323 670 | v -0.2106141 0.2389446 -0.2185978 671 | v -0.2509578 0.1845412 -0.2077877 672 | v -0.219278 0.3069429 -0.2162763 673 | v -0.223166 0.2129751 -0.1335043 674 | v -0.2062046 0.278509 -0.1380491 675 | v -0.1959726 0.3069429 -0.1292996 676 | v -0.2237644 0.278509 -0.203583 677 | v -0.2276525 0.1845412 -0.1208109 678 | v -0.2407258 0.2129751 -0.1990382 679 | v 0.04152133 0.04343766 -0.155857 680 | v 0.1440603 0.1495938 -0.1833323 681 | v -0.1403943 0.08229352 -0.274492 682 | v -0.1779262 0.2273055 -0.2644353 683 | v -0.03354246 0.3334618 -0.1357438 684 | v -0.1618397 0.05049495 -0.2316669 685 | v 0.1279738 0.3264045 -0.2161007 686 | v 0.1065284 0.2946059 -0.1732756 687 | v -0.4388398 0.2296975 -0.1378492 688 | v -0.3907667 0.2632632 -0.1507304 689 | v -0.4603205 0.2626714 -0.1320934 690 | v -0.4122474 0.296237 -0.1449746 691 | v -0.3777194 0.3136739 -0.1542263 692 | v -0.4376689 0.3501902 -0.1381629 693 | v -0.403141 0.3676271 -0.1474147 694 | v -0.3642119 0.3136739 -0.1038157 695 | v -0.3772592 0.2632632 -0.1003197 696 | v -0.4253323 0.2296976 -0.08743853 697 | v -0.446813 0.2626714 -0.08168278 698 | v -0.3987399 0.296237 -0.09456394 699 | v -0.4241615 0.3501902 -0.08775225 700 | v -0.3896335 0.3676271 -0.097004 701 | 702 | vn 0.3547407 -0.6246369 -1.089501 703 | vn -0.5755832 -0.228633 1.148676 704 | vn -0.02776965 0.8532698 -0.9870078 705 | vn -0.8913316 0.9227743 0.2388316 706 | vn 0.8913316 -0.9227743 -0.2388316 707 | vn -0.3377588 0 -1.260533 708 | vn -1.217582 0.3377588 0.32625 709 | vn 0.8519651 -0.6246369 0.7661653 710 | vn -0.3547407 0.6246369 1.089501 711 | vn -1.072808 -0.228633 -0.7069907 712 | vn 1.217582 0.3377588 -0.32625 713 | vn -0.32625 -1.260533 0.08741842 714 | vn 0.3377588 0 1.260533 715 | vn -0.6439288 -1.121878 0.1725402 716 | vn -0.4694546 -0.8532698 -0.8686586 717 | vn 1.072808 0.228633 0.7069907 718 | vn 0.32625 1.260533 -0.08741842 719 | vn 0.4694546 0.8532698 0.8686586 720 | vn 0.02776965 -0.8532698 0.9870078 721 | vn -0.8519651 0.6246369 -0.7661653 722 | vn 0.5755832 0.228633 -1.148676 723 | vn -1.217582 -0.3377588 0.32625 724 | vn -0.0158332 1.304897 0.004242492 725 | vn 0.2682099 1.275117 -0.07186662 726 | vn 0.2797058 0.01599883 1.274572 727 | vn -0.3835577 -1.243119 0.102774 728 | vn 1.13293 0.5721375 -0.3035676 729 | vn -0.3950535 0.0159988 -1.243664 730 | vn -1.045067 -0.7296885 0.2800249 731 | vn -0.7048249 1.081933 0.1888573 732 | vn -1.13293 -0.5721375 0.3035676 733 | vn -0.5526424 1.172895 0.1480801 734 | vn 0.7048249 -1.081933 -0.1888573 735 | 736 | vt -3.869872 1.980028 737 | vt -7.358948 6.720208 738 | vt -2.986462 3.472564 739 | vt -5.671307 7.120132 740 | vt 0.7630825 1.69934 741 | vt 0.1936281 4.586632 742 | vt 2.197878 2.67373 743 | vt 1.321487 7.117274 744 | vt -0.3758263 7.473926 745 | vt -6.418823 4.086717 746 | vt -7.602262 5.354607 747 | vt -2.162902 5.635999 748 | vt -2.0715 7.367969 749 | vt 1.358268 6.831572 750 | vt -1.358268 6.831572 751 | vt 1.358268 9.774485 752 | vt -1.358268 9.774485 753 | vt -1.358268 3.888658 754 | vt -1.358268 9.774485 755 | vt 1.358268 3.888658 756 | vt 1.358268 9.774485 757 | vt 0.9475608 4.366 758 | vt 1.709243 7.208636 759 | vt 2.969295 5.567358 760 | vt 1.979841 9.260051 761 | vt -0.3717111 9.28959 762 | vt 1.023406 5.497218 763 | vt 1.023406 7.544029 764 | vt 1.358268 8.432101 765 | vt -1.358268 8.432101 766 | vt -1.023406 7.544029 767 | vt -1.358268 4.609145 768 | vt 1.358268 4.609145 769 | vt -1.023406 5.497218 770 | vt 3.869872 1.980028 771 | vt 2.986462 3.472564 772 | vt 7.358948 6.720208 773 | vt 5.671307 7.120132 774 | vt -5.148258 1.310455 775 | vt -8.350846 4.513043 776 | vt -0.773441 2.482684 777 | vt 0.3987877 6.857501 778 | vt -7.178617 8.88786 779 | vt -2.803801 10.06009 780 | vt 0.9951879 4.938269 781 | vt -0.6924538 5.338192 782 | vt 3.680032 8.585837 783 | vt 1.052084 7.708282 784 | vt 2.796622 10.07837 785 | vt -0.7630824 1.699339 786 | vt -2.197877 2.67373 787 | vt -0.1936281 4.586632 788 | vt -1.321487 7.117274 789 | vt 0.3758262 7.473926 790 | vt -1.358268 1.519566 791 | vt -1.358268 7.405393 792 | vt 1.358268 1.519566 793 | vt 1.358268 7.405393 794 | vt -1.358268 0.5738207 795 | vt 1.358268 0.5738209 796 | vt -1.358267 -5.312006 797 | vt 1.358268 -5.312006 798 | vt -0.9475608 4.366 799 | vt -2.969295 5.567358 800 | vt -1.709243 7.208636 801 | vt -1.979841 9.260051 802 | vt 0.3717111 9.28959 803 | vt 1.358268 5.396655 804 | vt 1.358268 3.044917 805 | vt -1.358268 5.396655 806 | vt -1.358268 3.044917 807 | vt -5.664443 0.03136122 808 | vt -5.573042 1.763331 809 | vt -0.1336809 2.044723 810 | vt -1.31712 3.312613 811 | vt 6.321003 2.795516 812 | vt 4.62369 3.152167 813 | vt 5.182095 8.570102 814 | vt 3.747299 7.595711 815 | vt -1.358268 0.5738209 816 | vt 1.358268 0.5738207 817 | vt -1.358268 -5.312006 818 | vt 1.358267 -5.312006 819 | vt 6.418823 4.086717 820 | vt 2.162902 5.635998 821 | vt 7.602262 5.354606 822 | vt 2.0715 7.367968 823 | vt 5.148258 1.310455 824 | vt 0.773441 2.482684 825 | vt 8.350846 4.513043 826 | vt -0.3987877 6.857501 827 | vt 7.178617 8.88786 828 | vt 2.803801 10.06009 829 | vt 5.664443 0.03136138 830 | vt 0.133681 2.044723 831 | vt 5.573042 1.763331 832 | vt 1.31712 3.312613 833 | vt -0.9951879 4.938269 834 | vt -3.680032 8.585837 835 | vt 0.6924538 5.338192 836 | vt -1.052084 7.708282 837 | vt -2.796622 10.07837 838 | vt -6.321003 2.795516 839 | vt -5.182094 8.570102 840 | vt -4.62369 3.152167 841 | vt -3.747299 7.595711 842 | vt 1.358268 1.519566 843 | vt -1.358268 1.519566 844 | vt 1.358268 4.462479 845 | vt -1.358268 4.462479 846 | vt -1.358265 -1.863374 847 | vt -1.358268 0.488364 848 | vt 1.35827 -1.86337 849 | vt 1.358267 0.4883673 850 | vt 8.990396 6.929664 851 | vt 7.488934 7.942294 852 | vt 9.661302 7.924438 853 | vt 8.15984 8.937069 854 | vt 7.081431 9.463116 855 | vt 8.953828 10.56476 856 | vt 7.87542 11.09081 857 | vt -0.7872345 8.93279 858 | vt 0.7872356 8.93279 859 | vt -1.023405 3.946878 860 | vt 1.023406 3.946878 861 | vt -2.689748 6.410617 862 | vt -7.445069 7.927855 863 | vt -2.160549 8.387834 864 | vt -7.037993 9.448791 865 | vt -0.7872354 9.550522 866 | vt 0.7872347 9.550522 867 | vt -1.023406 4.56461 868 | vt 1.023405 4.56461 869 | vt -8.990396 6.929664 870 | vt -9.661302 7.924438 871 | vt -7.488934 7.942294 872 | vt -8.15984 8.937069 873 | vt -7.081431 9.463116 874 | vt -8.953828 10.56476 875 | vt -7.87542 11.09081 876 | vt -0.787235 11.60981 877 | vt -0.7872349 13.42083 878 | vt 0.7872352 11.60981 879 | vt 0.7872352 13.42083 880 | vt 2.689748 6.410617 881 | vt 2.160549 8.387834 882 | vt 7.445069 7.927855 883 | vt 7.037993 9.448791 884 | vt 0.787235 10.77212 885 | vt -0.7872352 10.77212 886 | vt 0.787235 11.972 887 | vt -0.7872352 11.972 888 | vt 0.7872353 -3.578937 889 | vt -0.7872349 -3.578937 890 | vt 0.7872352 -1.767914 891 | vt -0.787235 -1.767914 892 | vt 0.787235 11.60981 893 | vt -0.7872352 11.60981 894 | vt 0.7872349 13.42083 895 | vt -0.7872352 13.42083 896 | vt -0.7872348 -3.415637 897 | vt -0.7872349 -2.215766 898 | vt 0.7872353 -3.415637 899 | vt 0.7872352 -2.215766 900 | vt -0.7872353 -3.578937 901 | vt -0.7872352 -1.767914 902 | vt 0.7872349 -3.578937 903 | vt 0.787235 -1.767914 904 | 905 | usemtl brownDark 906 | 907 | f 93/313/61 92/312/61 91/311/61 908 | f 92/312/61 93/313/61 94/314/61 909 | f 97/317/62 96/316/62 95/315/62 910 | f 96/316/62 97/317/62 98/318/62 911 | f 96/316/62 98/318/62 99/319/62 912 | f 102/322/63 101/321/63 100/320/63 913 | f 101/321/63 102/322/63 103/323/63 914 | f 106/326/64 105/325/64 104/324/64 915 | f 105/325/64 106/326/64 103/327/64 916 | f 91/330/65 108/329/65 107/328/65 917 | f 108/329/65 91/330/65 92/331/65 918 | f 111/334/66 110/333/66 109/332/66 919 | f 110/333/66 111/334/66 112/335/66 920 | f 110/333/66 112/335/66 105/336/66 921 | f 115/339/67 114/338/67 113/337/67 922 | f 114/338/67 115/339/67 112/340/67 923 | f 114/338/67 112/340/67 116/341/67 924 | f 116/341/67 112/340/67 111/342/67 925 | f 117/343/67 113/337/67 111/342/67 926 | f 113/337/67 117/343/67 115/339/67 927 | f 111/342/67 113/337/67 118/344/67 928 | f 111/342/67 118/344/67 116/341/67 929 | f 108/347/68 119/346/68 107/345/68 930 | f 119/346/68 108/347/68 120/348/68 931 | f 121/351/66 94/350/66 93/349/66 932 | f 94/350/66 121/351/66 122/352/66 933 | f 94/350/66 122/352/66 100/353/66 934 | f 100/353/66 122/352/66 102/354/66 935 | f 123/357/69 99/356/69 98/355/69 936 | f 99/356/69 123/357/69 104/358/69 937 | f 104/358/69 123/357/69 106/359/69 938 | f 109/362/70 121/361/70 124/360/70 939 | f 121/361/70 109/362/70 122/363/70 940 | f 122/363/70 109/362/70 110/364/70 941 | f 92/367/71 125/366/71 108/365/71 942 | f 125/366/71 92/367/71 101/368/71 943 | f 91/371/72 95/370/72 124/369/72 944 | f 95/370/72 91/371/72 107/372/72 945 | f 99/375/73 117/374/73 96/373/73 946 | f 117/374/73 99/375/73 115/376/73 947 | f 115/376/73 99/375/73 104/377/73 948 | f 111/380/74 96/379/74 117/378/74 949 | f 96/379/74 111/380/74 109/381/74 950 | f 124/384/75 93/383/75 91/382/75 951 | f 93/383/75 124/384/75 121/385/75 952 | f 125/388/76 120/387/76 108/386/76 953 | f 120/387/76 125/388/76 126/389/76 954 | f 125/392/77 103/391/77 106/390/77 955 | f 103/391/77 125/392/77 101/393/77 956 | f 125/396/78 123/395/78 126/394/78 957 | f 123/395/78 125/396/78 106/397/78 958 | f 120/400/73 97/399/73 119/398/73 959 | f 97/399/73 120/400/73 98/401/73 960 | f 98/401/73 120/400/73 126/402/73 961 | f 98/401/73 126/402/73 123/403/73 962 | f 119/406/79 95/405/79 107/404/79 963 | f 95/405/79 119/406/79 97/407/79 964 | f 110/410/80 102/409/80 122/408/80 965 | f 102/409/80 110/410/80 105/411/80 966 | f 102/409/80 105/411/80 103/412/80 967 | f 94/415/81 101/414/81 92/413/81 968 | f 101/414/81 94/415/81 100/416/81 969 | f 96/419/82 124/418/82 95/417/82 970 | f 124/418/82 96/419/82 109/420/82 971 | f 115/423/83 105/422/83 112/421/83 972 | f 105/422/83 115/423/83 104/424/83 973 | 974 | usemtl brownLight 975 | 976 | f 129/427/66 128/426/66 127/425/66 977 | f 128/426/66 129/427/66 130/428/66 978 | f 128/426/66 130/428/66 131/429/66 979 | f 131/429/66 130/428/66 132/430/66 980 | f 131/429/66 132/430/66 133/431/66 981 | f 114/434/84 131/433/84 134/432/84 982 | f 131/433/84 114/434/84 116/435/84 983 | f 114/438/85 135/437/85 113/436/85 984 | f 135/437/85 114/438/85 134/439/85 985 | f 118/442/86 135/441/86 128/440/86 986 | f 135/441/86 118/442/86 113/443/86 987 | f 135/446/73 137/445/73 136/444/73 988 | f 137/445/73 135/446/73 138/447/73 989 | f 138/447/73 135/446/73 134/448/73 990 | f 138/447/73 134/448/73 139/449/73 991 | f 139/449/73 134/448/73 140/450/73 992 | f 131/453/87 140/452/87 134/451/87 993 | f 140/452/87 131/453/87 133/454/87 994 | f 128/457/88 116/456/88 118/455/88 995 | f 116/456/88 128/457/88 131/458/88 996 | f 137/461/89 127/460/89 136/459/89 997 | f 127/460/89 137/461/89 129/462/89 998 | f 138/465/90 129/464/90 137/463/90 999 | f 129/464/90 138/465/90 130/466/90 1000 | f 139/469/91 130/468/91 138/467/91 1001 | f 130/468/91 139/469/91 132/470/91 1002 | f 139/473/92 133/472/92 132/471/92 1003 | f 133/472/92 139/473/92 140/474/92 1004 | f 127/477/93 135/476/93 136/475/93 1005 | f 135/476/93 127/477/93 128/478/93 1006 | 1007 | g leg 1008 | 1009 | v 0.04349409 1.341783E-09 0.1934645 1010 | v 0.1767482 0.1379548 0.2291698 1011 | v 0.04152131 0.04343766 0.155857 1012 | v 0.1440603 0.1495938 0.1833323 1013 | v -0.1618397 0.05049495 0.2316669 1014 | v -0.1862269 0.1447198 0.2251323 1015 | v -0.1403943 0.08229352 0.274492 1016 | v -0.1779262 0.2273056 0.2644353 1017 | v -0.2106141 0.2389446 0.2185978 1018 | v 0.1065284 0.2946059 0.1732756 1019 | v 0.1279738 0.3264045 0.2161007 1020 | v -0.03354246 0.3334618 0.1357437 1021 | v -0.05405466 0.3768994 0.1673263 1022 | v -0.143987 0.307922 0.2364505 1023 | v -0.1206817 0.307922 0.1494737 1024 | v -0.07736001 0.3768994 0.2543031 1025 | v 0.02018873 2.683566E-09 0.2804412 1026 | v 0.1534428 0.1379548 0.3161466 1027 | v -0.1629215 0.1447198 0.1381555 1028 | v -0.1873087 0.2389446 0.131621 1029 | v -0.2276525 0.1845412 0.1208109 1030 | v -0.1959726 0.3069429 0.1292995 1031 | v -0.2407258 0.2129751 0.1990382 1032 | v -0.2237644 0.278509 0.203583 1033 | v -0.219278 0.3069429 0.2162763 1034 | v -0.2062046 0.278509 0.1380491 1035 | v -0.2509578 0.1845412 0.2077877 1036 | v -0.223166 0.2129751 0.1335043 1037 | v -0.0003234595 0.04343766 0.3120238 1038 | v 0.1022155 0.1495938 0.3394991 1039 | v -0.09854957 0.08229352 0.1183251 1040 | v -0.1360815 0.2273055 0.1082685 1041 | v -0.07538723 0.3334618 0.2919106 1042 | v -0.1385343 0.05049495 0.1446901 1043 | v 0.1046684 0.3264045 0.3030775 1044 | v 0.06468368 0.2946059 0.3294424 1045 | v -0.4253323 0.2296975 0.08743853 1046 | v -0.3772592 0.2632632 0.1003197 1047 | v -0.446813 0.2626714 0.08168278 1048 | v -0.3987399 0.296237 0.09456393 1049 | v -0.3642119 0.3136739 0.1038157 1050 | v -0.4241615 0.3501902 0.08775225 1051 | v -0.3896335 0.3676271 0.097004 1052 | v -0.3777194 0.3136739 0.1542263 1053 | v -0.3907667 0.2632632 0.1507303 1054 | v -0.4388398 0.2296976 0.1378492 1055 | v -0.4603205 0.2626714 0.1320934 1056 | v -0.4122474 0.296237 0.1449746 1057 | v -0.4376689 0.3501902 0.1381629 1058 | v -0.403141 0.3676271 0.1474147 1059 | 1060 | vn 0.8519651 -0.6246369 -0.7661653 1061 | vn -1.072808 -0.228633 0.7069907 1062 | vn 0.4694546 0.8532698 -0.8686586 1063 | vn -0.8913316 0.9227743 -0.2388316 1064 | vn 0.8913316 -0.9227743 0.2388316 1065 | vn 0.3377588 0 -1.260533 1066 | vn -1.217582 0.3377588 -0.32625 1067 | vn 0.3547407 -0.6246369 1.089501 1068 | vn -0.8519651 0.6246369 0.7661653 1069 | vn -0.5755832 -0.228633 -1.148676 1070 | vn 1.217582 0.3377588 0.32625 1071 | vn -0.32625 -1.260533 -0.08741842 1072 | vn -0.3377588 0 1.260533 1073 | vn -0.6439288 -1.121878 -0.1725402 1074 | vn 0.02776965 -0.8532698 -0.9870078 1075 | vn 0.5755832 0.228633 1.148676 1076 | vn 0.32625 1.260533 0.08741842 1077 | vn -0.02776965 0.8532698 0.9870078 1078 | vn -0.4694546 -0.8532698 0.8686586 1079 | vn -0.3547407 0.6246369 -1.089501 1080 | vn 1.072808 0.228633 -0.7069907 1081 | vn -1.217582 -0.3377588 -0.32625 1082 | vn -0.0158332 1.304897 -0.004242492 1083 | vn 0.2682099 1.275117 0.07186662 1084 | vn -0.3950535 0.01599883 1.243664 1085 | vn -0.3835577 -1.243119 -0.102774 1086 | vn 1.13293 0.5721375 0.3035676 1087 | vn 0.2797058 0.0159988 -1.274572 1088 | vn -1.045067 -0.7296885 -0.2800249 1089 | vn -0.7048249 1.081933 -0.1888573 1090 | vn -1.13293 -0.5721375 -0.3035676 1091 | vn -0.5526424 1.172895 -0.1480801 1092 | vn 0.7048249 -1.081933 0.1888573 1093 | 1094 | 1095 | usemtl brownDark 1096 | 1097 | f 143/313/94 142/312/94 141/311/94 1098 | f 142/312/94 143/313/94 144/314/94 1099 | f 147/317/95 146/316/95 145/315/95 1100 | f 146/316/95 147/317/95 148/318/95 1101 | f 146/316/95 148/318/95 149/319/95 1102 | f 152/322/96 151/321/96 150/320/96 1103 | f 151/321/96 152/322/96 153/323/96 1104 | f 156/326/97 155/325/97 154/324/97 1105 | f 155/325/97 156/326/97 153/327/97 1106 | f 141/330/98 158/329/98 157/328/98 1107 | f 158/329/98 141/330/98 142/331/98 1108 | f 161/334/99 160/333/99 159/332/99 1109 | f 160/333/99 161/334/99 162/335/99 1110 | f 160/333/99 162/335/99 155/336/99 1111 | f 165/339/100 164/338/100 163/337/100 1112 | f 164/338/100 165/339/100 162/340/100 1113 | f 164/338/100 162/340/100 166/341/100 1114 | f 166/341/100 162/340/100 161/342/100 1115 | f 167/343/100 163/337/100 161/342/100 1116 | f 163/337/100 167/343/100 165/339/100 1117 | f 161/342/100 163/337/100 168/344/100 1118 | f 161/342/100 168/344/100 166/341/100 1119 | f 158/347/101 169/346/101 157/345/101 1120 | f 169/346/101 158/347/101 170/348/101 1121 | f 171/351/99 144/350/99 143/349/99 1122 | f 144/350/99 171/351/99 172/352/99 1123 | f 144/350/99 172/352/99 150/353/99 1124 | f 150/353/99 172/352/99 152/354/99 1125 | f 173/357/102 149/356/102 148/355/102 1126 | f 149/356/102 173/357/102 154/358/102 1127 | f 154/358/102 173/357/102 156/359/102 1128 | f 159/362/103 171/361/103 174/360/103 1129 | f 171/361/103 159/362/103 172/363/103 1130 | f 172/363/103 159/362/103 160/364/103 1131 | f 142/367/104 175/366/104 158/365/104 1132 | f 175/366/104 142/367/104 151/368/104 1133 | f 141/371/105 145/370/105 174/369/105 1134 | f 145/370/105 141/371/105 157/372/105 1135 | f 149/375/106 167/374/106 146/373/106 1136 | f 167/374/106 149/375/106 165/376/106 1137 | f 165/376/106 149/375/106 154/377/106 1138 | f 161/380/107 146/379/107 167/378/107 1139 | f 146/379/107 161/380/107 159/381/107 1140 | f 174/384/108 143/383/108 141/382/108 1141 | f 143/383/108 174/384/108 171/385/108 1142 | f 175/388/109 170/387/109 158/386/109 1143 | f 170/387/109 175/388/109 176/389/109 1144 | f 175/392/110 153/391/110 156/390/110 1145 | f 153/391/110 175/392/110 151/393/110 1146 | f 175/396/111 173/395/111 176/394/111 1147 | f 173/395/111 175/396/111 156/397/111 1148 | f 170/400/106 147/399/106 169/398/106 1149 | f 147/399/106 170/400/106 148/401/106 1150 | f 148/401/106 170/400/106 176/402/106 1151 | f 148/401/106 176/402/106 173/403/106 1152 | f 169/406/112 145/405/112 157/404/112 1153 | f 145/405/112 169/406/112 147/407/112 1154 | f 160/410/113 152/409/113 172/408/113 1155 | f 152/409/113 160/410/113 155/411/113 1156 | f 152/409/113 155/411/113 153/412/113 1157 | f 144/415/114 151/414/114 142/413/114 1158 | f 151/414/114 144/415/114 150/416/114 1159 | f 146/419/115 174/418/115 145/417/115 1160 | f 174/418/115 146/419/115 159/420/115 1161 | f 165/423/116 155/422/116 162/421/116 1162 | f 155/422/116 165/423/116 154/424/116 1163 | 1164 | usemtl brownLight 1165 | 1166 | f 179/427/99 178/426/99 177/425/99 1167 | f 178/426/99 179/427/99 180/428/99 1168 | f 178/426/99 180/428/99 181/429/99 1169 | f 181/429/99 180/428/99 182/430/99 1170 | f 181/429/99 182/430/99 183/431/99 1171 | f 164/434/117 181/433/117 184/432/117 1172 | f 181/433/117 164/434/117 166/435/117 1173 | f 164/438/118 185/437/118 163/436/118 1174 | f 185/437/118 164/438/118 184/439/118 1175 | f 168/442/119 185/441/119 178/440/119 1176 | f 185/441/119 168/442/119 163/443/119 1177 | f 185/446/106 187/445/106 186/444/106 1178 | f 187/445/106 185/446/106 188/447/106 1179 | f 188/447/106 185/446/106 184/448/106 1180 | f 188/447/106 184/448/106 189/449/106 1181 | f 189/449/106 184/448/106 190/450/106 1182 | f 181/453/120 190/452/120 184/451/120 1183 | f 190/452/120 181/453/120 183/454/120 1184 | f 178/457/121 166/456/121 168/455/121 1185 | f 166/456/121 178/457/121 181/458/121 1186 | f 187/461/122 177/460/122 186/459/122 1187 | f 177/460/122 187/461/122 179/462/122 1188 | f 188/465/123 179/464/123 187/463/123 1189 | f 179/464/123 188/465/123 180/466/123 1190 | f 189/469/124 180/468/124 188/467/124 1191 | f 180/468/124 189/469/124 182/470/124 1192 | f 190/474/125 182/471/125 189/473/125 1193 | f 182/471/125 190/474/125 183/472/125 1194 | f 177/477/126 185/476/126 186/475/126 1195 | f 185/476/126 177/477/126 178/478/126 1196 | 1197 | -------------------------------------------------------------------------------- /src/camera.rs: -------------------------------------------------------------------------------- 1 | use cgmath::{Angle, InnerSpace, Rad, Vector3}; 2 | #[repr(C)] 3 | #[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)] 4 | pub struct Uniform { 5 | view_position: [f32; 4], 6 | view_proj: [[f32; 4]; 4], 7 | } 8 | 9 | impl Uniform { 10 | fn new() -> Self { 11 | // needed to access ::identity() 12 | use cgmath::SquareMatrix; 13 | Self { 14 | view_position: [0.0; 4], 15 | view_proj: cgmath::Matrix4::identity().into(), 16 | } 17 | } 18 | 19 | pub fn update(&mut self, eye: &cgmath::Point3, view_proj: cgmath::Matrix4) { 20 | // We don't specifically need homogeneous coordinates since we're just using 21 | // a vec3 in the shader. We're using Point3 for the camera.eye, and this is 22 | // the easiest way to convert to Vector4. We're using Vector4 because of 23 | // the uniforms 16 byte spacing requirement 24 | self.view_position = eye.to_homogeneous().into(); 25 | self.view_proj = view_proj.into(); 26 | } 27 | } 28 | 29 | #[rustfmt::skip] 30 | pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( 31 | 1.0, 0.0, 0.0, 0.0, 32 | 0.0, 1.0, 0.0, 0.0, 33 | 0.0, 0.0, 0.5, 0.0, 34 | 0.0, 0.0, 0.5, 1.0, 35 | ); 36 | 37 | pub struct Camera { 38 | pub position: cgmath::Point3, 39 | pub yaw: Rad, 40 | pub pitch: Rad, 41 | pub aspect: f32, 42 | pub fovy: f32, 43 | pub z_near: f32, 44 | pub z_far: f32, 45 | pub uniform: Uniform, 46 | } 47 | 48 | impl Camera { 49 | pub fn new(aspect: f32) -> Self { 50 | Self { 51 | position: (0., 1., 2.).into(), 52 | yaw: Rad::(-90f32), 53 | pitch: Rad::(-20f32), 54 | aspect, 55 | fovy: 45.0, 56 | z_near: 0.1, 57 | z_far: 500.0, 58 | uniform: Uniform::new(), 59 | } 60 | } 61 | 62 | pub fn update_uniform(&mut self) { 63 | self.uniform 64 | .update(&self.position, self.build_view_projection_matrix()); 65 | } 66 | 67 | pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4 { 68 | let view = cgmath::Matrix4::look_to_rh( 69 | self.position, 70 | Vector3::new(self.yaw.0.cos(), self.pitch.0.sin(), self.yaw.sin()).normalize(), 71 | Vector3::unit_y(), 72 | ); 73 | let proj = 74 | cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.z_near, self.z_far); 75 | OPENGL_TO_WGPU_MATRIX * proj * view 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/camera_controller.rs: -------------------------------------------------------------------------------- 1 | use std::{f32::consts::FRAC_PI_2, time::Duration}; 2 | 3 | use cgmath::{InnerSpace, Rad, Vector3}; 4 | use winit::{ 5 | dpi::PhysicalPosition, 6 | event::{ElementState, MouseScrollDelta, VirtualKeyCode}, 7 | }; 8 | 9 | use crate::camera::Camera; 10 | 11 | #[derive(Debug)] 12 | pub struct CameraController { 13 | amount_left: f32, 14 | amount_right: f32, 15 | amount_forward: f32, 16 | amount_backward: f32, 17 | amount_up: f32, 18 | amount_down: f32, 19 | rotate_horizontal: f32, 20 | rotate_vertical: f32, 21 | scroll: f32, 22 | speed: f32, 23 | sensitivity: f32, 24 | } 25 | 26 | impl CameraController { 27 | pub fn new(speed: f32, sensitivity: f32) -> Self { 28 | Self { 29 | amount_left: 0.0, 30 | amount_right: 0.0, 31 | amount_forward: 0.0, 32 | amount_backward: 0.0, 33 | amount_up: 0.0, 34 | amount_down: 0.0, 35 | rotate_horizontal: 0.0, 36 | rotate_vertical: 0.0, 37 | scroll: 0.0, 38 | speed, 39 | sensitivity, 40 | } 41 | } 42 | 43 | pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool { 44 | let amount = if state == ElementState::Pressed { 45 | 1.0 46 | } else { 47 | 0.0 48 | }; 49 | match key { 50 | VirtualKeyCode::W | VirtualKeyCode::Up => { 51 | self.amount_forward = amount; 52 | true 53 | } 54 | VirtualKeyCode::S | VirtualKeyCode::Down => { 55 | self.amount_backward = amount; 56 | true 57 | } 58 | VirtualKeyCode::A | VirtualKeyCode::Left => { 59 | self.amount_left = amount; 60 | true 61 | } 62 | VirtualKeyCode::D | VirtualKeyCode::Right => { 63 | self.amount_right = amount; 64 | true 65 | } 66 | VirtualKeyCode::Space => { 67 | self.amount_up = amount; 68 | true 69 | } 70 | VirtualKeyCode::LShift => { 71 | self.amount_down = amount; 72 | true 73 | } 74 | _ => false, 75 | } 76 | } 77 | 78 | pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { 79 | self.rotate_horizontal = mouse_dx as f32; 80 | self.rotate_vertical = mouse_dy as f32; 81 | } 82 | 83 | pub fn process_scroll(&mut self, delta: &MouseScrollDelta) { 84 | self.scroll = -match delta { 85 | // I'm assuming a line is about 100 pixels 86 | MouseScrollDelta::LineDelta(_, scroll) => scroll * 100.0, 87 | MouseScrollDelta::PixelDelta(PhysicalPosition { y: scroll, .. }) => *scroll as f32, 88 | }; 89 | } 90 | 91 | pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) { 92 | let dt = dt.as_secs_f32(); 93 | 94 | // Move forward/backward and left/right 95 | let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); 96 | let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); 97 | let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); 98 | camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt; 99 | camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt; 100 | 101 | // Move in/out (aka. "zoom") 102 | // Note: this isn't an actual zoom. The camera's position 103 | // changes when zooming. I've added this to make it easier 104 | // to get closer to an object you want to focus on. 105 | let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos(); 106 | let scrollward = 107 | Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize(); 108 | camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt; 109 | self.scroll = 0.0; 110 | 111 | // Move up/down. Since we don't use roll, we can just 112 | // modify the y coordinate directly. 113 | camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; 114 | 115 | // Rotate 116 | camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; 117 | camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt; 118 | 119 | // If process_mouse isn't called every frame, these values 120 | // will not get set to zero, and the camera will rotate 121 | // when moving in a non cardinal direction. 122 | self.rotate_horizontal = 0.0; 123 | self.rotate_vertical = 0.0; 124 | 125 | // Keep the camera's angle from going too high/low. 126 | if camera.pitch < -Rad(FRAC_PI_2) { 127 | camera.pitch = -Rad(FRAC_PI_2); 128 | } else if camera.pitch > Rad(FRAC_PI_2) { 129 | camera.pitch = Rad(FRAC_PI_2); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/color.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] 3 | pub struct Color(pub [u8; 4]); 4 | 5 | impl Into<[f32; 4]> for Color { 6 | fn into(self) -> [f32; 4] { 7 | [ 8 | self.0[0] as f32 / 255., 9 | self.0[1] as f32 / 255., 10 | self.0[2] as f32 / 255., 11 | self.0[3] as f32 / 255., 12 | ] 13 | } 14 | } 15 | 16 | impl Into<[u8; 4]> for Color { 17 | fn into(self) -> [u8; 4] { 18 | self.0 19 | } 20 | } 21 | 22 | impl Into<[f32; 3]> for Color { 23 | fn into(self) -> [f32; 3] { 24 | [ 25 | self.0[0] as f32 / 255., 26 | self.0[1] as f32 / 255., 27 | self.0[2] as f32 / 255., 28 | ] 29 | } 30 | } 31 | 32 | impl From<[u8; 3]> for Color { 33 | fn from(rgb: [u8; 3]) -> Self { 34 | Color([rgb[0], rgb[1], rgb[2], 255u8]) 35 | } 36 | } 37 | 38 | impl From<[f32; 3]> for Color { 39 | fn from(rgb: [f32; 3]) -> Self { 40 | Color::new(rgb[0], rgb[1], rgb[2], 1f32) 41 | } 42 | } 43 | 44 | impl Color { 45 | pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color { 46 | Color([ 47 | (r.min(1.).max(0.) * 255.) as u8, 48 | (g.min(1.).max(0.) * 255.) as u8, 49 | (b.min(1.).max(0.) * 255.) as u8, 50 | (a.min(1.).max(0.) * 255.) as u8, 51 | ]) 52 | } 53 | } 54 | 55 | #[allow(dead_code)] 56 | pub mod colors { 57 | use super::Color; 58 | pub const LIGHTGRAY: Color = Color([200, 200, 200, 255]); 59 | pub const GRAY: Color = Color([130, 130, 130, 255]); 60 | pub const DARKGRAY: Color = Color([80, 80, 80, 255]); 61 | pub const YELLOW: Color = Color([253, 249, 0, 255]); 62 | pub const GOLD: Color = Color([255, 203, 0, 255]); 63 | pub const ORANGE: Color = Color([255, 161, 0, 255]); 64 | pub const PINK: Color = Color([255, 109, 194, 255]); 65 | pub const RED: Color = Color([230, 41, 55, 255]); 66 | pub const MAROON: Color = Color([190, 33, 55, 255]); 67 | pub const GREEN: Color = Color([0, 228, 48, 255]); 68 | pub const LIME: Color = Color([0, 158, 47, 255]); 69 | pub const DARKGREEN: Color = Color([0, 117, 44, 255]); 70 | pub const SKYBLUE: Color = Color([102, 191, 255, 255]); 71 | pub const BLUE: Color = Color([0, 121, 241, 255]); 72 | pub const DARKBLUE: Color = Color([0, 82, 172, 255]); 73 | pub const PURPLE: Color = Color([200, 122, 255, 255]); 74 | pub const VIOLET: Color = Color([135, 60, 190, 255]); 75 | pub const DARKPURPLE: Color = Color([112, 31, 126, 255]); 76 | pub const BEIGE: Color = Color([211, 176, 131, 255]); 77 | pub const BROWN: Color = Color([127, 106, 79, 255]); 78 | pub const DARKBROWN: Color = Color([76, 63, 47, 255]); 79 | pub const WHITE: Color = Color([255, 255, 255, 255]); 80 | pub const BLACK: Color = Color([0, 0, 0, 255]); 81 | pub const BLANK: Color = Color([0, 0, 0, 0]); 82 | pub const MAGENTA: Color = Color([255, 0, 255, 255]); 83 | } 84 | -------------------------------------------------------------------------------- /src/depth_pass.rs: -------------------------------------------------------------------------------- 1 | use wgpu::util::DeviceExt; 2 | 3 | use crate::{model::ModelVertex, rendering::vertex_desc::VertexDesc, texture::Texture, Vertex}; 4 | 5 | pub struct DepthPass { 6 | pipeline: wgpu::RenderPipeline, 7 | bind_group_layout: wgpu::BindGroupLayout, 8 | bind_group: wgpu::BindGroup, 9 | pub texture: Texture, 10 | index_buffer: wgpu::Buffer, 11 | vertex_buffer: wgpu::Buffer, 12 | num_indices: u32, 13 | } 14 | 15 | pub const DEPTH_VERTICES: &[Vertex] = &[ 16 | Vertex { 17 | position: [0.0, 0.0, 0.0], 18 | tex_coords: [0.0, 1.0], 19 | }, 20 | Vertex { 21 | position: [1.0, 0.0, 0.0], 22 | tex_coords: [1.0, 1.0], 23 | }, 24 | Vertex { 25 | position: [1.0, 1.0, 0.0], 26 | tex_coords: [1.0, 0.0], 27 | }, 28 | Vertex { 29 | position: [0.0, 1.0, 0.0], 30 | tex_coords: [0.0, 0.0], 31 | }, 32 | ]; 33 | 34 | pub const DEPTH_INDICES: &[u16] = &[0, 1, 2, 0, 2, 3]; 35 | 36 | impl DepthPass { 37 | pub fn new(device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self { 38 | let texture = Texture::create_depth_texture(&device, &sc_desc, "depth_texture"); 39 | let shader_module = crate::rendering::render_utils::create_shader_module( 40 | device, 41 | include_str!("depth_pass.wgsl"), 42 | "depth pass", 43 | ); 44 | 45 | let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 46 | label: Some("depth_pass.bind_group_layout"), 47 | entries: &[ 48 | wgpu::BindGroupLayoutEntry { 49 | binding: 0, 50 | visibility: wgpu::ShaderStage::FRAGMENT, 51 | ty: wgpu::BindingType::Texture { 52 | sample_type: wgpu::TextureSampleType::Depth, 53 | view_dimension: wgpu::TextureViewDimension::D2, 54 | multisampled: false, 55 | }, 56 | count: None, 57 | }, 58 | wgpu::BindGroupLayoutEntry { 59 | binding: 1, 60 | visibility: wgpu::ShaderStage::FRAGMENT, 61 | ty: wgpu::BindingType::Sampler { 62 | filtering: true, 63 | comparison: true, 64 | }, 65 | count: None, 66 | }, 67 | ], 68 | }); 69 | 70 | let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 71 | label: Some("depth_pass.bind_group"), 72 | layout: &bind_group_layout, 73 | entries: &[ 74 | wgpu::BindGroupEntry { 75 | binding: 0, 76 | resource: wgpu::BindingResource::TextureView(&texture.view), 77 | }, 78 | wgpu::BindGroupEntry { 79 | binding: 1, 80 | resource: wgpu::BindingResource::Sampler(&texture.sampler), 81 | }, 82 | ], 83 | }); 84 | 85 | let depth_pipeline_layout = 86 | device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 87 | label: Some("depth_pass.layout"), 88 | bind_group_layouts: &[&bind_group_layout], 89 | push_constant_ranges: &[], 90 | }); 91 | 92 | let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { 93 | label: Some("depth_pass.pipeline"), 94 | layout: Some(&depth_pipeline_layout), 95 | vertex: wgpu::VertexState { 96 | module: &shader_module, 97 | entry_point: "vs_main", 98 | buffers: &[ModelVertex::desc()], 99 | }, 100 | primitive: wgpu::PrimitiveState { 101 | topology: wgpu::PrimitiveTopology::TriangleList, 102 | strip_index_format: None, 103 | front_face: wgpu::FrontFace::Ccw, 104 | cull_mode: Some(wgpu::Face::Back), 105 | clamp_depth: false, 106 | polygon_mode: wgpu::PolygonMode::Fill, 107 | conservative: false, 108 | }, 109 | depth_stencil: None, 110 | multisample: wgpu::MultisampleState { 111 | count: 1, 112 | mask: !0, 113 | alpha_to_coverage_enabled: false, 114 | }, 115 | fragment: Some(wgpu::FragmentState { 116 | module: &shader_module, 117 | entry_point: "fs_main", 118 | targets: &[wgpu::ColorTargetState { 119 | format: sc_desc.format, 120 | blend: Some(wgpu::BlendState::REPLACE), 121 | write_mask: wgpu::ColorWrite::ALL, 122 | }], 123 | }), 124 | }); 125 | 126 | let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 127 | label: Some("depth_pass.vertex_buffer"), 128 | contents: bytemuck::cast_slice(DEPTH_VERTICES), 129 | usage: wgpu::BufferUsage::VERTEX, 130 | }); 131 | let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 132 | label: Some("depth_pass.index_buffer"), 133 | contents: bytemuck::cast_slice(DEPTH_INDICES), 134 | usage: wgpu::BufferUsage::INDEX, 135 | }); 136 | let num_indices = DEPTH_INDICES.len() as u32; 137 | 138 | Self { 139 | pipeline, 140 | texture, 141 | bind_group, 142 | bind_group_layout, 143 | vertex_buffer, 144 | index_buffer, 145 | num_indices, 146 | } 147 | } 148 | 149 | pub fn resize(&mut self, device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) { 150 | self.texture = Texture::create_depth_texture(device, sc_desc, "depth_texture"); 151 | self.bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 152 | label: Some("depth_pass.bind_group"), 153 | layout: &self.bind_group_layout, 154 | entries: &[ 155 | wgpu::BindGroupEntry { 156 | binding: 0, 157 | resource: wgpu::BindingResource::TextureView(&self.texture.view), 158 | }, 159 | wgpu::BindGroupEntry { 160 | binding: 1, 161 | resource: wgpu::BindingResource::Sampler(&self.texture.sampler), 162 | }, 163 | ], 164 | }); 165 | } 166 | 167 | pub fn render(&self, frame: &wgpu::SwapChainTexture, encoder: &mut wgpu::CommandEncoder) { 168 | let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 169 | label: Some("render_pass.depth_visual"), 170 | color_attachments: &[wgpu::RenderPassColorAttachment { 171 | view: &frame.view, 172 | resolve_target: None, 173 | ops: wgpu::Operations { 174 | load: wgpu::LoadOp::Load, 175 | store: true, 176 | }, 177 | }], 178 | depth_stencil_attachment: None, 179 | }); 180 | render_pass.set_pipeline(&self.pipeline); 181 | render_pass.set_bind_group(0, &self.bind_group, &[]); 182 | render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); 183 | render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); 184 | render_pass.draw_indexed(0..self.num_indices, 0, 0..1); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/depth_pass.wgsl: -------------------------------------------------------------------------------- 1 | struct VertexOutput { 2 | [[builtin(position)]] builtin_position: vec4; 3 | [[location(0)]] tex_coords: vec2; 4 | }; 5 | 6 | [[stage(vertex)]] 7 | fn vs_main( 8 | [[location(0)]] position: vec3, 9 | [[location(1)]] tex_coords: vec2, 10 | ) -> VertexOutput { 11 | var out: VertexOutput; 12 | out.tex_coords = tex_coords; 13 | out.builtin_position = vec4(position, 1.0); 14 | return out; 15 | } 16 | 17 | [[group(0), binding(0)]] 18 | var t_depth: texture_depth_2d; 19 | 20 | [[group(0), binding(1)]] 21 | var s_depth: sampler_comparison; 22 | 23 | [[stage(fragment), early_depth_test]] 24 | fn fs_main( 25 | in: VertexOutput, 26 | ) -> [[location(0)]] vec4 { 27 | let near = 0.1; 28 | let far = 100.0; 29 | let depth = textureSampleCompare(t_depth, s_depth, in.tex_coords, 1.0); 30 | let r = (2.0 * near * far) / (far + near - depth * (far - near)); 31 | return vec4(vec3(r), 1.0); 32 | } -------------------------------------------------------------------------------- /src/light.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] 3 | pub struct Light { 4 | pub position: [f32; 3], 5 | // due to uniforms requireing 16 byte (4 float) spacing, we need to use a padding field here 6 | pub _padding: u32, 7 | pub color: [f32; 3], 8 | } 9 | 10 | pub fn create_light_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { 11 | device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 12 | label: Some("light_bind_group_layout"), 13 | entries: &[wgpu::BindGroupLayoutEntry { 14 | binding: 0, 15 | visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, 16 | ty: wgpu::BindingType::Buffer { 17 | ty: wgpu::BufferBindingType::Uniform, 18 | has_dynamic_offset: false, 19 | min_binding_size: None, 20 | }, 21 | count: None, 22 | }], 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /src/light.wgsl: -------------------------------------------------------------------------------- 1 | [[block]] 2 | struct CameraUniform { 3 | position: vec3; 4 | projection_view: mat4x4; 5 | }; 6 | 7 | [[group(0), binding(0)]] 8 | var u_camera: CameraUniform; 9 | 10 | struct VertexOutput { 11 | [[builtin(position)]] builtin_position: vec4; 12 | [[location(0)]] color: vec2; 13 | }; 14 | 15 | 16 | [[block]] 17 | struct LightUniform { 18 | position: vec3; 19 | color: vec3; 20 | }; 21 | 22 | [[group(1), binding(0)]] 23 | var u_light: LightUniform; 24 | 25 | [[stage(vertex)]] 26 | fn vs_main( 27 | [[location(0)]] position: vec3, 28 | [[location(1)]] tex_coords: vec2, 29 | [[location(2)]] normal: vec3, 30 | [[location(3)]] diffuse_color: vec3, 31 | ) -> VertexOutput { 32 | var out: VertexOutput; 33 | let scale = 0.25; 34 | let scaled_position = position * scale + u_light.position; 35 | out.builtin_position = u_camera.projection_view * vec4(scaled_position, 1.0); 36 | return out; 37 | } 38 | 39 | [[stage(fragment), early_depth_test]] 40 | fn fs_main( 41 | in: VertexOutput, 42 | ) -> [[location(0)]] vec4 { 43 | return vec4(u_light.color, 1.0); 44 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use camera::Camera; 2 | use camera_controller::*; 3 | use cgmath::{InnerSpace, Zero}; 4 | use futures::executor::block_on; 5 | use model::Model; 6 | use rendering::gpu_resources::GpuResources; 7 | use voxel_tools::chunks::Chunks; 8 | use wgpu::util::DeviceExt; 9 | use winit::{ 10 | event::*, 11 | event_loop::{ControlFlow, EventLoop}, 12 | window::{Window, WindowBuilder}, 13 | }; 14 | 15 | use crate::{ 16 | depth_pass::DepthPass, 17 | light::Light, 18 | rendering::{ 19 | render_utils::create_render_pipeline, vertex_desc::VertexDesc, vertex_instance::*, 20 | }, 21 | voxel_tools::{ 22 | rendering::voxel_pipeline::create_voxel_pipeline, 23 | }, 24 | }; 25 | 26 | mod camera; 27 | mod camera_controller; 28 | mod color; 29 | mod depth_pass; 30 | mod light; 31 | mod model; 32 | mod rendering; 33 | mod texture; 34 | mod voxel_tools; 35 | 36 | #[repr(C)] 37 | #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] 38 | pub struct Vertex { 39 | pub position: [f32; 3], 40 | //color: [f32; 3], 41 | pub tex_coords: [f32; 2], 42 | } 43 | 44 | pub const NUM_INSTANCES_PER_ROW: u32 = 100; 45 | pub const NUM_INSTANCES: u32 = NUM_INSTANCES_PER_ROW * NUM_INSTANCES_PER_ROW; 46 | pub const INSTANCE_DISPLACEMENT: cgmath::Vector3 = cgmath::Vector3::new( 47 | NUM_INSTANCES_PER_ROW as f32 * 0.5f32, 48 | 0.0, 49 | NUM_INSTANCES_PER_ROW as f32 * 0.5f32, 50 | ); 51 | 52 | struct State { 53 | gpu_resources: GpuResources, 54 | instance_buffer: wgpu::Buffer, 55 | rotation: f32, 56 | surface: wgpu::Surface, 57 | device: wgpu::Device, 58 | queue: wgpu::Queue, 59 | sc_desc: wgpu::SwapChainDescriptor, 60 | swap_chain: wgpu::SwapChain, 61 | render_pipeline: wgpu::RenderPipeline, 62 | size: winit::dpi::PhysicalSize, 63 | clear_color: wgpu::Color, 64 | camera_uniform_buffer: wgpu::Buffer, 65 | camera_bind_group: wgpu::BindGroup, 66 | camera: Camera, 67 | camera_controller: CameraController, 68 | depth_pass: depth_pass::DepthPass, 69 | obj_model: Model, 70 | 71 | light_render_pipeline: wgpu::RenderPipeline, 72 | light_bind_group: wgpu::BindGroup, 73 | light: Light, 74 | light_buffer: wgpu::Buffer, 75 | 76 | voxel_render_pipeline: wgpu::RenderPipeline, 77 | mouse_pressed: bool, 78 | 79 | chunks: Chunks, 80 | } 81 | 82 | impl State { 83 | async fn new(window: &Window) -> Self { 84 | let size = window.inner_size(); 85 | 86 | // handler for our gpu 87 | let instance = wgpu::Instance::new(wgpu::BackendBit::DX12); 88 | let surface = unsafe { instance.create_surface(window) }; 89 | let adapter = instance 90 | .request_adapter(&wgpu::RequestAdapterOptions { 91 | power_preference: wgpu::PowerPreference::default(), 92 | compatible_surface: Some(&surface), 93 | }) 94 | .await 95 | .unwrap(); 96 | let (device, queue) = adapter 97 | .request_device( 98 | &wgpu::DeviceDescriptor { 99 | //features: wgpu::Features::empty(), 100 | features: wgpu::Features::NON_FILL_POLYGON_MODE, 101 | limits: wgpu::Limits::default(), 102 | label: None, 103 | }, 104 | None, // trace path 105 | ) 106 | .await 107 | .unwrap(); 108 | let sc_desc = wgpu::SwapChainDescriptor { 109 | usage: wgpu::TextureUsage::RENDER_ATTACHMENT, 110 | format: adapter 111 | .get_swap_chain_preferred_format(&surface) 112 | .unwrap_or(wgpu::TextureFormat::Rgba8UnormSrgb), 113 | width: size.width, 114 | height: size.height, 115 | present_mode: wgpu::PresentMode::Fifo, 116 | }; 117 | let swap_chain = device.create_swap_chain(&surface, &sc_desc); 118 | 119 | let texture_bind_group_layout = 120 | device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 121 | entries: &[ 122 | wgpu::BindGroupLayoutEntry { 123 | binding: 0, 124 | visibility: wgpu::ShaderStage::FRAGMENT, 125 | ty: wgpu::BindingType::Texture { 126 | multisampled: false, 127 | view_dimension: wgpu::TextureViewDimension::D2, 128 | sample_type: wgpu::TextureSampleType::Float { filterable: false }, 129 | }, 130 | count: None, 131 | }, 132 | wgpu::BindGroupLayoutEntry { 133 | binding: 1, 134 | visibility: wgpu::ShaderStage::FRAGMENT, 135 | ty: wgpu::BindingType::Sampler { 136 | comparison: false, 137 | filtering: true, 138 | }, 139 | count: None, 140 | }, 141 | ], 142 | label: Some("texture_bind_group_layout"), 143 | }); 144 | 145 | let light = Light { 146 | position: [50.0, 2.0, 50.0], 147 | _padding: 0, 148 | color: [1.0, 1.0, 1.0], 149 | }; 150 | 151 | let light_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 152 | label: Some("light buffer"), 153 | contents: bytemuck::cast_slice(&[light]), 154 | usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, 155 | }); 156 | 157 | let light_bind_group_layout = light::create_light_bind_group_layout(&device); 158 | 159 | let light_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 160 | label: Some("light bind group"), 161 | layout: &light_bind_group_layout, 162 | entries: &[wgpu::BindGroupEntry { 163 | binding: 0, 164 | resource: light_buffer.as_entire_binding(), 165 | }], 166 | }); 167 | 168 | let clear_color = wgpu::Color { 169 | r: 0.1, 170 | g: 0.2, 171 | b: 0.3, 172 | a: 1.0, 173 | }; 174 | let aspect = sc_desc.width as f32 / sc_desc.height as f32; 175 | let mut camera = Camera::new(aspect); 176 | 177 | let offset = 8f32; 178 | let instances = (0..NUM_INSTANCES_PER_ROW) 179 | .flat_map(|z| { 180 | (0..NUM_INSTANCES_PER_ROW).map(move |x| { 181 | let position = cgmath::Vector3::new(x as f32 * offset, 0f32, z as f32 * offset) 182 | - INSTANCE_DISPLACEMENT; 183 | let rotation = if position.is_zero() { 184 | cgmath::Quaternion::from_axis_angle( 185 | cgmath::Vector3::unit_z(), 186 | cgmath::Deg(0.0), 187 | ) 188 | } else { 189 | cgmath::Quaternion::from_axis_angle( 190 | position.clone().normalize(), 191 | cgmath::Deg(45.0), 192 | ) 193 | }; 194 | //let rotation = cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(), cgmath::Deg(0.0)); 195 | VertexInstance { position, rotation } 196 | }) 197 | }) 198 | .collect::>(); 199 | use cgmath::Rotation3; 200 | 201 | let instance_data = instances 202 | .iter() 203 | .map(VertexInstance::to_raw) 204 | .collect::>(); 205 | let instance_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 206 | label: Some("instance_buffer"), 207 | contents: bytemuck::cast_slice(&instance_data), 208 | usage: wgpu::BufferUsage::VERTEX, 209 | }); 210 | 211 | camera.update_uniform(); 212 | let camera_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 213 | label: Some("uniform buffer"), 214 | contents: bytemuck::cast_slice(&[camera.uniform]), 215 | usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, 216 | }); 217 | 218 | let camera_bind_group_layout = 219 | device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 220 | label: Some("uniform_bind_group_layout"), 221 | entries: &[wgpu::BindGroupLayoutEntry { 222 | binding: 0, 223 | visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, 224 | ty: wgpu::BindingType::Buffer { 225 | ty: wgpu::BufferBindingType::Uniform, 226 | has_dynamic_offset: false, 227 | min_binding_size: None, 228 | }, 229 | count: None, 230 | }], 231 | }); 232 | 233 | let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 234 | layout: &camera_bind_group_layout, 235 | entries: &[wgpu::BindGroupEntry { 236 | binding: 0, 237 | resource: camera_uniform_buffer.as_entire_binding(), 238 | }], 239 | label: Some("uniform_bind_group"), 240 | }); 241 | 242 | let shader_flags = wgpu::ShaderFlags::empty(); 243 | use std::borrow::Cow; 244 | let shader_module = device.create_shader_module(&wgpu::ShaderModuleDescriptor { 245 | label: Some("shader"), 246 | source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))), 247 | flags: shader_flags, 248 | }); 249 | 250 | let render_pipeline_layout = 251 | device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 252 | label: Some("Render Pipeline Layout"), 253 | bind_group_layouts: &[ 254 | &camera_bind_group_layout, 255 | &texture_bind_group_layout, 256 | &light_bind_group_layout, 257 | ], 258 | push_constant_ranges: &[], 259 | }); 260 | 261 | println!("creating pipeline"); 262 | let render_pipeline = create_render_pipeline( 263 | &device, 264 | &render_pipeline_layout, 265 | sc_desc.format, 266 | Some(texture::Texture::DEPTH_FORMAT), 267 | &[model::ModelVertex::desc(), VertexInstanceRaw::desc()], 268 | shader_module, 269 | "render_pipeline", 270 | ); 271 | 272 | let shader_module = device.create_shader_module(&wgpu::ShaderModuleDescriptor { 273 | label: Some("light-shader"), 274 | source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("light.wgsl"))), 275 | flags: shader_flags, 276 | }); 277 | 278 | let light_render_pipeline = { 279 | let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 280 | label: Some("light_pipeline_layout"), 281 | bind_group_layouts: &[&camera_bind_group_layout, &light_bind_group_layout], 282 | push_constant_ranges: &[], 283 | }); 284 | create_render_pipeline( 285 | &device, 286 | &layout, 287 | sc_desc.format, 288 | Some(texture::Texture::DEPTH_FORMAT), 289 | &[model::ModelVertex::desc()], 290 | shader_module, 291 | "light_render_pipeline", 292 | ) 293 | }; 294 | 295 | let camera_controller = CameraController::new(10.2, 1.0); 296 | let depth_pass = DepthPass::new(&device, &sc_desc); 297 | 298 | let obj_model = model::Model::load( 299 | &device, 300 | &queue, 301 | &texture_bind_group_layout, 302 | std::path::Path::new("res/turkey.obj"), 303 | ) 304 | .unwrap(); 305 | 306 | let voxel_render_pipeline = 307 | create_voxel_pipeline(&device, sc_desc.format, &light_bind_group_layout); 308 | 309 | let mut gpu_resources = GpuResources::new(); 310 | 311 | let mut chunks = Chunks::new(); 312 | // find what chunks needs to be loaded 313 | chunks.update_load_data_queue(); 314 | chunks.update_load_mesh_queue(); 315 | 316 | // load voxel data in chunks 317 | chunks.build_chunk_data_in_queue(); 318 | 319 | // load meshes based on voxel data in chunk 320 | chunks.build_chunk_meshes_in_queue(&device, &mut gpu_resources); 321 | 322 | Self { 323 | gpu_resources, 324 | chunks, 325 | rotation: 0f32, 326 | surface, 327 | camera, 328 | camera_controller, 329 | camera_uniform_buffer, 330 | camera_bind_group: uniform_bind_group, 331 | device, 332 | queue, 333 | depth_pass, 334 | sc_desc, 335 | swap_chain, 336 | size, 337 | clear_color, 338 | render_pipeline, 339 | instance_buffer, 340 | obj_model, 341 | light_bind_group, 342 | light, 343 | light_buffer, 344 | light_render_pipeline, 345 | voxel_render_pipeline, 346 | mouse_pressed: false, 347 | } 348 | } 349 | 350 | fn resize(&mut self, new_size: winit::dpi::PhysicalSize) { 351 | self.size = new_size; 352 | self.sc_desc.width = new_size.width; 353 | self.sc_desc.height = new_size.height; 354 | self.camera.aspect = new_size.width as f32 / new_size.height as f32; 355 | self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc); 356 | self.depth_pass.resize(&self.device, &self.sc_desc); 357 | } 358 | 359 | fn input(&mut self, event: &DeviceEvent) -> bool { 360 | match event { 361 | DeviceEvent::MouseMotion { delta } => { 362 | if self.mouse_pressed { 363 | self.camera_controller.process_mouse(delta.0, delta.1); 364 | } 365 | true 366 | } 367 | DeviceEvent::MouseWheel { delta } => { 368 | self.camera_controller.process_scroll(delta); 369 | true 370 | } 371 | DeviceEvent::Button { button: 1, state } => { 372 | self.mouse_pressed = *state == ElementState::Pressed; 373 | true 374 | } 375 | DeviceEvent::Key(KeyboardInput { 376 | virtual_keycode: Some(key), 377 | state, 378 | .. 379 | }) => self.camera_controller.process_keyboard(*key, *state), 380 | _ => false, 381 | } 382 | } 383 | 384 | fn update(&mut self, dt: std::time::Duration) { 385 | use cgmath::Rotation3; 386 | let old_position: cgmath::Vector3<_> = self.light.position.into(); 387 | self.light.position = 388 | (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) 389 | * old_position) 390 | .into(); 391 | self.queue 392 | .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light])); 393 | 394 | self.camera_controller.update_camera(&mut self.camera, dt); 395 | self.camera.update_uniform(); 396 | self.rotation += 3f32; 397 | self.queue.write_buffer( 398 | &self.camera_uniform_buffer, 399 | 0, 400 | bytemuck::cast_slice(&[self.camera.uniform]), 401 | ); 402 | 403 | self.chunks.position = ( 404 | self.camera.position.x, 405 | self.camera.position.y, 406 | self.camera.position.z, 407 | ) 408 | .into(); 409 | 410 | use rand::*; 411 | if rand::thread_rng().gen_range(0..5) == 0 { 412 | self.chunks.update_load_data_queue(); 413 | self.chunks.update_load_mesh_queue(); 414 | 415 | self.chunks.update_unload_mesh_queue(); 416 | self.chunks.update_unload_data_queue(); 417 | } 418 | self.chunks 419 | .build_chunk_data_in_queue(); 420 | self.chunks 421 | .build_chunk_meshes_in_queue(&self.device, &mut self.gpu_resources); 422 | self.chunks.unload_data_queue(); 423 | self.chunks.unload_mesh_queue(&mut self.gpu_resources); 424 | } 425 | 426 | fn render(&mut self) -> Result<(), wgpu::SwapChainError> { 427 | let frame = self.swap_chain.get_current_frame()?.output; 428 | let mut encoder = self 429 | .device 430 | .create_command_encoder(&wgpu::CommandEncoderDescriptor { 431 | label: Some("Render encoder"), 432 | }); 433 | 434 | let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 435 | label: Some("main render pass"), 436 | color_attachments: &[wgpu::RenderPassColorAttachment { 437 | //attachment: &frame.view, 438 | view: &frame.view, 439 | resolve_target: None, 440 | ops: wgpu::Operations { 441 | load: wgpu::LoadOp::Clear(self.clear_color), 442 | store: true, 443 | }, 444 | }], 445 | depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { 446 | view: &self.depth_pass.texture.view, 447 | depth_ops: Some(wgpu::Operations { 448 | load: wgpu::LoadOp::Clear(1.0), 449 | store: true, 450 | }), 451 | stencil_ops: None, 452 | }), 453 | }); 454 | 455 | render_pass.set_pipeline(&self.voxel_render_pipeline); 456 | 457 | let _ = self.chunks.draw( 458 | &mut render_pass, 459 | &self.camera_bind_group, 460 | &self.light_bind_group, 461 | &self.gpu_resources, 462 | ); 463 | 464 | let pipeline = &self.render_pipeline; 465 | use crate::model::DrawLight; 466 | render_pass.set_pipeline(&self.light_render_pipeline); 467 | render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); 468 | render_pass.draw_light_model( 469 | &self.obj_model, 470 | &self.camera_bind_group, 471 | &self.light_bind_group, 472 | ); 473 | 474 | render_pass.set_pipeline(pipeline); 475 | 476 | // encoder.finish needs ownership of encoder, render_pass is not needed any more and holds a ref, so drop it 477 | drop(render_pass); 478 | self.depth_pass.render(&frame, &mut encoder); 479 | self.queue.submit(std::iter::once(encoder.finish())); 480 | Ok(()) 481 | } 482 | } 483 | 484 | fn main() { 485 | env_logger::init(); 486 | let event_loop = EventLoop::new(); 487 | let window = WindowBuilder::new().build(&event_loop).unwrap(); 488 | let mut state = block_on(State::new(&window)); 489 | 490 | let mut last_render_time = std::time::Instant::now(); 491 | event_loop.run(move |event, _, control_flow| match event { 492 | Event::RedrawRequested(_window_id) => { 493 | let now = std::time::Instant::now(); 494 | let dt = now - last_render_time; 495 | last_render_time = now; 496 | state.update(dt); 497 | match state.render() { 498 | Ok(_) => {} 499 | // recreate swap_chain if lost 500 | Err(wgpu::SwapChainError::Lost) => state.resize(state.size), 501 | Err(wgpu::SwapChainError::OutOfMemory) => *control_flow = ControlFlow::Exit, 502 | // all other errors (Outdated, Timeout) should be resolved by the next frame 503 | Err(e) => println!("{:?}", e), 504 | } 505 | } 506 | Event::DeviceEvent { ref event, .. } => { 507 | state.input(event); 508 | } 509 | Event::MainEventsCleared => { 510 | // all events have been handled 511 | window.request_redraw(); 512 | } 513 | Event::WindowEvent { 514 | ref event, 515 | window_id, 516 | } if window_id == window.id() => { 517 | match event { 518 | WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, 519 | WindowEvent::KeyboardInput { input, .. } => match input { 520 | KeyboardInput { 521 | state: ElementState::Pressed, 522 | virtual_keycode: Some(VirtualKeyCode::Escape), 523 | .. 524 | } => *control_flow = ControlFlow::Exit, 525 | _ => {} 526 | }, 527 | WindowEvent::Resized(physical_size) => { 528 | state.resize(*physical_size); 529 | } 530 | WindowEvent::ScaleFactorChanged { new_inner_size, .. } => { 531 | // new_inner_size is &&mut so we have to dereference twice 532 | state.resize(**new_inner_size); 533 | } 534 | _ => {} 535 | } 536 | } 537 | _ => {} 538 | }); 539 | } 540 | -------------------------------------------------------------------------------- /src/model.rs: -------------------------------------------------------------------------------- 1 | use anyhow::*; 2 | use std::{ops::Range, path::Path}; 3 | use tobj::LoadOptions; 4 | use wgpu::util::DeviceExt; 5 | 6 | use crate::{ 7 | color::{self, Color}, 8 | rendering::vertex_desc::VertexDesc, 9 | texture::Texture, 10 | }; 11 | pub trait DrawModel<'a, 'b> 12 | where 13 | 'b: 'a, 14 | { 15 | fn draw_mesh( 16 | &mut self, 17 | mesh: &'b Mesh, 18 | material: &'b Material, 19 | uniform: &'b wgpu::BindGroup, 20 | light: &'b wgpu::BindGroup, 21 | ); 22 | fn draw_mesh_instanced( 23 | &mut self, 24 | mesh: &'b Mesh, 25 | material: &'b Material, 26 | instances: Range, 27 | uniform: &'b wgpu::BindGroup, 28 | light: &'b wgpu::BindGroup, 29 | ); 30 | fn draw_model( 31 | &mut self, 32 | model: &'b Model, 33 | uniform: &'b wgpu::BindGroup, 34 | light: &'b wgpu::BindGroup, 35 | ); 36 | fn draw_model_instanced( 37 | &mut self, 38 | model: &'b Model, 39 | instances: Range, 40 | uniform: &'b wgpu::BindGroup, 41 | light: &'b wgpu::BindGroup, 42 | ); 43 | } 44 | 45 | impl<'a, 'b> DrawModel<'a, 'b> for wgpu::RenderPass<'a> 46 | where 47 | 'b: 'a, 48 | { 49 | fn draw_mesh( 50 | &mut self, 51 | mesh: &'b Mesh, 52 | material: &'b Material, 53 | uniforms: &'b wgpu::BindGroup, 54 | light: &'b wgpu::BindGroup, 55 | ) { 56 | self.draw_mesh_instanced(mesh, material, 0..1, uniforms, light); 57 | } 58 | 59 | fn draw_mesh_instanced( 60 | &mut self, 61 | mesh: &'b Mesh, 62 | material: &'b Material, 63 | instances: Range, 64 | uniforms: &'b wgpu::BindGroup, 65 | light: &'b wgpu::BindGroup, 66 | ) { 67 | self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); 68 | self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); 69 | self.set_bind_group(0, &uniforms, &[]); 70 | self.set_bind_group(1, &material.bind_group, &[]); 71 | self.set_bind_group(2, &light, &[]); 72 | self.draw_indexed(0..mesh.num_indices, 0, instances); 73 | } 74 | 75 | fn draw_model( 76 | &mut self, 77 | model: &'b Model, 78 | uniform: &'b wgpu::BindGroup, 79 | light: &'b wgpu::BindGroup, 80 | ) { 81 | self.draw_model_instanced(model, 0..1, uniform, light); 82 | } 83 | 84 | fn draw_model_instanced( 85 | &mut self, 86 | model: &'b Model, 87 | instances: Range, 88 | uniform: &'b wgpu::BindGroup, 89 | light: &'b wgpu::BindGroup, 90 | ) { 91 | for mesh in model.meshes.iter() { 92 | let material = &model.materials[mesh.material_id]; 93 | self.draw_mesh_instanced(mesh, material, instances.clone(), uniform, light); 94 | } 95 | } 96 | } 97 | 98 | #[repr(C)] 99 | #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] 100 | pub struct ModelVertex { 101 | position: [f32; 3], 102 | tex_coords: [f32; 2], 103 | normal: [f32; 3], 104 | color_diffuse: [f32; 3], 105 | } 106 | 107 | impl VertexDesc for ModelVertex { 108 | fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { 109 | use std::mem; 110 | wgpu::VertexBufferLayout { 111 | array_stride: mem::size_of::() as wgpu::BufferAddress, 112 | step_mode: wgpu::InputStepMode::Vertex, 113 | attributes: &[ 114 | // position 115 | wgpu::VertexAttribute { 116 | format: wgpu::VertexFormat::Float32x3, 117 | offset: 0, 118 | shader_location: 0, 119 | }, 120 | // tex coord 121 | wgpu::VertexAttribute { 122 | format: wgpu::VertexFormat::Float32x2, 123 | offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, 124 | shader_location: 1, 125 | }, 126 | // normal 127 | wgpu::VertexAttribute { 128 | format: wgpu::VertexFormat::Float32x3, 129 | offset: mem::size_of::<[f32; 5]>() as wgpu::BufferAddress, 130 | shader_location: 2, 131 | }, 132 | // diffuse color 133 | wgpu::VertexAttribute { 134 | format: wgpu::VertexFormat::Float32x3, 135 | offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, 136 | shader_location: 3, 137 | }, 138 | ], 139 | } 140 | } 141 | } 142 | 143 | pub struct Material { 144 | pub name: String, 145 | pub diffuse_texture: Texture, 146 | pub diffuse_color: Color, 147 | pub bind_group: wgpu::BindGroup, 148 | } 149 | 150 | pub struct Mesh { 151 | pub name: String, 152 | pub vertex_buffer: wgpu::Buffer, 153 | pub index_buffer: wgpu::Buffer, 154 | pub num_indices: u32, 155 | pub material_id: usize, 156 | } 157 | 158 | pub struct Model { 159 | pub meshes: Vec, 160 | pub materials: Vec, 161 | } 162 | 163 | impl Model { 164 | pub fn load>( 165 | device: &wgpu::Device, 166 | queue: &wgpu::Queue, 167 | layout: &wgpu::BindGroupLayout, 168 | path: P, 169 | ) -> Result { 170 | let (obj_models, obj_materials) = tobj::load_obj( 171 | path.as_ref(), 172 | &LoadOptions { 173 | single_index: true, 174 | triangulate: true, 175 | ..Default::default() 176 | }, 177 | )?; 178 | let obj_materials = obj_materials?; 179 | 180 | // assuming texture files are stored with the obj file 181 | let containing_folder = path.as_ref().parent().context("Directory has no parent")?; 182 | 183 | let mut materials = Vec::new(); 184 | for mat in obj_materials { 185 | println!("mat data: {:?}", mat); 186 | let diffuse_path = mat.diffuse_texture; 187 | // no diffuse texture 188 | let diffuse_texture = if diffuse_path.len() != 0 { 189 | Texture::load(device, queue, containing_folder.join(diffuse_path.clone())).unwrap() 190 | } else { 191 | use color::colors::*; 192 | Texture::from_color(device, queue, WHITE, 128, 128).unwrap() 193 | }; 194 | //} else { 195 | // None 196 | //}; 197 | let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 198 | label: Some(&diffuse_path), 199 | layout: layout, 200 | entries: &[ 201 | wgpu::BindGroupEntry { 202 | binding: 0, 203 | resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), 204 | }, 205 | wgpu::BindGroupEntry { 206 | binding: 1, 207 | resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), 208 | }, 209 | ], 210 | }); 211 | let diffuse_color = Color::from(mat.diffuse); 212 | materials.push(Material { 213 | name: mat.name, 214 | diffuse_texture: diffuse_texture, 215 | bind_group, 216 | diffuse_color: diffuse_color, 217 | }); 218 | } 219 | 220 | let mut meshes = Vec::new(); 221 | for m in obj_models { 222 | let mut vertices = Vec::new(); 223 | println!("mesh indices: {:?}", m.mesh.indices.len()); 224 | println!("mesh postiions: {:?}", m.mesh.positions.len()); 225 | println!("mesh normals: {:?}", m.mesh.normals.len()); 226 | for i in 0..m.mesh.positions.len() / 3 { 227 | vertices.push(ModelVertex { 228 | position: [ 229 | m.mesh.positions[i * 3], 230 | m.mesh.positions[i * 3 + 1], 231 | m.mesh.positions[i * 3 + 2], 232 | ], 233 | tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]], 234 | normal: [ 235 | m.mesh.normals[i * 3], 236 | m.mesh.normals[i * 3 + 1], 237 | m.mesh.normals[i * 3 + 2], 238 | ], 239 | color_diffuse: materials[m.mesh.material_id.unwrap()].diffuse_color.into(), 240 | }); 241 | } 242 | let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 243 | label: Some(&format!("{:?} vertex_buffer", path.as_ref())), 244 | contents: bytemuck::cast_slice(&vertices), 245 | usage: wgpu::BufferUsage::VERTEX, 246 | }); 247 | let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 248 | label: Some(&format!("{:?} index_buffer", path.as_ref())), 249 | contents: bytemuck::cast_slice(&m.mesh.indices), 250 | usage: wgpu::BufferUsage::INDEX, 251 | }); 252 | meshes.push(Mesh { 253 | name: m.name, 254 | vertex_buffer, 255 | index_buffer, 256 | num_indices: m.mesh.indices.len() as u32, 257 | material_id: m.mesh.material_id.unwrap_or(0), 258 | }); 259 | } 260 | Ok(Self { meshes, materials }) 261 | } 262 | } 263 | 264 | pub trait DrawLight<'a, 'b> 265 | where 266 | 'b: 'a, 267 | { 268 | fn draw_light_mesh( 269 | &mut self, 270 | mesh: &'b Mesh, 271 | uniforms: &'b wgpu::BindGroup, 272 | light: &'b wgpu::BindGroup, 273 | ); 274 | fn draw_light_mesh_instanced( 275 | &mut self, 276 | mesh: &'b Mesh, 277 | instances: Range, 278 | uniforms: &'b wgpu::BindGroup, 279 | light: &'b wgpu::BindGroup, 280 | ) where 281 | 'b: 'a; 282 | 283 | fn draw_light_model( 284 | &mut self, 285 | model: &'b Model, 286 | uniforms: &'b wgpu::BindGroup, 287 | light: &'b wgpu::BindGroup, 288 | ); 289 | fn draw_light_model_instanced( 290 | &mut self, 291 | model: &'b Model, 292 | instances: Range, 293 | uniforms: &'b wgpu::BindGroup, 294 | light: &'b wgpu::BindGroup, 295 | ); 296 | } 297 | 298 | impl<'a, 'b> DrawLight<'a, 'b> for wgpu::RenderPass<'a> 299 | where 300 | 'b: 'a, 301 | { 302 | fn draw_light_mesh( 303 | &mut self, 304 | mesh: &'b Mesh, 305 | uniforms: &'b wgpu::BindGroup, 306 | light: &'b wgpu::BindGroup, 307 | ) { 308 | self.draw_light_mesh_instanced(mesh, 0..1, uniforms, light); 309 | } 310 | 311 | fn draw_light_mesh_instanced( 312 | &mut self, 313 | mesh: &'b Mesh, 314 | instances: Range, 315 | uniforms: &'b wgpu::BindGroup, 316 | light: &'b wgpu::BindGroup, 317 | ) { 318 | self.set_vertex_buffer(0, mesh.vertex_buffer.slice(..)); 319 | self.set_index_buffer(mesh.index_buffer.slice(..), wgpu::IndexFormat::Uint32); 320 | self.set_bind_group(0, uniforms, &[]); 321 | self.set_bind_group(1, light, &[]); 322 | self.draw_indexed(0..mesh.num_indices, 0, instances); 323 | } 324 | 325 | fn draw_light_model( 326 | &mut self, 327 | model: &'b Model, 328 | uniforms: &'b wgpu::BindGroup, 329 | light: &'b wgpu::BindGroup, 330 | ) { 331 | self.draw_light_model_instanced(model, 0..1, uniforms, light); 332 | } 333 | fn draw_light_model_instanced( 334 | &mut self, 335 | model: &'b Model, 336 | instances: Range, 337 | uniforms: &'b wgpu::BindGroup, 338 | light: &'b wgpu::BindGroup, 339 | ) { 340 | for mesh in &model.meshes { 341 | self.draw_light_mesh_instanced(mesh, instances.clone(), uniforms, light); 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /src/rendering.rs: -------------------------------------------------------------------------------- 1 | pub mod gpu_resources; 2 | pub mod render_utils; 3 | pub mod vertex_desc; 4 | pub mod vertex_instance; 5 | -------------------------------------------------------------------------------- /src/rendering/gpu_resources.rs: -------------------------------------------------------------------------------- 1 | use generational_arena::*; 2 | pub struct GpuResources { 3 | pub buffer_arena: Arena, 4 | } 5 | 6 | impl GpuResources { 7 | pub fn new() -> Self { 8 | Self { 9 | buffer_arena: Arena::with_capacity(32), 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/rendering/render_utils.rs: -------------------------------------------------------------------------------- 1 | use wgpu::{BindGroupLayout, ShaderModule}; 2 | 3 | pub fn create_render_pipeline( 4 | device: &wgpu::Device, 5 | layout: &wgpu::PipelineLayout, 6 | color_format: wgpu::TextureFormat, 7 | depth_format: Option, 8 | vertex_layouts: &[wgpu::VertexBufferLayout], 9 | shader_module: wgpu::ShaderModule, 10 | label: &str, 11 | ) -> wgpu::RenderPipeline { 12 | let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { 13 | label: Some(label), 14 | layout: Some(layout), 15 | vertex: wgpu::VertexState { 16 | module: &shader_module, 17 | entry_point: "vs_main", 18 | buffers: vertex_layouts, 19 | }, 20 | fragment: Some(wgpu::FragmentState { 21 | module: &shader_module, 22 | entry_point: "fs_main", 23 | targets: &[wgpu::ColorTargetState { 24 | format: color_format, 25 | blend: Some(wgpu::BlendState::REPLACE), 26 | write_mask: wgpu::ColorWrite::ALL, 27 | }], 28 | }), 29 | primitive: wgpu::PrimitiveState { 30 | topology: wgpu::PrimitiveTopology::TriangleList, 31 | strip_index_format: None, 32 | front_face: wgpu::FrontFace::Ccw, 33 | clamp_depth: false, 34 | cull_mode: Some(wgpu::Face::Back), 35 | conservative: false, 36 | // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE 37 | polygon_mode: wgpu::PolygonMode::Fill, 38 | }, 39 | depth_stencil: depth_format.map(|format| wgpu::DepthStencilState { 40 | format: format, 41 | depth_write_enabled: true, 42 | depth_compare: wgpu::CompareFunction::Less, 43 | stencil: wgpu::StencilState::default(), 44 | bias: wgpu::DepthBiasState::default(), 45 | }), 46 | multisample: wgpu::MultisampleState { 47 | count: 1, 48 | mask: !0, 49 | alpha_to_coverage_enabled: false, 50 | }, 51 | }); 52 | render_pipeline 53 | } 54 | 55 | // less params exposed resulting in shorter code 56 | use std::borrow::Cow; 57 | pub fn create_shader_module(device: &wgpu::Device, shader_str: &str, label: &str) -> ShaderModule { 58 | device.create_shader_module(&wgpu::ShaderModuleDescriptor { 59 | label: Some(label), 60 | source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(shader_str)), 61 | flags: wgpu::ShaderFlags::empty(), 62 | }) 63 | } 64 | 65 | // less params exposed resulting in shorter code 66 | pub fn create_bind_group_layout( 67 | device: &wgpu::Device, 68 | label: &str, 69 | binding_location: u32, 70 | visibility: wgpu::ShaderStage, 71 | ) -> BindGroupLayout { 72 | device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 73 | label: Some(label), 74 | entries: &[wgpu::BindGroupLayoutEntry { 75 | binding: binding_location, 76 | visibility, 77 | ty: wgpu::BindingType::Buffer { 78 | ty: wgpu::BufferBindingType::Uniform, 79 | has_dynamic_offset: false, 80 | min_binding_size: None, 81 | }, 82 | count: None, 83 | }], 84 | }) 85 | } 86 | 87 | // less params exposed resulting in shorter code 88 | pub fn create_pipeline_layout( 89 | device: &wgpu::Device, 90 | label: &str, 91 | bind_group_layouts: &[&BindGroupLayout], 92 | ) -> wgpu::PipelineLayout { 93 | device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 94 | label: Some(label), 95 | bind_group_layouts, 96 | push_constant_ranges: &[], 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /src/rendering/vertex_desc.rs: -------------------------------------------------------------------------------- 1 | pub trait VertexDesc { 2 | fn desc<'a>() -> wgpu::VertexBufferLayout<'a>; 3 | } 4 | -------------------------------------------------------------------------------- /src/rendering/vertex_instance.rs: -------------------------------------------------------------------------------- 1 | use super::vertex_desc::VertexDesc; 2 | 3 | #[repr(C)] 4 | #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] 5 | pub struct VertexInstanceRaw { 6 | pub model: [[f32; 4]; 4], 7 | pub normal_matrix: [[f32; 4]; 4], 8 | } 9 | 10 | impl VertexDesc for VertexInstanceRaw { 11 | fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { 12 | use std::mem; 13 | wgpu::VertexBufferLayout { 14 | array_stride: mem::size_of::() as wgpu::BufferAddress, 15 | step_mode: wgpu::InputStepMode::Instance, 16 | attributes: &[ 17 | // model 18 | wgpu::VertexAttribute { 19 | offset: 0, 20 | shader_location: 5, 21 | format: wgpu::VertexFormat::Float32x4, 22 | }, 23 | wgpu::VertexAttribute { 24 | offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, 25 | shader_location: 6, 26 | format: wgpu::VertexFormat::Float32x4, 27 | }, 28 | wgpu::VertexAttribute { 29 | offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, 30 | shader_location: 7, 31 | format: wgpu::VertexFormat::Float32x4, 32 | }, 33 | wgpu::VertexAttribute { 34 | offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress, 35 | shader_location: 8, 36 | format: wgpu::VertexFormat::Float32x4, 37 | }, 38 | // normal matrix 39 | wgpu::VertexAttribute { 40 | offset: mem::size_of::<[f32; 16]>() as wgpu::BufferAddress, 41 | shader_location: 9, 42 | format: wgpu::VertexFormat::Float32x4, 43 | }, 44 | wgpu::VertexAttribute { 45 | offset: mem::size_of::<[f32; 20]>() as wgpu::BufferAddress, 46 | shader_location: 10, 47 | format: wgpu::VertexFormat::Float32x4, 48 | }, 49 | wgpu::VertexAttribute { 50 | offset: mem::size_of::<[f32; 24]>() as wgpu::BufferAddress, 51 | shader_location: 11, 52 | format: wgpu::VertexFormat::Float32x4, 53 | }, 54 | wgpu::VertexAttribute { 55 | offset: mem::size_of::<[f32; 28]>() as wgpu::BufferAddress, 56 | shader_location: 12, 57 | format: wgpu::VertexFormat::Float32x4, 58 | }, 59 | ], 60 | } 61 | } 62 | } 63 | 64 | pub struct VertexInstance { 65 | pub position: cgmath::Vector3, 66 | pub rotation: cgmath::Quaternion, 67 | } 68 | 69 | impl VertexInstance { 70 | pub fn to_raw(&self) -> VertexInstanceRaw { 71 | // needed to make invert() and transpose() available 72 | use cgmath::{Matrix, SquareMatrix}; 73 | let model = 74 | cgmath::Matrix4::from_translation(self.position) * cgmath::Matrix4::from(self.rotation); 75 | let normal_matrix = model 76 | .invert() 77 | .expect("can't inverse model matrix") 78 | .transpose(); 79 | VertexInstanceRaw { 80 | model: model.into(), 81 | normal_matrix: normal_matrix.into(), 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/shader.wgsl: -------------------------------------------------------------------------------- 1 | [[block]] 2 | struct CameraUniform { 3 | position: vec3; 4 | projection_view: mat4x4; 5 | }; 6 | 7 | [[group(0), binding(0)]] 8 | var u_camera: CameraUniform; 9 | 10 | struct VertexOutput { 11 | [[builtin(position)]] builtin_position: vec4; 12 | [[location(0)]] vex_coords: vec2; 13 | [[location(1)]] diffuse_color: vec3; 14 | [[location(2)]] normal: vec3; 15 | [[location(3)]] position: vec3; 16 | }; 17 | 18 | [[stage(vertex)]] 19 | fn vs_main( 20 | [[location(0)]] position: vec3, 21 | [[location(1)]] tex_coords: vec2, 22 | [[location(2)]] normal: vec3, 23 | [[location(3)]] diffuse_color: vec3, 24 | 25 | [[location(5)]] model_matrix_0: vec4, 26 | [[location(6)]] model_matrix_1: vec4, 27 | [[location(7)]] model_matrix_2: vec4, 28 | [[location(8)]] model_matrix_3: vec4, 29 | 30 | [[location(9)]] normal_matrix_0: vec4, 31 | [[location(10)]] normal_matrix_1: vec4, 32 | [[location(11)]] normal_matrix_2: vec4, 33 | [[location(12)]] normal_matrix_3: vec4, 34 | ) -> VertexOutput { 35 | var out: VertexOutput; 36 | let model_matrix = mat4x4(model_matrix_0, model_matrix_1, model_matrix_2, model_matrix_3); 37 | out.vex_coords = tex_coords; 38 | 39 | let normal_matrix = mat3x3(normal_matrix_0.xyz, normal_matrix_1.xyz, normal_matrix_2.xyz); 40 | 41 | //let normal_matrix = transpose(mat3x3(model_matrix.x.xyz, model_matrix.y.xyz, model_matrix.z.xyz)); 42 | //let normal_matrix = mat3x3(u_camera.projection_view.x.xyz, u_camera.projection_view.y.xyz, u_camera.projection_view.z.xyz); 43 | out.normal = normal_matrix * normal; 44 | let model_space = model_matrix * vec4(position, 1.0); 45 | out.position = model_space.xyz; 46 | out.diffuse_color = diffuse_color; 47 | 48 | out.builtin_position = u_camera.projection_view * model_space; 49 | return out; 50 | } 51 | 52 | 53 | [[block]] 54 | struct LightUniform { 55 | position: vec3; 56 | color: vec3; 57 | }; 58 | 59 | [[group(2), binding(0)]] 60 | var u_light: LightUniform; 61 | 62 | [[group(1), binding(0)]] var t_diffuse: texture_2d; 63 | [[group(1), binding(1)]] var s_diffuse: sampler; 64 | 65 | [[stage(fragment), early_depth_test]] 66 | fn fs_main( 67 | in: VertexOutput, 68 | ) -> [[location(0)]] vec4 { 69 | let ambient_strength = 0.01; 70 | let ambient_color = u_light.color * ambient_strength; 71 | 72 | let normal = normalize(in.normal); 73 | let light_dir = normalize(u_light.position - in.position); 74 | let diffuse_strength = max(dot(normal, light_dir), 0.0); 75 | let diffuse_color = u_light.color * diffuse_strength; 76 | 77 | //let view_dir = normalize(u_camera.position - vec3(in.builtin_position.xyz)); 78 | let view_dir = normalize(u_camera.position - in.position); 79 | let half_dir = normalize(view_dir + light_dir); 80 | 81 | let specular_strength = pow(max(dot(normal, half_dir), 0.0), 32.0); 82 | let specular_color = specular_strength * u_light.color; 83 | //let specular_color = 0.0; 84 | 85 | var surface_color: vec4 = textureSample(t_diffuse, s_diffuse, in.vex_coords); 86 | surface_color = surface_color * vec4(in.diffuse_color, 1.0); 87 | 88 | let result = (diffuse_color) * surface_color.xyz; 89 | 90 | return vec4(result, surface_color.a); 91 | //return surface_color * vec4(light_ambient_color, 1.0); 92 | } -------------------------------------------------------------------------------- /src/texture.rs: -------------------------------------------------------------------------------- 1 | use anyhow::*; 2 | use image::GenericImageView; 3 | use std::path::Path; 4 | use wgpu::util::DeviceExt; 5 | 6 | use crate::color::Color; 7 | 8 | pub struct Texture { 9 | pub texture: wgpu::Texture, 10 | pub view: wgpu::TextureView, 11 | pub sampler: wgpu::Sampler, 12 | } 13 | 14 | impl Texture { 15 | #[allow(dead_code)] 16 | pub fn from_bytes_to_image( 17 | device: &wgpu::Device, 18 | queue: &wgpu::Queue, 19 | bytes: &[u8], 20 | label: &str, 21 | ) -> Result { 22 | let img = image::load_from_memory(bytes)?; 23 | Self::from_image(device, queue, &img, Some(label)) 24 | } 25 | 26 | pub fn from_color( 27 | device: &wgpu::Device, 28 | queue: &wgpu::Queue, 29 | color: Color, 30 | width: u32, 31 | height: u32, 32 | ) -> Result { 33 | let mut bytes = Vec::with_capacity((width * height) as usize); 34 | for _y in 0..height { 35 | for _x in 0..width { 36 | let colors: [u8; 4] = color.into(); 37 | bytes.push(colors[0]); 38 | bytes.push(colors[1]); 39 | bytes.push(colors[2]); 40 | bytes.push(colors[3]); 41 | } 42 | } 43 | let bytes: &[u8] = bytes.as_ref(); 44 | Self::from_bytes(device, queue, &bytes, width, height, Some("color texture")) 45 | } 46 | 47 | pub fn from_bytes( 48 | device: &wgpu::Device, 49 | queue: &wgpu::Queue, 50 | bytes: &[u8], 51 | width: u32, 52 | height: u32, 53 | label: Option<&str>, 54 | ) -> Result { 55 | let texture_size = wgpu::Extent3d { 56 | width, 57 | height, 58 | depth_or_array_layers: 1, 59 | }; 60 | 61 | let texture_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 62 | label, 63 | contents: bytes, 64 | usage: wgpu::BufferUsage::COPY_SRC, 65 | }); 66 | 67 | let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor { 68 | label: Some("temp texture encoder"), 69 | }); 70 | 71 | let texture = device.create_texture(&wgpu::TextureDescriptor { 72 | size: texture_size, 73 | mip_level_count: 1, 74 | sample_count: 1, 75 | dimension: wgpu::TextureDimension::D2, 76 | format: wgpu::TextureFormat::Rgba8UnormSrgb, 77 | // sampled: use in shader 78 | // copy dst, we want to copy data to this texture 79 | usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, 80 | label: Some("my texture"), 81 | }); 82 | encoder.copy_buffer_to_texture( 83 | wgpu::ImageCopyBuffer { 84 | buffer: &texture_buffer, 85 | layout: wgpu::ImageDataLayout { 86 | offset: 0, 87 | bytes_per_row: std::num::NonZeroU32::new(4 * width), 88 | rows_per_image: std::num::NonZeroU32::new(height), 89 | }, 90 | }, 91 | wgpu::ImageCopyTexture { 92 | texture: &texture, 93 | mip_level: 0, 94 | origin: wgpu::Origin3d::ZERO, 95 | }, 96 | texture_size, 97 | ); 98 | queue.submit(std::iter::once(encoder.finish())); 99 | let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); 100 | let address_mode = wgpu::AddressMode::ClampToEdge; 101 | let filter_mode = wgpu::FilterMode::Nearest; 102 | let sampler = device.create_sampler(&wgpu::SamplerDescriptor { 103 | address_mode_u: address_mode, 104 | address_mode_v: address_mode, 105 | address_mode_w: address_mode, 106 | mag_filter: filter_mode, 107 | min_filter: filter_mode, 108 | mipmap_filter: filter_mode, 109 | ..Default::default() 110 | }); 111 | Ok(Self { 112 | texture, 113 | view, 114 | sampler, 115 | }) 116 | } 117 | 118 | pub fn from_image( 119 | device: &wgpu::Device, 120 | queue: &wgpu::Queue, 121 | image: &image::DynamicImage, 122 | label: Option<&str>, 123 | ) -> Result { 124 | let diffuse_rgba = image.to_rgba8(); 125 | let dimensions = image.dimensions(); 126 | Self::from_bytes( 127 | device, 128 | queue, 129 | &diffuse_rgba, 130 | dimensions.0, 131 | dimensions.1, 132 | label, 133 | ) 134 | } 135 | 136 | pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; 137 | pub fn create_depth_texture( 138 | device: &wgpu::Device, 139 | sc_desc: &wgpu::SwapChainDescriptor, 140 | label: &str, 141 | ) -> Self { 142 | let size = wgpu::Extent3d { 143 | width: sc_desc.width, 144 | height: sc_desc.height, 145 | depth_or_array_layers: 1, 146 | }; 147 | let desc = wgpu::TextureDescriptor { 148 | label: Some(label), 149 | size, 150 | mip_level_count: 1, 151 | sample_count: 1, 152 | dimension: wgpu::TextureDimension::D2, 153 | format: Self::DEPTH_FORMAT, 154 | usage: wgpu::TextureUsage::RENDER_ATTACHMENT | wgpu::TextureUsage::SAMPLED, 155 | }; 156 | let texture = device.create_texture(&desc); 157 | let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); 158 | let sampler = device.create_sampler(&wgpu::SamplerDescriptor { 159 | address_mode_u: wgpu::AddressMode::ClampToEdge, 160 | address_mode_v: wgpu::AddressMode::ClampToEdge, 161 | address_mode_w: wgpu::AddressMode::ClampToEdge, 162 | mag_filter: wgpu::FilterMode::Linear, 163 | min_filter: wgpu::FilterMode::Linear, 164 | mipmap_filter: wgpu::FilterMode::Nearest, 165 | compare: Some(wgpu::CompareFunction::LessEqual), 166 | lod_min_clamp: -100.0, 167 | lod_max_clamp: 100.0, 168 | ..Default::default() 169 | }); 170 | Self { 171 | texture, 172 | view, 173 | sampler, 174 | } 175 | } 176 | 177 | pub fn load>( 178 | device: &wgpu::Device, 179 | queue: &wgpu::Queue, 180 | path: P, 181 | ) -> Result { 182 | // uuh borrow checker pls... 183 | let path_copy = path.as_ref().to_path_buf(); 184 | let label = path_copy.to_str(); 185 | println!("loading image from: {:?}", label); 186 | let img = image::open(path)?; 187 | Self::from_image(device, queue, &img, label) 188 | //let path_copy = 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/voxel_tools.rs: -------------------------------------------------------------------------------- 1 | pub mod chunk; 2 | pub mod chunks; 3 | pub mod direction; 4 | pub mod mesh_builder; 5 | pub mod quad; 6 | pub mod rendering; 7 | pub mod voxel; 8 | -------------------------------------------------------------------------------- /src/voxel_tools/chunk.rs: -------------------------------------------------------------------------------- 1 | use super::voxel::Voxel; 2 | 3 | // argument-flavor struct 4 | #[derive(Debug, Clone, Copy)] 5 | pub struct LocalCoordinate(pub i32, pub i32, pub i32); 6 | 7 | // dimension size 8 | pub const SIZE: usize = 16; 9 | // chunk size in bits (5 = 32) (4 = 16) 10 | //pub const BIT_SIZE: i32 = 4; 11 | use lazy_static::*; 12 | lazy_static! { 13 | // when SIZE 16, BIT_SIZE is 4 14 | // by shifting 16 << 4 we get 1 15 | // we with this get indexes from the collapsed array 16 | pub static ref BIT_SIZE: i32 = (SIZE as f32).log2() as i32; 17 | } 18 | 19 | pub struct ChunkMesh { 20 | pub vertex_buffer: Option, 21 | pub index_buffer: Option, 22 | pub num_indices: u32, 23 | // debug info 24 | pub num_vertices: u32, 25 | } 26 | 27 | impl ChunkMesh { 28 | pub fn new() -> Self { 29 | Self { 30 | vertex_buffer: None, 31 | index_buffer: None, 32 | num_indices: 0, 33 | num_vertices: 0, 34 | } 35 | } 36 | 37 | pub fn update_vertex_buffers( 38 | &mut self, 39 | vertex_buffer: generational_arena::Index, 40 | index_buffer: generational_arena::Index, 41 | num_indices: u32, 42 | num_vertices: u32, 43 | ) { 44 | self.vertex_buffer = Some(vertex_buffer); 45 | self.index_buffer = Some(index_buffer); 46 | self.num_indices = num_indices; 47 | self.num_vertices = num_vertices; 48 | } 49 | } 50 | 51 | impl lifeguard::Recycleable for ChunkMesh { 52 | fn new() -> Self { 53 | ChunkMesh::new() 54 | } 55 | 56 | fn reset(&mut self) { 57 | self.vertex_buffer = None; 58 | self.index_buffer = None; 59 | self.num_indices = 0u32; 60 | } 61 | } 62 | 63 | pub struct Chunk { 64 | pub voxels: [Voxel; SIZE * SIZE * SIZE], 65 | } 66 | 67 | impl lifeguard::Recycleable for Chunk { 68 | fn new() -> Self { 69 | Chunk::new() 70 | } 71 | 72 | fn reset(&mut self) { 73 | for voxel in self.voxels.iter_mut() { 74 | voxel.set_density_fraciton(0f32); 75 | } 76 | } 77 | } 78 | 79 | impl Chunk { 80 | // convert 3d coordinate to array index 81 | pub fn get_index(coordinate: LocalCoordinate) -> usize { 82 | (coordinate.2 | (coordinate.1 << *BIT_SIZE) | (coordinate.0 << (*BIT_SIZE * 2))) as usize 83 | } 84 | 85 | pub fn get_local_coordinate(index: i32) -> LocalCoordinate { 86 | LocalCoordinate( 87 | (index as f32 / (SIZE * SIZE) as f32) as i32, 88 | ((index as f32 / SIZE as f32) % SIZE as f32) as i32, 89 | (index as f32 % SIZE as f32) as i32, 90 | ) 91 | } 92 | 93 | pub fn get_voxel(&self, coordinate: LocalCoordinate) -> Option<&Voxel> { 94 | let index = Self::get_index(coordinate); 95 | self.get_voxel_from_index(index) 96 | } 97 | 98 | #[allow(dead_code)] 99 | pub fn get_voxel_from_index_mut(&mut self, index: usize) -> Option<&mut Voxel> { 100 | self.voxels.get_mut(index).map_or(None, |v| Some(v)) 101 | } 102 | 103 | pub fn get_voxel_from_index(&self, index: usize) -> Option<&Voxel> { 104 | //self.voxels.get(index).map_or(Voxel::new_empty(), |v| *v) 105 | self.voxels.get(index) 106 | } 107 | 108 | pub fn new() -> Self { 109 | let chunk = Self { 110 | voxels: [Voxel::new_empty(); SIZE * SIZE * SIZE], 111 | }; 112 | chunk 113 | } 114 | 115 | pub fn build_voxel_data(&mut self, chunk_world_pos: &cgmath::Vector3) { 116 | use noise::{NoiseFn, Perlin, Seedable}; 117 | let perlin = Perlin::new(); 118 | perlin.set_seed(484); 119 | for (index, voxel) in self.voxels.iter_mut().enumerate() { 120 | let local_coord = Self::get_local_coordinate(index as i32); 121 | let (l_x, l_y, l_z) = (local_coord.0, local_coord.1, local_coord.2); 122 | 123 | // convert noise to world 124 | let down_scale = 0.027f64; 125 | let x = (chunk_world_pos.x as f64 + l_x as f64) * down_scale; 126 | let y = (chunk_world_pos.y as f64 + l_y as f64) * down_scale; 127 | let z = (chunk_world_pos.z as f64 + l_z as f64) * down_scale; 128 | let density = perlin.get([x, y, z]); 129 | if density > 0.3f64 { 130 | voxel.set_density_fraciton(1f32); 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/voxel_tools/chunks.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Context; 2 | use anyhow::*; 3 | use cgmath::InnerSpace; 4 | use lifeguard::*; 5 | use std::{ 6 | collections::{HashMap, VecDeque}, 7 | }; 8 | 9 | use crate::rendering::gpu_resources::GpuResources; 10 | 11 | use super::mesh_builder; 12 | use super::{ 13 | chunk::Chunk, 14 | rendering::voxel_rendering::{self}, 15 | }; 16 | use super::{ 17 | chunk::{ChunkMesh, LocalCoordinate, SIZE}, 18 | voxel::Voxel, 19 | }; 20 | 21 | // max amount of per-chunk data we can load 22 | pub const DEFAULT_MAX_CHUNK_DATAS: usize = 10000; 23 | // max amount of per-chunk meshes we can load 24 | pub const DEFAULT_MAX_MESH_DATAS: usize = 10000; 25 | pub const RENDER_DIST_RADIUS: i32 = 8; 26 | 27 | pub const MAX_DATA_QUEUE: usize = 16; 28 | pub const MAX_MESH_QUEUE: usize = 16; 29 | 30 | pub const MAX_DATA_UNLOAD_QUEUE: usize = 16; 31 | pub const MAX_MESH_UNLOAD_QUEUE: usize = 16; 32 | 33 | pub struct Chunks { 34 | // chunk_map owns the current chunks, but when unloaded puts them back to chunk_pool 35 | chunk_data_map: HashMap, Chunk>, 36 | chunk_mesh_map: HashMap, ChunkMesh>, 37 | 38 | // chunk data is recycled from these pools 39 | chunk_pool: Pool, 40 | chunk_mesh_pool: Pool, 41 | 42 | // chunk data are put in queue due to heavy data processing 43 | chunk_data_load_queue: VecDeque>, 44 | chunk_mesh_load_queue: VecDeque>, 45 | 46 | chunk_data_unload_queue: VecDeque>, 47 | chunk_mesh_unload_queue: VecDeque>, 48 | 49 | pub position: cgmath::Vector3, 50 | 51 | render_distance: i32, 52 | } 53 | 54 | impl Chunks { 55 | pub fn new() -> Self { 56 | let chunks = Self { 57 | chunk_data_map: HashMap::with_capacity(DEFAULT_MAX_CHUNK_DATAS), 58 | chunk_mesh_map: HashMap::with_capacity(DEFAULT_MAX_MESH_DATAS), 59 | chunk_pool: pool().with(StartingSize(DEFAULT_MAX_CHUNK_DATAS)).build(), 60 | chunk_mesh_pool: pool().with(StartingSize(DEFAULT_MAX_MESH_DATAS)).build(), 61 | // position of chunks to load in 62 | chunk_data_load_queue: VecDeque::with_capacity(MAX_DATA_QUEUE), 63 | chunk_mesh_load_queue: VecDeque::with_capacity(MAX_MESH_QUEUE), 64 | chunk_data_unload_queue: VecDeque::with_capacity(MAX_DATA_QUEUE), 65 | chunk_mesh_unload_queue: VecDeque::with_capacity(MAX_MESH_QUEUE), 66 | position: cgmath::Vector3::::new(0., 0., 0.), 67 | render_distance: RENDER_DIST_RADIUS, 68 | }; 69 | chunks 70 | } 71 | 72 | pub fn build_chunk_data_in_queue( 73 | &mut self, 74 | ) { 75 | while let Some(chunk_pos) = self.chunk_data_load_queue.pop_front() { 76 | self.build_chunk_data(chunk_pos); 77 | } 78 | } 79 | 80 | pub fn make_coords_valid( 81 | chunk_pos: &mut cgmath::Vector3, 82 | local_pos: &mut LocalCoordinate, 83 | ) { 84 | let chunk_size = SIZE as i32; 85 | while local_pos.0 < 0 { 86 | local_pos.0 += chunk_size; 87 | chunk_pos.x -= 1; 88 | } 89 | while local_pos.0 > chunk_size { 90 | local_pos.0 -= chunk_size; 91 | chunk_pos.x += 1; 92 | } 93 | while local_pos.1 < 0 { 94 | local_pos.1 += chunk_size; 95 | chunk_pos.y -= 1; 96 | } 97 | while local_pos.1 > chunk_size { 98 | local_pos.1 -= chunk_size; 99 | chunk_pos.y += 1; 100 | } 101 | while local_pos.2 < 0 { 102 | local_pos.2 += chunk_size; 103 | chunk_pos.z -= 1; 104 | } 105 | while local_pos.2 > chunk_size { 106 | local_pos.2 -= chunk_size; 107 | chunk_pos.z += 1; 108 | } 109 | } 110 | 111 | // if the local coordinate goes outside bounds, the adjacent chunk will be checked instead 112 | pub fn try_get_voxel( 113 | &self, 114 | chunk_pos: &cgmath::Vector3, 115 | local_pos: &LocalCoordinate, 116 | ) -> Result<&Voxel> { 117 | let mut chunk_pos = *chunk_pos; 118 | let mut local_pos = *local_pos; 119 | Self::make_coords_valid(&mut chunk_pos, &mut local_pos); 120 | 121 | let chunk = self.chunk_data_map.get(&chunk_pos).context("")?; 122 | chunk.get_voxel(local_pos).context("") 123 | } 124 | 125 | pub fn get_chunk_mesh_mut( 126 | &mut self, 127 | chunk_pos: &cgmath::Vector3, 128 | ) -> Option<&mut ChunkMesh> { 129 | self.chunk_mesh_map.get_mut(chunk_pos) 130 | } 131 | 132 | pub fn build_chunk_data( 133 | &mut self, 134 | chunk_pos: cgmath::Vector3, 135 | ) { 136 | let mut chunk = self.chunk_pool.detached(); 137 | let chunk_world_pos = Self::chunk_to_world(chunk_pos); 138 | 139 | chunk.build_voxel_data(&chunk_world_pos); 140 | println!("loaded chunk data at world pos: {:?}", chunk_world_pos); 141 | self.chunk_data_map.insert(chunk_pos, chunk); 142 | } 143 | 144 | pub fn build_chunk_meshes_in_queue( 145 | &mut self, 146 | device: &wgpu::Device, 147 | gpu_resources: &mut GpuResources, 148 | ) { 149 | while let Some(chunk_pos) = self.chunk_mesh_load_queue.pop_front() { 150 | if self.chunk_mesh_map.len() >= DEFAULT_MAX_CHUNK_DATAS { 151 | return; 152 | } 153 | let chunk_mesh = self.chunk_mesh_pool.detached(); 154 | self.chunk_mesh_map.insert(chunk_pos, chunk_mesh); 155 | 156 | println!("building chunk mesh at: {:?}", chunk_pos); 157 | let chunk_world_pos = Self::chunk_to_world(chunk_pos); 158 | if mesh_builder::build_chunk_mesh( 159 | self, 160 | device, 161 | gpu_resources, 162 | &chunk_pos, 163 | &chunk_world_pos, 164 | ) { 165 | // successfully built return for now, 'only one per frame' 166 | return; 167 | } 168 | } 169 | } 170 | 171 | pub fn is_chunk_processing(&self, chunk_pos: &cgmath::Vector3) -> bool { 172 | self.chunk_data_map.contains_key(chunk_pos) 173 | || self.chunk_data_load_queue.contains(chunk_pos) 174 | } 175 | 176 | pub fn is_mesh_processing(&self, chunk_pos: &cgmath::Vector3) -> bool { 177 | self.chunk_mesh_map.contains_key(chunk_pos) 178 | || self.chunk_mesh_load_queue.contains(chunk_pos) 179 | } 180 | 181 | pub fn chunk_to_world(chunk_pos: cgmath::Vector3) -> cgmath::Vector3 { 182 | cgmath::Vector3::::new( 183 | chunk_pos.x as f32 * SIZE as f32, 184 | chunk_pos.y as f32 * SIZE as f32, 185 | chunk_pos.z as f32 * SIZE as f32, 186 | ) 187 | } 188 | 189 | pub fn in_range(&self, chunk_pos: cgmath::Vector3) -> bool { 190 | // convert from i32 postion to world f32 pos 191 | let chunk_real_pos = Self::chunk_to_world(chunk_pos); 192 | let delta = self.position - chunk_real_pos; 193 | let distance_sq: f32 = delta.magnitude2().into(); 194 | let render_dist = (self.render_distance as f32) * SIZE as f32; 195 | let render_distance_sq = render_dist * render_dist; 196 | distance_sq < render_distance_sq 197 | } 198 | 199 | // based on current position load all meshes 200 | pub fn update_load_mesh_queue(&mut self) { 201 | if self.chunk_mesh_map.len() >= DEFAULT_MAX_MESH_DATAS 202 | || self.chunk_mesh_load_queue.len() >= MAX_MESH_QUEUE 203 | { 204 | return; 205 | } 206 | for y in -self.render_distance..self.render_distance { 207 | //for y in 0..1 { 208 | for z in -self.render_distance..self.render_distance { 209 | for x in -self.render_distance..self.render_distance { 210 | let current_chunk_pos = cgmath::Vector3::::new( 211 | (self.position.x / SIZE as f32) as i32, 212 | (self.position.y / SIZE as f32) as i32, 213 | (self.position.z / SIZE as f32) as i32, 214 | ); 215 | let chunk_pos = current_chunk_pos + cgmath::Vector3::::new(x, y, z); 216 | 217 | // chunk is already being loaded, or is loaded 218 | let is_mesh_proccessing = self.is_mesh_processing(&chunk_pos); 219 | if is_mesh_proccessing { 220 | continue; 221 | } 222 | 223 | let in_range = self.in_range(current_chunk_pos); 224 | // check if adjacent chunks are loaded 225 | 226 | use cgmath::Vector3 as vec; 227 | // check if all adjacent chunks data are loaded 228 | let adj_chunk_data_bad = [ 229 | -vec::::unit_x(), 230 | vec::::unit_x(), 231 | -vec::::unit_y(), 232 | vec::::unit_y(), 233 | -vec::::unit_z(), 234 | vec::::unit_z(), 235 | ] 236 | .iter_mut() 237 | .map(|v| *v + chunk_pos) 238 | .any(|v| !self.chunk_data_map.contains_key(&v)); 239 | 240 | // queue chunk for mesh creation 241 | if in_range && !adj_chunk_data_bad { 242 | self.chunk_mesh_load_queue.push_back(chunk_pos); 243 | if self.chunk_mesh_load_queue.len() >= MAX_MESH_QUEUE { 244 | return; 245 | } 246 | } 247 | } 248 | } 249 | } 250 | } 251 | 252 | pub fn update_unload_data_queue(&mut self) { 253 | let current_chunk_pos = cgmath::Vector3::::new( 254 | (self.position.x / SIZE as f32) as i32, 255 | (self.position.y / SIZE as f32) as i32, 256 | (self.position.z / SIZE as f32) as i32, 257 | ); 258 | // find currently loaded meshes positions not contained in range 259 | // BOX BOUND CHECK IS FAST 260 | let outside = self 261 | .chunk_mesh_map 262 | .iter() 263 | .filter(|(p, _m)| { 264 | p.x < current_chunk_pos.x - self.render_distance 265 | || p.x > current_chunk_pos.x + self.render_distance 266 | || p.y < current_chunk_pos.y - self.render_distance 267 | || p.y > current_chunk_pos.y + self.render_distance 268 | || p.z < current_chunk_pos.z - self.render_distance 269 | || p.z > current_chunk_pos.z + self.render_distance 270 | }) 271 | .map(|(p, _m)| p) 272 | .collect::>(); 273 | 274 | for chunk_pos in outside { 275 | // already proccessing skip 276 | if self.chunk_data_unload_queue.contains(chunk_pos) { 277 | continue; 278 | } 279 | println!("queueing chunk for data unload: {:?}", chunk_pos); 280 | self.chunk_data_unload_queue.push_back(*chunk_pos); 281 | if self.chunk_data_unload_queue.len() >= MAX_DATA_UNLOAD_QUEUE { 282 | return; 283 | } 284 | } 285 | } 286 | 287 | // based on current position load all meshes 288 | pub fn update_unload_mesh_queue(&mut self) { 289 | let current_chunk_pos = cgmath::Vector3::::new( 290 | (self.position.x / SIZE as f32) as i32, 291 | (self.position.y / SIZE as f32) as i32, 292 | (self.position.z / SIZE as f32) as i32, 293 | ); 294 | // find currently loaded meshes positions not contained in range 295 | // BOX BOUND CHECK IS FAST 296 | let outside = self 297 | .chunk_mesh_map 298 | .iter() 299 | .filter(|(p, _m)| { 300 | p.x < current_chunk_pos.x - self.render_distance 301 | || p.x > current_chunk_pos.x + self.render_distance 302 | || p.y < current_chunk_pos.y - self.render_distance 303 | || p.y > current_chunk_pos.y + self.render_distance 304 | || p.z < current_chunk_pos.z - self.render_distance 305 | || p.z > current_chunk_pos.z + self.render_distance 306 | }) 307 | .map(|(p, _m)| p) 308 | .collect::>(); 309 | 310 | for chunk_pos in outside { 311 | // already proccessing skip 312 | if self.chunk_mesh_unload_queue.contains(chunk_pos) { 313 | continue; 314 | } 315 | self.chunk_mesh_unload_queue.push_back(*chunk_pos); 316 | println!("queueing chunk for mesh unload: {:?}", chunk_pos); 317 | if self.chunk_mesh_unload_queue.len() >= MAX_MESH_UNLOAD_QUEUE { 318 | return; 319 | } 320 | } 321 | } 322 | 323 | pub fn unload_data_queue(&mut self) { 324 | while let Some(chunk_pos) = self.chunk_data_unload_queue.pop_front() { 325 | // detach chunk data 326 | if let Some(chunk_data) = self.chunk_data_map.remove(&chunk_pos) { 327 | println!("unloading data at: {:?}", chunk_pos); 328 | self.chunk_pool.attach(chunk_data); 329 | } 330 | } 331 | } 332 | 333 | // generate meshes queued up 334 | pub fn unload_mesh_queue(&mut self, gpu_resources: &mut GpuResources) { 335 | while let Some(chunk_pos) = self.chunk_mesh_unload_queue.pop_front() { 336 | // detach mesh data 337 | if let Some(chunk_mesh) = self.chunk_mesh_map.remove(&chunk_pos) { 338 | println!("unloading mesh at: {:?}", chunk_pos); 339 | if let Some(v_buf_key) = chunk_mesh.vertex_buffer { 340 | if let Some(v_buffer) = gpu_resources.buffer_arena.get_mut(v_buf_key) { 341 | v_buffer.destroy(); 342 | } 343 | gpu_resources.buffer_arena.remove(v_buf_key); 344 | } 345 | if let Some(i_buf_key) = chunk_mesh.index_buffer { 346 | if let Some(i_buffer) = gpu_resources.buffer_arena.get_mut(i_buf_key) { 347 | i_buffer.destroy(); 348 | } 349 | gpu_resources.buffer_arena.remove(i_buf_key); 350 | } 351 | self.chunk_mesh_pool.attach(chunk_mesh); 352 | } 353 | } 354 | } 355 | 356 | // based on current position load all meshes 357 | pub fn update_load_data_queue(&mut self) { 358 | if self.chunk_data_map.len() >= DEFAULT_MAX_CHUNK_DATAS 359 | || self.chunk_data_load_queue.len() >= MAX_DATA_QUEUE 360 | { 361 | return; 362 | } 363 | for y in -self.render_distance..self.render_distance { 364 | //for y in 0..1 { 365 | for z in -self.render_distance..self.render_distance { 366 | for x in -self.render_distance..self.render_distance { 367 | let current_chunk_pos = cgmath::Vector3::::new( 368 | (self.position.x / SIZE as f32) as i32, 369 | (self.position.y / SIZE as f32) as i32, 370 | (self.position.z / SIZE as f32) as i32, 371 | ); 372 | let chunk_pos = current_chunk_pos + cgmath::Vector3::::new(x, y, z); 373 | 374 | // chunk is already being loaded, or is loaded 375 | let is_chunk_proccessing = self.is_chunk_processing(&chunk_pos); 376 | if is_chunk_proccessing { 377 | continue; 378 | } 379 | 380 | let in_range = self.in_range(current_chunk_pos); 381 | if in_range { 382 | // load chunk 383 | self.chunk_data_load_queue.push_back(chunk_pos); 384 | } 385 | // check if we don't wan to load any more 386 | if self.chunk_data_load_queue.len() >= MAX_DATA_QUEUE { 387 | println!("done"); 388 | return; 389 | } 390 | } 391 | } 392 | } 393 | } 394 | 395 | pub fn draw<'a, '_b>( 396 | &mut self, 397 | render_pass: &mut wgpu::RenderPass<'a>, 398 | camera_bind_group: &'a wgpu::BindGroup, 399 | light_bind_group: &'a wgpu::BindGroup, 400 | gpu_resources: &'a GpuResources, 401 | ) -> anyhow::Result<()> { 402 | for (_pos, chunk_mesh) in self.chunk_mesh_map.iter() { 403 | let vertex_buffer_index = chunk_mesh.vertex_buffer.as_ref().context("no vertices")?; 404 | let index_buffer_index = chunk_mesh.index_buffer.as_ref().context("no indices")?; 405 | let num_indices = chunk_mesh.num_indices; 406 | let vertex_buffer = gpu_resources 407 | .buffer_arena 408 | .get(*vertex_buffer_index) 409 | .context("no vertex buf")?; 410 | let index_buffer = gpu_resources 411 | .buffer_arena 412 | .get(*index_buffer_index) 413 | .context("no vertex buf")?; 414 | let _ = voxel_rendering::draw_chunk( 415 | render_pass, 416 | num_indices, 417 | camera_bind_group, 418 | light_bind_group, 419 | vertex_buffer, 420 | index_buffer, 421 | ); 422 | } 423 | Ok(()) 424 | } 425 | 426 | #[allow(dead_code)] 427 | pub fn get_vertex_count(&self) -> u32 { 428 | self.chunk_mesh_map 429 | .iter() 430 | .map(|(_i, m)| m.num_vertices) 431 | .sum() 432 | } 433 | } 434 | pub fn adjacent_voxels<'a>( 435 | chunks: &'a mut Chunks, 436 | local_pos: (i32, i32, i32), 437 | chunk_pos: &cgmath::Vector3, 438 | ) -> Result<(&'a Voxel, &'a Voxel, &'a Voxel, &'a Voxel)> { 439 | let (x, y, z) = (local_pos.0, local_pos.1, local_pos.2); 440 | let voxel = chunks 441 | .try_get_voxel(chunk_pos, &LocalCoordinate(x, y, z)) 442 | .context("no voxel")?; 443 | let back = chunks 444 | .try_get_voxel(chunk_pos, &LocalCoordinate(x, y, z - 1)) 445 | .context("no back voxel")?; 446 | let left = chunks 447 | .try_get_voxel(chunk_pos, &LocalCoordinate(x - 1, y, z)) 448 | .context("no left voxel")?; 449 | let down = chunks 450 | .try_get_voxel(chunk_pos, &LocalCoordinate(x, y - 1, z)) 451 | .context("no down voxel")?; 452 | Ok((voxel, back, left, down)) 453 | } 454 | -------------------------------------------------------------------------------- /src/voxel_tools/direction.rs: -------------------------------------------------------------------------------- 1 | pub enum Direction { 2 | Left, 3 | Right, 4 | Down, 5 | Up, 6 | Back, 7 | Forward, 8 | } 9 | 10 | impl Direction { 11 | pub fn get_normal(&self) -> cgmath::Vector3 { 12 | match self { 13 | Direction::Left => -cgmath::Vector3::::unit_x(), 14 | Direction::Right => cgmath::Vector3::::unit_x(), 15 | Direction::Down => -cgmath::Vector3::::unit_y(), 16 | Direction::Up => cgmath::Vector3::::unit_y(), 17 | Direction::Back => -cgmath::Vector3::::unit_z(), 18 | Direction::Forward => cgmath::Vector3::::unit_z(), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/voxel_tools/mesh_builder.rs: -------------------------------------------------------------------------------- 1 | use crate::rendering::gpu_resources::GpuResources; 2 | 3 | use super::{ 4 | chunk, 5 | chunks::{adjacent_voxels, Chunks}, 6 | }; 7 | use super::{ 8 | direction::Direction, 9 | quad::Quad, 10 | rendering::voxel_vertex::VoxelVertex, 11 | voxel::Voxel, 12 | }; 13 | use wgpu::util::DeviceExt; 14 | 15 | pub fn build_chunk_mesh( 16 | chunks: &mut Chunks, 17 | //chunk: &mut Chunk, 18 | device: &wgpu::Device, 19 | gpu_resources: &mut GpuResources, 20 | chunk_pos: &cgmath::Vector3, 21 | chunk_world_pos: &cgmath::Vector3, 22 | ) -> bool { 23 | let chunk_size = chunk::SIZE as i32; 24 | let mut quads = Vec::::new(); 25 | for x in 0..chunk_size { 26 | for y in 0..chunk_size { 27 | for z in 0..chunk_size { 28 | let voxel_pos_local = cgmath::Vector3::::new(x as f32, y as f32, z as f32); 29 | let voxel_pos_world = chunk_world_pos + voxel_pos_local; 30 | if let Ok((voxel, back, left, down)) = adjacent_voxels(chunks, (x, y, z), chunk_pos) 31 | { 32 | process_voxel(&voxel, voxel_pos_world, &left, &down, &back, &mut quads); 33 | } 34 | } 35 | } 36 | } 37 | if quads.is_empty() { 38 | //panic!("ouuuuh woops"); 39 | } 40 | let mut voxel_vertices = Vec::::new(); 41 | let mut indices = Vec::::new(); 42 | let mut vert_index = 0; 43 | for quad in quads { 44 | let normal = quad.direction.get_normal(); 45 | (0..4).for_each(|index| { 46 | voxel_vertices.push(VoxelVertex { 47 | position: quad.corners[index].into(), 48 | normal: normal.into(), 49 | color_diffuse: quad.color.into(), 50 | }); 51 | }); 52 | indices.push(vert_index); 53 | indices.push(vert_index + 1); 54 | indices.push(vert_index + 2); 55 | indices.push(vert_index); 56 | indices.push(vert_index + 2); 57 | indices.push(vert_index + 3); 58 | vert_index += 4; 59 | } 60 | if let Some(chunk_mesh) = chunks.get_chunk_mesh_mut(chunk_pos) { 61 | let num_indices = indices.len() as u32; 62 | let num_vertices = voxel_vertices.len() as u32; 63 | let (v_buf, i_buf) = construct_buffers(device, voxel_vertices, indices); 64 | let v_buf = gpu_resources.buffer_arena.insert(v_buf); 65 | let i_buf = gpu_resources.buffer_arena.insert(i_buf); 66 | chunk_mesh.update_vertex_buffers(v_buf, i_buf, num_indices, num_vertices); 67 | return num_vertices != 0; 68 | } 69 | false 70 | } 71 | 72 | fn process_voxel( 73 | voxel: &Voxel, 74 | voxel_pos: cgmath::Vector3, 75 | left: &Voxel, 76 | down: &Voxel, 77 | back: &Voxel, 78 | quads: &mut Vec, 79 | ) { 80 | match voxel.is_solid() { 81 | true => { 82 | // voxel is solid 83 | if !left.is_solid() { 84 | quads.push(Quad::from_direction(Direction::Left, voxel_pos)); 85 | } 86 | if !down.is_solid() { 87 | quads.push(Quad::from_direction(Direction::Down, voxel_pos)); 88 | } 89 | if !back.is_solid() { 90 | quads.push(Quad::from_direction(Direction::Back, voxel_pos)); 91 | } 92 | } 93 | false => { 94 | // voxel is not solid 95 | if left.is_solid() { 96 | quads.push(Quad::from_direction(Direction::Right, voxel_pos)); 97 | } 98 | if down.is_solid() { 99 | quads.push(Quad::from_direction(Direction::Up, voxel_pos)); 100 | } 101 | if back.is_solid() { 102 | quads.push(Quad::from_direction(Direction::Forward, voxel_pos)); 103 | } 104 | } 105 | } 106 | } 107 | 108 | fn construct_buffers( 109 | device: &wgpu::Device, 110 | vertices: Vec, 111 | indices: Vec, 112 | ) -> (wgpu::Buffer, wgpu::Buffer) { 113 | let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 114 | label: Some("voxel_chunk_vertices"), 115 | contents: bytemuck::cast_slice(&vertices), 116 | usage: wgpu::BufferUsage::VERTEX, 117 | }); 118 | let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { 119 | label: Some("voxel_chunk_indices"), 120 | contents: bytemuck::cast_slice(&indices), 121 | usage: wgpu::BufferUsage::INDEX, 122 | }); 123 | (vertex_buffer, index_buffer) 124 | } 125 | -------------------------------------------------------------------------------- /src/voxel_tools/quad.rs: -------------------------------------------------------------------------------- 1 | use super::direction::Direction; 2 | use crate::color::Color; 3 | use cgmath::Vector3; 4 | use rand::Rng; 5 | 6 | pub struct Quad { 7 | pub color: Color, 8 | pub direction: Direction, 9 | // in world position 10 | pub corners: [Vector3; 4], 11 | } 12 | 13 | const HALF_SIZE: f32 = 0.5f32; 14 | 15 | impl Quad { 16 | pub fn from_direction(direction: Direction, pos: Vector3) -> Self { 17 | let corners = match direction { 18 | Direction::Left => [ 19 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 20 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 21 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z + HALF_SIZE), 22 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 23 | ], 24 | Direction::Right => [ 25 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 26 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z + HALF_SIZE), 27 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 28 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 29 | ], 30 | // assuming it's correct this is under i believe 31 | Direction::Down => [ 32 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 33 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 34 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 35 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 36 | ], 37 | Direction::Up => [ 38 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 39 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z + HALF_SIZE), 40 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 41 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 42 | ], 43 | Direction::Back => [ 44 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 45 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 46 | Vector3::new(pos.x + HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 47 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 48 | ], 49 | Direction::Forward => [ 50 | Vector3::new(pos.x + HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 51 | Vector3::new(pos.x + HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 52 | Vector3::new(pos.x - HALF_SIZE, pos.y + HALF_SIZE, pos.z - HALF_SIZE), 53 | Vector3::new(pos.x - HALF_SIZE, pos.y - HALF_SIZE, pos.z - HALF_SIZE), 54 | ], 55 | }; 56 | 57 | let green_range = 0.4f32; 58 | Self { 59 | corners, 60 | //color: color::colors::GREEN, 61 | //color: Color::new(0.7f32, (1.-green_range) + rand::thread_rng().gen_range(0f32..green_range), 0.3f32, 1.), 62 | color: Color::new( 63 | rand::thread_rng().gen_range(0f32..0.1f32), 64 | (1. - green_range) + rand::thread_rng().gen_range(0f32..green_range), 65 | rand::thread_rng().gen_range(0f32..0.1f32), 66 | 1., 67 | ), 68 | direction, 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/voxel_tools/rendering.rs: -------------------------------------------------------------------------------- 1 | pub mod voxel_pipeline; 2 | pub mod voxel_rendering; 3 | pub mod voxel_vertex; 4 | -------------------------------------------------------------------------------- /src/voxel_tools/rendering/voxel.wgsl: -------------------------------------------------------------------------------- 1 | [[block]] 2 | struct CameraUniform { 3 | position: vec3; 4 | projection_view: mat4x4; 5 | }; 6 | 7 | [[group(0), binding(0)]] 8 | var u_camera: CameraUniform; 9 | 10 | struct VertexOutput { 11 | [[builtin(position)]] builtin_position: vec4; 12 | [[location(1)]] diffuse_color: vec3; 13 | [[location(2)]] normal: vec3; 14 | [[location(3)]] position: vec3; 15 | }; 16 | 17 | [[stage(vertex)]] 18 | fn vs_main( 19 | [[location(0)]] position: vec3, 20 | [[location(1)]] normal: vec3, 21 | [[location(2)]] diffuse_color: vec3, 22 | ) -> VertexOutput { 23 | var out: VertexOutput; 24 | out.normal = normal; 25 | let model_space = vec4(position, 1.0); 26 | out.position = model_space.xyz; 27 | out.diffuse_color = diffuse_color; 28 | 29 | out.builtin_position = u_camera.projection_view * model_space; 30 | return out; 31 | } 32 | 33 | 34 | [[block]] 35 | struct LightUniform { 36 | position: vec3; 37 | color: vec3; 38 | }; 39 | 40 | [[group(1), binding(0)]] 41 | var u_light: LightUniform; 42 | 43 | [[stage(fragment), early_depth_test]] 44 | fn fs_main( 45 | in: VertexOutput, 46 | ) -> [[location(0)]] vec4 { 47 | let ambient_strength = 0.2; 48 | let ambient_color = u_light.color * ambient_strength; 49 | 50 | let normal = normalize(in.normal); 51 | let light_dir = normalize(u_light.position - in.position); 52 | let diffuse_strength = max(dot(normal, light_dir), 0.0); 53 | let diffuse_color = u_light.color * diffuse_strength; 54 | 55 | let view_dir = normalize(u_camera.position - in.position); 56 | let half_dir = normalize(view_dir + light_dir); 57 | 58 | let specular_strength = pow(max(dot(normal, half_dir), 0.0), 32.0); 59 | let specular_color = specular_strength * u_light.color; 60 | 61 | let surface_color = vec4(in.diffuse_color, 1.0); 62 | 63 | let result = (diffuse_color + ambient_color + specular_color) * surface_color.xyz; 64 | 65 | return vec4(result, surface_color.a); 66 | } -------------------------------------------------------------------------------- /src/voxel_tools/rendering/voxel_pipeline.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | create_render_pipeline, 3 | rendering::{render_utils, vertex_desc::VertexDesc}, 4 | texture, 5 | voxel_tools::rendering::voxel_vertex::VoxelVertex, 6 | }; 7 | 8 | pub fn create_voxel_pipeline( 9 | device: &wgpu::Device, 10 | texture_format: wgpu::TextureFormat, 11 | light_bind_group_layout: &wgpu::BindGroupLayout, 12 | ) -> wgpu::RenderPipeline { 13 | let visibility = wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT; 14 | let camera_bind_group_layout = 15 | render_utils::create_bind_group_layout(&device, "camera_bind_layout", 0, visibility); 16 | 17 | let shader_module = render_utils::create_shader_module( 18 | &device, 19 | include_str!("voxel.wgsl"), 20 | "voxel_shader_module", 21 | ); 22 | 23 | let bind_group_layouts = &[&camera_bind_group_layout, &light_bind_group_layout]; 24 | let pipeline_layout = 25 | render_utils::create_pipeline_layout(&device, "voxel_pipeline", bind_group_layouts); 26 | 27 | println!("creating pipeline"); 28 | let render_pipeline = create_render_pipeline( 29 | &device, 30 | &pipeline_layout, 31 | texture_format, 32 | Some(texture::Texture::DEPTH_FORMAT), 33 | &[VoxelVertex::desc()], 34 | shader_module, 35 | "voxel_pipeline", 36 | ); 37 | render_pipeline 38 | } 39 | -------------------------------------------------------------------------------- /src/voxel_tools/rendering/voxel_rendering.rs: -------------------------------------------------------------------------------- 1 | use anyhow::*; 2 | 3 | pub fn draw_chunk<'a, 'b>( 4 | render_pass: &mut wgpu::RenderPass<'a>, 5 | num_indices: u32, 6 | camera_u: &'a wgpu::BindGroup, 7 | light_u: &'a wgpu::BindGroup, 8 | vertex_buffer: &'a wgpu::Buffer, 9 | index_buffer: &'a wgpu::Buffer, 10 | ) -> Result<()> { 11 | render_pass.set_vertex_buffer(0, vertex_buffer.slice(..)); 12 | render_pass.set_index_buffer(index_buffer.slice(..), wgpu::IndexFormat::Uint32); 13 | render_pass.set_bind_group(0, &camera_u, &[]); 14 | render_pass.set_bind_group(1, &light_u, &[]); 15 | render_pass.draw_indexed(0..num_indices, 0, 0..1); 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /src/voxel_tools/rendering/voxel_vertex.rs: -------------------------------------------------------------------------------- 1 | use crate::rendering::vertex_desc::VertexDesc; 2 | 3 | #[repr(C)] 4 | #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] 5 | pub struct VoxelVertex { 6 | pub position: [f32; 3], 7 | pub normal: [f32; 3], 8 | pub color_diffuse: [f32; 3], 9 | } 10 | 11 | impl VertexDesc for VoxelVertex { 12 | fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { 13 | use std::mem; 14 | wgpu::VertexBufferLayout { 15 | array_stride: mem::size_of::() as wgpu::BufferAddress, 16 | step_mode: wgpu::InputStepMode::Vertex, 17 | attributes: &[ 18 | // position 19 | wgpu::VertexAttribute { 20 | format: wgpu::VertexFormat::Float32x3, 21 | offset: 0, 22 | shader_location: 0, 23 | }, 24 | // normal 25 | wgpu::VertexAttribute { 26 | format: wgpu::VertexFormat::Float32x3, 27 | offset: mem::size_of::<[f32; 3]>() as wgpu::BufferAddress, 28 | shader_location: 1, 29 | }, 30 | // diffuse color 31 | wgpu::VertexAttribute { 32 | format: wgpu::VertexFormat::Float32x3, 33 | offset: mem::size_of::<[f32; 6]>() as wgpu::BufferAddress, 34 | shader_location: 2, 35 | }, 36 | ], 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/voxel_tools/voxel.rs: -------------------------------------------------------------------------------- 1 | #[derive(Copy, Clone, Debug)] 2 | pub struct Voxel { 3 | density: u8, 4 | } 5 | 6 | // decorative argument type 7 | pub struct Density(u8); 8 | 9 | impl Voxel { 10 | pub fn new(density: Density) -> Self { 11 | Self { density: density.0 } 12 | } 13 | 14 | pub fn new_empty() -> Self { 15 | Self::new(Density(0u8)) 16 | } 17 | 18 | #[allow(dead_code)] 19 | pub fn new_solid() -> Self { 20 | Self::new(Density(255u8)) 21 | } 22 | 23 | pub fn is_solid(&self) -> bool { 24 | self.density > 0u8 25 | } 26 | 27 | #[allow(dead_code)] 28 | pub fn density_fraction(&self) -> f32 { 29 | self.density as f32 / 255f32 30 | } 31 | 32 | pub fn set_density_fraciton(&mut self, fraction: f32) { 33 | self.density = (fraction * 255f32) as u8; 34 | } 35 | } 36 | --------------------------------------------------------------------------------