diff --git a/Cargo.lock b/Cargo.lock index a028e16d..47b84708 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,6 +58,11 @@ name = "android_log-sys" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "anyhow" +version = "1.0.32" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "approx" version = "0.3.2" @@ -153,7 +158,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytemuck" -version = "1.2.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -175,7 +180,7 @@ dependencies = [ name = "camera" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -549,15 +554,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "framework" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.23.7 (registry+https://github.com/rust-lang/crates.io-index)", "shaderc 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tobj 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tobj 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "wgpu 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.22.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -838,11 +846,9 @@ dependencies = [ "framework 0.1.0", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", - "image 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.23.7 (registry+https://github.com/rust-lang/crates.io-index)", "shaderc 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tobj 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "wgpu 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winit 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -928,7 +934,7 @@ name = "image" version = "0.23.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)", "jpeg-decoder 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -977,6 +983,26 @@ dependencies = [ "adler32 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "instancing" +version = "0.1.0" +dependencies = [ + "anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "framework 0.1.0", + "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "image 0.23.7 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "shaderc 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tobj 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wgpu 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winit 0.22.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "instant" version = "0.1.6" @@ -1471,7 +1497,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "performance" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1540,7 +1566,7 @@ dependencies = [ name = "pong" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2069,12 +2095,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "tobj" -version = "0.1.12" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "tobj" -version = "1.0.0" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2101,7 +2127,7 @@ dependencies = [ name = "tutorial10-lighting" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2116,7 +2142,7 @@ dependencies = [ name = "tutorial11-normals" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2131,7 +2157,7 @@ dependencies = [ name = "tutorial12-camera" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2170,7 +2196,7 @@ dependencies = [ name = "tutorial4-buffer" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "image 0.22.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2183,7 +2209,7 @@ dependencies = [ name = "tutorial5-textures" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2197,7 +2223,7 @@ dependencies = [ name = "tutorial6-uniforms" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2211,7 +2237,7 @@ dependencies = [ name = "tutorial7-instancing" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2225,7 +2251,7 @@ dependencies = [ name = "tutorial8-depth" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2240,7 +2266,7 @@ dependencies = [ name = "tutorial9-models" version = "0.1.0" dependencies = [ - "bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2665,6 +2691,7 @@ dependencies = [ "checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e" "checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" "checksum android_log-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b8052e2d8aabbb8d556d6abbcce2a22b9590996c5f849b9c7ce4544a2e3b984e" +"checksum anyhow 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" "checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum ash 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c69a8137596e84c22d57f3da1b5de1d4230b1742a710091c85f4d7ce50f00f38" @@ -2677,7 +2704,7 @@ dependencies = [ "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" "checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" -"checksum bytemuck 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37fa13df2292ecb479ec23aa06f4507928bef07839be9ef15281411076629431" +"checksum bytemuck 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "db7a1029718df60331e557c9e83a55523c955e5dd2a7bfeffad6bbd50b538ae9" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160" "checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" @@ -2886,8 +2913,8 @@ dependencies = [ "checksum tiff 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b7c2cfc4742bd8a32f2e614339dd8ce30dbcf676bb262bd63a2327bc5df57d" "checksum tiff 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f3b8a87c4da944c3f27e5943289171ac71a6150a79ff6bacfff06d159dfff2f" "checksum tinyvec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" -"checksum tobj 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "fe69d3e3b94bf71dfd868eb38b0830917bb177a7b32b58cab7ca72691aba7729" "checksum tobj 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2b9d0bafde95a2f8f50dd3c10bc127b462efa8c3c0b60dfa276b7e032100e21d" +"checksum tobj 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6172100cd5b17cdd085c94f261e31101ca31886c86a2337a6687dac6d2fb3cf1" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum twox-hash 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bfd5b7557925ce778ff9b9ef90e3ade34c524b5ff10e239c69a42d546d2af56" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" diff --git a/code/intermediate/tutorial12-camera/src/main.rs b/code/intermediate/tutorial12-camera/src/main.rs index 2667372a..48e43b79 100644 --- a/code/intermediate/tutorial12-camera/src/main.rs +++ b/code/intermediate/tutorial12-camera/src/main.rs @@ -170,6 +170,7 @@ impl State { let surface = wgpu::Surface::create(window); + let adapter = wgpu::Adapter::request( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::Default, diff --git a/code/intermediate/tutorial12-camera/src/world_space.vert b/code/intermediate/tutorial12-camera/src/world_space.vert deleted file mode 100644 index 1e963992..00000000 --- a/code/intermediate/tutorial12-camera/src/world_space.vert +++ /dev/null @@ -1,44 +0,0 @@ -#version 450 - -layout(location=0) in vec3 a_position; -layout(location=1) in vec2 a_tex_coords; -layout(location=2) in vec3 a_normal; -// NEW! -layout(location=3) in vec3 a_tangent; -layout(location=4) in vec3 a_bitangent; - -layout(location=0) out vec2 v_tex_coords; -layout(location=1) out vec3 v_position; // UPDATED! -layout(location=2) out mat3 v_tangent_matrix; // NEW! - -layout(set=1, binding=0) -uniform Uniforms { - vec3 u_view_position; - mat4 u_view_proj; -}; - -layout(set=1, binding=1) -buffer Instances { - mat4 s_models[]; -}; - -void main() { - v_tex_coords = a_tex_coords; - - mat4 model_matrix = s_models[gl_InstanceIndex]; - - mat3 normal_matrix = mat3(transpose(inverse(model_matrix))); - vec3 normal = normalize(normal_matrix * a_normal); - vec3 tangent = normalize(normal_matrix * a_tangent); - vec3 bitangent = normalize(normal_matrix * a_bitangent); - v_tangent_matrix = mat3( - tangent, - bitangent, - normal - ); - - vec4 model_space = model_matrix * vec4(a_position, 1.0); - v_position = model_space.xyz; - - gl_Position = u_view_proj * model_space; -} \ No newline at end of file diff --git a/code/showcase/framework/Cargo.toml b/code/showcase/framework/Cargo.toml index 4ee72967..829b83b7 100644 --- a/code/showcase/framework/Cargo.toml +++ b/code/showcase/framework/Cargo.toml @@ -7,12 +7,20 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -image = "0.22.4" -winit = "0.20.0" -shaderc = "0.6" -cgmath = "0.17.0" +anyhow = "1.0" +bytemuck = "1.3" +image = "0.23" failure = "0.1" -futures = "0.3.4" -tobj = "1.0.0" -wgpu = "0.5.0" -bytemuck = "1.2.0" \ No newline at end of file +futures = "0.3" +tobj = "2" +winit = "0.22" +wgpu = "0.5" + +[dependencies.cgmath] +version = "0.17" +features = ["swizzle"] + +[build-dependencies] +fs_extra = "1.1" +glob = "0.3" +shaderc = "0.6" \ No newline at end of file diff --git a/code/showcase/framework/src/buffer.rs b/code/showcase/framework/src/buffer.rs index 70926924..3b67c118 100644 --- a/code/showcase/framework/src/buffer.rs +++ b/code/showcase/framework/src/buffer.rs @@ -28,7 +28,7 @@ impl RawBuffer { Self::from_parts(buffer, data, usage) } - pub fn from_parts(buffer: wgpu::Buffer, data: Vec, usage: wgpu::BufferUsage) -> Self { + pub fn from_parts(buffer: wgpu::Buffer, data: Vec, _usage: wgpu::BufferUsage) -> Self { Self { buffer, data } } @@ -40,7 +40,7 @@ impl RawBuffer { pub struct Buffer, R: Copy + bytemuck::Pod + bytemuck::Zeroable> { pub data: Vec, pub raw_buffer: RawBuffer, - usage: wgpu::BufferUsage, + pub usage: wgpu::BufferUsage, } impl, R: Copy + bytemuck::Pod + bytemuck::Zeroable> Buffer { diff --git a/code/showcase/framework/src/camera.rs b/code/showcase/framework/src/camera.rs index 9dda9765..90f1c4c0 100644 --- a/code/showcase/framework/src/camera.rs +++ b/code/showcase/framework/src/camera.rs @@ -1,25 +1,220 @@ +use cgmath::*; +use winit::event::*; +use winit::dpi::LogicalPosition; +use std::time::Duration; +use std::f32::consts::FRAC_PI_2; + #[cfg_attr(rustfmt, rustfmt_skip)] pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( 1.0, 0.0, 0.0, 0.0, - 0.0, -1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.0, 0.0, 0.0, 0.5, 1.0, ); +pub fn camera_setup< + V: Into>, + Y: Into>, + P: Into>, +>( + position: V, + yaw: Y, + pitch: P, + width: u32, + height: u32, +) -> (Camera, Projection, CameraController) { + ( + Camera::new(position, yaw, pitch), + Projection::new(width, height, Deg(45.0), 0.1, 100.0), + CameraController::new(4.0, 0.4), + ) +} + +#[derive(Debug)] pub struct Camera { - eye: cgmath::Point3, - target: cgmath::Point3, - up: cgmath::Vector3, + pub position: Point3, + yaw: Rad, + pitch: Rad, +} + +impl Camera { + pub fn new< + V: Into>, + Y: Into>, + P: Into>, + >( + position: V, + yaw: Y, + pitch: P, + ) -> Self { + Self { + position: position.into(), + yaw: yaw.into(), + pitch: pitch.into(), + } + } + + pub fn calc_matrix(&self) -> Matrix4 { + Matrix4::look_at_dir( + self.position, + Vector3::new( + self.yaw.0.cos(), + self.pitch.0.sin(), + self.yaw.0.sin(), + ).normalize(), + Vector3::unit_y(), + ) + } +} + +pub struct Projection { aspect: f32, - fovy: f32, + fovy: Rad, znear: f32, zfar: f32, } -impl Camera { - pub fn build_view_projection_matrix(&self) -> cgmath::Matrix4 { - let view = cgmath::Matrix4::look_at(self.eye, self.target, self.up); - let proj = cgmath::perspective(cgmath::Deg(self.fovy), self.aspect, self.znear, self.zfar); - return proj * view; +impl Projection { + pub fn new>>( + width: u32, + height: u32, + fovy: F, + znear: f32, + zfar: f32, + ) -> Self { + Self { + aspect: width as f32 / height as f32, + fovy: fovy.into(), + znear, + zfar, + } + } + + pub fn resize(&mut self, width: u32, height: u32) { + self.aspect = width as f32 / height as f32; + } + + pub fn calc_matrix(&self) -> Matrix4 { + OPENGL_TO_WGPU_MATRIX * perspective(self.fovy, self.aspect, self.znear, self.zfar) + } +} + +#[derive(Debug)] +pub struct CameraController { + amount_left: f32, + amount_right: f32, + amount_forward: f32, + amount_backward: f32, + amount_up: f32, + amount_down: f32, + rotate_horizontal: f32, + rotate_vertical: f32, + scroll: f32, + speed: f32, + sensitivity: f32, +} + +impl CameraController { + pub fn new(speed: f32, sensitivity: f32) -> Self { + Self { + amount_left: 0.0, + amount_right: 0.0, + amount_forward: 0.0, + amount_backward: 0.0, + amount_up: 0.0, + amount_down: 0.0, + rotate_horizontal: 0.0, + rotate_vertical: 0.0, + scroll: 0.0, + speed, + sensitivity, + } + } + + pub fn process_keyboard(&mut self, key: VirtualKeyCode, state: ElementState) -> bool{ + let amount = if state == ElementState::Pressed { 1.0 } else { 0.0 }; + match key { + VirtualKeyCode::W | VirtualKeyCode::Up => { + self.amount_forward = amount; + true + } + VirtualKeyCode::S | VirtualKeyCode::Down => { + self.amount_backward = amount; + true + } + VirtualKeyCode::A | VirtualKeyCode::Left => { + self.amount_left = amount; + true + } + VirtualKeyCode::D | VirtualKeyCode::Right => { + self.amount_right = amount; + true + } + VirtualKeyCode::Space => { + self.amount_up = amount; + true + } + VirtualKeyCode::LShift => { + self.amount_down = amount; + true + } + _ => false, + } + } + + pub fn process_mouse(&mut self, mouse_dx: f64, mouse_dy: f64) { + self.rotate_horizontal = mouse_dx as f32; + self.rotate_vertical = mouse_dy as f32; + } + + pub fn process_scroll(&mut self, delta: &MouseScrollDelta) { + self.scroll = -match delta { + // I'm assuming a line is about 100 pixels + MouseScrollDelta::LineDelta(_, scroll) => scroll * 100.0, + MouseScrollDelta::PixelDelta(LogicalPosition { + y: scroll, + .. + }) => *scroll as f32, + }; + } + + pub fn update_camera(&mut self, camera: &mut Camera, dt: Duration) { + let dt = dt.as_secs_f32(); + + // Move forward/backward and left/right + let (yaw_sin, yaw_cos) = camera.yaw.0.sin_cos(); + let forward = Vector3::new(yaw_cos, 0.0, yaw_sin).normalize(); + let right = Vector3::new(-yaw_sin, 0.0, yaw_cos).normalize(); + camera.position += forward * (self.amount_forward - self.amount_backward) * self.speed * dt; + camera.position += right * (self.amount_right - self.amount_left) * self.speed * dt; + + // Move in/out (aka. "zoom") + // Note: this isn't an actual zoom. The camera's position + // changes when zooming. I've added this to make it easier + // to get closer to an object you want to focus on. + let (pitch_sin, pitch_cos) = camera.pitch.0.sin_cos(); + let scrollward = Vector3::new(pitch_cos * yaw_cos, pitch_sin, pitch_cos * yaw_sin).normalize(); + camera.position += scrollward * self.scroll * self.speed * self.sensitivity * dt; + + // Move up/down. Since we don't use roll, we can just + // modify the y coordinate directly. + camera.position.y += (self.amount_up - self.amount_down) * self.speed * dt; + + // Rotate + camera.yaw += Rad(self.rotate_horizontal) * self.sensitivity * dt; + camera.pitch += Rad(-self.rotate_vertical) * self.sensitivity * dt; + + // If process_mouse isn't called every frame, these values + // will not get set to zero, and the camera will rotate + // when moving in a non cardinal direction. + self.rotate_horizontal = 0.0; + self.rotate_vertical = 0.0; + + // Keep the camera's angle from going too high/low. + if camera.pitch < -Rad(FRAC_PI_2) { + camera.pitch = -Rad(FRAC_PI_2); + } else if camera.pitch > Rad(FRAC_PI_2) { + camera.pitch = Rad(FRAC_PI_2); + } } } \ No newline at end of file diff --git a/code/showcase/framework/src/lib.rs b/code/showcase/framework/src/lib.rs index 34ed1bc9..b1bdc98d 100644 --- a/code/showcase/framework/src/lib.rs +++ b/code/showcase/framework/src/lib.rs @@ -1,9 +1,254 @@ mod buffer; mod camera; +mod light; mod model; +mod pipeline; mod texture; +pub mod prelude; pub use buffer::*; pub use camera::*; +pub use light::*; pub use model::*; -pub use texture::*; \ No newline at end of file +pub use pipeline::*; +pub use texture::*; + +use anyhow::*; +use cgmath::*; +use std::time::{Duration, Instant}; +use winit::event::*; +use winit::event_loop::{ControlFlow, EventLoop}; +use winit::window::{Window, WindowBuilder}; + +pub struct Display { + _adapter: wgpu::Adapter, + surface: wgpu::Surface, + pub sc_desc: wgpu::SwapChainDescriptor, + pub swap_chain: wgpu::SwapChain, + pub device: wgpu::Device, + pub queue: wgpu::Queue, +} + +impl Display { + pub async fn new(window: &Window) -> Result { + let size = window.inner_size(); + let surface = wgpu::Surface::create(window); + let _adapter: wgpu::Adapter = wgpu::Adapter::request( + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + compatible_surface: Some(&surface), + }, + wgpu::BackendBit::PRIMARY, + ).await.context("Unable to find valid device!")?; + let (device, queue) = _adapter.request_device(&Default::default()).await; + let sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Fifo, + }; + let swap_chain = device.create_swap_chain(&surface, &sc_desc); + + Ok(Self { + _adapter, + surface, + sc_desc, + swap_chain, + device, + queue, + }) + } + + pub fn resize(&mut self, width: u32, height: u32) { + self.sc_desc.width = width; + self.sc_desc.height = height; + self.swap_chain = self.device.create_swap_chain(&self.surface, &self.sc_desc); + } +} + + +/** + * Holds the camera data to be passed to wgpu. + */ +#[repr(C)] +#[derive(Copy, Clone)] +pub struct UniformData { + view_position: cgmath::Vector4, + view_proj: cgmath::Matrix4, +} + +unsafe impl bytemuck::Zeroable for UniformData {} +unsafe impl bytemuck::Pod for UniformData {} + +pub struct Uniforms { + data: UniformData, + buffer: wgpu::Buffer, +} + +impl Uniforms { + pub fn new(device: &wgpu::Device) -> Self { + let data = UniformData { + view_position: Zero::zero(), + view_proj: cgmath::Matrix4::identity(), + }; + let buffer = device.create_buffer_with_data( + bytemuck::cast_slice(&[data]), + wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM, + ); + + Self { data, buffer } + } + + pub fn update_view_proj(&mut self, camera: &camera::Camera, projection: &camera::Projection) { + self.data.view_position = camera.position.to_homogeneous(); + self.data.view_proj = projection.calc_matrix() * camera.calc_matrix() + } + + pub fn update_buffer(&self, device: &wgpu::Device, encoder: &mut wgpu::CommandEncoder) { + let staging_buffer = device.create_buffer_with_data( + bytemuck::cast_slice(&[self.data]), + wgpu::BufferUsage::COPY_SRC, + ); + encoder.copy_buffer_to_buffer( + &staging_buffer, + 0, + &self.buffer, + 0, + std::mem::size_of::() as _, + ); + } +} + +/** + * Holds the wgpu::BindGroupLayout and one wgpu::BindGroup for the + * just the Uniforms struct. + */ +pub struct UniformBinding { + pub layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} + +impl UniformBinding { + pub fn new(device: &wgpu::Device, uniforms: &Uniforms) -> Self { + let layout = device.create_bind_group_layout( + &wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + ], + label: Some("UniformBinding::layout"), + } + ); + let bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + layout: &layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniforms.buffer, + range: 0..std::mem::size_of_val(&uniforms.data) as _, + }, + }, + ], + label: Some("UniformBinding::bind_group") + } + ); + + Self { layout, bind_group } + } + + pub fn rebind(&mut self, device: &wgpu::Device, uniforms: &Uniforms) { + self.bind_group = device.create_bind_group( + &wgpu::BindGroupDescriptor { + layout: &self.layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniforms.buffer, + range: 0..std::mem::size_of_val(&uniforms) as wgpu::BufferAddress, + }, + }, + ], + label: Some("UniformBinding::bind_group") + } + ); + } +} + +pub trait Demo: 'static + Sized { + fn init(display: &Display) -> Result; + fn process_mouse(&mut self, dx: f64, dy: f64); + fn resize(&mut self, display: &Display); + fn update(&mut self, display: &Display, dt: Duration); + fn render(&mut self, display: &mut Display); +} + +pub async fn run() -> Result<(), Error> { + let event_loop = EventLoop::new(); + let window = WindowBuilder::new() + .with_title(env!("CARGO_PKG_NAME")) + .build(&event_loop)?; + let mut display = Display::new(&window).await?; + let mut demo = D::init(&mut display)?; + let mut last_update = Instant::now(); + let mut is_resumed = true; + let mut is_focused = true; + + event_loop.run(move |event, _, control_flow| { + *control_flow = if is_resumed && is_focused { + ControlFlow::Poll + } else { + ControlFlow::Wait + }; + + match event { + Event::Resumed => is_resumed = true, + Event::Suspended => is_resumed = false, + Event::RedrawRequested(wid) => if wid == window.id() { + let now = Instant::now(); + let dt = now - last_update; + last_update = now; + + demo.update(&mut display, dt); + demo.render(&mut display); + } + Event::MainEventsCleared => { + if is_focused && is_resumed { + window.request_redraw(); + } else { + // Freeze time while the demo is not in the foreground + last_update = Instant::now(); + } + } + Event::WindowEvent { + event, + window_id, + .. + } => if window_id == window.id() { + match event { + WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit, + WindowEvent::Focused(f) => is_focused = f, + WindowEvent::ScaleFactorChanged { + new_inner_size, + .. + } => { + display.resize(new_inner_size.width, new_inner_size.height); + demo.resize(&mut display); + } + WindowEvent::Resized(new_inner_size) => { + display.resize(new_inner_size.width, new_inner_size.height); + demo.resize(&mut display); + } + _ => {} + } + } + _ => {} + } + }); +} \ No newline at end of file diff --git a/code/showcase/framework/src/light.rs b/code/showcase/framework/src/light.rs new file mode 100644 index 00000000..132e5351 --- /dev/null +++ b/code/showcase/framework/src/light.rs @@ -0,0 +1,36 @@ +use cgmath::*; + +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct LightData { + pub position: Vector4, + pub color: Vector4, +} + +unsafe impl bytemuck::Pod for LightData {} +unsafe impl bytemuck::Zeroable for LightData {} + +pub struct Light { + data: LightData, + buffer: wgpu::Buffer, +} + +impl Light { + pub fn new(device: &wgpu::Device, position: Vector3, color: Vector3) -> Self { + let data = LightData { + position: Vector4::new(position.x, position.y, position.z, 1.0), + color: Vector4::new(color.x, color.y, color.z, 1.0), + }; + let buffer = device.create_buffer_with_data( + bytemuck::cast_slice(&[data]), + wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::UNIFORM, + ); + + Self { data, buffer } + } +} + +pub struct LightBinding { + pub layout: wgpu::BindGroupLayout, + pub bind_group: wgpu::BindGroup, +} \ No newline at end of file diff --git a/code/showcase/framework/src/model.rs b/code/showcase/framework/src/model.rs index fb54a351..453dd74b 100644 --- a/code/showcase/framework/src/model.rs +++ b/code/showcase/framework/src/model.rs @@ -1,5 +1,6 @@ use std::ops::Range; use std::path::Path; +use anyhow::*; use crate::texture; @@ -10,10 +11,13 @@ pub trait Vertex { #[repr(C)] #[derive(Copy, Clone, Debug)] pub struct ModelVertex { - position: [f32; 3], - tex_coords: [f32; 2], - normal: [f32; 3], + position: cgmath::Vector3, + tex_coords: cgmath::Vector2, + normal: cgmath::Vector3, + tangent: cgmath::Vector3, + bitangent: cgmath::Vector3, } + unsafe impl bytemuck::Zeroable for ModelVertex {} unsafe impl bytemuck::Pod for ModelVertex {} @@ -39,6 +43,17 @@ impl Vertex for ModelVertex { shader_location: 2, format: wgpu::VertexFormat::Float3, }, + // Tangent and bitangent + wgpu::VertexAttributeDescriptor { + offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, + shader_location: 3, + format: wgpu::VertexFormat::Float3, + }, + wgpu::VertexAttributeDescriptor { + offset: mem::size_of::<[f32; 11]>() as wgpu::BufferAddress, + shader_location: 4, + format: wgpu::VertexFormat::Float3, + }, ], } } @@ -47,9 +62,50 @@ impl Vertex for ModelVertex { pub struct Material<'a> { pub name: String, pub diffuse_texture: texture::Texture<'a>, + pub normal_texture: texture::Texture<'a>, pub bind_group: wgpu::BindGroup, } +impl<'a> Material<'a> { + pub fn new( + device: &wgpu::Device, + name: &str, + diffuse_texture: texture::Texture<'a>, + normal_texture: texture::Texture<'a>, + layout: &wgpu::BindGroupLayout, + ) -> Self { + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), + }, + wgpu::Binding { + binding: 1, + resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), + }, + wgpu::Binding { + binding: 2, + resource: wgpu::BindingResource::TextureView(&normal_texture.view), + }, + wgpu::Binding { + binding: 3, + resource: wgpu::BindingResource::Sampler(&normal_texture.sampler), + }, + ], + label: Some(name), + }); + + Self { + name: String::from(name), + diffuse_texture, + normal_texture, + bind_group, + } + } +} + pub struct Mesh { pub name: String, pub vertex_buffer: wgpu::Buffer, @@ -68,42 +124,36 @@ impl<'a> Model<'a> { device: &wgpu::Device, layout: &wgpu::BindGroupLayout, path: P, - ) -> Result<(Self, Vec), failure::Error> { - let (obj_models, obj_materials) = tobj::load_obj(path.as_ref())?; + ) -> Result<(Self, Vec)> { + let (obj_models, obj_materials) = tobj::load_obj(path.as_ref(), true)?; // We're assuming that the texture files are stored with the obj file - let containing_folder = path.as_ref().parent().unwrap(); + let containing_folder = path.as_ref() + .parent() + .context("Unable to find parent for model")?; // Our `Texure` struct currently returns a `CommandBuffer` when it's created so we need to collect those and return them. let mut command_buffers = Vec::new(); let mut materials = Vec::new(); for mat in obj_materials { + let name = mat.name; let diffuse_path = mat.diffuse_texture; - let (diffuse_texture, cmds) = - texture::Texture::load(&device, containing_folder.join(diffuse_path))?; - - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout, - bindings: &[ - wgpu::Binding { - binding: 0, - resource: wgpu::BindingResource::TextureView(&diffuse_texture.view), - }, - wgpu::Binding { - binding: 1, - resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler), - }, - ], - label: None, - }); + let (diffuse_texture, cmds) = texture::Texture::load(device, containing_folder.join(diffuse_path), false)?; + command_buffers.push(cmds); + + let normal_path = mat.unknown_param.get("map_Bump") + .with_context(|| format!("No normal map specified for {}", name))?; + let (normal_texture, cmds) = texture::Texture::load(device, containing_folder.join(normal_path), true)?; + command_buffers.push(cmds); - materials.push(Material { - name: mat.name, + materials.push(Material::new( + device, + &name, diffuse_texture, - bind_group, - }); - command_buffers.push(cmds); + normal_texture, + layout, + )); } let mut meshes = Vec::new(); @@ -115,23 +165,76 @@ impl<'a> Model<'a> { m.mesh.positions[i * 3], m.mesh.positions[i * 3 + 1], m.mesh.positions[i * 3 + 2], - ], - tex_coords: [m.mesh.texcoords[i * 2], m.mesh.texcoords[i * 2 + 1]], + ].into(), + tex_coords: [ + m.mesh.texcoords[i * 2], + m.mesh.texcoords[i * 2 + 1] + ].into(), normal: [ m.mesh.normals[i * 3], m.mesh.normals[i * 3 + 1], m.mesh.normals[i * 3 + 2], - ], + ].into(), + // We'll calculate these later + tangent: [0.0; 3].into(), + bitangent: [0.0; 3].into(), }); } + let indices = &m.mesh.indices; + + // Calculate tangents and bitangets. We're going to + // use the triangles, so we need to loop through the + // indices in chunks of 3 + for c in indices.chunks(3) { + let v0 = vertices[c[0] as usize]; + let v1 = vertices[c[1] as usize]; + let v2 = vertices[c[2] as usize]; + + let pos0 = v0.position; + let pos1 = v1.position; + let pos2 = v2.position; + + let uv0 = v0.tex_coords; + let uv1 = v1.tex_coords; + let uv2 = v2.tex_coords; + + // Calculate the edges of the triangle + let delta_pos1 = pos1 - pos0; + let delta_pos2 = pos2 - pos0; + + // This will give us a direction to calculate the + // tangent and bitangent + let delta_uv1 = uv1 - uv0; + let delta_uv2 = uv2 - uv0; + + // Solving the following system of equations will + // give us the tangent and bitangent. + // delta_pos1 = delta_uv1.x * T + delta_u.y * B + // delta_pos2 = delta_uv2.x * T + delta_uv2.y * B + // Luckily, the place I found this equation provided + // the solution! + let r = 1.0 / (delta_uv1 .x * delta_uv2.y - delta_uv1.y * delta_uv2.x); + let tangent = (delta_pos1 * delta_uv2.y - delta_pos2 * delta_uv1.y) * r; + let bitangent = (delta_pos2 * delta_uv1.x - delta_pos1 * delta_uv2.x) * r; + + // We'll use the same tangent/bitangent for each vertex in the triangle + vertices[c[0] as usize].tangent = tangent; + vertices[c[1] as usize].tangent = tangent; + vertices[c[2] as usize].tangent = tangent; + + vertices[c[0] as usize].bitangent = bitangent; + vertices[c[1] as usize].bitangent = bitangent; + vertices[c[2] as usize].bitangent = bitangent; + } + let vertex_buffer = device.create_buffer_with_data( bytemuck::cast_slice(&vertices), wgpu::BufferUsage::VERTEX, ); let index_buffer = device.create_buffer_with_data( - bytemuck::cast_slice(&m.mesh.indices), + bytemuck::cast_slice(indices), wgpu::BufferUsage::INDEX, ); @@ -181,6 +284,14 @@ where uniforms: &'b wgpu::BindGroup, light: &'b wgpu::BindGroup, ); + fn draw_model_instanced_with_material( + &mut self, + model: &'b Model, + material: &'b Material, + instances: Range, + uniforms: &'b wgpu::BindGroup, + light: &'b wgpu::BindGroup, + ); } impl<'a, 'b> DrawModel<'a, 'b> for wgpu::RenderPass<'a> @@ -234,6 +345,19 @@ where self.draw_mesh_instanced(mesh, material, instances.clone(), uniforms, light); } } + + fn draw_model_instanced_with_material( + &mut self, + model: &'b Model, + material: &'b Material, + instances: Range, + uniforms: &'b wgpu::BindGroup, + light: &'b wgpu::BindGroup, + ) { + for mesh in &model.meshes { + self.draw_mesh_instanced(mesh, material, instances.clone(), uniforms, light); + } + } } pub trait DrawLight<'a, 'b> @@ -317,3 +441,9 @@ where } } } + + +pub struct ModelPass { + pipeline: wgpu::RenderPipeline, + // uniforms: +} \ No newline at end of file diff --git a/code/showcase/framework/src/pipeline.rs b/code/showcase/framework/src/pipeline.rs new file mode 100644 index 00000000..1c1c262c --- /dev/null +++ b/code/showcase/framework/src/pipeline.rs @@ -0,0 +1,250 @@ +use anyhow::*; +use crate::model::Vertex; + +pub struct RenderPipelineBuilder<'a> { + layout: Option<&'a wgpu::PipelineLayout>, + vertex_shader: Option<&'a [u8]>, + fragment_shader: Option<&'a [u8]>, + front_face: wgpu::FrontFace, + cull_mode: wgpu::CullMode, + depth_bias: i32, + depth_bias_slope_scale: f32, + depth_bias_clamp: f32, + primitive_topology: wgpu::PrimitiveTopology, + color_states: Vec, + depth_stencil_state: Option, + index_format: wgpu::IndexFormat, + vertex_buffers: Vec>, + sample_count: u32, + sample_mask: u32, + alpha_to_coverage_enabled: bool, +} + +impl<'a> RenderPipelineBuilder<'a> { + pub fn new() -> Self { + Self { + layout: None, + vertex_shader: None, + fragment_shader: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::None, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: Vec::new(), + depth_stencil_state: None, + index_format: wgpu::IndexFormat::Uint32, + vertex_buffers: Vec::new(), + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + } + } + + pub fn layout(&mut self, layout: &'a wgpu::PipelineLayout) -> &mut Self { + self.layout = Some(layout); + self + } + + pub fn vertex_shader(&mut self, spv: &'a [u8]) -> &mut Self { + self.vertex_shader = Some(spv); + self + } + + pub fn fragment_shader(&mut self, spv: &'a [u8]) -> &mut Self { + self.fragment_shader = Some(spv); + self + } + + #[allow(dead_code)] + pub fn front_face(&mut self, ff: wgpu::FrontFace) -> &mut Self { + self.front_face = ff; + self + } + + #[allow(dead_code)] + pub fn cull_mode(&mut self, cm: wgpu::CullMode) -> &mut Self { + self.cull_mode = cm; + self + } + + + #[allow(dead_code)] + pub fn depth_bias(&mut self, db: i32) -> &mut Self { + self.depth_bias = db; + self + } + + #[allow(dead_code)] + pub fn depth_bias_slope_scale(&mut self, dbss: f32) -> &mut Self { + self.depth_bias_slope_scale = dbss; + self + } + + #[allow(dead_code)] + pub fn depth_bias_clamp(&mut self, dbc: f32) -> &mut Self { + self.depth_bias_clamp = dbc; + self + } + + #[allow(dead_code)] + pub fn primitive_topology(&mut self, pt: wgpu::PrimitiveTopology) -> &mut Self { + self.primitive_topology = pt; + self + } + + pub fn color_state(&mut self, cs: wgpu::ColorStateDescriptor) -> &mut Self { + self.color_states.push(cs); + self + } + + /// Helper method for [RenderPipelineBuilder::color_state] + pub fn color_solid(&mut self, format: wgpu::TextureFormat) -> &mut Self { + self.color_state( + wgpu::ColorStateDescriptor { + format, + alpha_blend: wgpu::BlendDescriptor::REPLACE, + color_blend: wgpu::BlendDescriptor::REPLACE, + write_mask: wgpu::ColorWrite::ALL, + } + ) + } + + pub fn depth_stencil_state(&mut self, dss: wgpu::DepthStencilStateDescriptor) -> &mut Self { + self.depth_stencil_state = Some(dss); + self + } + + /// Helper method for [RenderPipelineBuilder::depth_stencil_state] + pub fn depth_no_stencil( + &mut self, + format: wgpu::TextureFormat, + depth_write_enabled: bool, + depth_compare: wgpu::CompareFunction, + ) -> &mut Self { + self.depth_stencil_state( + wgpu::DepthStencilStateDescriptor { + format, + depth_write_enabled, + depth_compare, + stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + } + ) + } + + /// Helper method for [RenderPipelineBuilder::depth_no_stencil] + pub fn depth_format(&mut self, format: wgpu::TextureFormat) -> &mut Self { + self.depth_no_stencil(format, true, wgpu::CompareFunction::Less) + } + + #[allow(dead_code)] + pub fn index_format(&mut self, ifmt: wgpu::IndexFormat) -> &mut Self { + self.index_format = ifmt; + self + } + + pub fn vertex_buffer(&mut self) -> &mut Self { + self.vertex_buffers.push(V::desc()); + self + } + + pub fn vertex_buffer_desc(&mut self, vb: wgpu::VertexBufferDescriptor<'a>) -> &mut Self { + self.vertex_buffers.push(vb); + self + } + + #[allow(dead_code)] + pub fn sample_count(&mut self, sc: u32) -> &mut Self { + self.sample_count = sc; + self + } + + #[allow(dead_code)] + pub fn sample_mask(&mut self, sm: u32) -> &mut Self { + self.sample_mask = sm; + self + } + + #[allow(dead_code)] + pub fn alpha_to_coverage_enabled(&mut self, atce: bool) -> &mut Self { + self.alpha_to_coverage_enabled = atce; + self + } + + pub fn build(&self, device: &wgpu::Device) -> Result { + // We need a layout + if self.layout.is_none() { + bail!("No pipeline layout supplied!"); + } + let layout = self.layout.unwrap(); + + // Render pipelines always have a vertex shader, but due + // to the way the builder pattern works, we can't + // guarantee that the user will specify one, so we'll + // just return an error if they forgot. + // + // We could supply a default one, but a "default" vertex + // could take on many forms. An error is much more + // explicit. + if self.vertex_shader.is_none() { + bail!("No vertex shader supplied!") + } + let vs = create_shader_module(device, self.vertex_shader.context("Please include a vertex shader")?); + + // The fragment shader is optional (IDK why, but it is). + // Having the shader be optional is giving me issues with + // the borrow checker so I'm going to use a default shader + // if the user doesn't supply one. + let fs_spv = self.fragment_shader.context("Please include a fragment shader")?; + let fs = create_shader_module(device, fs_spv); + + let pipeline = device.create_render_pipeline( + &wgpu::RenderPipelineDescriptor { + layout: &layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs, + entry_point: "main", + }, + fragment_stage: Some( + wgpu::ProgrammableStageDescriptor { + module: &fs, + entry_point: "main", + } + ), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: self.front_face, + cull_mode: self.cull_mode, + depth_bias: self.depth_bias, + depth_bias_slope_scale: self.depth_bias_slope_scale, + depth_bias_clamp: self.depth_bias_clamp, + }), + primitive_topology: self.primitive_topology, + color_states: &self.color_states, + depth_stencil_state: self.depth_stencil_state.clone(), + vertex_state: wgpu::VertexStateDescriptor { + index_format: self.index_format, + vertex_buffers: &self.vertex_buffers, + }, + sample_count: self.sample_count, + sample_mask: self.sample_mask, + alpha_to_coverage_enabled: self.alpha_to_coverage_enabled, + } + ); + Ok(pipeline) + } +} + + +fn create_shader_module(device: &wgpu::Device, spirv: &[u8]) -> wgpu::ShaderModule { + device.create_shader_module( + &wgpu::read_spirv( + std::io::Cursor::new( + spirv + ) + ).unwrap() + ) +} \ No newline at end of file diff --git a/code/showcase/framework/src/prelude.rs b/code/showcase/framework/src/prelude.rs new file mode 100644 index 00000000..01202ba9 --- /dev/null +++ b/code/showcase/framework/src/prelude.rs @@ -0,0 +1 @@ +pub use crate::model::{DrawLight, DrawModel}; \ No newline at end of file diff --git a/code/showcase/framework/src/texture.rs b/code/showcase/framework/src/texture.rs index c2dbec76..1e31a77f 100644 --- a/code/showcase/framework/src/texture.rs +++ b/code/showcase/framework/src/texture.rs @@ -1,6 +1,7 @@ use image::GenericImageView; use std::path::Path; use std::mem; +use anyhow::*; use crate::buffer; @@ -15,30 +16,19 @@ pub struct Texture<'a> { impl<'a> Texture<'a> { pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; - pub fn load>(device: &wgpu::Device, path: P) -> Result<(Self, wgpu::CommandBuffer), failure::Error> { + pub fn load>( + device: &wgpu::Device, + path: P, + is_normal_map: bool, + ) -> Result<(Self, wgpu::CommandBuffer)> { let img = image::open(path)?; - Self::from_image(device, &img) + Self::from_image(device, &img, is_normal_map) } - pub fn create_depth_texture(device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self { - let desc = wgpu::TextureDescriptor { - label: None, - size: wgpu::Extent3d { - width: sc_desc.width, - height: sc_desc.height, - depth: 1, - }, - array_layer_count: 1, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - }; - Self::from_descriptor(device, desc) - } - - pub fn from_descriptor(device: &wgpu::Device, desc: wgpu::TextureDescriptor<'a>) -> Self { + pub fn from_descriptor( + device: &wgpu::Device, + desc: wgpu::TextureDescriptor<'a> + ) -> Self { let texture = device.create_texture(&desc); let view = texture.create_default_view(); @@ -57,12 +47,20 @@ impl<'a> Texture<'a> { Self { texture, view, sampler, desc } } - pub fn from_bytes(device: &wgpu::Device, bytes: &[u8]) -> Result<(Self, wgpu::CommandBuffer), failure::Error> { + pub fn from_bytes( + device: &wgpu::Device, + is_normal_map: bool, + bytes: &[u8], + ) -> Result<(Self, wgpu::CommandBuffer)> { let img = image::load_from_memory(bytes)?; - Self::from_image(device, &img) + Self::from_image(device, &img, is_normal_map) } - pub fn from_image(device: &wgpu::Device, img: &image::DynamicImage) -> Result<(Self, wgpu::CommandBuffer), failure::Error> { + pub fn from_image( + device: &wgpu::Device, + img: &image::DynamicImage, + is_normal_map: bool, + ) -> Result<(Self, wgpu::CommandBuffer)> { let rgba = img.to_rgba(); let dimensions = img.dimensions(); @@ -77,7 +75,11 @@ impl<'a> Texture<'a> { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: wgpu::TextureFormat::Rgba8UnormSrgb, + format: if is_normal_map { + wgpu::TextureFormat::Rgba8Unorm + } else { + wgpu::TextureFormat::Rgba8UnormSrgb + }, usage: wgpu::TextureUsage::SAMPLED | wgpu::TextureUsage::COPY_DST, label: None, }; @@ -126,6 +128,24 @@ impl<'a> Texture<'a> { Ok((Self { texture, view, sampler, desc }, cmd_buffer)) } + pub fn create_depth_texture(device: &wgpu::Device, sc_desc: &wgpu::SwapChainDescriptor) -> Self { + let desc = wgpu::TextureDescriptor { + label: None, + size: wgpu::Extent3d { + width: sc_desc.width, + height: sc_desc.height, + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }; + Self::from_descriptor(device, desc) + } + pub fn prepare_buffer_rgba(&self, device: &wgpu::Device) -> buffer::RawBuffer<[f32;4]> { let num_pixels = self.desc.size.width * self.desc.size.height * self.desc.size.depth; @@ -144,4 +164,4 @@ impl<'a> Texture<'a> { raw_buffer } -} \ No newline at end of file +} \ No newline at end of file diff --git a/code/showcase/gifs/Cargo.toml b/code/showcase/gifs/Cargo.toml index fd26ddeb..a4556c62 100644 --- a/code/showcase/gifs/Cargo.toml +++ b/code/showcase/gifs/Cargo.toml @@ -7,14 +7,12 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -image = "0.22.4" -winit = "0.20.0" +image = "0.23" shaderc = "0.6" cgmath = "0.17.0" failure = "0.1" -tobj = "0.1" -wgpu = "0.5.0" -futures = "0.3.4" +wgpu = "0.5" +futures = "0.3" gif = "0.10.3" framework = { path = "../framework" } \ No newline at end of file diff --git a/code/showcase/gifs/src/main.rs b/code/showcase/gifs/src/main.rs index 1d927952..3e45bb4b 100644 --- a/code/showcase/gifs/src/main.rs +++ b/code/showcase/gifs/src/main.rs @@ -153,21 +153,6 @@ fn save_gif(path: &str, frames: &mut Vec>, speed: i32, size: u16) -> Res Ok(()) } -// The image crate currently doesn't support looping gifs, so I'm not using this -// code. I'm keeping it around in case image adds looping support. -#[allow(unused)] -fn save_gif_old(path: &str, frames: &mut Vec>, speed: i32, size: u16) -> Result<(), failure::Error> { - let output = std::fs::File::create(path)?; - let mut encoder = image::gif::Encoder::new(output); - - for mut data in frames { - let frame = image::gif::Frame::from_rgba_speed(size, size, &mut data, speed); - encoder.encode(&frame)?; - } - - Ok(()) -} - fn create_render_pipeline(device: &wgpu::Device, target: &framework::Texture) -> wgpu::RenderPipeline { let vs_src = include_str!("res/shader.vert"); diff --git a/code/showcase/instancing/Cargo.toml b/code/showcase/instancing/Cargo.toml new file mode 100644 index 00000000..1a05a982 --- /dev/null +++ b/code/showcase/instancing/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "instancing" +version = "0.1.0" +authors = ["Ben Hansen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +bytemuck = "1.3" +image = "0.23" +framework = { path = "../framework"} +futures = "0.3" +rand = "0.7" +tobj = "2" +winit = "0.22" +wgpu = "0.5" + +[dependencies.cgmath] +version = "0.17" +features = ["swizzle"] + +[build-dependencies] +failure = "0.1" +fs_extra = "1.1" +glob = "0.3" +shaderc = "0.6" + +[[bin]] +name = "instancing-storage-buffers" +path = "src/storage_buffers.rs" \ No newline at end of file diff --git a/code/showcase/instancing/build.rs b/code/showcase/instancing/build.rs new file mode 100644 index 00000000..e4b5178a --- /dev/null +++ b/code/showcase/instancing/build.rs @@ -0,0 +1,88 @@ +use glob::glob; +use failure::bail; +use fs_extra::copy_items; +use fs_extra::dir::CopyOptions; +use std::env; +use std::fs::{read_to_string, write}; +use std::path::{PathBuf}; + +fn main() { + copy_res(); + compile_shaders(); +} + +fn copy_res() { + // This tells cargo to rerun this script if something in /res/ changes. + println!("cargo:rerun-if-changed=res/*"); + + let out_dir = env::var("OUT_DIR").unwrap(); + let mut copy_options = CopyOptions::new(); + copy_options.overwrite = true; + let mut paths_to_copy = Vec::new(); + paths_to_copy.push("res/"); + copy_items(&paths_to_copy, out_dir, ©_options).unwrap(); +} + +fn compile_shaders() { + // This tells cargo to rerun this script if something in /src/ changes. + println!("cargo:rerun-if-changed=src/*"); + + // Collect all shaders recursively within /src/ + let mut shader_paths = [ + glob("./src/**/*.vert").unwrap(), + glob("./src/**/*.frag").unwrap(), + glob("./src/**/*.comp").unwrap(), + ]; + + // This could be parallelized + let shaders = shader_paths.iter_mut() + .flatten() + .map(|glob_result| { + ShaderData::load(glob_result.unwrap()).unwrap() + }) + .collect::>(); + + let mut compiler = shaderc::Compiler::new().unwrap(); + + // This can't be parallelized. The [shaderc::Compiler] is not + // thread safe. Also, it creates a lot of resources. You could + // spawn multiple processes to handle this, but it would probably + // be better just to only compile shaders that have been changed + // recently. + for shader in shaders { + let compiled = compiler.compile_into_spirv( + &shader.src, + shader.kind, + &shader.src_path.to_str().unwrap(), + "main", + None + ).unwrap(); + write(shader.spv_path, compiled.as_binary_u8()).unwrap(); + } + + // panic!("Debugging..."); +} + +struct ShaderData { + src: String, + src_path: PathBuf, + spv_path: PathBuf, + kind: shaderc::ShaderKind, +} + +impl ShaderData { + pub fn load(src_path: PathBuf) -> Result { + let extension = src_path.extension().unwrap().to_str().unwrap(); + let kind = match extension { + "vert" => shaderc::ShaderKind::Vertex, + "frag" => shaderc::ShaderKind::Fragment, + "comp" => shaderc::ShaderKind::Compute, + _ => bail!("Unsupported shader: {}", src_path.display()), + }; + + let src = read_to_string(src_path.clone())?; + let spv_path = src_path.with_extension(format!("{}.spv", extension)); + + Ok(Self { src, src_path, spv_path, kind }) + } +} \ No newline at end of file diff --git a/code/showcase/instancing/res/cobble-diffuse.png b/code/showcase/instancing/res/cobble-diffuse.png new file mode 100644 index 00000000..93eda7e3 Binary files /dev/null and b/code/showcase/instancing/res/cobble-diffuse.png differ diff --git a/code/showcase/instancing/res/cobble-normal.png b/code/showcase/instancing/res/cobble-normal.png new file mode 100644 index 00000000..b75fe812 Binary files /dev/null and b/code/showcase/instancing/res/cobble-normal.png differ diff --git a/code/showcase/instancing/res/cube-diffuse.jpg b/code/showcase/instancing/res/cube-diffuse.jpg new file mode 100644 index 00000000..c89b31d5 Binary files /dev/null and b/code/showcase/instancing/res/cube-diffuse.jpg differ diff --git a/code/showcase/instancing/res/cube-normal.png b/code/showcase/instancing/res/cube-normal.png new file mode 100644 index 00000000..5bbac0af Binary files /dev/null and b/code/showcase/instancing/res/cube-normal.png differ diff --git a/code/showcase/instancing/res/cube.mtl b/code/showcase/instancing/res/cube.mtl new file mode 100644 index 00000000..6be388c0 --- /dev/null +++ b/code/showcase/instancing/res/cube.mtl @@ -0,0 +1,14 @@ +# Blender MTL File: 'cube.blend' +# Material Count: 1 + +newmtl Material.001 +Ns 323.999994 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.000000 0.000000 0.000000 +Ni 1.450000 +d 1.000000 +illum 2 +map_Bump cube-normal.png +map_Kd cube-diffuse.jpg diff --git a/code/showcase/instancing/res/cube.obj b/code/showcase/instancing/res/cube.obj new file mode 100644 index 00000000..03b3bcae --- /dev/null +++ b/code/showcase/instancing/res/cube.obj @@ -0,0 +1,1143 @@ +# Blender v2.82 (sub 7) OBJ File: 'cube.blend' +# www.blender.org +mtllib cube.mtl +o Cube_Finished_Cube.001 +v 0.900000 0.900000 -1.000000 +v 0.900000 1.000000 -0.900000 +v 1.000000 0.900000 -0.900000 +v 0.900000 0.930907 -0.995104 +v 0.900000 0.958769 -0.980909 +v 0.930907 0.900000 -0.995104 +v 0.931727 0.931906 -0.989305 +v 0.930693 0.957414 -0.975905 +v 0.958769 0.900000 -0.980909 +v 0.957466 0.930772 -0.975834 +v 0.952912 0.952912 -0.966338 +v 0.930907 0.995104 -0.900000 +v 0.958769 0.980909 -0.900000 +v 0.900000 0.995104 -0.930907 +v 0.931906 0.989305 -0.931727 +v 0.957414 0.975905 -0.930693 +v 0.900000 0.980909 -0.958769 +v 0.930772 0.975834 -0.957466 +v 0.952912 0.966338 -0.952912 +v 0.995104 0.900000 -0.930907 +v 0.980909 0.900000 -0.958769 +v 0.995104 0.930907 -0.900000 +v 0.989305 0.931727 -0.931906 +v 0.975905 0.930693 -0.957414 +v 0.980909 0.958769 -0.900000 +v 0.975834 0.957466 -0.930772 +v 0.966338 0.952912 -0.952912 +v 0.900000 -1.000000 -0.900000 +v 0.900000 -0.900000 -1.000000 +v 1.000000 -0.900000 -0.900000 +v 0.900000 -0.995104 -0.930907 +v 0.900000 -0.980909 -0.958769 +v 0.930907 -0.995104 -0.900000 +v 0.931727 -0.989305 -0.931906 +v 0.930693 -0.975905 -0.957414 +v 0.958769 -0.980909 -0.900000 +v 0.957466 -0.975834 -0.930772 +v 0.952912 -0.966338 -0.952912 +v 0.930907 -0.900000 -0.995104 +v 0.958769 -0.900000 -0.980909 +v 0.900000 -0.930907 -0.995104 +v 0.931906 -0.931727 -0.989305 +v 0.957414 -0.930693 -0.975905 +v 0.900000 -0.958769 -0.980909 +v 0.930772 -0.957466 -0.975834 +v 0.952912 -0.952912 -0.966338 +v 0.995104 -0.930907 -0.900000 +v 0.980909 -0.958769 -0.900000 +v 0.995104 -0.900000 -0.930907 +v 0.989305 -0.931906 -0.931727 +v 0.975905 -0.957414 -0.930693 +v 0.980909 -0.900000 -0.958769 +v 0.975834 -0.930772 -0.957466 +v 0.966338 -0.952912 -0.952912 +v 1.000000 0.900000 0.900000 +v 0.900000 1.000000 0.900000 +v 0.900000 0.900000 1.000000 +v 0.995104 0.930907 0.900000 +v 0.980909 0.958769 0.900000 +v 0.995104 0.900000 0.930907 +v 0.989305 0.931906 0.931727 +v 0.975905 0.957414 0.930693 +v 0.980909 0.900000 0.958769 +v 0.975834 0.930772 0.957466 +v 0.966338 0.952912 0.952912 +v 0.900000 0.995104 0.930907 +v 0.900000 0.980909 0.958769 +v 0.930907 0.995104 0.900000 +v 0.931727 0.989305 0.931906 +v 0.930693 0.975905 0.957414 +v 0.958769 0.980909 0.900000 +v 0.957466 0.975834 0.930772 +v 0.952912 0.966338 0.952912 +v 0.930907 0.900000 0.995104 +v 0.958769 0.900000 0.980909 +v 0.900000 0.930907 0.995104 +v 0.931906 0.931727 0.989305 +v 0.957414 0.930693 0.975905 +v 0.900000 0.958769 0.980909 +v 0.930772 0.957466 0.975834 +v 0.952912 0.952912 0.966338 +v 1.000000 -0.900000 0.900000 +v 0.900000 -0.900000 1.000000 +v 0.900000 -1.000000 0.900000 +v 0.995104 -0.900000 0.930907 +v 0.980909 -0.900000 0.958769 +v 0.995104 -0.930907 0.900000 +v 0.989305 -0.931727 0.931906 +v 0.975905 -0.930693 0.957414 +v 0.980909 -0.958769 0.900000 +v 0.975834 -0.957466 0.930772 +v 0.966338 -0.952912 0.952912 +v 0.900000 -0.930907 0.995104 +v 0.900000 -0.958769 0.980909 +v 0.930907 -0.900000 0.995104 +v 0.931727 -0.931906 0.989305 +v 0.930693 -0.957414 0.975905 +v 0.958769 -0.900000 0.980909 +v 0.957466 -0.930772 0.975834 +v 0.952912 -0.952912 0.966338 +v 0.930907 -0.995104 0.900000 +v 0.958769 -0.980909 0.900000 +v 0.900000 -0.995104 0.930907 +v 0.931906 -0.989305 0.931727 +v 0.957414 -0.975905 0.930693 +v 0.900000 -0.980909 0.958769 +v 0.930772 -0.975834 0.957466 +v 0.952912 -0.966338 0.952912 +v -0.900000 0.900000 -1.000000 +v -1.000000 0.900000 -0.900000 +v -0.900000 1.000000 -0.900000 +v -0.930907 0.900000 -0.995104 +v -0.958769 0.900000 -0.980909 +v -0.900000 0.930907 -0.995104 +v -0.931906 0.931727 -0.989305 +v -0.957414 0.930693 -0.975905 +v -0.900000 0.958769 -0.980909 +v -0.930772 0.957466 -0.975834 +v -0.952912 0.952912 -0.966338 +v -0.995104 0.930907 -0.900000 +v -0.980909 0.958769 -0.900000 +v -0.995104 0.900000 -0.930907 +v -0.989305 0.931906 -0.931727 +v -0.975905 0.957414 -0.930693 +v -0.980909 0.900000 -0.958769 +v -0.975834 0.930772 -0.957466 +v -0.966338 0.952912 -0.952912 +v -0.900000 0.995104 -0.930907 +v -0.900000 0.980909 -0.958769 +v -0.930907 0.995104 -0.900000 +v -0.931727 0.989305 -0.931906 +v -0.930693 0.975905 -0.957414 +v -0.958769 0.980909 -0.900000 +v -0.957466 0.975834 -0.930772 +v -0.952912 0.966338 -0.952912 +v -1.000000 -0.900000 -0.900000 +v -0.900000 -0.900000 -1.000000 +v -0.900000 -1.000000 -0.900000 +v -0.995104 -0.900000 -0.930907 +v -0.980909 -0.900000 -0.958769 +v -0.995104 -0.930907 -0.900000 +v -0.989305 -0.931727 -0.931906 +v -0.975905 -0.930693 -0.957414 +v -0.980909 -0.958769 -0.900000 +v -0.975834 -0.957466 -0.930772 +v -0.966338 -0.952912 -0.952912 +v -0.900000 -0.930907 -0.995104 +v -0.900000 -0.958769 -0.980909 +v -0.930907 -0.900000 -0.995104 +v -0.931727 -0.931906 -0.989305 +v -0.930693 -0.957414 -0.975905 +v -0.958769 -0.900000 -0.980909 +v -0.957466 -0.930772 -0.975834 +v -0.952912 -0.952912 -0.966338 +v -0.930907 -0.995104 -0.900000 +v -0.958769 -0.980909 -0.900000 +v -0.900000 -0.995104 -0.930907 +v -0.931906 -0.989305 -0.931727 +v -0.957414 -0.975905 -0.930693 +v -0.900000 -0.980909 -0.958769 +v -0.930772 -0.975834 -0.957466 +v -0.952912 -0.966338 -0.952912 +v -1.000000 0.900000 0.900000 +v -0.900000 0.900000 1.000000 +v -0.900000 1.000000 0.900000 +v -0.995104 0.900000 0.930907 +v -0.980909 0.900000 0.958769 +v -0.995104 0.930907 0.900000 +v -0.989305 0.931727 0.931906 +v -0.975905 0.930693 0.957414 +v -0.980909 0.958769 0.900000 +v -0.975834 0.957466 0.930772 +v -0.966338 0.952912 0.952912 +v -0.900000 0.930907 0.995104 +v -0.900000 0.958769 0.980909 +v -0.930907 0.900000 0.995104 +v -0.931727 0.931906 0.989305 +v -0.930693 0.957414 0.975905 +v -0.958769 0.900000 0.980909 +v -0.957466 0.930772 0.975834 +v -0.952912 0.952912 0.966338 +v -0.930907 0.995104 0.900000 +v -0.958769 0.980909 0.900000 +v -0.900000 0.995104 0.930907 +v -0.931906 0.989305 0.931727 +v -0.957414 0.975905 0.930693 +v -0.900000 0.980909 0.958769 +v -0.930772 0.975834 0.957466 +v -0.952912 0.966338 0.952912 +v -0.900000 -1.000000 0.900000 +v -0.900000 -0.900000 1.000000 +v -1.000000 -0.900000 0.900000 +v -0.900000 -0.995104 0.930907 +v -0.900000 -0.980909 0.958769 +v -0.930907 -0.995104 0.900000 +v -0.931727 -0.989305 0.931906 +v -0.930693 -0.975905 0.957414 +v -0.958769 -0.980909 0.900000 +v -0.957466 -0.975834 0.930772 +v -0.952912 -0.966338 0.952912 +v -0.930907 -0.900000 0.995104 +v -0.958769 -0.900000 0.980909 +v -0.900000 -0.930907 0.995104 +v -0.931906 -0.931727 0.989305 +v -0.957414 -0.930693 0.975905 +v -0.900000 -0.958769 0.980909 +v -0.930772 -0.957466 0.975834 +v -0.952912 -0.952912 0.966338 +v -0.995104 -0.930907 0.900000 +v -0.980909 -0.958769 0.900000 +v -0.995104 -0.900000 0.930907 +v -0.989305 -0.931906 0.931727 +v -0.975905 -0.957414 0.930693 +v -0.980909 -0.900000 0.958769 +v -0.975834 -0.930772 0.957466 +v -0.966338 -0.952912 0.952912 +vt 0.362500 0.512500 +vt 0.137500 0.737500 +vt 0.137500 0.512500 +vt 0.612500 0.012500 +vt 0.387500 0.237500 +vt 0.387500 0.012500 +vt 0.612500 0.762500 +vt 0.387500 0.987500 +vt 0.387500 0.762500 +vt 0.862500 0.512500 +vt 0.637500 0.737500 +vt 0.637500 0.512500 +vt 0.612500 0.512500 +vt 0.387500 0.737500 +vt 0.387500 0.512500 +vt 0.616363 0.487500 +vt 0.612500 0.491363 +vt 0.612500 0.487500 +vt 0.619846 0.487500 +vt 0.616488 0.491466 +vt 0.625000 0.487500 +vt 0.619677 0.491337 +vt 0.612500 0.494846 +vt 0.619114 0.494114 +vt 0.616346 0.494683 +vt 0.625000 0.491347 +vt 0.633637 0.512500 +vt 0.637500 0.508637 +vt 0.630154 0.512500 +vt 0.633512 0.508534 +vt 0.619846 0.512500 +vt 0.630323 0.508663 +vt 0.637500 0.505154 +vt 0.630886 0.505886 +vt 0.633654 0.505317 +vt 0.619683 0.508653 +vt 0.612500 0.508637 +vt 0.616363 0.512500 +vt 0.612500 0.505154 +vt 0.616466 0.508512 +vt 0.616337 0.505323 +vt 0.619114 0.505886 +vt 0.625000 0.494114 +vt 0.619114 0.500000 +vt 0.362500 0.508637 +vt 0.366363 0.512500 +vt 0.362500 0.505154 +vt 0.366466 0.508512 +vt 0.362500 0.500000 +vt 0.366337 0.505323 +vt 0.369846 0.512500 +vt 0.369114 0.505886 +vt 0.369683 0.508653 +vt 0.366347 0.500000 +vt 0.387500 0.491363 +vt 0.383637 0.487500 +vt 0.387500 0.487500 +vt 0.387500 0.494846 +vt 0.383534 0.491488 +vt 0.387500 0.505154 +vt 0.383663 0.494677 +vt 0.380154 0.487500 +vt 0.380886 0.494114 +vt 0.380317 0.491346 +vt 0.383653 0.505317 +vt 0.383637 0.512500 +vt 0.387500 0.508637 +vt 0.380154 0.512500 +vt 0.383512 0.508534 +vt 0.380323 0.508663 +vt 0.380886 0.505886 +vt 0.369114 0.500000 +vt 0.375000 0.505886 +vt 0.616363 0.737500 +vt 0.612500 0.741363 +vt 0.612500 0.737500 +vt 0.619846 0.737500 +vt 0.616488 0.741466 +vt 0.630154 0.737500 +vt 0.619677 0.741337 +vt 0.612500 0.744846 +vt 0.619114 0.744114 +vt 0.616346 0.744683 +vt 0.630317 0.741346 +vt 0.637500 0.741363 +vt 0.633637 0.737500 +vt 0.637500 0.744846 +vt 0.633534 0.741488 +vt 0.637500 0.750000 +vt 0.633664 0.744677 +vt 0.630886 0.744114 +vt 0.633653 0.750000 +vt 0.612500 0.758637 +vt 0.616363 0.762500 +vt 0.612500 0.755154 +vt 0.616466 0.758512 +vt 0.616337 0.755323 +vt 0.619846 0.762500 +vt 0.619114 0.755886 +vt 0.619683 0.758653 +vt 0.625000 0.744114 +vt 0.619114 0.750000 +vt 0.387500 0.741363 +vt 0.383637 0.737500 +vt 0.387500 0.744846 +vt 0.383534 0.741488 +vt 0.387500 0.755154 +vt 0.383663 0.744677 +vt 0.380154 0.737500 +vt 0.380886 0.744114 +vt 0.380317 0.741346 +vt 0.383653 0.755317 +vt 0.383637 0.762500 +vt 0.387500 0.758637 +vt 0.380154 0.762500 +vt 0.383512 0.758534 +vt 0.375000 0.762500 +vt 0.380323 0.758663 +vt 0.380886 0.755886 +vt 0.375000 0.758654 +vt 0.366363 0.737500 +vt 0.362500 0.741363 +vt 0.362500 0.737500 +vt 0.369846 0.737500 +vt 0.366488 0.741466 +vt 0.369677 0.741337 +vt 0.362500 0.744846 +vt 0.369114 0.744114 +vt 0.366347 0.744683 +vt 0.380886 0.750000 +vt 0.375000 0.744114 +vt 0.612500 0.258637 +vt 0.616363 0.262500 +vt 0.612500 0.262500 +vt 0.612500 0.255154 +vt 0.616466 0.258512 +vt 0.612500 0.244846 +vt 0.616337 0.255323 +vt 0.619846 0.262500 +vt 0.619114 0.255886 +vt 0.619683 0.258653 +vt 0.616346 0.244683 +vt 0.616363 0.237500 +vt 0.612500 0.241363 +vt 0.612500 0.237500 +vt 0.619846 0.237500 +vt 0.616488 0.241466 +vt 0.625000 0.237500 +vt 0.619677 0.241337 +vt 0.619114 0.244114 +vt 0.625000 0.241347 +vt 0.862500 0.508637 +vt 0.866363 0.512500 +vt 0.862500 0.505154 +vt 0.866466 0.508512 +vt 0.862500 0.500000 +vt 0.866337 0.505323 +vt 0.869846 0.512500 +vt 0.869114 0.505886 +vt 0.869683 0.508653 +vt 0.866347 0.500000 +vt 0.619114 0.250000 +vt 0.625000 0.255886 +vt 0.387500 0.241363 +vt 0.383637 0.237500 +vt 0.387500 0.244846 +vt 0.383534 0.241488 +vt 0.387500 0.255154 +vt 0.383663 0.244677 +vt 0.380154 0.237500 +vt 0.380886 0.244114 +vt 0.380317 0.241346 +vt 0.383653 0.255317 +vt 0.383637 0.262500 +vt 0.387500 0.258637 +vt 0.387500 0.262500 +vt 0.380154 0.262500 +vt 0.383512 0.258534 +vt 0.375000 0.262500 +vt 0.380323 0.258663 +vt 0.380886 0.255886 +vt 0.375000 0.258653 +vt 0.133637 0.512500 +vt 0.137500 0.508637 +vt 0.130154 0.512500 +vt 0.133512 0.508534 +vt 0.125000 0.512500 +vt 0.130323 0.508663 +vt 0.137500 0.505154 +vt 0.130886 0.505886 +vt 0.133653 0.505317 +vt 0.125000 0.508654 +vt 0.380886 0.250000 +vt 0.375000 0.244114 +vt 0.612500 0.008637 +vt 0.616363 0.012500 +vt 0.612500 0.005154 +vt 0.616466 0.008512 +vt 0.612500 0.000000 +vt 0.616337 0.005323 +vt 0.619846 0.012500 +vt 0.619114 0.005886 +vt 0.619683 0.008654 +vt 0.616346 0.000000 +vt 0.616363 0.987500 +vt 0.612500 0.991363 +vt 0.612500 0.987500 +vt 0.619846 0.987500 +vt 0.616488 0.991466 +vt 0.625000 0.987500 +vt 0.619677 0.991337 +vt 0.612500 0.994846 +vt 0.619114 0.994114 +vt 0.616346 0.994683 +vt 0.625000 0.991346 +vt 0.866363 0.737500 +vt 0.862500 0.741363 +vt 0.862500 0.737500 +vt 0.869846 0.737500 +vt 0.866488 0.741466 +vt 0.875000 0.737500 +vt 0.869677 0.741337 +vt 0.862500 0.744846 +vt 0.869114 0.744114 +vt 0.866346 0.744683 +vt 0.875000 0.741347 +vt 0.619114 0.000000 +vt 0.625000 0.005886 +vt 0.137500 0.741363 +vt 0.133637 0.737500 +vt 0.137500 0.744846 +vt 0.133534 0.741488 +vt 0.137500 0.750000 +vt 0.133663 0.744677 +vt 0.130154 0.737500 +vt 0.130886 0.744114 +vt 0.130317 0.741346 +vt 0.133653 0.750000 +vt 0.387500 0.991363 +vt 0.383637 0.987500 +vt 0.387500 0.994846 +vt 0.383534 0.991488 +vt 0.387500 1.000000 +vt 0.383663 0.994677 +vt 0.380154 0.987500 +vt 0.380886 0.994114 +vt 0.380317 0.991346 +vt 0.383654 1.000000 +vt 0.383637 0.012500 +vt 0.387500 0.008637 +vt 0.380154 0.012500 +vt 0.383512 0.008534 +vt 0.375000 0.012500 +vt 0.380323 0.008663 +vt 0.387500 0.005154 +vt 0.380886 0.005886 +vt 0.383653 0.005317 +vt 0.375000 0.008653 +vt 0.130886 0.750000 +vt 0.125000 0.744114 +vt 0.630886 0.750000 +vt 0.375000 0.755886 +vt 0.625000 0.244114 +vt 0.869114 0.500000 +vt 0.375000 0.255886 +vt 0.125000 0.505886 +vt 0.625000 0.994114 +vt 0.875000 0.744114 +vt 0.380886 1.000000 +vt 0.375000 0.005886 +vt 0.125000 0.737500 +vt 0.137500 0.500000 +vt 0.612500 1.000000 +vt 0.862500 0.750000 +vt 0.362500 0.750000 +vt 0.875000 0.512500 +vt 0.637500 0.500000 +vn 0.0779 -0.9939 -0.0779 +vn -0.0779 -0.9939 0.0779 +vn -0.0779 -0.9939 -0.0779 +vn -0.9939 0.0779 0.0779 +vn -0.9939 -0.0779 -0.0779 +vn -0.9939 -0.0779 0.0779 +vn 0.0779 0.0779 0.9939 +vn -0.0779 -0.0779 0.9939 +vn 0.0779 -0.0779 0.9939 +vn -0.0779 0.9939 -0.0779 +vn 0.0779 0.9939 0.0779 +vn 0.0779 0.9939 -0.0779 +vn 0.9939 0.0779 -0.0779 +vn 0.9939 -0.0779 0.0779 +vn 0.9939 -0.0779 -0.0779 +vn 0.0783 0.3064 -0.9486 +vn 0.3066 0.0787 -0.9485 +vn 0.0779 0.0779 -0.9939 +vn 0.0754 0.5855 -0.8071 +vn 0.3089 0.3098 -0.8992 +vn 0.0757 0.8072 -0.5853 +vn 0.2866 0.5718 -0.7687 +vn 0.5853 0.0757 -0.8072 +vn 0.5154 0.5156 -0.6844 +vn 0.5719 0.2870 -0.7685 +vn 0.2870 0.7685 -0.5719 +vn 0.3064 0.9486 -0.0783 +vn 0.0787 0.9485 -0.3066 +vn 0.5855 0.8071 -0.0754 +vn 0.3098 0.8992 -0.3089 +vn 0.8072 0.5853 -0.0757 +vn 0.5718 0.7687 -0.2866 +vn 0.5156 0.6844 -0.5154 +vn 0.7685 0.5719 -0.2870 +vn 0.9486 0.0783 -0.3064 +vn 0.9485 0.3066 -0.0787 +vn 0.8071 0.0754 -0.5855 +vn 0.8992 0.3089 -0.3098 +vn 0.7687 0.2866 -0.5718 +vn 0.6844 0.5154 -0.5156 +vn 0.0783 -0.9486 -0.3064 +vn 0.3066 -0.9485 -0.0787 +vn 0.0754 -0.8071 -0.5855 +vn 0.3089 -0.8992 -0.3098 +vn 0.0757 -0.5853 -0.8072 +vn 0.2866 -0.7687 -0.5718 +vn 0.5853 -0.8072 -0.0757 +vn 0.5154 -0.6844 -0.5156 +vn 0.5719 -0.7685 -0.2870 +vn 0.2870 -0.5719 -0.7685 +vn 0.3064 -0.0783 -0.9486 +vn 0.0787 -0.3066 -0.9485 +vn 0.0779 -0.0779 -0.9939 +vn 0.5855 -0.0754 -0.8071 +vn 0.3098 -0.3089 -0.8992 +vn 0.8072 -0.0757 -0.5853 +vn 0.5718 -0.2866 -0.7687 +vn 0.5156 -0.5154 -0.6844 +vn 0.7685 -0.2870 -0.5719 +vn 0.9486 -0.3064 -0.0783 +vn 0.9485 -0.0787 -0.3066 +vn 0.8071 -0.5855 -0.0754 +vn 0.8992 -0.3098 -0.3089 +vn 0.7687 -0.5718 -0.2866 +vn 0.6844 -0.5156 -0.5154 +vn 0.9486 0.3064 0.0783 +vn 0.9485 0.0787 0.3066 +vn 0.9939 0.0779 0.0779 +vn 0.8071 0.5855 0.0754 +vn 0.8992 0.3098 0.3089 +vn 0.5853 0.8072 0.0757 +vn 0.7687 0.5718 0.2866 +vn 0.8072 0.0757 0.5853 +vn 0.6844 0.5156 0.5154 +vn 0.7685 0.2870 0.5719 +vn 0.5719 0.7685 0.2870 +vn 0.0783 0.9486 0.3064 +vn 0.3066 0.9485 0.0787 +vn 0.0754 0.8071 0.5855 +vn 0.3089 0.8992 0.3098 +vn 0.0757 0.5853 0.8072 +vn 0.2866 0.7687 0.5718 +vn 0.5154 0.6844 0.5156 +vn 0.2870 0.5719 0.7685 +vn 0.3064 0.0783 0.9486 +vn 0.0787 0.3066 0.9485 +vn 0.5855 0.0754 0.8071 +vn 0.3098 0.3089 0.8992 +vn 0.5718 0.2866 0.7687 +vn 0.5156 0.5154 0.6844 +vn 0.9486 -0.0783 0.3064 +vn 0.9485 -0.3066 0.0787 +vn 0.8071 -0.0754 0.5855 +vn 0.8992 -0.3089 0.3098 +vn 0.5853 -0.0757 0.8072 +vn 0.7687 -0.2866 0.5718 +vn 0.8072 -0.5853 0.0757 +vn 0.6844 -0.5154 0.5156 +vn 0.7685 -0.5719 0.2870 +vn 0.5719 -0.2870 0.7685 +vn 0.0783 -0.3064 0.9486 +vn 0.3066 -0.0787 0.9485 +vn 0.0754 -0.5855 0.8071 +vn 0.3089 -0.3098 0.8992 +vn 0.0757 -0.8072 0.5853 +vn 0.2866 -0.5718 0.7687 +vn 0.5154 -0.5156 0.6844 +vn 0.2870 -0.7685 0.5719 +vn 0.3064 -0.9486 0.0783 +vn 0.0787 -0.9485 0.3066 +vn 0.0779 -0.9939 0.0779 +vn 0.5855 -0.8071 0.0754 +vn 0.3098 -0.8992 0.3089 +vn 0.5718 -0.7687 0.2866 +vn 0.5156 -0.6844 0.5154 +vn -0.3064 0.0783 -0.9486 +vn -0.0787 0.3066 -0.9485 +vn -0.0779 0.0779 -0.9939 +vn -0.5855 0.0754 -0.8071 +vn -0.3098 0.3089 -0.8992 +vn -0.8072 0.0757 -0.5853 +vn -0.5718 0.2866 -0.7687 +vn -0.0757 0.5853 -0.8072 +vn -0.5156 0.5154 -0.6844 +vn -0.2870 0.5719 -0.7685 +vn -0.7685 0.2870 -0.5719 +vn -0.9486 0.3064 -0.0783 +vn -0.9485 0.0787 -0.3066 +vn -0.9939 0.0779 -0.0779 +vn -0.8071 0.5855 -0.0754 +vn -0.8992 0.3098 -0.3089 +vn -0.5853 0.8072 -0.0757 +vn -0.7687 0.5718 -0.2866 +vn -0.6844 0.5156 -0.5154 +vn -0.5719 0.7685 -0.2870 +vn -0.0783 0.9486 -0.3064 +vn -0.3066 0.9485 -0.0787 +vn -0.0754 0.8071 -0.5855 +vn -0.3089 0.8992 -0.3098 +vn -0.2866 0.7687 -0.5718 +vn -0.5154 0.6844 -0.5156 +vn -0.9486 -0.0783 -0.3064 +vn -0.9485 -0.3066 -0.0787 +vn -0.8071 -0.0754 -0.5855 +vn -0.8992 -0.3089 -0.3098 +vn -0.5853 -0.0757 -0.8072 +vn -0.7687 -0.2866 -0.5718 +vn -0.8072 -0.5853 -0.0757 +vn -0.6844 -0.5154 -0.5156 +vn -0.7685 -0.5719 -0.2870 +vn -0.5719 -0.2870 -0.7685 +vn -0.0783 -0.3064 -0.9486 +vn -0.3066 -0.0787 -0.9485 +vn -0.0779 -0.0779 -0.9939 +vn -0.0754 -0.5855 -0.8071 +vn -0.3089 -0.3098 -0.8992 +vn -0.0757 -0.8072 -0.5853 +vn -0.2866 -0.5718 -0.7687 +vn -0.5154 -0.5156 -0.6844 +vn -0.2870 -0.7685 -0.5719 +vn -0.3064 -0.9486 -0.0783 +vn -0.0787 -0.9485 -0.3066 +vn -0.5855 -0.8071 -0.0754 +vn -0.3098 -0.8992 -0.3089 +vn -0.5718 -0.7687 -0.2866 +vn -0.5156 -0.6844 -0.5154 +vn -0.9486 0.0783 0.3064 +vn -0.9485 0.3066 0.0787 +vn -0.8071 0.0754 0.5855 +vn -0.8992 0.3089 0.3098 +vn -0.5853 0.0757 0.8072 +vn -0.7687 0.2866 0.5718 +vn -0.8072 0.5853 0.0757 +vn -0.6844 0.5154 0.5156 +vn -0.7685 0.5719 0.2870 +vn -0.5719 0.2870 0.7685 +vn -0.0783 0.3064 0.9486 +vn -0.3066 0.0787 0.9485 +vn -0.0779 0.0779 0.9939 +vn -0.0754 0.5855 0.8071 +vn -0.3089 0.3098 0.8992 +vn -0.0757 0.8072 0.5853 +vn -0.2866 0.5718 0.7687 +vn -0.5154 0.5156 0.6844 +vn -0.2870 0.7685 0.5719 +vn -0.3064 0.9486 0.0783 +vn -0.0787 0.9485 0.3066 +vn -0.0779 0.9939 0.0779 +vn -0.5855 0.8071 0.0754 +vn -0.3098 0.8992 0.3089 +vn -0.5718 0.7687 0.2866 +vn -0.5156 0.6844 0.5154 +vn -0.0783 -0.9486 0.3064 +vn -0.3066 -0.9485 0.0787 +vn -0.0754 -0.8071 0.5855 +vn -0.3089 -0.8992 0.3098 +vn -0.0757 -0.5853 0.8072 +vn -0.2866 -0.7687 0.5718 +vn -0.5853 -0.8072 0.0757 +vn -0.5154 -0.6844 0.5156 +vn -0.5719 -0.7685 0.2870 +vn -0.2870 -0.5719 0.7685 +vn -0.3064 -0.0783 0.9486 +vn -0.0787 -0.3066 0.9485 +vn -0.5855 -0.0754 0.8071 +vn -0.3098 -0.3089 0.8992 +vn -0.8072 -0.0757 0.5853 +vn -0.5718 -0.2866 0.7687 +vn -0.5156 -0.5154 0.6844 +vn -0.7685 -0.2870 0.5719 +vn -0.9486 -0.3064 0.0783 +vn -0.9485 -0.0787 0.3066 +vn -0.8071 -0.5855 0.0754 +vn -0.8992 -0.3098 0.3089 +vn -0.7687 -0.5718 0.2866 +vn -0.6844 -0.5156 0.5154 +usemtl Material.001 +s 1 +f 28/1/1 190/2/2 138/3/3 +f 163/4/4 136/5/5 192/6/6 +f 57/7/7 191/8/8 83/9/9 +f 111/10/10 56/11/11 2/12/12 +f 3/13/13 82/14/14 30/15/15 +f 4/16/16 6/17/17 1/18/18 +f 5/19/19 7/20/20 4/16/16 +f 17/21/21 8/22/22 5/19/19 +f 7/20/20 9/23/23 6/17/17 +f 7/20/20 11/24/24 10/25/25 +f 18/26/26 11/24/24 8/22/22 +f 12/27/27 14/28/28 2/12/12 +f 13/29/29 15/30/30 12/27/27 +f 25/31/31 16/32/32 13/29/29 +f 15/30/30 17/33/21 14/28/28 +f 15/30/30 19/34/33 18/35/26 +f 26/36/34 19/34/33 16/32/32 +f 20/37/35 22/38/36 3/13/13 +f 21/39/37 23/40/38 20/37/35 +f 9/23/23 24/41/39 21/39/37 +f 23/40/38 25/31/31 22/38/36 +f 23/40/38 27/42/40 26/36/34 +f 10/25/25 27/42/40 24/41/39 +f 11/24/24 19/43/33 27/44/40 +f 31/45/41 33/46/42 28/1/1 +f 32/47/43 34/48/44 31/45/41 +f 44/49/45 35/50/46 32/47/43 +f 34/48/44 36/51/47 33/46/42 +f 34/48/44 38/52/48 37/53/49 +f 45/54/50 38/52/48 35/50/46 +f 39/55/51 41/56/52 29/57/53 +f 40/58/54 42/59/55 39/55/51 +f 52/60/56 43/61/57 40/58/54 +f 42/59/55 44/62/45 41/56/52 +f 42/59/55 46/63/58 45/64/50 +f 53/65/59 46/63/58 43/61/57 +f 47/66/60 49/67/61 30/15/15 +f 48/68/62 50/69/63 47/66/60 +f 36/51/47 51/70/64 48/68/62 +f 50/69/63 52/60/56 49/67/61 +f 50/69/63 54/71/65 53/65/59 +f 37/53/49 54/71/65 51/70/64 +f 38/52/48 46/72/58 54/73/65 +f 58/74/66 60/75/67 55/76/68 +f 59/77/69 61/78/70 58/74/66 +f 71/79/71 62/80/72 59/77/69 +f 61/78/70 63/81/73 60/75/67 +f 61/78/70 65/82/74 64/83/75 +f 72/84/76 65/82/74 62/80/72 +f 66/85/77 68/86/78 56/11/11 +f 67/87/79 69/88/80 66/85/77 +f 79/89/81 70/90/82 67/87/79 +f 69/88/80 71/79/71 68/86/78 +f 69/88/80 73/91/83 72/84/76 +f 80/92/84 73/91/83 70/90/82 +f 74/93/85 76/94/86 57/7/7 +f 75/95/87 77/96/88 74/93/85 +f 63/81/73 78/97/89 75/95/87 +f 77/96/88 79/98/81 76/94/86 +f 77/96/88 81/99/90 80/100/84 +f 64/83/75 81/99/90 78/97/89 +f 65/82/74 73/101/83 81/102/90 +f 85/103/91 87/104/92 82/14/14 +f 86/105/93 88/106/94 85/103/91 +f 98/107/95 89/108/96 86/105/93 +f 88/106/94 90/109/97 87/104/92 +f 88/106/94 92/110/98 91/111/99 +f 99/112/100 92/110/98 89/108/96 +f 93/113/101 95/114/102 83/9/9 +f 94/115/103 96/116/104 93/113/101 +f 106/117/105 97/118/106 94/115/103 +f 96/116/104 98/107/95 95/114/102 +f 96/116/104 100/119/107 99/112/100 +f 107/120/108 100/119/107 97/118/106 +f 101/121/109 103/122/110 84/123/111 +f 102/124/112 104/125/113 101/121/109 +f 90/109/97 105/126/114 102/124/112 +f 104/125/113 106/127/105 103/122/110 +f 104/125/113 108/128/115 107/129/108 +f 91/111/99 108/128/115 105/126/114 +f 92/110/98 100/130/107 108/131/115 +f 112/132/116 114/133/117 109/134/118 +f 113/135/119 115/136/120 112/132/116 +f 125/137/121 116/138/122 113/135/119 +f 115/136/120 117/139/123 114/133/117 +f 115/136/120 119/140/124 118/141/125 +f 126/142/126 119/140/124 116/138/122 +f 120/143/127 122/144/128 110/145/129 +f 121/146/130 123/147/131 120/143/127 +f 133/148/132 124/149/133 121/146/130 +f 123/147/131 125/137/121 122/144/128 +f 123/147/131 127/150/134 126/142/126 +f 134/151/135 127/150/134 124/149/133 +f 128/152/136 130/153/137 111/10/10 +f 129/154/138 131/155/139 128/152/136 +f 117/156/123 132/157/140 129/154/138 +f 131/155/139 133/158/132 130/153/137 +f 131/155/139 135/159/141 134/160/135 +f 118/161/125 135/159/141 132/157/140 +f 119/140/124 127/162/134 135/163/141 +f 139/164/142 141/165/143 136/5/5 +f 140/166/144 142/167/145 139/164/142 +f 152/168/146 143/169/147 140/166/144 +f 142/167/145 144/170/148 141/165/143 +f 142/167/145 146/171/149 145/172/150 +f 153/173/151 146/171/149 143/169/147 +f 147/174/152 149/175/153 137/176/154 +f 148/177/155 150/178/156 147/174/152 +f 160/179/157 151/180/158 148/177/155 +f 150/178/156 152/168/146 149/175/153 +f 150/178/156 154/181/159 153/173/151 +f 161/182/160 154/181/159 151/180/158 +f 155/183/161 157/184/162 138/3/3 +f 156/185/163 158/186/164 155/183/161 +f 144/187/148 159/188/165 156/185/163 +f 158/186/164 160/189/157 157/184/162 +f 158/186/164 162/190/166 161/191/160 +f 145/192/150 162/190/166 159/188/165 +f 146/171/149 154/193/159 162/194/166 +f 166/195/167 168/196/168 163/4/4 +f 167/197/169 169/198/170 166/195/167 +f 179/199/171 170/200/172 167/197/169 +f 169/198/170 171/201/173 168/196/168 +f 169/198/170 173/202/174 172/203/175 +f 180/204/176 173/202/174 170/200/172 +f 174/205/177 176/206/178 164/207/179 +f 175/208/180 177/209/181 174/205/177 +f 187/210/182 178/211/183 175/208/180 +f 177/209/181 179/212/171 176/206/178 +f 177/209/181 181/213/184 180/214/176 +f 188/215/185 181/213/184 178/211/183 +f 182/216/186 184/217/187 165/218/188 +f 183/219/189 185/220/190 182/216/186 +f 171/221/173 186/222/191 183/219/189 +f 185/220/190 187/223/182 184/217/187 +f 185/220/190 189/224/192 188/225/185 +f 172/226/175 189/224/192 186/222/191 +f 173/202/174 181/227/184 189/228/192 +f 193/229/193 195/230/194 190/2/2 +f 194/231/195 196/232/196 193/229/193 +f 206/233/197 197/234/198 194/231/195 +f 196/232/196 198/235/199 195/230/194 +f 196/232/196 200/236/200 199/237/201 +f 207/238/202 200/236/200 197/234/198 +f 201/239/203 203/240/204 191/8/8 +f 202/241/205 204/242/206 201/239/203 +f 214/243/207 205/244/208 202/241/205 +f 204/242/206 206/245/197 203/240/204 +f 204/242/206 208/246/209 207/247/202 +f 215/248/210 208/246/209 205/244/208 +f 209/249/211 211/250/212 192/6/6 +f 210/251/213 212/252/214 209/249/211 +f 198/253/199 213/254/215 210/251/213 +f 212/252/214 214/255/207 211/250/212 +f 212/252/214 216/256/216 215/257/210 +f 199/258/201 216/256/216 213/254/215 +f 200/236/200 208/259/209 216/260/216 +f 190/2/2 155/183/161 138/3/3 +f 195/230/194 156/185/163 155/183/161 +f 198/235/199 144/187/148 156/185/163 +f 210/251/213 141/165/143 144/170/148 +f 209/249/211 136/5/5 141/165/143 +f 138/3/3 31/45/41 28/1/1 +f 157/184/162 32/47/43 31/45/41 +f 160/189/157 44/49/45 32/47/43 +f 148/177/155 41/56/52 44/62/45 +f 147/174/152 29/57/53 41/56/52 +f 30/15/15 20/37/35 3/13/13 +f 49/67/61 21/39/37 20/37/35 +f 52/60/56 9/23/23 21/39/37 +f 40/58/54 6/17/17 9/23/23 +f 39/55/51 1/18/18 6/17/17 +f 164/207/179 201/239/203 191/8/8 +f 176/206/178 202/241/205 201/239/203 +f 179/212/171 214/243/207 202/241/205 +f 167/197/169 211/250/212 214/255/207 +f 166/195/167 192/6/6 211/250/212 +f 83/9/9 74/93/85 57/7/7 +f 95/114/102 75/95/87 74/93/85 +f 98/107/95 63/81/73 75/95/87 +f 86/105/93 60/75/67 63/81/73 +f 85/103/91 55/76/68 60/75/67 +f 137/176/154 112/132/116 109/134/118 +f 149/175/153 113/135/119 112/132/116 +f 152/168/146 125/137/121 113/135/119 +f 140/166/144 122/144/128 125/137/121 +f 139/164/142 110/145/129 122/144/128 +f 165/218/188 66/85/77 56/11/11 +f 184/217/187 67/87/79 66/85/77 +f 187/223/182 79/89/81 67/87/79 +f 175/208/180 76/94/86 79/98/81 +f 174/205/177 57/7/7 76/94/86 +f 56/11/11 12/27/27 2/12/12 +f 68/86/78 13/29/29 12/27/27 +f 71/79/71 25/31/31 13/29/29 +f 59/77/69 22/38/36 25/31/31 +f 58/74/66 3/13/13 22/38/36 +f 84/123/111 193/229/193 190/2/2 +f 103/122/110 194/231/195 193/229/193 +f 106/127/105 206/233/197 194/231/195 +f 94/115/103 203/240/204 206/245/197 +f 93/113/101 191/8/8 203/240/204 +f 111/10/10 182/216/186 165/218/188 +f 130/153/137 183/219/189 182/216/186 +f 133/158/132 171/221/173 183/219/189 +f 121/146/130 168/196/168 171/201/173 +f 120/143/127 163/4/4 168/196/168 +f 2/12/12 128/152/136 111/10/10 +f 14/28/28 129/154/138 128/152/136 +f 17/33/21 117/156/123 129/154/138 +f 5/19/19 114/133/117 117/139/123 +f 4/16/16 109/134/118 114/133/117 +f 28/1/1 101/121/109 84/123/111 +f 33/46/42 102/124/112 101/121/109 +f 36/51/47 90/109/97 102/124/112 +f 48/68/62 87/104/92 90/109/97 +f 47/66/60 82/14/14 87/104/92 +f 109/134/118 29/57/53 137/176/154 +f 28/1/1 84/123/111 190/2/2 +f 163/4/4 110/145/129 136/5/5 +f 57/7/7 164/207/179 191/8/8 +f 111/10/10 165/218/188 56/11/11 +f 3/13/13 55/76/68 82/14/14 +f 4/16/16 7/20/20 6/17/17 +f 5/19/19 8/22/22 7/20/20 +f 17/21/21 18/26/26 8/22/22 +f 7/20/20 10/25/25 9/23/23 +f 7/20/20 8/22/22 11/24/24 +f 18/26/26 19/43/33 11/24/24 +f 12/27/27 15/30/30 14/28/28 +f 13/29/29 16/32/32 15/30/30 +f 25/31/31 26/36/34 16/32/32 +f 15/30/30 18/35/26 17/33/21 +f 15/30/30 16/32/32 19/34/33 +f 26/36/34 27/42/40 19/34/33 +f 20/37/35 23/40/38 22/38/36 +f 21/39/37 24/41/39 23/40/38 +f 9/23/23 10/25/25 24/41/39 +f 23/40/38 26/36/34 25/31/31 +f 23/40/38 24/41/39 27/42/40 +f 10/25/25 11/24/24 27/42/40 +f 31/45/41 34/48/44 33/46/42 +f 32/47/43 35/50/46 34/48/44 +f 44/49/45 45/54/50 35/50/46 +f 34/48/44 37/53/49 36/51/47 +f 34/48/44 35/50/46 38/52/48 +f 45/54/50 46/72/58 38/52/48 +f 39/55/51 42/59/55 41/56/52 +f 40/58/54 43/61/57 42/59/55 +f 52/60/56 53/65/59 43/61/57 +f 42/59/55 45/64/50 44/62/45 +f 42/59/55 43/61/57 46/63/58 +f 53/65/59 54/71/65 46/63/58 +f 47/66/60 50/69/63 49/67/61 +f 48/68/62 51/70/64 50/69/63 +f 36/51/47 37/53/49 51/70/64 +f 50/69/63 53/65/59 52/60/56 +f 50/69/63 51/70/64 54/71/65 +f 37/53/49 38/52/48 54/71/65 +f 58/74/66 61/78/70 60/75/67 +f 59/77/69 62/80/72 61/78/70 +f 71/79/71 72/84/76 62/80/72 +f 61/78/70 64/83/75 63/81/73 +f 61/78/70 62/80/72 65/82/74 +f 72/84/76 73/91/83 65/82/74 +f 66/85/77 69/88/80 68/86/78 +f 67/87/79 70/90/82 69/88/80 +f 79/89/81 80/92/84 70/90/82 +f 69/88/80 72/84/76 71/79/71 +f 69/88/80 70/90/82 73/91/83 +f 80/92/84 81/261/90 73/91/83 +f 74/93/85 77/96/88 76/94/86 +f 75/95/87 78/97/89 77/96/88 +f 63/81/73 64/83/75 78/97/89 +f 77/96/88 80/100/84 79/98/81 +f 77/96/88 78/97/89 81/99/90 +f 64/83/75 65/82/74 81/99/90 +f 85/103/91 88/106/94 87/104/92 +f 86/105/93 89/108/96 88/106/94 +f 98/107/95 99/112/100 89/108/96 +f 88/106/94 91/111/99 90/109/97 +f 88/106/94 89/108/96 92/110/98 +f 99/112/100 100/119/107 92/110/98 +f 93/113/101 96/116/104 95/114/102 +f 94/115/103 97/118/106 96/116/104 +f 106/117/105 107/120/108 97/118/106 +f 96/116/104 99/112/100 98/107/95 +f 96/116/104 97/118/106 100/119/107 +f 107/120/108 108/262/115 100/119/107 +f 101/121/109 104/125/113 103/122/110 +f 102/124/112 105/126/114 104/125/113 +f 90/109/97 91/111/99 105/126/114 +f 104/125/113 107/129/108 106/127/105 +f 104/125/113 105/126/114 108/128/115 +f 91/111/99 92/110/98 108/128/115 +f 112/132/116 115/136/120 114/133/117 +f 113/135/119 116/138/122 115/136/120 +f 125/137/121 126/142/126 116/138/122 +f 115/136/120 118/141/125 117/139/123 +f 115/136/120 116/138/122 119/140/124 +f 126/142/126 127/150/134 119/140/124 +f 120/143/127 123/147/131 122/144/128 +f 121/146/130 124/149/133 123/147/131 +f 133/148/132 134/151/135 124/149/133 +f 123/147/131 126/142/126 125/137/121 +f 123/147/131 124/149/133 127/150/134 +f 134/151/135 135/263/141 127/150/134 +f 128/152/136 131/155/139 130/153/137 +f 129/154/138 132/157/140 131/155/139 +f 117/156/123 118/161/125 132/157/140 +f 131/155/139 134/160/135 133/158/132 +f 131/155/139 132/157/140 135/159/141 +f 118/161/125 119/264/124 135/159/141 +f 139/164/142 142/167/145 141/165/143 +f 140/166/144 143/169/147 142/167/145 +f 152/168/146 153/173/151 143/169/147 +f 142/167/145 145/172/150 144/170/148 +f 142/167/145 143/169/147 146/171/149 +f 153/173/151 154/181/159 146/171/149 +f 147/174/152 150/178/156 149/175/153 +f 148/177/155 151/180/158 150/178/156 +f 160/179/157 161/182/160 151/180/158 +f 150/178/156 153/173/151 152/168/146 +f 150/178/156 151/180/158 154/181/159 +f 161/182/160 162/265/166 154/181/159 +f 155/183/161 158/186/164 157/184/162 +f 156/185/163 159/188/165 158/186/164 +f 144/187/148 145/192/150 159/188/165 +f 158/186/164 161/191/160 160/189/157 +f 158/186/164 159/188/165 162/190/166 +f 145/192/150 146/266/149 162/190/166 +f 166/195/167 169/198/170 168/196/168 +f 167/197/169 170/200/172 169/198/170 +f 179/199/171 180/204/176 170/200/172 +f 169/198/170 172/203/175 171/201/173 +f 169/198/170 170/200/172 173/202/174 +f 180/204/176 181/227/184 173/202/174 +f 174/205/177 177/209/181 176/206/178 +f 175/208/180 178/211/183 177/209/181 +f 187/210/182 188/215/185 178/211/183 +f 177/209/181 180/214/176 179/212/171 +f 177/209/181 178/211/183 181/213/184 +f 188/215/185 189/267/192 181/213/184 +f 182/216/186 185/220/190 184/217/187 +f 183/219/189 186/222/191 185/220/190 +f 171/221/173 172/226/175 186/222/191 +f 185/220/190 188/225/185 187/223/182 +f 185/220/190 186/222/191 189/224/192 +f 172/226/175 173/268/174 189/224/192 +f 193/229/193 196/232/196 195/230/194 +f 194/231/195 197/234/198 196/232/196 +f 206/233/197 207/238/202 197/234/198 +f 196/232/196 199/237/201 198/235/199 +f 196/232/196 197/234/198 200/236/200 +f 207/238/202 208/259/209 200/236/200 +f 201/239/203 204/242/206 203/240/204 +f 202/241/205 205/244/208 204/242/206 +f 214/243/207 215/248/210 205/244/208 +f 204/242/206 207/247/202 206/245/197 +f 204/242/206 205/244/208 208/246/209 +f 215/248/210 216/269/216 208/246/209 +f 209/249/211 212/252/214 211/250/212 +f 210/251/213 213/254/215 212/252/214 +f 198/253/199 199/258/201 213/254/215 +f 212/252/214 215/257/210 214/255/207 +f 212/252/214 213/254/215 216/256/216 +f 199/258/201 200/270/200 216/256/216 +f 190/2/2 195/230/194 155/183/161 +f 195/230/194 198/235/199 156/185/163 +f 198/235/199 210/271/213 144/187/148 +f 210/251/213 209/249/211 141/165/143 +f 209/249/211 192/6/6 136/5/5 +f 138/3/3 157/184/162 31/45/41 +f 157/184/162 160/189/157 32/47/43 +f 160/189/157 148/272/155 44/49/45 +f 148/177/155 147/174/152 41/56/52 +f 147/174/152 137/176/154 29/57/53 +f 30/15/15 49/67/61 20/37/35 +f 49/67/61 52/60/56 21/39/37 +f 52/60/56 40/58/54 9/23/23 +f 40/58/54 39/55/51 6/17/17 +f 39/55/51 29/57/53 1/18/18 +f 164/207/179 176/206/178 201/239/203 +f 176/206/178 179/212/171 202/241/205 +f 179/212/171 167/273/169 214/243/207 +f 167/197/169 166/195/167 211/250/212 +f 166/195/167 163/4/4 192/6/6 +f 83/9/9 95/114/102 74/93/85 +f 95/114/102 98/107/95 75/95/87 +f 98/107/95 86/105/93 63/81/73 +f 86/105/93 85/103/91 60/75/67 +f 85/103/91 82/14/14 55/76/68 +f 137/176/154 149/175/153 112/132/116 +f 149/175/153 152/168/146 113/135/119 +f 152/168/146 140/166/144 125/137/121 +f 140/166/144 139/164/142 122/144/128 +f 139/164/142 136/5/5 110/145/129 +f 165/218/188 184/217/187 66/85/77 +f 184/217/187 187/223/182 67/87/79 +f 187/223/182 175/274/180 79/89/81 +f 175/208/180 174/205/177 76/94/86 +f 174/205/177 164/207/179 57/7/7 +f 56/11/11 68/86/78 12/27/27 +f 68/86/78 71/79/71 13/29/29 +f 71/79/71 59/77/69 25/31/31 +f 59/77/69 58/74/66 22/38/36 +f 58/74/66 55/76/68 3/13/13 +f 84/123/111 103/122/110 193/229/193 +f 103/122/110 106/127/105 194/231/195 +f 106/127/105 94/275/103 206/233/197 +f 94/115/103 93/113/101 203/240/204 +f 93/113/101 83/9/9 191/8/8 +f 111/10/10 130/153/137 182/216/186 +f 130/153/137 133/158/132 183/219/189 +f 133/158/132 121/276/130 171/221/173 +f 121/146/130 120/143/127 168/196/168 +f 120/143/127 110/145/129 163/4/4 +f 2/12/12 14/28/28 128/152/136 +f 14/28/28 17/33/21 129/154/138 +f 17/33/21 5/277/19 117/156/123 +f 5/19/19 4/16/16 114/133/117 +f 4/16/16 1/18/18 109/134/118 +f 28/1/1 33/46/42 101/121/109 +f 33/46/42 36/51/47 102/124/112 +f 36/51/47 48/68/62 90/109/97 +f 48/68/62 47/66/60 87/104/92 +f 47/66/60 30/15/15 82/14/14 +f 109/134/118 1/18/18 29/57/53 diff --git a/code/showcase/instancing/res/cube.zip b/code/showcase/instancing/res/cube.zip new file mode 100644 index 00000000..857be55e Binary files /dev/null and b/code/showcase/instancing/res/cube.zip differ diff --git a/code/showcase/instancing/src/light.frag b/code/showcase/instancing/src/light.frag new file mode 100644 index 00000000..a7ae2f2a --- /dev/null +++ b/code/showcase/instancing/src/light.frag @@ -0,0 +1,8 @@ +#version 450 + +layout(location=0) in vec3 v_color; +layout(location=0) out vec4 f_color; + +void main() { + f_color = vec4(v_color, 1.0); +} \ No newline at end of file diff --git a/code/showcase/instancing/src/light.frag.spv b/code/showcase/instancing/src/light.frag.spv new file mode 100644 index 00000000..d722658d Binary files /dev/null and b/code/showcase/instancing/src/light.frag.spv differ diff --git a/code/showcase/instancing/src/light.vert b/code/showcase/instancing/src/light.vert new file mode 100644 index 00000000..1f0ca333 --- /dev/null +++ b/code/showcase/instancing/src/light.vert @@ -0,0 +1,27 @@ +#version 450 + +layout(location=0) in vec3 a_position; + +layout(location=0) out vec3 v_color; + +layout(set=0, binding=0) +uniform Uniforms { + vec3 u_view_position; + mat4 u_view_proj; +}; + +layout(set=1, binding=0) +uniform Light { + vec3 u_position; + vec3 u_color; +}; + +// Let's keep our light smaller than our other objects +float scale = 0.25; + +void main() { + vec3 v_position = a_position * scale + u_position; + gl_Position = u_view_proj * vec4(v_position, 1); + + v_color = u_color; +} diff --git a/code/showcase/instancing/src/light.vert.spv b/code/showcase/instancing/src/light.vert.spv new file mode 100644 index 00000000..4b95eeba Binary files /dev/null and b/code/showcase/instancing/src/light.vert.spv differ diff --git a/code/intermediate/tutorial12-camera/src/world_space.frag b/code/showcase/instancing/src/shader.frag similarity index 76% rename from code/intermediate/tutorial12-camera/src/world_space.frag rename to code/showcase/instancing/src/shader.frag index f287179a..33137a0a 100644 --- a/code/intermediate/tutorial12-camera/src/world_space.frag +++ b/code/showcase/instancing/src/shader.frag @@ -2,7 +2,8 @@ layout(location=0) in vec2 v_tex_coords; layout(location=1) in vec3 v_position; // UPDATED! -layout(location=2) in mat3 v_tangent_matrix; // NEW! +layout(location=2) in vec3 v_light_position; // NEW! +layout(location=3) in vec3 v_view_position; // NEW! layout(location=0) out vec4 f_color; @@ -11,12 +12,6 @@ layout(set = 0, binding = 1) uniform sampler s_diffuse; layout(set = 0, binding = 2) uniform texture2D t_normal; layout(set = 0, binding = 3) uniform sampler s_normal; -layout(set=1, binding=0) -uniform Uniforms { - vec3 u_view_position; - mat4 u_view_proj; // unused -}; - layout(set = 2, binding = 0) uniform Light { vec3 light_position; vec3 light_color; @@ -29,13 +24,13 @@ void main() { float ambient_strength = 0.1; vec3 ambient_color = light_color * ambient_strength; - vec3 normal = normalize(v_tangent_matrix * (object_normal.rgb * 2.0 - 1.0)); - vec3 light_dir = normalize(light_position - v_position); + vec3 normal = normalize(object_normal.rgb * 2.0 - 1.0); // UPDATED! + vec3 light_dir = normalize(v_light_position - v_position); // UPDATED! float diffuse_strength = max(dot(normal, light_dir), 0.0); vec3 diffuse_color = light_color * diffuse_strength; - vec3 view_dir = normalize(u_view_position - v_position); + vec3 view_dir = normalize(v_view_position - v_position); // UPDATED! vec3 half_dir = normalize(view_dir + light_dir); float specular_strength = pow(max(dot(normal, half_dir), 0.0), 32); vec3 specular_color = specular_strength * light_color; diff --git a/code/showcase/instancing/src/shader.frag.spv b/code/showcase/instancing/src/shader.frag.spv new file mode 100644 index 00000000..da16852f Binary files /dev/null and b/code/showcase/instancing/src/shader.frag.spv differ diff --git a/code/intermediate/tutorial12-camera/src/shader-wrong.vert b/code/showcase/instancing/src/shader.vert similarity index 65% rename from code/intermediate/tutorial12-camera/src/shader-wrong.vert rename to code/showcase/instancing/src/shader.vert index 484449a7..6121023b 100644 --- a/code/intermediate/tutorial12-camera/src/shader-wrong.vert +++ b/code/showcase/instancing/src/shader.vert @@ -7,23 +7,23 @@ layout(location=3) in vec3 a_tangent; layout(location=4) in vec3 a_bitangent; layout(location=0) out vec2 v_tex_coords; -layout(location=1) out vec3 v_position; // UPDATED! -layout(location=2) out vec3 v_light_position; // NEW! -layout(location=3) out vec3 v_view_position; // NEW! +layout(location=1) out vec3 v_position; +layout(location=2) out vec3 v_light_position; +layout(location=3) out vec3 v_view_position; -layout(set=1, binding=0) +layout(set=0, binding=0) uniform Uniforms { vec3 u_view_position; mat4 u_view_proj; }; -layout(set=1, binding=1) +layout(set=2, binding=0) buffer Instances { mat4 s_models[]; }; // NEW! -layout(set=2, binding=0) uniform Light { +layout(set=1, binding=0) uniform Light { vec3 light_position; vec3 light_color; }; @@ -49,12 +49,9 @@ void main() { v_position = model_space.xyz; // NEW! - // v_position = tangent_matrix * model_space.xyz; - // v_light_position = tangent_matrix * light_position; - // v_view_position = tangent_matrix * u_view_position; - v_position = model_space.xyz; - v_light_position = light_position; - v_view_position = u_view_position; + v_position = tangent_matrix * model_space.xyz; + v_light_position = tangent_matrix * light_position; + v_view_position = tangent_matrix * u_view_position; gl_Position = u_view_proj * model_space; } \ No newline at end of file diff --git a/code/showcase/instancing/src/shader.vert.spv b/code/showcase/instancing/src/shader.vert.spv new file mode 100644 index 00000000..fdee40b5 Binary files /dev/null and b/code/showcase/instancing/src/shader.vert.spv differ diff --git a/code/showcase/instancing/src/storage_buffers.rs b/code/showcase/instancing/src/storage_buffers.rs new file mode 100644 index 00000000..688c2ed1 --- /dev/null +++ b/code/showcase/instancing/src/storage_buffers.rs @@ -0,0 +1,262 @@ +use anyhow::Result; +use cgmath::*; +use rand::Rng; +use std::path::Path; +use std::time::Duration; +use framework::prelude::*; + + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +struct InstanceData { + model_matrix: Matrix4, +} + +unsafe impl bytemuck::Pod for InstanceData {} +unsafe impl bytemuck::Zeroable for InstanceData {} + +struct StorageBuffersDemo<'a> { + depth_texture: framework::Texture<'a>, + cube_model: framework::Model<'a>, + model_pipeline: wgpu::RenderPipeline, + instances: Vec, + instance_buffer: wgpu::Buffer, + instance_bind_group: wgpu::BindGroup, + uniforms: framework::Uniforms, + uniform_binding: framework::UniformBinding, + camera: framework::Camera, + controller: framework::CameraController, + projection: framework::Projection, +} + +impl framework::Demo for StorageBuffersDemo<'static> { + fn init(display: &framework::Display) -> Result { + let texture_layout = display.device.create_bind_group_layout( + &wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + multisampled: false, + component_type: wgpu::TextureComponentType::Float, + dimension: wgpu::TextureViewDimension::D2, + } + }, + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { comparison: false }, + }, + // normal map + wgpu::BindGroupLayoutEntry { + binding: 2, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + multisampled: false, + component_type: wgpu::TextureComponentType::Float, + dimension: wgpu::TextureViewDimension::D2, + }, + }, + wgpu::BindGroupLayoutEntry { + binding: 3, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler { comparison: false }, + }, + ], + label: Some("texture_layout") + } + ); + + let depth_texture = framework::Texture::create_depth_texture(&display.device, &display.sc_desc); + + let mut res_cmds = Vec::new(); + let res_dir = Path::new(env!("OUT_DIR")).join("res"); + let (cube_model, cmds) = framework::Model::load( + &display.device, + &texture_layout, + res_dir.join("cube.obj") + )?; + res_cmds.extend(cmds); + + let mut encoder = display.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { + label: Some("init::encoder") + } + ); + + let (camera, projection, controller) = framework::camera_setup( + (0.0, 5.0, 10.0), + cgmath::Deg(-90.0), + cgmath::Deg(-20.0), + display.sc_desc.width, + display.sc_desc.height, + ); + + let mut uniforms = framework::Uniforms::new(&display.device); + uniforms.update_view_proj(&camera, &projection); + uniforms.update_buffer(&display.device, &mut encoder); + let uniform_binding = framework::UniformBinding::new(&display.device, &uniforms); + + const NUM_INSTANCES: u32 = 100; + const RADIUS: f32 = 50.0; + let instances = (0..NUM_INSTANCES).map(|_| { + let mut rng = rand::thread_rng(); + let position = Vector3::new( + rng.gen_range(-RADIUS, RADIUS), + rng.gen_range(-RADIUS, RADIUS), + rng.gen_range(-RADIUS, RADIUS), + ); + let model_matrix = Matrix4::from_translation(position); + + InstanceData { model_matrix } + }).collect::>(); + let instance_buffer = display.device.create_buffer_with_data( + bytemuck::cast_slice(&instances), + wgpu::BufferUsage::COPY_DST | wgpu::BufferUsage::STORAGE_READ, + ); + let instance_layout = display.device.create_bind_group_layout( + &wgpu::BindGroupLayoutDescriptor { + label: Some("instance_layout"), + bindings: &[ + wgpu::BindGroupLayoutEntry { + binding: 1, + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::StorageBuffer { + dynamic: false, + readonly: true, + }, + }, + ] + } + ); + let instance_buffer_size = instances.len() * std::mem::size_of::(); + let instance_bind_group = display.device.create_bind_group( + &wgpu::BindGroupDescriptor { + label: Some("instance_bind_group"), + layout: &instance_layout, + bindings: &[ + wgpu::Binding { + binding: 1, + resource: wgpu::BindingResource::Buffer { + buffer: &instance_buffer, + range: 0..instance_buffer_size as _, + }, + }, + ] + } + ); + + let model_layout = display.device.create_pipeline_layout( + &wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[ + &texture_layout, + &uniform_binding.layout, + &instance_layout, + ], + } + ); + + let model_pipeline = framework::RenderPipelineBuilder::new() + .layout(&model_layout) + .depth_format(framework::Texture::DEPTH_FORMAT) + .color_solid(display.sc_desc.format) + .vertex_buffer::() + .vertex_shader(include_bytes!("shader.vert.spv")) + .fragment_shader(include_bytes!("shader.frag.spv")) + .build(&display.device)?; + + res_cmds.push(encoder.finish()); + display.queue.submit(&res_cmds); + + + Ok(Self { + depth_texture, + cube_model, + model_pipeline, + instances, + instance_buffer, + instance_bind_group, + uniforms, + uniform_binding, + camera, + controller, + projection, + }) + } + + fn process_mouse(&mut self, dx: f64, dy: f64) { + self.controller.process_mouse(dx, dy); + } + + fn resize(&mut self, display: &framework::Display) { + + } + + fn update(&mut self, display: &framework::Display, dt: Duration) { + self.controller.update_camera(&mut self.camera, dt); + self.uniforms.update_view_proj(&self.camera, &self.projection); + + let mut encoder = display.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { + label: Some("update::encoder") + } + ); + self.uniforms.update_buffer(&display.device, &mut encoder); + + display.queue.submit(&[encoder.finish()]); + } + + fn render(&mut self, display: &mut framework::Display) { + let mut encoder = display.device.create_command_encoder( + &wgpu::CommandEncoderDescriptor { label: Some("render::encoder")} + ); + let mut frame = display.swap_chain.get_next_texture().expect("Timeout"); + + { + let mut pass = encoder.begin_render_pass( + &wgpu::RenderPassDescriptor { + color_attachments: &[ + wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }, + } + ], + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &self.depth_texture.view, + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_stencil: 0, + } + ) + } + ); + + pass.set_pipeline(&self.model_pipeline); + pass.set_bind_group(0, &self.uniform_binding.bind_group, &[]); + // pass.set_bind_group(1, &self.light_binding.bind_group, &[]); + for mesh in &self.cube_model.meshes { + let mat = &self.cube_model.materials[mesh.material]; + pass.set_bind_group(2, &mat.bind_group, &[]); + pass.draw_indexed(0..mesh.num_elements, 0, 0..self.instances.len() as _); + } + } + } +} + + +fn main() -> Result<()> { + futures::executor::block_on(framework::run::()) +} diff --git a/docs/.vuepress/dist b/docs/.vuepress/dist index 037a594e..6580a9a0 160000 --- a/docs/.vuepress/dist +++ b/docs/.vuepress/dist @@ -1 +1 @@ -Subproject commit 037a594e0406e14c88976ac1c486234b81d6a0b5 +Subproject commit 6580a9a0350cfa2852a9abf4af433e41f7fe3448