diff --git a/Cargo.lock b/Cargo.lock index 9ed23c10a..21c42d330 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,6 +313,9 @@ name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +dependencies = [ + "serde", +] [[package]] name = "as-raw-xcb-connection" @@ -3947,6 +3950,7 @@ checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", + "serde", ] [[package]] @@ -4744,8 +4748,10 @@ dependencies = [ "indexmap 2.2.6", "log", "num-traits", + "petgraph 0.6.5", "pp-rs", "rustc-hash", + "serde", "spirv 0.3.0+sdk-1.3.268.0", "termcolor", "thiserror", @@ -4797,6 +4803,7 @@ dependencies = [ "instant", "lyon", "nannou_core", + "nannou_wgpu", "noise", "notosans", "num_cpus", @@ -4808,6 +4815,7 @@ dependencies = [ "toml 0.8.14", "walkdir", "web-sys", + "wgpu", ] [[package]] @@ -4864,6 +4872,18 @@ dependencies = [ "zip", ] +[[package]] +name = "nannou_wgpu" +version = "0.19.0" +dependencies = [ + "futures 0.3.30", + "image 0.25.1", + "instant", + "num_cpus", + "tokio 1.38.0", + "wgpu", +] + [[package]] name = "native-tls" version = "0.2.12" @@ -8356,6 +8376,7 @@ dependencies = [ "parking_lot 0.12.3", "profiling", "raw-window-handle", + "serde", "smallvec 1.13.2", "static_assertions", "wasm-bindgen", @@ -8375,6 +8396,7 @@ dependencies = [ "arrayvec 0.7.4", "bit-vec", "bitflags 2.6.0", + "bytemuck", "cfg_aliases 0.1.1", "codespan-reporting", "document-features", @@ -8385,7 +8407,9 @@ dependencies = [ "parking_lot 0.12.3", "profiling", "raw-window-handle", + "ron", "rustc-hash", + "serde", "smallvec 1.13.2", "thiserror", "web-sys", @@ -8446,6 +8470,7 @@ checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" dependencies = [ "bitflags 2.6.0", "js-sys", + "serde", "web-sys", ] diff --git a/Cargo.toml b/Cargo.toml index 466feb01c..a0f00f731 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "nannou_new", "nannou_osc", "nannou_package", + "nannou_wgpu", "nature_of_code", "scripts/run_all_examples", "scripts/set_version", @@ -26,9 +27,11 @@ resolver = "2" bevy = "0.14.0" bevy_egui = "0.28.0" bevy-inspector-egui = "0.25.0" +image = "0.25" rayon = "1.10" bevy_common_assets = "0.11.0" serde = "1" serde_json = "1" toml = "0.8" -serde_yaml = "0.9" \ No newline at end of file +serde_yaml = "0.9" +wgpu = "0.20" \ No newline at end of file diff --git a/examples/Cargo.toml b/examples/Cargo.toml index 4e8493452..0a8ba9c44 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -230,4 +230,24 @@ required-features = ["video"] [[example]] name = "video_material" path = "video/video_material.rs" -required-features = ["video"] \ No newline at end of file +required-features = ["video"] + +# WebGPU +[[example]] +name = "wgpu_compute_shader" +path = "wgpu/wgpu_compute_shader/wgpu_compute_shader.rs" +[[example]] +name = "wgpu_image" +path = "wgpu/wgpu_image/wgpu_image.rs" +[[example]] +name = "wgpu_image_sequence" +path = "wgpu/wgpu_image_sequence/wgpu_image_sequence.rs" +[[example]] +name = "wgpu_instancing" +path = "wgpu/wgpu_instancing/wgpu_instancing.rs" +[[example]] +name = "wgpu_teapot" +path = "wgpu/wgpu_teapot/wgpu_teapot.rs" +[[example]] +name = "wgpu_triangle" +path = "wgpu/wgpu_triangle/wgpu_triangle.rs" \ No newline at end of file diff --git a/examples/wgpu/wgpu_compute_shader/shaders/cs.wgsl b/examples/wgpu/wgpu_compute_shader/shaders/cs.wgsl new file mode 100644 index 000000000..9daac0bfc --- /dev/null +++ b/examples/wgpu/wgpu_compute_shader/shaders/cs.wgsl @@ -0,0 +1,22 @@ +struct Buffer { + data: array, +}; + +struct Uniforms { + time: f32, + freq: f32, + oscillator_count: u32, +}; + +@group(0) @binding(0) +var output: Buffer; +@group(0) @binding(1) +var uniforms: Uniforms; + +@compute @workgroup_size(1, 1, 1) +fn main(@builtin(global_invocation_id) id: vec3) { + let index: u32 = id.x; + let phase: f32 = uniforms.time + f32(index) * uniforms.freq / f32(uniforms.oscillator_count); + output.data[index] = sin(phase) * 0.5 + 0.5; + return; +} diff --git a/examples/wgpu/wgpu_compute_shader/wgpu_compute_shader.rs b/examples/wgpu/wgpu_compute_shader/wgpu_compute_shader.rs new file mode 100644 index 000000000..c3feab36e --- /dev/null +++ b/examples/wgpu/wgpu_compute_shader/wgpu_compute_shader.rs @@ -0,0 +1,303 @@ +//! A small GPU compute shader demonstration. +//! +//! Here we use a compute shader to calculate the amplitude of `OSCILLATOR_COUNT` number of +//! oscillators. The oscillator amplitudes are then laid out across the screen using rectangles +//! with a gray value equal to the amplitude. Real-time interaction is demonstrated by providing +//! access to time, frequency (mouse `x`) and the number of oscillators via uniform data. + +use nannou::prelude::futures_lite::future; +use nannou::prelude::*; +use nannou::wgpu::BufferInitDescriptor; +use std::sync::{Arc, Mutex}; + +struct Model { + compute: Compute, + window: Entity, + oscillators: Arc>>, + task: Option>, +} + +struct Compute { + oscillator_buffer: wgpu::Buffer, + oscillator_buffer_size: wgpu::BufferAddress, + uniform_buffer: wgpu::Buffer, + bind_group: wgpu::BindGroup, + pipeline: wgpu::ComputePipeline, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Uniforms { + time: f32, + freq: f32, + oscillator_count: u32, +} + +const OSCILLATOR_COUNT: u32 = 128; + +fn main() { + nannou::app(model).update(update).run(); +} + +fn model(app: &App) -> Model { + let w_id = app + .new_window() + .primary() + .size(1440, 512) + .view(view) + .build(); + let window = app.window(w_id); + let device = window.device(); + + // Create the compute shader module. + let cs_desc = wgpu::include_wgsl!("shaders/cs.wgsl"); + let cs_mod = device.create_shader_module(cs_desc); + + // Create the buffer that will store the result of our compute operation. + let oscillator_buffer_size = + (OSCILLATOR_COUNT as usize * std::mem::size_of::()) as wgpu::BufferAddress; + let oscillator_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("oscillators"), + size: oscillator_buffer_size, + usage: wgpu::BufferUsages::STORAGE + | wgpu::BufferUsages::COPY_DST + | wgpu::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }); + + // Create the buffer that will store time. + let uniforms = create_uniforms(app.time(), app.mouse().x, window.rect()); + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST; + let uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: Some("uniform-buffer"), + contents: uniforms_bytes, + usage, + }); + + // Create the bind group and pipeline. + let bind_group_layout = create_bind_group_layout(&device); + let bind_group = create_bind_group( + &device, + &bind_group_layout, + &oscillator_buffer, + oscillator_buffer_size, + &uniform_buffer, + ); + let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout); + let pipeline = create_compute_pipeline(&device, &pipeline_layout, &cs_mod); + + let compute = Compute { + oscillator_buffer, + oscillator_buffer_size, + uniform_buffer, + bind_group, + pipeline, + }; + + // The vector that we will write oscillator values to. + let oscillators = Arc::new(Mutex::new(vec![0.0; OSCILLATOR_COUNT as usize])); + + Model { + compute, + window: w_id, + oscillators, + task: None, + } +} + +fn update(app: &App, model: &mut Model) { + let window = app.main_window(); + let device = window.device(); + let win_rect = window.rect(); + let compute = &mut model.compute; + + if let Some(task) = &mut model.task { + if let Some(_) = block_on(future::poll_once(task)) { + model.task = None; + } else { + return; + } + } + + // The buffer into which we'll read some data. + let read_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("read-oscillators"), + size: compute.oscillator_buffer_size, + usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + // An update for the uniform buffer with the current time. + let uniforms = create_uniforms(app.time(), app.mouse().x, win_rect); + let uniforms_size = std::mem::size_of::() as wgpu::BufferAddress; + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::COPY_SRC; + let new_uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: Some("uniform-data-transfer"), + contents: uniforms_bytes, + usage, + }); + + // The encoder we'll use to encode the compute pass. + let desc = wgpu::CommandEncoderDescriptor { + label: Some("oscillator-compute"), + }; + let mut encoder = device.create_command_encoder(&desc); + encoder.copy_buffer_to_buffer( + &new_uniform_buffer, + 0, + &compute.uniform_buffer, + 0, + uniforms_size, + ); + { + let pass_desc = wgpu::ComputePassDescriptor { + label: Some("nannou-wgpu_compute_shader-compute_pass"), + timestamp_writes: None, + }; + let mut cpass = encoder.begin_compute_pass(&pass_desc); + cpass.set_pipeline(&compute.pipeline); + cpass.set_bind_group(0, &compute.bind_group, &[]); + cpass.dispatch_workgroups(OSCILLATOR_COUNT as u32, 1, 1); + } + encoder.copy_buffer_to_buffer( + &compute.oscillator_buffer, + 0, + &read_buffer, + 0, + compute.oscillator_buffer_size, + ); + + // Submit the compute pass to the device's queue. + window.queue().submit(Some(encoder.finish())); + + // Spawn a future that reads the result of the compute pass. + let oscillators = model.oscillators.clone(); + let future = async move { + let slice = read_buffer.slice(..); + let (tx, rx) = futures::channel::oneshot::channel(); + slice.map_async(wgpu::MapMode::Read, |res| { + tx.send(res).expect("The channel was closed"); + }); + if let Ok(_) = rx.await { + if let Ok(mut oscillators) = oscillators.lock() { + let bytes = &slice.get_mapped_range()[..]; + // "Cast" the slice of bytes to a slice of floats as required. + let floats = { + let len = bytes.len() / std::mem::size_of::(); + let ptr = bytes.as_ptr() as *const f32; + unsafe { std::slice::from_raw_parts(ptr, len) } + }; + oscillators.copy_from_slice(floats); + } + } + }; + + let thread_pool = AsyncComputeTaskPool::get(); + let task = thread_pool.spawn(future); + + model.task = Some(task); + // Check for resource cleanups and mapping callbacks. + // + // Note that this line is not necessary in our case, as the device we are using already gets + // polled when nannou submits the command buffer for drawing and presentation after `view` + // completes. If we were to use a standalone device to create our buffer and perform our + // compute (rather than the device requested during window creation), calling `poll` regularly + // would be a must. + // + // device.poll(false); +} + +fn view(app: &App, model: &Model) { + let draw = app.draw(); + draw.background().color(BLACK); + let window = app.window(model.window); + let rect = window.rect(); + + if let Ok(oscillators) = model.oscillators.lock() { + let w = rect.w() / OSCILLATOR_COUNT as f32; + let h = rect.h(); + let half_w = w * 0.5; + for (i, &osc) in oscillators.iter().enumerate() { + let x = half_w + map_range(i as u32, 0, OSCILLATOR_COUNT, rect.left(), rect.right()); + draw.rect().w_h(w, h).x(x).color(Color::gray(osc)); + } + } +} + +fn create_uniforms(time: f32, mouse_x: f32, win_rect: geom::Rect) -> Uniforms { + let freq = map_range( + mouse_x, + win_rect.left(), + win_rect.right(), + 0.0, + win_rect.w(), + ); + let oscillator_count = OSCILLATOR_COUNT; + Uniforms { + time, + freq, + oscillator_count, + } +} + +fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + let storage_dynamic = false; + let storage_readonly = false; + let uniform_dynamic = false; + wgpu::BindGroupLayoutBuilder::new() + .storage_buffer( + wgpu::ShaderStages::COMPUTE, + storage_dynamic, + storage_readonly, + ) + .uniform_buffer(wgpu::ShaderStages::COMPUTE, uniform_dynamic) + .build(device) +} + +fn create_bind_group( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + oscillator_buffer: &wgpu::Buffer, + oscillator_buffer_size: wgpu::BufferAddress, + uniform_buffer: &wgpu::Buffer, +) -> wgpu::BindGroup { + let buffer_size_bytes = std::num::NonZeroU64::new(oscillator_buffer_size).unwrap(); + wgpu::BindGroupBuilder::new() + .buffer_bytes(oscillator_buffer, 0, Some(buffer_size_bytes)) + .buffer::(uniform_buffer, 0..1) + .build(device, layout) +} + +fn create_pipeline_layout( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, +) -> wgpu::PipelineLayout { + device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: Some("nannou"), + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }) +} + +fn create_compute_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + cs_mod: &wgpu::ShaderModule, +) -> wgpu::ComputePipeline { + let desc = wgpu::ComputePipelineDescriptor { + label: Some("nannou"), + layout: Some(layout), + module: &cs_mod, + entry_point: "main", + compilation_options: Default::default(), + }; + device.create_compute_pipeline(&desc) +} + +// See `nannou::wgpu::bytes` docs for why these are necessary. + +fn uniforms_as_bytes(uniforms: &Uniforms) -> &[u8] { + unsafe { wgpu::bytes::from(uniforms) } +} diff --git a/examples/wgpu/wgpu_image/shaders/fs.wgsl b/examples/wgpu/wgpu_image/shaders/fs.wgsl new file mode 100644 index 000000000..5fd305572 --- /dev/null +++ b/examples/wgpu/wgpu_image/shaders/fs.wgsl @@ -0,0 +1,14 @@ +struct FragmentOutput { + @location(0) f_color: vec4, +}; + +@group(0) @binding(0) +var tex: texture_2d; +@group(0) @binding(1) +var tex_sampler: sampler; + +@fragment +fn main(@location(0) tex_coords: vec2) -> FragmentOutput { + let out_color: vec4 = textureSample(tex, tex_sampler, tex_coords); + return FragmentOutput(out_color); +} diff --git a/examples/wgpu/wgpu_image/shaders/vs.wgsl b/examples/wgpu/wgpu_image/shaders/vs.wgsl new file mode 100644 index 000000000..e9925b28b --- /dev/null +++ b/examples/wgpu/wgpu_image/shaders/vs.wgsl @@ -0,0 +1,11 @@ +struct VertexOutput { + @location(0) tex_coords: vec2, + @builtin(position) out_pos: vec4, +}; + +@vertex +fn main(@location(0) pos: vec2) -> VertexOutput { + let tex_coords: vec2 = vec2(pos.x * 0.5 + 0.5, 1.0 - (pos.y * 0.5 + 0.5)); + let out_pos: vec4 = vec4(pos, 0.0, 1.0); + return VertexOutput(tex_coords, out_pos); +} diff --git a/examples/wgpu/wgpu_image/wgpu_image.rs b/examples/wgpu/wgpu_image/wgpu_image.rs new file mode 100644 index 000000000..a4e2971d5 --- /dev/null +++ b/examples/wgpu/wgpu_image/wgpu_image.rs @@ -0,0 +1,171 @@ +use nannou::image; +use nannou::image::GenericImageView; +use nannou::prelude::*; +use std::sync::Arc; + +#[derive(Clone)] +struct Model { + bind_group: Arc, + render_pipeline: Arc, + vertex_buffer: Arc, +} + +// The vertex type that we will use to represent a point on our triangle. +#[repr(C)] +#[derive(Clone, Copy)] +struct Vertex { + position: [f32; 2], +} + +// The vertices that make up the rectangle to which the image will be drawn. +const VERTICES: [Vertex; 4] = [ + Vertex { + position: [-1.0, 1.0], + }, + Vertex { + position: [-1.0, -1.0], + }, + Vertex { + position: [1.0, 1.0], + }, + Vertex { + position: [1.0, -1.0], + }, +]; + +fn main() { + nannou::app(model).render(render).run(); +} + +fn model(app: &App) -> Model { + // Load the image. + let logo_path = app.assets_path().join("images").join("nannou.png"); + let image = image::open(logo_path).unwrap(); + let (img_w, img_h) = image.dimensions(); + + let w_id = app + .new_window::() + .hdr(true) + .size(img_w, img_h) + .build(); + let window = app.window(w_id); + let device = window.device(); + let format = Frame::TEXTURE_FORMAT; + let msaa_samples = window.msaa_samples(); + + let vs_desc = wgpu::include_wgsl!("shaders/vs.wgsl"); + let fs_desc = wgpu::include_wgsl!("shaders/fs.wgsl"); + let vs_mod = device.create_shader_module(vs_desc); + let fs_mod = device.create_shader_module(fs_desc); + + // Load the image as a texture. + let texture = wgpu::Texture::from_image(&window, &image); + let texture_view = texture.view().build(); + + // Create the sampler for sampling from the source texture. + let sampler_desc = wgpu::SamplerBuilder::new().into_descriptor(); + let sampler_filtering = wgpu::sampler_filtering(&sampler_desc); + let sampler = device.create_sampler(&sampler_desc); + + let bind_group_layout = + create_bind_group_layout(&device, texture_view.sample_type(), sampler_filtering); + let bind_group = create_bind_group(&device, &bind_group_layout, &texture_view, &sampler); + let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout); + let render_pipeline = create_render_pipeline( + &device, + &pipeline_layout, + &vs_mod, + &fs_mod, + format, + msaa_samples, + ); + + let vertices_bytes = vertices_as_bytes(&VERTICES[..]); + let usage = wgpu::BufferUsages::VERTEX; + let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: vertices_bytes, + usage, + }); + + Model { + bind_group: Arc::new(bind_group), + vertex_buffer: Arc::new(vertex_buffer), + render_pipeline: Arc::new(render_pipeline), + } +} + +fn render(_app: &RenderApp, model: &Model, frame: Frame) { + let mut encoder = frame.command_encoder(); + let mut render_pass = wgpu::RenderPassBuilder::new() + .color_attachment(frame.resolve_target_view().unwrap(), |color| color) + .begin(&mut encoder); + render_pass.set_bind_group(0, &model.bind_group, &[]); + render_pass.set_pipeline(&model.render_pipeline); + render_pass.set_vertex_buffer(0, model.vertex_buffer.slice(..)); + let vertex_range = 0..VERTICES.len() as u32; + let instance_range = 0..1; + render_pass.draw(vertex_range, instance_range); +} + +fn create_bind_group_layout( + device: &wgpu::Device, + texture_sample_type: wgpu::TextureSampleType, + sampler_filtering: bool, +) -> wgpu::BindGroupLayout { + wgpu::BindGroupLayoutBuilder::new() + .texture( + wgpu::ShaderStages::FRAGMENT, + false, + wgpu::TextureViewDimension::D2, + texture_sample_type, + ) + .sampler(wgpu::ShaderStages::FRAGMENT, sampler_filtering) + .build(device) +} + +fn create_bind_group( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + texture: &wgpu::TextureView, + sampler: &wgpu::Sampler, +) -> wgpu::BindGroup { + wgpu::BindGroupBuilder::new() + .texture_view(texture) + .sampler(sampler) + .build(device, layout) +} + +fn create_pipeline_layout( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, +) -> wgpu::PipelineLayout { + let desc = wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }; + device.create_pipeline_layout(&desc) +} + +fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + vs_mod: &wgpu::ShaderModule, + fs_mod: &wgpu::ShaderModule, + dst_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::RenderPipeline { + wgpu::RenderPipelineBuilder::from_layout(layout, vs_mod) + .fragment_shader(fs_mod) + .color_format(dst_format) + .add_vertex_buffer::(&wgpu::vertex_attr_array![0 => Float32x2]) + .sample_count(sample_count) + .primitive_topology(wgpu::PrimitiveTopology::TriangleStrip) + .build(device) +} + +// See the `nannou::wgpu::bytes` documentation for why this is necessary. +fn vertices_as_bytes(data: &[Vertex]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} diff --git a/examples/wgpu/wgpu_image_sequence/shaders/fs.wgsl b/examples/wgpu/wgpu_image_sequence/shaders/fs.wgsl new file mode 100644 index 000000000..5fd305572 --- /dev/null +++ b/examples/wgpu/wgpu_image_sequence/shaders/fs.wgsl @@ -0,0 +1,14 @@ +struct FragmentOutput { + @location(0) f_color: vec4, +}; + +@group(0) @binding(0) +var tex: texture_2d; +@group(0) @binding(1) +var tex_sampler: sampler; + +@fragment +fn main(@location(0) tex_coords: vec2) -> FragmentOutput { + let out_color: vec4 = textureSample(tex, tex_sampler, tex_coords); + return FragmentOutput(out_color); +} diff --git a/examples/wgpu/wgpu_image_sequence/shaders/vs.wgsl b/examples/wgpu/wgpu_image_sequence/shaders/vs.wgsl new file mode 100644 index 000000000..e9925b28b --- /dev/null +++ b/examples/wgpu/wgpu_image_sequence/shaders/vs.wgsl @@ -0,0 +1,11 @@ +struct VertexOutput { + @location(0) tex_coords: vec2, + @builtin(position) out_pos: vec4, +}; + +@vertex +fn main(@location(0) pos: vec2) -> VertexOutput { + let tex_coords: vec2 = vec2(pos.x * 0.5 + 0.5, 1.0 - (pos.y * 0.5 + 0.5)); + let out_pos: vec4 = vec4(pos, 0.0, 1.0); + return VertexOutput(tex_coords, out_pos); +} diff --git a/examples/wgpu/wgpu_image_sequence/wgpu_image_sequence.rs b/examples/wgpu/wgpu_image_sequence/wgpu_image_sequence.rs new file mode 100644 index 000000000..cac3751f0 --- /dev/null +++ b/examples/wgpu/wgpu_image_sequence/wgpu_image_sequence.rs @@ -0,0 +1,262 @@ +//! A demonstration of playing back a sequence of images. +//! +//! This approach loads a directory of images into a single texture array. We only ever present a +//! single layer of the texture at a time by creating a texture view. We select which layer to view +//! by using a `current_layer` variable and updating it based on a frame rate that we determine by +//! the mouse x position. +//! +//! An interesting exercise might be to make a copy of this example and attempt to smooth the slow +//! frame rates by interpolating between two of the layers at a time. Hint: this would likely +//! require adding a second texture view binding to the bind group and its layout. + +use nannou::image; +use nannou::image::RgbaImage; +use nannou::prelude::*; +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +#[derive(Clone)] +struct Model { + current_layer: f32, + texture_array: wgpu::Texture, + texture_view: wgpu::TextureView, + sampler: Arc, + bind_group_layout: Arc, + bind_group: Arc, + render_pipeline: Arc, + vertex_buffer: Arc, +} + +// The vertex type that we will use to represent a point on our triangle. +#[repr(C)] +#[derive(Clone, Copy)] +struct Vertex { + position: [f32; 2], +} + +// The vertices that make up the rectangle to which the image will be drawn. +const VERTICES: [Vertex; 4] = [ + Vertex { + position: [-1.0, 1.0], + }, + Vertex { + position: [-1.0, -1.0], + }, + Vertex { + position: [1.0, 1.0], + }, + Vertex { + position: [1.0, -1.0], + }, +]; + +fn main() { + nannou::app(model).update(update).render(render).run(); +} + +fn model(app: &App) -> Model { + // Load the images. + let sequence_path = app.assets_path().join("images").join("spinning_dancer"); + + println!("Loading images..."); + let (images, (img_w, img_h)) = load_images(&sequence_path); + println!("Done!"); + + let w_id = app + .new_window::() + .primary() + .hdr(true) + .size(img_w, img_h) + .build(); + + let window = app.window(w_id); + let device = window.device(); + let format = Frame::TEXTURE_FORMAT; + let msaa_samples = window.msaa_samples(); + + let vs_desc = wgpu::include_wgsl!("shaders/vs.wgsl"); + let fs_desc = wgpu::include_wgsl!("shaders/fs.wgsl"); + let vs_mod = device.create_shader_module(vs_desc); + let fs_mod = device.create_shader_module(fs_desc); + + let texture_array = { + // The wgpu device queue used to load the image data. + let queue = window.queue(); + // Describe how we will use the texture so that the GPU may handle it efficiently. + let usage = wgpu::TextureUsages::TEXTURE_BINDING; + let iter = images.iter().map(|&(_, ref img)| img); + wgpu::Texture::load_array_from_image_buffers(&device, &queue, usage, iter) + .expect("tied to load texture array with an empty image buffer sequence") + }; + let layer = 0; + let texture_view = texture_array.view().layer(layer).build(); + + // Create the sampler for sampling from the source texture. + let sampler_desc = wgpu::SamplerBuilder::new().into_descriptor(); + let sampler_filtering = wgpu::sampler_filtering(&sampler_desc); + let sampler = device.create_sampler(&sampler_desc); + + let bind_group_layout = + create_bind_group_layout(&device, texture_view.sample_type(), sampler_filtering); + let bind_group = create_bind_group(&device, &bind_group_layout, &texture_view, &sampler); + let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout); + let render_pipeline = create_render_pipeline( + &device, + &pipeline_layout, + &vs_mod, + &fs_mod, + format, + msaa_samples, + ); + + // Create the vertex buffer. + let vertices_bytes = vertices_as_bytes(&VERTICES[..]); + let usage = wgpu::BufferUsages::VERTEX; + let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: vertices_bytes, + usage, + }); + + Model { + current_layer: 0.0, + texture_array, + texture_view, + sampler: Arc::new(sampler), + bind_group_layout: Arc::new(bind_group_layout), + bind_group: Arc::new(bind_group), + vertex_buffer: Arc::new(vertex_buffer), + render_pipeline: Arc::new(render_pipeline), + } +} + +fn update(app: &App, model: &mut Model) { + // Update which layer in the texture array that are viewing. + let window = app.main_window(); + let device = window.device(); + + // Determine how fast to play back the frames based on the mouse x. + let win_rect = window.rect(); + let fps = map_range( + app.mouse().x, + win_rect.left(), + win_rect.right(), + -100.0, + 100.0, + ); + + // Update which layer we are viewing based on the playback speed and layer count. + let layer_count = model.texture_array.extent().depth_or_array_layers; + model.current_layer = fmod( + model.current_layer + app.time_delta() * fps, + layer_count as f32, + ); + + // Update the view and the bind group ready for drawing. + let layer = model.current_layer as u32; + model.texture_view = model.texture_array.view().layer(layer).build(); + model.bind_group = Arc::new(create_bind_group( + &device, + &model.bind_group_layout, + &model.texture_view, + &model.sampler, + )); +} + +fn render(_app: &RenderApp, model: &Model, frame: Frame) { + let mut encoder = frame.command_encoder(); + let mut render_pass = wgpu::RenderPassBuilder::new() + .color_attachment(frame.resolve_target_view().unwrap(), |color| color) + .begin(&mut encoder); + render_pass.set_bind_group(0, &model.bind_group, &[]); + render_pass.set_pipeline(&model.render_pipeline); + render_pass.set_vertex_buffer(0, model.vertex_buffer.slice(..)); + let vertex_range = 0..VERTICES.len() as u32; + let instance_range = 0..1; + render_pass.draw(vertex_range, instance_range); +} + +// Load a directory of images and returns them sorted by filename alongside their dimensions. +// This function assumes all the images have the same dimensions. +fn load_images(dir: &Path) -> (Vec<(PathBuf, RgbaImage)>, (u32, u32)) { + let mut images = vec![]; + let mut dims = (0, 0); + for entry in std::fs::read_dir(dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + let image = match image::open(&path) { + Ok(img) => img.into_rgba8(), + Err(err) => { + eprintln!("failed to open {} as an image: {}", path.display(), err); + continue; + } + }; + let (w, h) = image.dimensions(); + dims = (w, h); + images.push((path, image)); + } + images.sort_by_key(|(path, _)| path.clone()); + (images, dims) +} + +fn create_bind_group_layout( + device: &wgpu::Device, + texture_sample_type: wgpu::TextureSampleType, + sampler_filtering: bool, +) -> wgpu::BindGroupLayout { + wgpu::BindGroupLayoutBuilder::new() + .texture( + wgpu::ShaderStages::FRAGMENT, + false, + wgpu::TextureViewDimension::D2, + texture_sample_type, + ) + .sampler(wgpu::ShaderStages::FRAGMENT, sampler_filtering) + .build(device) +} + +fn create_bind_group( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + texture: &wgpu::TextureView, + sampler: &wgpu::Sampler, +) -> wgpu::BindGroup { + wgpu::BindGroupBuilder::new() + .texture_view(texture) + .sampler(sampler) + .build(device, layout) +} + +fn create_pipeline_layout( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, +) -> wgpu::PipelineLayout { + let desc = wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }; + device.create_pipeline_layout(&desc) +} + +fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + vs_mod: &wgpu::ShaderModule, + fs_mod: &wgpu::ShaderModule, + dst_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::RenderPipeline { + wgpu::RenderPipelineBuilder::from_layout(layout, vs_mod) + .fragment_shader(fs_mod) + .color_format(dst_format) + .add_vertex_buffer::(&wgpu::vertex_attr_array![0 => Float32x2]) + .sample_count(sample_count) + .primitive_topology(wgpu::PrimitiveTopology::TriangleStrip) + .build(device) +} + +// See the `nannou::wgpu::bytes` documentation for why this is necessary. +fn vertices_as_bytes(data: &[Vertex]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} diff --git a/examples/wgpu/wgpu_instancing/data.rs b/examples/wgpu/wgpu_instancing/data.rs new file mode 100644 index 000000000..61aefab11 --- /dev/null +++ b/examples/wgpu/wgpu_instancing/data.rs @@ -0,0 +1,3354 @@ +use crate::{Normal, Vertex}; + +pub const VERTICES: [Vertex; 531] = [ + Vertex { + position: (0.0, 0.0, 0.0), + }, // dummy vector because in the original model indices + // start at 1 + Vertex { + position: (40.6266, 28.3457, -1.10804), + }, + Vertex { + position: (40.0714, 30.4443, -1.10804), + }, + Vertex { + position: (40.7155, 31.1438, -1.10804), + }, + Vertex { + position: (42.0257, 30.4443, -1.10804), + }, + Vertex { + position: (43.4692, 28.3457, -1.10804), + }, + Vertex { + position: (37.5425, 28.3457, 14.5117), + }, + Vertex { + position: (37.0303, 30.4443, 14.2938), + }, + Vertex { + position: (37.6244, 31.1438, 14.5466), + }, + Vertex { + position: (38.8331, 30.4443, 15.0609), + }, + Vertex { + position: (40.1647, 28.3457, 15.6274), + }, + Vertex { + position: (29.0859, 28.3457, 27.1468), + }, + Vertex { + position: (28.6917, 30.4443, 26.7527), + }, + Vertex { + position: (29.149, 31.1438, 27.2099), + }, + Vertex { + position: (30.0792, 30.4443, 28.1402), + }, + Vertex { + position: (31.1041, 28.3457, 29.165), + }, + Vertex { + position: (16.4508, 28.3457, 35.6034), + }, + Vertex { + position: (16.2329, 30.4443, 35.0912), + }, + Vertex { + position: (16.4857, 31.1438, 35.6853), + }, + Vertex { + position: (16.9999, 30.4443, 36.894), + }, + Vertex { + position: (17.5665, 28.3457, 38.2256), + }, + Vertex { + position: (0.831025, 28.3457, 38.6876), + }, + Vertex { + position: (0.831025, 30.4443, 38.1324), + }, + Vertex { + position: (0.831025, 31.1438, 38.7764), + }, + Vertex { + position: (0.831025, 30.4443, 40.0866), + }, + Vertex { + position: (0.831025, 28.3457, 41.5301), + }, + Vertex { + position: (-15.868, 28.3457, 35.6034), + }, + Vertex { + position: (-15.0262, 30.4443, 35.0912), + }, + Vertex { + position: (-14.9585, 31.1438, 35.6853), + }, + Vertex { + position: (-15.3547, 30.4443, 36.894), + }, + Vertex { + position: (-15.9044, 28.3457, 38.2256), + }, + Vertex { + position: (-28.3832, 28.3457, 27.1468), + }, + Vertex { + position: (-27.4344, 30.4443, 26.7527), + }, + Vertex { + position: (-27.6068, 31.1438, 27.2099), + }, + Vertex { + position: (-28.4322, 30.4443, 28.1402), + }, + Vertex { + position: (-29.4421, 28.3457, 29.165), + }, + Vertex { + position: (-36.2402, 28.3457, 14.5117), + }, + Vertex { + position: (-35.52, 30.4443, 14.2938), + }, + Vertex { + position: (-36.0073, 31.1438, 14.5466), + }, + Vertex { + position: (-37.1767, 30.4443, 15.0609), + }, + Vertex { + position: (-38.5027, 28.3457, 15.6274), + }, + Vertex { + position: (-38.9646, 28.3457, -1.10804), + }, + Vertex { + position: (-38.4094, 30.4443, -1.10804), + }, + Vertex { + position: (-39.0534, 31.1438, -1.10804), + }, + Vertex { + position: (-40.3636, 30.4443, -1.10804), + }, + Vertex { + position: (-41.8071, 28.3457, -1.10804), + }, + Vertex { + position: (-35.8804, 28.3457, -16.7278), + }, + Vertex { + position: (-35.3683, 30.4443, -16.5099), + }, + Vertex { + position: (-35.9624, 31.1438, -16.7627), + }, + Vertex { + position: (-37.1711, 30.4443, -17.2769), + }, + Vertex { + position: (-38.5027, 28.3457, -17.8435), + }, + Vertex { + position: (-27.4238, 28.3457, -29.3629), + }, + Vertex { + position: (-27.0297, 30.4443, -28.9687), + }, + Vertex { + position: (-27.4869, 31.1438, -29.426), + }, + Vertex { + position: (-28.4172, 30.4443, -30.3562), + }, + Vertex { + position: (-29.4421, 28.3457, -31.3811), + }, + Vertex { + position: (-14.7887, 28.3457, -37.8195), + }, + Vertex { + position: (-14.5708, 30.4443, -37.3073), + }, + Vertex { + position: (-14.8236, 31.1438, -37.9014), + }, + Vertex { + position: (-15.3379, 30.4443, -39.1101), + }, + Vertex { + position: (-15.9044, 28.3457, -40.4417), + }, + Vertex { + position: (0.831025, 28.3457, -40.9036), + }, + Vertex { + position: (0.831025, 30.4443, -40.3484), + }, + Vertex { + position: (0.831025, 31.1438, -40.9925), + }, + Vertex { + position: (0.831025, 30.4443, -42.3027), + }, + Vertex { + position: (0.831025, 28.3457, -43.7462), + }, + Vertex { + position: (16.4508, 28.3457, -37.8195), + }, + Vertex { + position: (16.2329, 30.4443, -37.3073), + }, + Vertex { + position: (16.4857, 31.1438, -37.9014), + }, + Vertex { + position: (16.9999, 30.4443, -39.1101), + }, + Vertex { + position: (17.5665, 28.3457, -40.4417), + }, + Vertex { + position: (29.0859, 28.3457, -29.3629), + }, + Vertex { + position: (28.6917, 30.4443, -28.9687), + }, + Vertex { + position: (29.149, 31.1438, -29.426), + }, + Vertex { + position: (30.0792, 30.4443, -30.3562), + }, + Vertex { + position: (31.1041, 28.3457, -31.3811), + }, + Vertex { + position: (37.5425, 28.3457, -16.7278), + }, + Vertex { + position: (37.0303, 30.4443, -16.5099), + }, + Vertex { + position: (37.6244, 31.1438, -16.7627), + }, + Vertex { + position: (38.8331, 30.4443, -17.2769), + }, + Vertex { + position: (40.1647, 28.3457, -17.8435), + }, + Vertex { + position: (48.6879, 17.1865, -1.10804), + }, + Vertex { + position: (53.2404, 6.22714, -1.10804), + }, + Vertex { + position: (56.4605, -4.33246, -1.10804), + }, + Vertex { + position: (57.6819, -14.2925, -1.10804), + }, + Vertex { + position: (44.979, 17.1865, 17.6758), + }, + Vertex { + position: (49.1787, 6.22714, 19.4626), + }, + Vertex { + position: (52.1492, -4.33246, 20.7265), + }, + Vertex { + position: (53.2759, -14.2925, 21.2059), + }, + Vertex { + position: (34.8094, 17.1865, 32.8703), + }, + Vertex { + position: (38.0417, 6.22714, 36.1026), + }, + Vertex { + position: (40.3279, -4.33246, 38.3889), + }, + Vertex { + position: (41.1951, -14.2925, 39.2561), + }, + Vertex { + position: (19.6148, 17.1865, 43.0399), + }, + Vertex { + position: (21.4017, 6.22714, 47.2396), + }, + Vertex { + position: (22.6656, -4.33246, 50.2101), + }, + Vertex { + position: (23.145, -14.2925, 51.3369), + }, + Vertex { + position: (0.831025, 17.1865, 46.7488), + }, + Vertex { + position: (0.831025, 6.22714, 51.3013), + }, + Vertex { + position: (0.831025, -4.33246, 54.5214), + }, + Vertex { + position: (0.831025, -14.2925, 55.7428), + }, + Vertex { + position: (-17.9528, 17.1865, 43.0399), + }, + Vertex { + position: (-19.7397, 6.22714, 47.2396), + }, + Vertex { + position: (-21.0035, -4.33246, 50.2101), + }, + Vertex { + position: (-21.4829, -14.2925, 51.3369), + }, + Vertex { + position: (-33.1474, 17.1865, 32.8703), + }, + Vertex { + position: (-36.3796, 6.22714, 36.1026), + }, + Vertex { + position: (-38.6659, -4.33246, 38.3889), + }, + Vertex { + position: (-39.5331, -14.2925, 39.2561), + }, + Vertex { + position: (-43.3169, 17.1865, 17.6758), + }, + Vertex { + position: (-47.5166, 6.22714, 19.4626), + }, + Vertex { + position: (-50.4871, -4.33246, 20.7265), + }, + Vertex { + position: (-51.6139, -14.2925, 21.2059), + }, + Vertex { + position: (-47.0258, 17.1865, -1.10804), + }, + Vertex { + position: (-51.5784, 6.22714, -1.10804), + }, + Vertex { + position: (-54.7984, -4.33246, -1.10804), + }, + Vertex { + position: (-56.0198, -14.2925, -1.10804), + }, + Vertex { + position: (-43.3169, 17.1865, -19.8919), + }, + Vertex { + position: (-47.5166, 6.22714, -21.6787), + }, + Vertex { + position: (-50.4871, -4.33246, -22.9426), + }, + Vertex { + position: (-51.6139, -14.2925, -23.422), + }, + Vertex { + position: (-33.1474, 17.1865, -35.0864), + }, + Vertex { + position: (-36.3796, 6.22714, -38.3187), + }, + Vertex { + position: (-38.6659, -4.33246, -40.6049), + }, + Vertex { + position: (-39.5331, -14.2925, -41.4721), + }, + Vertex { + position: (-17.9528, 17.1865, -45.256), + }, + Vertex { + position: (-19.7397, 6.22714, -49.4557), + }, + Vertex { + position: (-21.0035, -4.33246, -52.4262), + }, + Vertex { + position: (-21.4829, -14.2925, -53.5529), + }, + Vertex { + position: (0.831025, 17.1865, -48.9649), + }, + Vertex { + position: (0.831025, 6.22714, -53.5174), + }, + Vertex { + position: (0.831025, -4.33246, -56.7375), + }, + Vertex { + position: (0.831025, -14.2925, -57.9589), + }, + Vertex { + position: (19.6148, 17.1865, -45.256), + }, + Vertex { + position: (21.4017, 6.22714, -49.4557), + }, + Vertex { + position: (22.6656, -4.33246, -52.4262), + }, + Vertex { + position: (23.145, -14.2925, -53.5529), + }, + Vertex { + position: (34.8094, 17.1865, -35.0864), + }, + Vertex { + position: (38.0417, 6.22714, -38.3187), + }, + Vertex { + position: (40.3279, -4.33246, -40.6049), + }, + Vertex { + position: (41.1951, -14.2925, -41.4721), + }, + Vertex { + position: (44.979, 17.1865, -19.8919), + }, + Vertex { + position: (49.1787, 6.22714, -21.6787), + }, + Vertex { + position: (52.1492, -4.33246, -22.9426), + }, + Vertex { + position: (53.2759, -14.2925, -23.422), + }, + Vertex { + position: (55.4611, -22.7202, -1.10804), + }, + Vertex { + position: (50.5755, -28.9493, -1.10804), + }, + Vertex { + position: (45.6899, -33.1798, -1.10804), + }, + Vertex { + position: (43.4692, -35.6115, -1.10804), + }, + Vertex { + position: (51.2273, -22.7202, 20.3343), + }, + Vertex { + position: (46.7203, -28.9493, 18.4167), + }, + Vertex { + position: (42.2133, -33.1798, 16.4991), + }, + Vertex { + position: (40.1647, -35.6115, 15.6274), + }, + Vertex { + position: (39.6184, -22.7202, 37.6793), + }, + Vertex { + position: (36.1496, -28.9493, 34.2106), + }, + Vertex { + position: (32.6808, -33.1798, 30.7418), + }, + Vertex { + position: (31.1041, -35.6115, 29.165), + }, + Vertex { + position: (22.2733, -22.7202, 49.2882), + }, + Vertex { + position: (20.3557, -28.9493, 44.7813), + }, + Vertex { + position: (18.4381, -33.1798, 40.2743), + }, + Vertex { + position: (17.5665, -35.6115, 38.2256), + }, + Vertex { + position: (0.831025, -22.7202, 53.5221), + }, + Vertex { + position: (0.831025, -28.9493, 48.6365), + }, + Vertex { + position: (0.831025, -33.1798, 43.7508), + }, + Vertex { + position: (0.831025, -35.6115, 41.5301), + }, + Vertex { + position: (-20.6113, -22.7202, 49.2882), + }, + Vertex { + position: (-18.6937, -28.9493, 44.7813), + }, + Vertex { + position: (-16.7761, -33.1798, 40.2743), + }, + Vertex { + position: (-15.9044, -35.6115, 38.2256), + }, + Vertex { + position: (-37.9564, -22.7202, 37.6793), + }, + Vertex { + position: (-34.4876, -28.9493, 34.2106), + }, + Vertex { + position: (-31.0188, -33.1798, 30.7418), + }, + Vertex { + position: (-29.4421, -35.6115, 29.165), + }, + Vertex { + position: (-49.5653, -22.7202, 20.3343), + }, + Vertex { + position: (-45.0583, -28.9493, 18.4167), + }, + Vertex { + position: (-40.5513, -33.1798, 16.4991), + }, + Vertex { + position: (-38.5027, -35.6115, 15.6274), + }, + Vertex { + position: (-53.7991, -22.7202, -1.10804), + }, + Vertex { + position: (-48.9135, -28.9493, -1.10804), + }, + Vertex { + position: (-44.0279, -33.1798, -1.10804), + }, + Vertex { + position: (-41.8071, -35.6115, -1.10804), + }, + Vertex { + position: (-49.5653, -22.7202, -22.5504), + }, + Vertex { + position: (-45.0583, -28.9493, -20.6327), + }, + Vertex { + position: (-40.5513, -33.1798, -18.7151), + }, + Vertex { + position: (-38.5027, -35.6115, -17.8435), + }, + Vertex { + position: (-37.9564, -22.7202, -39.8954), + }, + Vertex { + position: (-34.4876, -28.9493, -36.4266), + }, + Vertex { + position: (-31.0188, -33.1798, -32.9578), + }, + Vertex { + position: (-29.4421, -35.6115, -31.3811), + }, + Vertex { + position: (-20.6113, -22.7202, -51.5043), + }, + Vertex { + position: (-18.6937, -28.9493, -46.9973), + }, + Vertex { + position: (-16.7761, -33.1798, -42.4903), + }, + Vertex { + position: (-15.9044, -35.6115, -40.4417), + }, + Vertex { + position: (0.831025, -22.7202, -55.7382), + }, + Vertex { + position: (0.831025, -28.9493, -50.8525), + }, + Vertex { + position: (0.831025, -33.1798, -45.9669), + }, + Vertex { + position: (0.831025, -35.6115, -43.7462), + }, + Vertex { + position: (22.2733, -22.7202, -51.5043), + }, + Vertex { + position: (20.3557, -28.9493, -46.9973), + }, + Vertex { + position: (18.4381, -33.1798, -42.4903), + }, + Vertex { + position: (17.5665, -35.6115, -40.4417), + }, + Vertex { + position: (39.6184, -22.7202, -39.8954), + }, + Vertex { + position: (36.1496, -28.9493, -36.4266), + }, + Vertex { + position: (32.6808, -33.1798, -32.9578), + }, + Vertex { + position: (31.1041, -35.6115, -31.3811), + }, + Vertex { + position: (51.2273, -22.7202, -22.5504), + }, + Vertex { + position: (46.7203, -28.9493, -20.6327), + }, + Vertex { + position: (42.2133, -33.1798, -18.7151), + }, + Vertex { + position: (40.1647, -35.6115, -17.8435), + }, + Vertex { + position: (42.5031, -37.1772, -1.10804), + }, + Vertex { + position: (37.3399, -38.5429, -1.10804), + }, + Vertex { + position: (24.5818, -39.5089, -1.10804), + }, + Vertex { + position: (0.831025, -39.8754, -1.10804), + }, + Vertex { + position: (39.2736, -37.1772, 15.2483), + }, + Vertex { + position: (34.5105, -38.5429, 13.2217), + }, + Vertex { + position: (22.7411, -39.5089, 8.21414), + }, + Vertex { + position: (30.4182, -37.1772, 28.4792), + }, + Vertex { + position: (26.7523, -38.5429, 24.8133), + }, + Vertex { + position: (17.6941, -39.5089, 15.755), + }, + Vertex { + position: (17.1873, -37.1772, 37.3345), + }, + Vertex { + position: (15.1608, -38.5429, 32.5714), + }, + Vertex { + position: (10.1532, -39.5089, 20.8021), + }, + Vertex { + position: (0.831025, -37.1772, 40.5641), + }, + Vertex { + position: (0.831025, -38.5429, 35.4009), + }, + Vertex { + position: (0.831025, -39.5089, 22.6427), + }, + Vertex { + position: (-15.5253, -37.1772, 37.3345), + }, + Vertex { + position: (-13.4987, -38.5429, 32.5714), + }, + Vertex { + position: (-8.49115, -39.5089, 20.8021), + }, + Vertex { + position: (-28.7562, -37.1772, 28.4792), + }, + Vertex { + position: (-25.0903, -38.5429, 24.8133), + }, + Vertex { + position: (-16.032, -39.5089, 15.755), + }, + Vertex { + position: (-37.6115, -37.1772, 15.2483), + }, + Vertex { + position: (-32.8484, -38.5429, 13.2217), + }, + Vertex { + position: (-21.0791, -39.5089, 8.21414), + }, + Vertex { + position: (-40.8411, -37.1772, -1.10804), + }, + Vertex { + position: (-35.6779, -38.5429, -1.10804), + }, + Vertex { + position: (-22.9198, -39.5089, -1.10804), + }, + Vertex { + position: (-37.6115, -37.1772, -17.4643), + }, + Vertex { + position: (-32.8484, -38.5429, -15.4378), + }, + Vertex { + position: (-21.0791, -39.5089, -10.4302), + }, + Vertex { + position: (-28.7562, -37.1772, -30.6952), + }, + Vertex { + position: (-25.0903, -38.5429, -27.0294), + }, + Vertex { + position: (-16.032, -39.5089, -17.9711), + }, + Vertex { + position: (-15.5253, -37.1772, -39.5506), + }, + Vertex { + position: (-13.4987, -38.5429, -34.7875), + }, + Vertex { + position: (-8.49115, -39.5089, -23.0181), + }, + Vertex { + position: (0.831025, -37.1772, -42.7802), + }, + Vertex { + position: (0.831025, -38.5429, -37.6169), + }, + Vertex { + position: (0.831025, -39.5089, -24.8588), + }, + Vertex { + position: (17.1873, -37.1772, -39.5506), + }, + Vertex { + position: (15.1608, -38.5429, -34.7875), + }, + Vertex { + position: (10.1532, -39.5089, -23.0181), + }, + Vertex { + position: (30.4182, -37.1772, -30.6952), + }, + Vertex { + position: (26.7523, -38.5429, -27.0294), + }, + Vertex { + position: (17.6941, -39.5089, -17.9711), + }, + Vertex { + position: (39.2736, -37.1772, -17.4643), + }, + Vertex { + position: (34.5105, -38.5429, -15.4378), + }, + Vertex { + position: (22.7411, -39.5089, -10.4302), + }, + Vertex { + position: (-44.6497, 17.6861, -1.10804), + }, + Vertex { + position: (-57.9297, 17.5862, -1.10804), + }, + Vertex { + position: (-67.7453, 16.8867, -1.10804), + }, + Vertex { + position: (-73.8301, 14.9879, -1.10804), + }, + Vertex { + position: (-75.9176, 11.2904, -1.10804), + }, + Vertex { + position: (-44.2055, 18.6855, 3.68876), + }, + Vertex { + position: (-58.3252, 18.5699, 3.68876), + }, + Vertex { + position: (-68.6891, 17.7611, 3.68876), + }, + Vertex { + position: (-75.0724, 15.5657, 3.68876), + }, + Vertex { + position: (-77.2501, 11.2904, 3.68876), + }, + Vertex { + position: (-43.2284, 20.884, 5.28769), + }, + Vertex { + position: (-59.1955, 20.7341, 5.28769), + }, + Vertex { + position: (-70.7655, 19.6848, 5.28769), + }, + Vertex { + position: (-77.8053, 16.8367, 5.28769), + }, + Vertex { + position: (-80.1814, 11.2904, 5.28769), + }, + Vertex { + position: (-42.2513, 23.0825, 3.68876), + }, + Vertex { + position: (-60.0657, 22.8983, 3.68876), + }, + Vertex { + position: (-72.8419, 21.6085, 3.68876), + }, + Vertex { + position: (-80.5381, 18.1077, 3.68876), + }, + Vertex { + position: (-83.1128, 11.2904, 3.68876), + }, + Vertex { + position: (-41.8071, 24.0819, -1.10804), + }, + Vertex { + position: (-60.4613, 23.882, -1.10804), + }, + Vertex { + position: (-73.7857, 22.4829, -1.10804), + }, + Vertex { + position: (-81.7804, 18.6855, -1.10804), + }, + Vertex { + position: (-84.4453, 11.2904, -1.10804), + }, + Vertex { + position: (-42.2513, 23.0825, -5.90483), + }, + Vertex { + position: (-60.0657, 22.8983, -5.90483), + }, + Vertex { + position: (-72.8419, 21.6085, -5.90483), + }, + Vertex { + position: (-80.5381, 18.1077, -5.90483), + }, + Vertex { + position: (-83.1128, 11.2904, -5.90483), + }, + Vertex { + position: (-43.2284, 20.884, -7.50376), + }, + Vertex { + position: (-59.1955, 20.7341, -7.50376), + }, + Vertex { + position: (-70.7655, 19.6848, -7.50376), + }, + Vertex { + position: (-77.8053, 16.8367, -7.50376), + }, + Vertex { + position: (-80.1814, 11.2904, -7.50376), + }, + Vertex { + position: (-44.2055, 18.6855, -5.90483), + }, + Vertex { + position: (-58.3252, 18.5699, -5.90483), + }, + Vertex { + position: (-68.6891, 17.7611, -5.90483), + }, + Vertex { + position: (-75.0724, 15.5657, -5.90483), + }, + Vertex { + position: (-77.2501, 11.2904, -5.90483), + }, + Vertex { + position: (-74.8073, 5.4943, -1.10804), + }, + Vertex { + position: (-71.2985, -1.50103, -1.10804), + }, + Vertex { + position: (-65.1248, -8.49634, -1.10804), + }, + Vertex { + position: (-56.0198, -14.2925, -1.10804), + }, + Vertex { + position: (-76.0183, 4.93477, 3.68876), + }, + Vertex { + position: (-72.159, -2.35462, 3.68876), + }, + Vertex { + position: (-65.4267, -9.55033, 3.68876), + }, + Vertex { + position: (-55.5757, -15.6249, 3.68876), + }, + Vertex { + position: (-78.6824, 3.70383, 5.28769), + }, + Vertex { + position: (-74.0522, -4.23253, 5.28769), + }, + Vertex { + position: (-66.0909, -11.8691, 5.28769), + }, + Vertex { + position: (-54.5986, -18.5563, 5.28769), + }, + Vertex { + position: (-81.3466, 2.47288, 3.68876), + }, + Vertex { + position: (-75.9454, -6.11044, 3.68876), + }, + Vertex { + position: (-66.755, -14.1878, 3.68876), + }, + Vertex { + position: (-53.6214, -21.4877, 3.68876), + }, + Vertex { + position: (-82.5576, 1.91336, -1.10804), + }, + Vertex { + position: (-76.8059, -6.96404, -1.10804), + }, + Vertex { + position: (-67.0569, -15.2418, -1.10804), + }, + Vertex { + position: (-53.1773, -22.8201, -1.10804), + }, + Vertex { + position: (-81.3466, 2.47288, -5.90483), + }, + Vertex { + position: (-75.9454, -6.11044, -5.90483), + }, + Vertex { + position: (-66.755, -14.1878, -5.90483), + }, + Vertex { + position: (-53.6214, -21.4877, -5.90483), + }, + Vertex { + position: (-78.6824, 3.70383, -7.50376), + }, + Vertex { + position: (-74.0522, -4.23253, -7.50376), + }, + Vertex { + position: (-66.0909, -11.8691, -7.50376), + }, + Vertex { + position: (-54.5986, -18.5563, -7.50376), + }, + Vertex { + position: (-76.0183, 4.93477, -5.90483), + }, + Vertex { + position: (-72.159, -2.35462, -5.90483), + }, + Vertex { + position: (-65.4267, -9.55033, -5.90483), + }, + Vertex { + position: (-55.5757, -15.6249, -5.90483), + }, + Vertex { + position: (49.1543, 0.630882, -1.10804), + }, + Vertex { + position: (62.7896, 3.76212, -1.10804), + }, + Vertex { + position: (68.6967, 11.2904, -1.10804), + }, + Vertex { + position: (71.939, 20.4176, -1.10804), + }, + Vertex { + position: (77.5797, 28.3457, -1.10804), + }, + Vertex { + position: (49.1543, -3.03333, 9.4449), + }, + Vertex { + position: (63.8305, 1.04519, 8.42059), + }, + Vertex { + position: (70.0292, 9.70814, 6.1671), + }, + Vertex { + position: (73.5629, 19.8451, 3.91361), + }, + Vertex { + position: (80.2446, 28.3457, 2.88929), + }, + Vertex { + position: (49.1543, -11.0946, 12.9626), + }, + Vertex { + position: (66.1207, -4.93206, 11.5968), + }, + Vertex { + position: (72.9605, 6.22714, 8.59214), + }, + Vertex { + position: (77.1355, 18.5855, 5.58749), + }, + Vertex { + position: (86.1073, 28.3457, 4.22173), + }, + Vertex { + position: (49.1543, -19.1559, 9.4449), + }, + Vertex { + position: (68.4108, -10.9093, 8.42059), + }, + Vertex { + position: (75.8919, 2.74614, 6.1671), + }, + Vertex { + position: (80.7081, 17.326, 3.91361), + }, + Vertex { + position: (91.97, 28.3457, 2.88929), + }, + Vertex { + position: (49.1543, -22.8201, -1.10804), + }, + Vertex { + position: (69.4518, -13.6262, -1.10804), + }, + Vertex { + position: (77.2244, 1.16386, -1.10804), + }, + Vertex { + position: (82.3321, 16.7534, -1.10804), + }, + Vertex { + position: (94.6349, 28.3457, -1.10804), + }, + Vertex { + position: (49.1543, -19.1559, -11.661), + }, + Vertex { + position: (68.4108, -10.9093, -10.6367), + }, + Vertex { + position: (75.8919, 2.74614, -8.38317), + }, + Vertex { + position: (80.7081, 17.326, -6.12968), + }, + Vertex { + position: (91.97, 28.3457, -5.10536), + }, + Vertex { + position: (49.1543, -11.0946, -15.1786), + }, + Vertex { + position: (66.1207, -4.93206, -13.8129), + }, + Vertex { + position: (72.9605, 6.22714, -10.8082), + }, + Vertex { + position: (77.1355, 18.5855, -7.80356), + }, + Vertex { + position: (86.1073, 28.3457, -6.4378), + }, + Vertex { + position: (49.1543, -3.03333, -11.661), + }, + Vertex { + position: (63.8305, 1.04519, -10.6367), + }, + Vertex { + position: (70.0292, 9.70814, -8.38317), + }, + Vertex { + position: (73.5629, 19.8451, -6.12968), + }, + Vertex { + position: (80.2446, 28.3457, -5.10536), + }, + Vertex { + position: (79.6227, 29.5449, -1.10804), + }, + Vertex { + position: (81.1329, 29.9446, -1.10804), + }, + Vertex { + position: (81.577, 29.5449, -1.10804), + }, + Vertex { + position: (80.4222, 28.3457, -1.10804), + }, + Vertex { + position: (82.4767, 29.6034, 2.63946), + }, + Vertex { + position: (83.8116, 30.0383, 2.08983), + }, + Vertex { + position: (83.8515, 29.6268, 1.54019), + }, + Vertex { + position: (82.1988, 28.3457, 1.29036), + }, + Vertex { + position: (88.7555, 29.7322, 3.88862), + }, + Vertex { + position: (89.7049, 30.2444, 3.15578), + }, + Vertex { + position: (88.8555, 29.8072, 2.42294), + }, + Vertex { + position: (86.1073, 28.3457, 2.08983), + }, + Vertex { + position: (95.0343, 29.8611, 2.63946), + }, + Vertex { + position: (95.5982, 30.4505, 2.08983), + }, + Vertex { + position: (93.8594, 29.9875, 1.54019), + }, + Vertex { + position: (90.0158, 28.3457, 1.29036), + }, + Vertex { + position: (97.8883, 29.9196, -1.10804), + }, + Vertex { + position: (98.2769, 30.5442, -1.10804), + }, + Vertex { + position: (96.1339, 30.0695, -1.10804), + }, + Vertex { + position: (91.7924, 28.3457, -1.10804), + }, + Vertex { + position: (95.0343, 29.8611, -4.85553), + }, + Vertex { + position: (95.5982, 30.4505, -4.3059), + }, + Vertex { + position: (93.8594, 29.9875, -3.75626), + }, + Vertex { + position: (90.0158, 28.3457, -3.50643), + }, + Vertex { + position: (88.7555, 29.7322, -6.10469), + }, + Vertex { + position: (89.7049, 30.2444, -5.37185), + }, + Vertex { + position: (88.8555, 29.8072, -4.63901), + }, + Vertex { + position: (86.1073, 28.3457, -4.3059), + }, + Vertex { + position: (82.4767, 29.6034, -4.85553), + }, + Vertex { + position: (83.8116, 30.0383, -4.3059), + }, + Vertex { + position: (83.8515, 29.6268, -3.75626), + }, + Vertex { + position: (82.1988, 28.3457, -3.50643), + }, + Vertex { + position: (0.831025, 49.6647, -1.10804), + }, + Vertex { + position: (10.5134, 48.2657, -1.10804), + }, + Vertex { + position: (10.0693, 44.868, -1.10804), + }, + Vertex { + position: (6.42728, 40.6708, -1.10804), + }, + Vertex { + position: (6.51611, 36.8733, -1.10804), + }, + Vertex { + position: (9.76642, 48.2657, 2.70243), + }, + Vertex { + position: (9.35632, 44.868, 2.52698), + }, + Vertex { + position: (5.9947, 40.6708, 1.09187), + }, + Vertex { + position: (6.07552, 36.8733, 1.12336), + }, + Vertex { + position: (7.71453, 48.2657, 5.77547), + }, + Vertex { + position: (7.39819, 44.868, 5.45913), + }, + Vertex { + position: (4.80736, 40.6708, 2.8683), + }, + Vertex { + position: (4.86744, 36.8733, 2.92838), + }, + Vertex { + position: (4.64149, 48.2657, 7.82736), + }, + Vertex { + position: (4.46604, 44.868, 7.41726), + }, + Vertex { + position: (3.03093, 40.6708, 4.05564), + }, + Vertex { + position: (3.06242, 36.8733, 4.13646), + }, + Vertex { + position: (0.831025, 48.2657, 8.57438), + }, + Vertex { + position: (0.831025, 44.868, 8.13023), + }, + Vertex { + position: (0.831025, 40.6708, 4.48822), + }, + Vertex { + position: (0.831025, 36.8733, 4.57705), + }, + Vertex { + position: (-2.97944, 48.2657, 7.82736), + }, + Vertex { + position: (-2.80399, 44.868, 7.41726), + }, + Vertex { + position: (-1.36888, 40.6708, 4.05564), + }, + Vertex { + position: (-1.40037, 36.8733, 4.13646), + }, + Vertex { + position: (-6.05248, 48.2657, 5.77547), + }, + Vertex { + position: (-5.73614, 44.868, 5.45913), + }, + Vertex { + position: (-3.14531, 40.6708, 2.8683), + }, + Vertex { + position: (-3.20539, 36.8733, 2.92838), + }, + Vertex { + position: (-8.10437, 48.2657, 2.70243), + }, + Vertex { + position: (-7.69427, 44.868, 2.52698), + }, + Vertex { + position: (-4.33265, 40.6708, 1.09187), + }, + Vertex { + position: (-4.41347, 36.8733, 1.12336), + }, + Vertex { + position: (-8.85139, 48.2657, -1.10804), + }, + Vertex { + position: (-8.40724, 44.868, -1.10804), + }, + Vertex { + position: (-4.76523, 40.6708, -1.10804), + }, + Vertex { + position: (-4.85406, 36.8733, -1.10804), + }, + Vertex { + position: (-8.10437, 48.2657, -4.9185), + }, + Vertex { + position: (-7.69427, 44.868, -4.74305), + }, + Vertex { + position: (-4.33265, 40.6708, -3.30794), + }, + Vertex { + position: (-4.41347, 36.8733, -3.33943), + }, + Vertex { + position: (-6.05248, 48.2657, -7.99154), + }, + Vertex { + position: (-5.73614, 44.868, -7.6752), + }, + Vertex { + position: (-3.14531, 40.6708, -5.08437), + }, + Vertex { + position: (-3.20539, 36.8733, -5.14445), + }, + Vertex { + position: (-2.97944, 48.2657, -10.0434), + }, + Vertex { + position: (-2.80399, 44.868, -9.63333), + }, + Vertex { + position: (-1.36888, 40.6708, -6.27171), + }, + Vertex { + position: (-1.40037, 36.8733, -6.35253), + }, + Vertex { + position: (0.831025, 48.2657, -10.7904), + }, + Vertex { + position: (0.831025, 44.868, -10.3463), + }, + Vertex { + position: (0.831025, 40.6708, -6.70429), + }, + Vertex { + position: (0.831025, 36.8733, -6.79312), + }, + Vertex { + position: (4.64149, 48.2657, -10.0434), + }, + Vertex { + position: (4.46604, 44.868, -9.63333), + }, + Vertex { + position: (3.03093, 40.6708, -6.27171), + }, + Vertex { + position: (3.06242, 36.8733, -6.35253), + }, + Vertex { + position: (7.71453, 48.2657, -7.99154), + }, + Vertex { + position: (7.39819, 44.868, -7.6752), + }, + Vertex { + position: (4.80736, 40.6708, -5.08437), + }, + Vertex { + position: (4.86744, 36.8733, -5.14445), + }, + Vertex { + position: (9.76642, 48.2657, -4.9185), + }, + Vertex { + position: (9.35632, 44.868, -4.74305), + }, + Vertex { + position: (5.9947, 40.6708, -3.30794), + }, + Vertex { + position: (6.07552, 36.8733, -3.33943), + }, + Vertex { + position: (13.8001, 34.3417, -1.10804), + }, + Vertex { + position: (24.282, 32.6095, -1.10804), + }, + Vertex { + position: (33.6979, 30.8773, -1.10804), + }, + Vertex { + position: (37.7841, 28.3457, -1.10804), + }, + Vertex { + position: (12.795, 34.3417, 3.98234), + }, + Vertex { + position: (22.4646, 32.6095, 8.09647), + }, + Vertex { + position: (31.1507, 30.8773, 11.7922), + }, + Vertex { + position: (34.9202, 28.3457, 13.396), + }, + Vertex { + position: (10.0391, 34.3417, 8.10003), + }, + Vertex { + position: (17.4812, 32.6095, 15.5422), + }, + Vertex { + position: (24.1665, 30.8773, 22.2275), + }, + Vertex { + position: (27.0677, 28.3457, 25.1286), + }, + Vertex { + position: (5.9214, 34.3417, 10.856), + }, + Vertex { + position: (10.0355, 32.6095, 20.5255), + }, + Vertex { + position: (13.7313, 30.8773, 29.2117), + }, + Vertex { + position: (15.3351, 28.3457, 32.9812), + }, + Vertex { + position: (0.831025, 34.3417, 11.8611), + }, + Vertex { + position: (0.831025, 32.6095, 22.3429), + }, + Vertex { + position: (0.831025, 30.8773, 31.7589), + }, + Vertex { + position: (0.831025, 28.3457, 35.845), + }, + Vertex { + position: (-4.25935, 34.3417, 10.856), + }, + Vertex { + position: (-8.37348, 32.6095, 20.5255), + }, + Vertex { + position: (-12.0692, 30.8773, 29.2117), + }, + Vertex { + position: (-13.673, 28.3457, 32.9812), + }, + Vertex { + position: (-8.37704, 34.3417, 8.10003), + }, + Vertex { + position: (-15.8192, 32.6095, 15.5422), + }, + Vertex { + position: (-22.5045, 30.8773, 22.2275), + }, + Vertex { + position: (-25.4056, 28.3457, 25.1286), + }, + Vertex { + position: (-11.133, 34.3417, 3.98234), + }, + Vertex { + position: (-20.8025, 32.6095, 8.09647), + }, + Vertex { + position: (-29.4887, 30.8773, 11.7922), + }, + Vertex { + position: (-33.2582, 28.3457, 13.396), + }, + Vertex { + position: (-12.1381, 34.3417, -1.10804), + }, + Vertex { + position: (-22.62, 32.6095, -1.10804), + }, + Vertex { + position: (-32.0359, 30.8773, -1.10804), + }, + Vertex { + position: (-36.122, 28.3457, -1.10804), + }, + Vertex { + position: (-11.133, 34.3417, -6.19841), + }, + Vertex { + position: (-20.8025, 32.6095, -10.3125), + }, + Vertex { + position: (-29.4887, 30.8773, -14.0083), + }, + Vertex { + position: (-33.2582, 28.3457, -15.6121), + }, + Vertex { + position: (-8.37704, 34.3417, -10.3161), + }, + Vertex { + position: (-15.8192, 32.6095, -17.7582), + }, + Vertex { + position: (-22.5045, 30.8773, -24.4435), + }, + Vertex { + position: (-25.4056, 28.3457, -27.3447), + }, + Vertex { + position: (-4.25935, 34.3417, -13.072), + }, + Vertex { + position: (-8.37348, 32.6095, -22.7416), + }, + Vertex { + position: (-12.0692, 30.8773, -31.4277), + }, + Vertex { + position: (-13.673, 28.3457, -35.1972), + }, + Vertex { + position: (0.831025, 34.3417, -14.0771), + }, + Vertex { + position: (0.831025, 32.6095, -24.559), + }, + Vertex { + position: (0.831025, 30.8773, -33.9749), + }, + Vertex { + position: (0.831025, 28.3457, -38.0611), + }, + Vertex { + position: (5.9214, 34.3417, -13.072), + }, + Vertex { + position: (10.0355, 32.6095, -22.7416), + }, + Vertex { + position: (13.7313, 30.8773, -31.4277), + }, + Vertex { + position: (15.3351, 28.3457, -35.1972), + }, + Vertex { + position: (10.0391, 34.3417, -10.3161), + }, + Vertex { + position: (17.4812, 32.6095, -17.7582), + }, + Vertex { + position: (24.1665, 30.8773, -24.4435), + }, + Vertex { + position: (27.0677, 28.3457, -27.3447), + }, + Vertex { + position: (12.795, 34.3417, -6.19841), + }, + Vertex { + position: (22.4646, 32.6095, -10.3125), + }, + Vertex { + position: (31.1507, 30.8773, -14.0083), + }, + Vertex { + position: (34.9202, 28.3457, -15.6121), + }, +]; + +pub const NORMALS: [Normal; 531] = [ + Normal { + normal: (0.0, 0.0, 0.0), + }, // dummy vector because in the original model indices + // start at 1 + Normal { + normal: (-0.966742, -0.255752, 0.0), + }, + Normal { + normal: (-0.966824, 0.255443, 0.0), + }, + Normal { + normal: (-0.092052, 0.995754, 0.0), + }, + Normal { + normal: (0.68205, 0.731305, 0.0), + }, + Normal { + normal: (0.870301, 0.492521, -0.0), + }, + Normal { + normal: (-0.893014, -0.256345, -0.369882), + }, + Normal { + normal: (-0.893437, 0.255997, -0.369102), + }, + Normal { + normal: (-0.0838771, 0.995843, -0.0355068), + }, + Normal { + normal: (0.629724, 0.73186, 0.260439), + }, + Normal { + normal: (0.803725, 0.49337, 0.332584), + }, + Normal { + normal: (-0.683407, -0.256729, -0.683407), + }, + Normal { + normal: (-0.683531, 0.256067, -0.683531), + }, + Normal { + normal: (-0.0649249, 0.995776, -0.0649248), + }, + Normal { + normal: (0.481398, 0.732469, 0.481398), + }, + Normal { + normal: (0.614804, 0.493997, 0.614804), + }, + Normal { + normal: (-0.369882, -0.256345, -0.893014), + }, + Normal { + normal: (-0.369102, 0.255997, -0.893437), + }, + Normal { + normal: (-0.0355067, 0.995843, -0.0838772), + }, + Normal { + normal: (0.260439, 0.73186, 0.629724), + }, + Normal { + normal: (0.332584, 0.49337, 0.803725), + }, + Normal { + normal: (-0.00284834, -0.257863, -0.966177), + }, + Normal { + normal: (-0.00192311, 0.254736, -0.967009), + }, + Normal { + normal: (-0.000266114, 0.995734, -0.0922702), + }, + Normal { + normal: (0.0, 0.731295, 0.682061), + }, + Normal { + normal: (0.0, 0.492521, 0.870301), + }, + Normal { + normal: (0.379058, -0.3593, -0.852771), + }, + Normal { + normal: (0.37711, 0.149086, -0.914091), + }, + Normal { + normal: (0.0275022, 0.992081, -0.122551), + }, + Normal { + normal: (-0.26101, 0.726762, 0.635367), + }, + Normal { + normal: (-0.332485, 0.492546, 0.804271), + }, + Normal { + normal: (0.663548, -0.410791, -0.625264), + }, + Normal { + normal: (0.712664, 0.0737216, -0.697621), + }, + Normal { + normal: (0.0997268, 0.987509, -0.121984), + }, + Normal { + normal: (-0.48732, 0.723754, 0.488568), + }, + Normal { + normal: (-0.615242, 0.492602, 0.615484), + }, + Normal { + normal: (0.880028, -0.332908, -0.338709), + }, + Normal { + normal: (0.917276, 0.167113, -0.361493), + }, + Normal { + normal: (0.113584, 0.992365, -0.0480695), + }, + Normal { + normal: (-0.63415, 0.727508, 0.261889), + }, + Normal { + normal: (-0.804126, 0.492634, 0.332705), + }, + Normal { + normal: (0.96669, -0.255738, 0.0104537), + }, + Normal { + normal: (0.967442, 0.252962, 0.00810329), + }, + Normal { + normal: (0.0934365, 0.995624, 0.00128063), + }, + Normal { + normal: (-0.682167, 0.731196, -0.00034353), + }, + Normal { + normal: (-0.870322, 0.492483, -0.0), + }, + Normal { + normal: (0.893014, -0.256345, 0.369882), + }, + Normal { + normal: (0.893437, 0.255997, 0.369102), + }, + Normal { + normal: (0.0838768, 0.995843, 0.0355066), + }, + Normal { + normal: (-0.629724, 0.73186, -0.260439), + }, + Normal { + normal: (-0.803725, 0.49337, -0.332584), + }, + Normal { + normal: (0.683407, -0.256729, 0.683407), + }, + Normal { + normal: (0.683531, 0.256067, 0.683531), + }, + Normal { + normal: (0.0649249, 0.995776, 0.0649249), + }, + Normal { + normal: (-0.481398, 0.732469, -0.481398), + }, + Normal { + normal: (-0.614804, 0.493997, -0.614804), + }, + Normal { + normal: (0.369882, -0.256345, 0.893014), + }, + Normal { + normal: (0.369102, 0.255997, 0.893437), + }, + Normal { + normal: (0.0355067, 0.995843, 0.083877), + }, + Normal { + normal: (-0.260439, 0.73186, -0.629724), + }, + Normal { + normal: (-0.332584, 0.49337, -0.803725), + }, + Normal { + normal: (0.0, -0.255752, 0.966742), + }, + Normal { + normal: (0.0, 0.255443, 0.966824), + }, + Normal { + normal: (0.0, 0.995754, 0.092052), + }, + Normal { + normal: (0.0, 0.731305, -0.68205), + }, + Normal { + normal: (-0.0, 0.492521, -0.870301), + }, + Normal { + normal: (-0.369882, -0.256345, 0.893014), + }, + Normal { + normal: (-0.369102, 0.255996, 0.893437), + }, + Normal { + normal: (-0.0355068, 0.995843, 0.0838771), + }, + Normal { + normal: (0.260439, 0.73186, -0.629724), + }, + Normal { + normal: (0.332584, 0.49337, -0.803725), + }, + Normal { + normal: (-0.683407, -0.256729, 0.683407), + }, + Normal { + normal: (-0.683531, 0.256067, 0.683531), + }, + Normal { + normal: (-0.0649249, 0.995776, 0.064925), + }, + Normal { + normal: (0.481398, 0.732469, -0.481398), + }, + Normal { + normal: (0.614804, 0.493997, -0.614804), + }, + Normal { + normal: (-0.893014, -0.256345, 0.369882), + }, + Normal { + normal: (-0.893437, 0.255997, 0.369102), + }, + Normal { + normal: (-0.0838767, 0.995843, 0.0355066), + }, + Normal { + normal: (0.629724, 0.73186, -0.260439), + }, + Normal { + normal: (0.803725, 0.49337, -0.332584), + }, + Normal { + normal: (0.915321, 0.402725, 0.0), + }, + Normal { + normal: (0.941808, 0.336151, -0.0), + }, + Normal { + normal: (0.97869, 0.205342, 0.0), + }, + Normal { + normal: (0.997804, -0.0662397, 0.0), + }, + Normal { + normal: (0.845438, 0.403546, 0.349835), + }, + Normal { + normal: (0.869996, 0.336859, 0.360047), + }, + Normal { + normal: (0.904193, 0.205791, 0.37428), + }, + Normal { + normal: (0.921879, -0.0663697, 0.381752), + }, + Normal { + normal: (0.646802, 0.404096, 0.646802), + }, + Normal { + normal: (0.665655, 0.337351, 0.665655), + }, + Normal { + normal: (0.691923, 0.20612, 0.691923), + }, + Normal { + normal: (0.705542, -0.0664796, 0.705543), + }, + Normal { + normal: (0.349835, 0.403546, 0.845438), + }, + Normal { + normal: (0.360047, 0.336859, 0.869996), + }, + Normal { + normal: (0.37428, 0.205791, 0.904193), + }, + Normal { + normal: (0.381752, -0.0663697, 0.921879), + }, + Normal { + normal: (-0.0, 0.402725, 0.915321), + }, + Normal { + normal: (0.0, 0.336151, 0.941808), + }, + Normal { + normal: (-0.0, 0.205342, 0.97869), + }, + Normal { + normal: (-0.0, -0.0662397, 0.997804), + }, + Normal { + normal: (-0.349835, 0.403546, 0.845438), + }, + Normal { + normal: (-0.360047, 0.336859, 0.869996), + }, + Normal { + normal: (-0.37428, 0.205791, 0.904193), + }, + Normal { + normal: (-0.381752, -0.0663697, 0.921879), + }, + Normal { + normal: (-0.646802, 0.404096, 0.646802), + }, + Normal { + normal: (-0.665655, 0.337351, 0.665655), + }, + Normal { + normal: (-0.691923, 0.20612, 0.691923), + }, + Normal { + normal: (-0.705543, -0.0664796, 0.705543), + }, + Normal { + normal: (-0.845438, 0.403546, 0.349835), + }, + Normal { + normal: (-0.869996, 0.336859, 0.360047), + }, + Normal { + normal: (-0.904193, 0.205791, 0.37428), + }, + Normal { + normal: (-0.921879, -0.0663697, 0.381752), + }, + Normal { + normal: (-0.915321, 0.402725, -0.0), + }, + Normal { + normal: (-0.941808, 0.336151, -0.0), + }, + Normal { + normal: (-0.97869, 0.205342, -0.0), + }, + Normal { + normal: (-0.997804, -0.0662397, -0.0), + }, + Normal { + normal: (-0.845438, 0.403546, -0.349835), + }, + Normal { + normal: (-0.869996, 0.336859, -0.360047), + }, + Normal { + normal: (-0.904193, 0.205791, -0.37428), + }, + Normal { + normal: (-0.921879, -0.0663697, -0.381752), + }, + Normal { + normal: (-0.646802, 0.404096, -0.646802), + }, + Normal { + normal: (-0.665655, 0.337351, -0.665655), + }, + Normal { + normal: (-0.691923, 0.20612, -0.691923), + }, + Normal { + normal: (-0.705542, -0.0664796, -0.705543), + }, + Normal { + normal: (-0.349835, 0.403546, -0.845438), + }, + Normal { + normal: (-0.360047, 0.336859, -0.869996), + }, + Normal { + normal: (-0.37428, 0.205791, -0.904193), + }, + Normal { + normal: (-0.381752, -0.0663697, -0.921879), + }, + Normal { + normal: (0.0, 0.402725, -0.915321), + }, + Normal { + normal: (-0.0, 0.336151, -0.941808), + }, + Normal { + normal: (0.0, 0.205342, -0.97869), + }, + Normal { + normal: (0.0, -0.0662397, -0.997804), + }, + Normal { + normal: (0.349835, 0.403546, -0.845438), + }, + Normal { + normal: (0.360047, 0.336859, -0.869996), + }, + Normal { + normal: (0.37428, 0.205791, -0.904193), + }, + Normal { + normal: (0.381752, -0.0663697, -0.921879), + }, + Normal { + normal: (0.646802, 0.404096, -0.646802), + }, + Normal { + normal: (0.665655, 0.337351, -0.665655), + }, + Normal { + normal: (0.691923, 0.20612, -0.691923), + }, + Normal { + normal: (0.705543, -0.0664796, -0.705542), + }, + Normal { + normal: (0.845438, 0.403546, -0.349835), + }, + Normal { + normal: (0.869996, 0.336859, -0.360047), + }, + Normal { + normal: (0.904193, 0.205791, -0.37428), + }, + Normal { + normal: (0.921879, -0.0663697, -0.381752), + }, + Normal { + normal: (0.900182, -0.435513, -0.0), + }, + Normal { + normal: (0.729611, -0.683863, -0.0), + }, + Normal { + normal: (0.693951, -0.720022, -0.0), + }, + Normal { + normal: (0.79395, -0.607984, 0.0), + }, + Normal { + normal: (0.831437, -0.43618, 0.344179), + }, + Normal { + normal: (0.673512, -0.684665, 0.278594), + }, + Normal { + normal: (0.640399, -0.720924, 0.264874), + }, + Normal { + normal: (0.732949, -0.608996, 0.303166), + }, + Normal { + normal: (0.636092, -0.436777, 0.636092), + }, + Normal { + normal: (0.514965, -0.685289, 0.514965), + }, + Normal { + normal: (0.489651, -0.721446, 0.489651), + }, + Normal { + normal: (0.560555, -0.609554, 0.560555), + }, + Normal { + normal: (0.344179, -0.43618, 0.831437), + }, + Normal { + normal: (0.278594, -0.684665, 0.673512), + }, + Normal { + normal: (0.264874, -0.720924, 0.640399), + }, + Normal { + normal: (0.303166, -0.608996, 0.732949), + }, + Normal { + normal: (0.0, -0.435513, 0.900182), + }, + Normal { + normal: (-0.0, -0.683863, 0.729611), + }, + Normal { + normal: (0.0, -0.720022, 0.693951), + }, + Normal { + normal: (-0.0, -0.607984, 0.79395), + }, + Normal { + normal: (-0.344179, -0.43618, 0.831437), + }, + Normal { + normal: (-0.278594, -0.684665, 0.673512), + }, + Normal { + normal: (-0.264874, -0.720924, 0.640399), + }, + Normal { + normal: (-0.303166, -0.608996, 0.732949), + }, + Normal { + normal: (-0.636092, -0.436777, 0.636092), + }, + Normal { + normal: (-0.514965, -0.685289, 0.514965), + }, + Normal { + normal: (-0.489651, -0.721446, 0.489651), + }, + Normal { + normal: (-0.560555, -0.609554, 0.560555), + }, + Normal { + normal: (-0.831437, -0.43618, 0.344179), + }, + Normal { + normal: (-0.673512, -0.684665, 0.278595), + }, + Normal { + normal: (-0.640399, -0.720924, 0.264874), + }, + Normal { + normal: (-0.732949, -0.608996, 0.303166), + }, + Normal { + normal: (-0.900182, -0.435513, -0.0), + }, + Normal { + normal: (-0.729611, -0.683863, -0.0), + }, + Normal { + normal: (-0.693951, -0.720022, 0.0), + }, + Normal { + normal: (-0.79395, -0.607983, -0.0), + }, + Normal { + normal: (-0.831437, -0.43618, -0.344179), + }, + Normal { + normal: (-0.673512, -0.684665, -0.278594), + }, + Normal { + normal: (-0.640399, -0.720924, -0.264874), + }, + Normal { + normal: (-0.732949, -0.608996, -0.303166), + }, + Normal { + normal: (-0.636092, -0.436777, -0.636092), + }, + Normal { + normal: (-0.514965, -0.685289, -0.514965), + }, + Normal { + normal: (-0.489651, -0.721446, -0.489651), + }, + Normal { + normal: (-0.560555, -0.609554, -0.560555), + }, + Normal { + normal: (-0.344179, -0.43618, -0.831437), + }, + Normal { + normal: (-0.278594, -0.684665, -0.673512), + }, + Normal { + normal: (-0.264874, -0.720924, -0.640399), + }, + Normal { + normal: (-0.303166, -0.608996, -0.732949), + }, + Normal { + normal: (-0.0, -0.435513, -0.900182), + }, + Normal { + normal: (0.0, -0.683863, -0.729611), + }, + Normal { + normal: (-0.0, -0.720022, -0.693951), + }, + Normal { + normal: (0.0, -0.607984, -0.79395), + }, + Normal { + normal: (0.344179, -0.43618, -0.831437), + }, + Normal { + normal: (0.278594, -0.684665, -0.673512), + }, + Normal { + normal: (0.264874, -0.720924, -0.640399), + }, + Normal { + normal: (0.303167, -0.608996, -0.732949), + }, + Normal { + normal: (0.636092, -0.436777, -0.636092), + }, + Normal { + normal: (0.514965, -0.685289, -0.514965), + }, + Normal { + normal: (0.489651, -0.721446, -0.489651), + }, + Normal { + normal: (0.560555, -0.609554, -0.560555), + }, + Normal { + normal: (0.831437, -0.43618, -0.344179), + }, + Normal { + normal: (0.673512, -0.684665, -0.278595), + }, + Normal { + normal: (0.640399, -0.720924, -0.264874), + }, + Normal { + normal: (0.732949, -0.608996, -0.303166), + }, + Normal { + normal: (0.62386, -0.781536, 0.0), + }, + Normal { + normal: (0.177291, -0.984159, -0.0), + }, + Normal { + normal: (0.0492072, -0.998789, 0.0), + }, + Normal { + normal: (0.0, -1.0, -0.0), + }, + Normal { + normal: (0.576229, -0.781801, 0.238217), + }, + Normal { + normal: (0.163629, -0.984208, 0.0675273), + }, + Normal { + normal: (0.0454217, -0.998792, 0.0187357), + }, + Normal { + normal: (0.440416, -0.782348, 0.440416), + }, + Normal { + normal: (0.124903, -0.984276, 0.124903), + }, + Normal { + normal: (0.0346621, -0.998798, 0.0346621), + }, + Normal { + normal: (0.238217, -0.781801, 0.576229), + }, + Normal { + normal: (0.0675273, -0.984208, 0.163629), + }, + Normal { + normal: (0.0187357, -0.998792, 0.0454217), + }, + Normal { + normal: (-0.0, -0.781536, 0.62386), + }, + Normal { + normal: (0.0, -0.984159, 0.177291), + }, + Normal { + normal: (-0.0, -0.998789, 0.0492072), + }, + Normal { + normal: (-0.238216, -0.781801, 0.576229), + }, + Normal { + normal: (-0.0675273, -0.984208, 0.163629), + }, + Normal { + normal: (-0.0187357, -0.998792, 0.0454217), + }, + Normal { + normal: (-0.440416, -0.782348, 0.440416), + }, + Normal { + normal: (-0.124903, -0.984276, 0.124903), + }, + Normal { + normal: (-0.0346621, -0.998798, 0.0346621), + }, + Normal { + normal: (-0.576229, -0.781801, 0.238217), + }, + Normal { + normal: (-0.163629, -0.984208, 0.0675273), + }, + Normal { + normal: (-0.0454217, -0.998792, 0.0187357), + }, + Normal { + normal: (-0.62386, -0.781536, -0.0), + }, + Normal { + normal: (-0.177291, -0.984159, 0.0), + }, + Normal { + normal: (-0.0492072, -0.998789, -0.0), + }, + Normal { + normal: (-0.576229, -0.781801, -0.238217), + }, + Normal { + normal: (-0.163629, -0.984208, -0.0675273), + }, + Normal { + normal: (-0.0454217, -0.998792, -0.0187357), + }, + Normal { + normal: (-0.440416, -0.782348, -0.440416), + }, + Normal { + normal: (-0.124903, -0.984276, -0.124903), + }, + Normal { + normal: (-0.0346621, -0.998798, -0.0346621), + }, + Normal { + normal: (-0.238217, -0.781801, -0.576229), + }, + Normal { + normal: (-0.0675273, -0.984208, -0.163629), + }, + Normal { + normal: (-0.0187357, -0.998792, -0.0454217), + }, + Normal { + normal: (0.0, -0.781536, -0.62386), + }, + Normal { + normal: (-0.0, -0.984159, -0.177291), + }, + Normal { + normal: (0.0, -0.998789, -0.0492072), + }, + Normal { + normal: (0.238217, -0.781801, -0.576229), + }, + Normal { + normal: (0.0675273, -0.984208, -0.163629), + }, + Normal { + normal: (0.0187357, -0.998792, -0.0454217), + }, + Normal { + normal: (0.440416, -0.782348, -0.440416), + }, + Normal { + normal: (0.124903, -0.984276, -0.124903), + }, + Normal { + normal: (0.0346621, -0.998798, -0.0346621), + }, + Normal { + normal: (0.576229, -0.781801, -0.238217), + }, + Normal { + normal: (0.163629, -0.984208, -0.0675273), + }, + Normal { + normal: (0.0454217, -0.998792, -0.0187357), + }, + Normal { + normal: (0.00778619, -0.99997, -0.000215809), + }, + Normal { + normal: (0.0391385, -0.999233, -0.000988567), + }, + Normal { + normal: (0.179511, -0.983746, -0.00436856), + }, + Normal { + normal: (0.6123, -0.790556, -0.0104598), + }, + Normal { + normal: (0.986152, -0.165707, -0.00666949), + }, + Normal { + normal: (0.00703893, -0.812495, 0.582926), + }, + Normal { + normal: (0.0361273, -0.837257, 0.545614), + }, + Normal { + normal: (0.161845, -0.810421, 0.563048), + }, + Normal { + normal: (0.482365, -0.595148, 0.642746), + }, + Normal { + normal: (0.73872, -0.114593, 0.664199), + }, + Normal { + normal: (-0.00190867, 0.162121, 0.986769), + }, + Normal { + normal: (0.0027616, 0.0171073, 0.99985), + }, + Normal { + normal: (0.0105326, 0.0733989, 0.997247), + }, + Normal { + normal: (-0.0660406, 0.130069, 0.989303), + }, + Normal { + normal: (-0.0944272, 0.0165946, 0.995393), + }, + Normal { + normal: (-0.009203, 0.871509, 0.490293), + }, + Normal { + normal: (-0.0486064, 0.840609, 0.539457), + }, + Normal { + normal: (-0.223298, 0.802881, 0.552739), + }, + Normal { + normal: (-0.596365, 0.559971, 0.575135), + }, + Normal { + normal: (-0.803337, 0.0682361, 0.591602), + }, + Normal { + normal: (-0.0105609, 0.999944, 0.000103364), + }, + Normal { + normal: (-0.0587986, 0.99827, 0.000709759), + }, + Normal { + normal: (-0.28071, 0.959787, 0.00326876), + }, + Normal { + normal: (-0.749723, 0.661738, 0.0042684), + }, + Normal { + normal: (-0.997351, 0.0727144, 0.00205923), + }, + Normal { + normal: (-0.00879197, 0.871493, -0.49033), + }, + Normal { + normal: (-0.0464937, 0.841178, -0.538756), + }, + Normal { + normal: (-0.217909, 0.806807, -0.549161), + }, + Normal { + normal: (-0.597291, 0.560026, -0.574121), + }, + Normal { + normal: (-0.804, 0.0629127, -0.591291), + }, + Normal { + normal: (-0.00180555, 0.161691, -0.98684), + }, + Normal { + normal: (0.00203087, 0.014555, -0.999892), + }, + Normal { + normal: (0.00921499, 0.0600698, -0.998152), + }, + Normal { + normal: (-0.0593333, 0.113865, -0.991723), + }, + Normal { + normal: (-0.0868992, 0.0122903, -0.996141), + }, + Normal { + normal: (0.00641779, -0.812379, -0.583094), + }, + Normal { + normal: (0.0337833, -0.837512, -0.545373), + }, + Normal { + normal: (0.157112, -0.811947, -0.56219), + }, + Normal { + normal: (0.484407, -0.589365, -0.646528), + }, + Normal { + normal: (0.73887, -0.10132, -0.666187), + }, + Normal { + normal: (0.946512, 0.32265, -0.0033571), + }, + Normal { + normal: (0.82583, 0.56387, -0.00745213), + }, + Normal { + normal: (0.650011, 0.759893, -0.00693681), + }, + Normal { + normal: (0.532429, 0.846458, -0.00524544), + }, + Normal { + normal: (0.725608, 0.259351, 0.637362), + }, + Normal { + normal: (0.645945, 0.461988, 0.607719), + }, + Normal { + normal: (0.531614, 0.63666, 0.558615), + }, + Normal { + normal: (0.424964, 0.681717, 0.59554), + }, + Normal { + normal: (-0.0495616, -0.019755, 0.998576), + }, + Normal { + normal: (-0.0378162, -0.0356243, 0.99865), + }, + Normal { + normal: (-0.0379139, -0.0365122, 0.998614), + }, + Normal { + normal: (-0.168854, -0.297946, 0.93953), + }, + Normal { + normal: (-0.742342, -0.299166, 0.599523), + }, + Normal { + normal: (-0.619602, -0.529406, 0.579503), + }, + Normal { + normal: (-0.483708, -0.685761, 0.543837), + }, + Normal { + normal: (-0.445293, -0.794355, 0.413176), + }, + Normal { + normal: (-0.926513, -0.376257, 0.00199587), + }, + Normal { + normal: (-0.75392, -0.656952, 0.00431723), + }, + Normal { + normal: (-0.566224, -0.824244, 0.00346105), + }, + Normal { + normal: (-0.481804, -0.876277, 0.00185047), + }, + Normal { + normal: (-0.744675, -0.294424, -0.598977), + }, + Normal { + normal: (-0.621949, -0.528114, -0.578165), + }, + Normal { + normal: (-0.481171, -0.68834, -0.542828), + }, + Normal { + normal: (-0.438055, -0.797035, -0.415744), + }, + Normal { + normal: (-0.0443368, -0.0170558, -0.998871), + }, + Normal { + normal: (-0.0261761, -0.0281665, -0.99926), + }, + Normal { + normal: (-0.0252939, -0.0283323, -0.999278), + }, + Normal { + normal: (-0.157482, -0.289392, -0.944167), + }, + Normal { + normal: (0.728244, 0.25241, -0.637142), + }, + Normal { + normal: (0.647055, 0.459725, -0.608254), + }, + Normal { + normal: (0.522994, 0.640657, -0.562171), + }, + Normal { + normal: (0.409978, 0.682857, -0.604669), + }, + Normal { + normal: (-0.230787, 0.972982, -0.00652338), + }, + Normal { + normal: (-0.548936, 0.835863, -0.00151111), + }, + Normal { + normal: (-0.875671, 0.482807, 0.00989278), + }, + Normal { + normal: (-0.877554, 0.479097, 0.0190923), + }, + Normal { + normal: (-0.69619, 0.717439, 0.024497), + }, + Normal { + normal: (-0.152878, 0.687211, 0.71019), + }, + Normal { + normal: (-0.316721, 0.63775, 0.702113), + }, + Normal { + normal: (-0.601067, 0.471452, 0.64533), + }, + Normal { + normal: (-0.635889, 0.44609, 0.6298), + }, + Normal { + normal: (-0.435746, 0.601008, 0.670011), + }, + Normal { + normal: (0.111112, -0.0850694, 0.99016), + }, + Normal { + normal: (0.22331, 0.00654036, 0.974726), + }, + Normal { + normal: (0.190097, 0.154964, 0.969458), + }, + Normal { + normal: (0.00527077, 0.189482, 0.98187), + }, + Normal { + normal: (-0.0117518, 0.246688, 0.969024), + }, + Normal { + normal: (0.343906, -0.722796, 0.599412), + }, + Normal { + normal: (0.572489, -0.567656, 0.591627), + }, + Normal { + normal: (0.787436, -0.256459, 0.560512), + }, + Normal { + normal: (0.647097, -0.306374, 0.698141), + }, + Normal { + normal: (0.427528, -0.499343, 0.753576), + }, + Normal { + normal: (0.410926, -0.911668, 0.00128446), + }, + Normal { + normal: (0.67152, -0.740986, -0.000899122), + }, + Normal { + normal: (0.922026, -0.38706, -0.00725269), + }, + Normal { + normal: (0.84691, -0.531556, -0.0138542), + }, + Normal { + normal: (0.535925, -0.8442, -0.0105045), + }, + Normal { + normal: (0.341188, -0.722822, -0.600931), + }, + Normal { + normal: (0.578664, -0.561139, -0.591838), + }, + Normal { + normal: (0.784869, -0.25102, -0.566542), + }, + Normal { + normal: (0.642681, -0.302257, -0.70399), + }, + Normal { + normal: (0.418589, -0.500042, -0.758117), + }, + Normal { + normal: (0.115806, -0.0791394, -0.990114), + }, + Normal { + normal: (0.232811, 0.0125652, -0.972441), + }, + Normal { + normal: (0.206662, 0.153601, -0.96628), + }, + Normal { + normal: (0.0244996, 0.161443, -0.986578), + }, + Normal { + normal: (0.00338193, 0.211115, -0.977455), + }, + Normal { + normal: (-0.134912, 0.687491, -0.713551), + }, + Normal { + normal: (-0.31954, 0.633073, -0.705062), + }, + Normal { + normal: (-0.603902, 0.461442, -0.649903), + }, + Normal { + normal: (-0.631816, 0.437169, -0.640072), + }, + Normal { + normal: (-0.424306, 0.612706, -0.66675), + }, + Normal { + normal: (-0.4258, 0.904753, 0.0108049), + }, + Normal { + normal: (0.0220472, 0.999756, 0.00162273), + }, + Normal { + normal: (0.999599, 0.0258705, 0.0115556), + }, + Normal { + normal: (0.709585, -0.704553, 0.00967183), + }, + Normal { + normal: (-0.259858, 0.791936, 0.552549), + }, + Normal { + normal: (0.00953916, 0.99972, -0.0216718), + }, + Normal { + normal: (0.410156, 0.332912, -0.849083), + }, + Normal { + normal: (0.541523, -0.54862, -0.637), + }, + Normal { + normal: (0.0463104, 0.455224, 0.889172), + }, + Normal { + normal: (-0.0106883, 0.988794, 0.148901), + }, + Normal { + normal: (-0.0443756, 0.682947, -0.729118), + }, + Normal { + normal: (0.122825, 0.00923214, -0.992385), + }, + Normal { + normal: (0.481839, -0.180439, 0.85748), + }, + Normal { + normal: (0.455272, 0.736752, 0.499925), + }, + Normal { + normal: (-0.220542, 0.907193, -0.358276), + }, + Normal { + normal: (-0.23592, 0.657249, -0.715797), + }, + Normal { + normal: (0.728092, -0.685302, -0.0155853), + }, + Normal { + normal: (0.888739, 0.45811, -0.0166791), + }, + Normal { + normal: (-0.260097, 0.965582, 0.000800195), + }, + Normal { + normal: (-0.371612, 0.928378, -0.00441745), + }, + Normal { + normal: (0.480166, -0.17836, -0.858853), + }, + Normal { + normal: (0.488103, 0.716801, -0.497947), + }, + Normal { + normal: (-0.222004, 0.905399, 0.361893), + }, + Normal { + normal: (-0.235405, 0.66318, 0.710477), + }, + Normal { + normal: (0.0587203, 0.437704, -0.8972), + }, + Normal { + normal: (0.00132612, 0.986459, -0.164003), + }, + Normal { + normal: (-0.0441901, 0.681677, 0.730317), + }, + Normal { + normal: (0.138801, -0.0341896, 0.98973), + }, + Normal { + normal: (-0.25889, 0.797206, -0.54538), + }, + Normal { + normal: (0.0122703, 0.999739, 0.0192865), + }, + Normal { + normal: (0.39863, 0.35489, 0.845663), + }, + Normal { + normal: (0.537564, -0.5814, 0.610737), + }, + Normal { + normal: (-0.0, 1.0, 0.0), + }, + Normal { + normal: (0.82454, 0.565804, 0.0), + }, + Normal { + normal: (0.917701, -0.397272, 0.0), + }, + Normal { + normal: (0.935269, -0.353939, 0.000112842), + }, + Normal { + normal: (0.780712, 0.624891, 0.0), + }, + Normal { + normal: (0.762641, 0.565035, 0.314825), + }, + Normal { + normal: (0.847982, -0.397998, 0.350034), + }, + Normal { + normal: (0.864141, -0.355261, 0.356441), + }, + Normal { + normal: (0.720991, 0.625625, 0.297933), + }, + Normal { + normal: (0.583357, 0.565165, 0.583338), + }, + Normal { + normal: (0.648485, -0.398726, 0.648448), + }, + Normal { + normal: (0.660872, -0.355894, 0.660748), + }, + Normal { + normal: (0.551862, 0.62529, 0.55178), + }, + Normal { + normal: (0.314824, 0.565051, 0.762629), + }, + Normal { + normal: (0.350045, -0.397976, 0.847988), + }, + Normal { + normal: (0.356474, -0.3552, 0.864153), + }, + Normal { + normal: (0.297983, 0.625515, 0.721067), + }, + Normal { + normal: (-0.0, 0.565804, 0.82454), + }, + Normal { + normal: (-0.0, -0.397272, 0.917701), + }, + Normal { + normal: (-0.000112839, -0.353939, 0.935269), + }, + Normal { + normal: (-0.0, 0.624891, 0.780712), + }, + Normal { + normal: (-0.314825, 0.565035, 0.762641), + }, + Normal { + normal: (-0.350034, -0.397998, 0.847982), + }, + Normal { + normal: (-0.356441, -0.355261, 0.864141), + }, + Normal { + normal: (-0.297933, 0.625625, 0.720991), + }, + Normal { + normal: (-0.583338, 0.565165, 0.583357), + }, + Normal { + normal: (-0.648448, -0.398726, 0.648485), + }, + Normal { + normal: (-0.660748, -0.355894, 0.660872), + }, + Normal { + normal: (-0.55178, 0.62529, 0.551862), + }, + Normal { + normal: (-0.762629, 0.565051, 0.314824), + }, + Normal { + normal: (-0.847988, -0.397976, 0.350045), + }, + Normal { + normal: (-0.864153, -0.3552, 0.356474), + }, + Normal { + normal: (-0.721067, 0.625515, 0.297983), + }, + Normal { + normal: (-0.82454, 0.565804, -0.0), + }, + Normal { + normal: (-0.917701, -0.397272, -0.0), + }, + Normal { + normal: (-0.935269, -0.353939, -0.000112839), + }, + Normal { + normal: (-0.780712, 0.624891, -0.0), + }, + Normal { + normal: (-0.76264, 0.565035, -0.314825), + }, + Normal { + normal: (-0.847982, -0.397998, -0.350034), + }, + Normal { + normal: (-0.864141, -0.355261, -0.356441), + }, + Normal { + normal: (-0.720991, 0.625625, -0.297933), + }, + Normal { + normal: (-0.583357, 0.565165, -0.583338), + }, + Normal { + normal: (-0.648485, -0.398726, -0.648448), + }, + Normal { + normal: (-0.660872, -0.355894, -0.660748), + }, + Normal { + normal: (-0.551862, 0.62529, -0.55178), + }, + Normal { + normal: (-0.314824, 0.565051, -0.762629), + }, + Normal { + normal: (-0.350045, -0.397976, -0.847988), + }, + Normal { + normal: (-0.356474, -0.3552, -0.864153), + }, + Normal { + normal: (-0.297983, 0.625515, -0.721067), + }, + Normal { + normal: (0.0, 0.565804, -0.82454), + }, + Normal { + normal: (0.0, -0.397272, -0.917701), + }, + Normal { + normal: (0.000112839, -0.353939, -0.935269), + }, + Normal { + normal: (0.0, 0.624891, -0.780712), + }, + Normal { + normal: (0.314825, 0.565035, -0.762641), + }, + Normal { + normal: (0.350034, -0.397998, -0.847982), + }, + Normal { + normal: (0.356441, -0.355261, -0.864141), + }, + Normal { + normal: (0.297933, 0.625625, -0.720991), + }, + Normal { + normal: (0.583338, 0.565165, -0.583357), + }, + Normal { + normal: (0.648448, -0.398726, -0.648485), + }, + Normal { + normal: (0.660748, -0.355894, -0.660872), + }, + Normal { + normal: (0.55178, 0.62529, -0.551862), + }, + Normal { + normal: (0.762629, 0.565051, -0.314824), + }, + Normal { + normal: (0.847988, -0.397976, -0.350045), + }, + Normal { + normal: (0.864153, -0.3552, -0.356474), + }, + Normal { + normal: (0.721067, 0.625515, -0.297983), + }, + Normal { + normal: (0.236584, 0.971611, 0.0), + }, + Normal { + normal: (0.173084, 0.984907, -0.0), + }, + Normal { + normal: (0.379703, 0.925108, 0.0), + }, + Normal { + normal: (0.526673, 0.850068, 0.0), + }, + Normal { + normal: (0.217978, 0.971775, 0.0902162), + }, + Normal { + normal: (0.15959, 0.984977, 0.0659615), + }, + Normal { + normal: (0.350498, 0.925312, 0.14474), + }, + Normal { + normal: (0.48559, 0.850653, 0.201474), + }, + Normal { + normal: (0.166631, 0.971838, 0.166631), + }, + Normal { + normal: (0.121908, 0.985026, 0.121908), + }, + Normal { + normal: (0.267668, 0.925585, 0.267668), + }, + Normal { + normal: (0.371315, 0.851029, 0.371315), + }, + Normal { + normal: (0.0902162, 0.971775, 0.217978), + }, + Normal { + normal: (0.0659615, 0.984977, 0.15959), + }, + Normal { + normal: (0.14474, 0.925312, 0.350498), + }, + Normal { + normal: (0.201474, 0.850653, 0.48559), + }, + Normal { + normal: (-0.0, 0.971611, 0.236584), + }, + Normal { + normal: (0.0, 0.984907, 0.173084), + }, + Normal { + normal: (0.0, 0.925108, 0.379703), + }, + Normal { + normal: (0.0, 0.850068, 0.526673), + }, + Normal { + normal: (-0.0902162, 0.971775, 0.217978), + }, + Normal { + normal: (-0.0659615, 0.984977, 0.15959), + }, + Normal { + normal: (-0.14474, 0.925312, 0.350498), + }, + Normal { + normal: (-0.201474, 0.850653, 0.48559), + }, + Normal { + normal: (-0.166631, 0.971838, 0.166631), + }, + Normal { + normal: (-0.121908, 0.985026, 0.121908), + }, + Normal { + normal: (-0.267668, 0.925585, 0.267668), + }, + Normal { + normal: (-0.371315, 0.851029, 0.371315), + }, + Normal { + normal: (-0.217978, 0.971775, 0.0902162), + }, + Normal { + normal: (-0.15959, 0.984977, 0.0659615), + }, + Normal { + normal: (-0.350498, 0.925312, 0.14474), + }, + Normal { + normal: (-0.48559, 0.850653, 0.201474), + }, + Normal { + normal: (-0.236583, 0.971611, -0.0), + }, + Normal { + normal: (-0.173084, 0.984907, 0.0), + }, + Normal { + normal: (-0.379703, 0.925108, -0.0), + }, + Normal { + normal: (-0.526673, 0.850068, 0.0), + }, + Normal { + normal: (-0.217978, 0.971775, -0.0902162), + }, + Normal { + normal: (-0.15959, 0.984977, -0.0659615), + }, + Normal { + normal: (-0.350498, 0.925312, -0.14474), + }, + Normal { + normal: (-0.48559, 0.850653, -0.201474), + }, + Normal { + normal: (-0.166631, 0.971838, -0.166631), + }, + Normal { + normal: (-0.121908, 0.985026, -0.121908), + }, + Normal { + normal: (-0.267668, 0.925585, -0.267668), + }, + Normal { + normal: (-0.371315, 0.851029, -0.371315), + }, + Normal { + normal: (-0.0902162, 0.971775, -0.217978), + }, + Normal { + normal: (-0.0659615, 0.984977, -0.15959), + }, + Normal { + normal: (-0.14474, 0.925312, -0.350498), + }, + Normal { + normal: (-0.201474, 0.850653, -0.485589), + }, + Normal { + normal: (0.0, 0.971611, -0.236584), + }, + Normal { + normal: (-0.0, 0.984907, -0.173084), + }, + Normal { + normal: (-0.0, 0.925108, -0.379703), + }, + Normal { + normal: (-0.0, 0.850068, -0.526673), + }, + Normal { + normal: (0.0902162, 0.971775, -0.217978), + }, + Normal { + normal: (0.0659615, 0.984977, -0.15959), + }, + Normal { + normal: (0.14474, 0.925312, -0.350498), + }, + Normal { + normal: (0.201474, 0.850653, -0.48559), + }, + Normal { + normal: (0.166631, 0.971838, -0.166631), + }, + Normal { + normal: (0.121908, 0.985026, -0.121908), + }, + Normal { + normal: (0.267668, 0.925585, -0.267668), + }, + Normal { + normal: (0.371315, 0.851029, -0.371315), + }, + Normal { + normal: (0.217978, 0.971775, -0.0902162), + }, + Normal { + normal: (0.15959, 0.984977, -0.0659615), + }, + Normal { + normal: (0.350498, 0.925312, -0.14474), + }, + Normal { + normal: (0.48559, 0.850653, -0.201474), + }, +]; + +pub const INDICES: [u16; 3072] = [ + 7, 6, 1, 1, 2, 7, 8, 7, 2, 2, 3, 8, 9, 8, 3, 3, 4, 9, 10, 9, 4, 4, 5, 10, 12, 11, 6, 6, 7, 12, + 13, 12, 7, 7, 8, 13, 14, 13, 8, 8, 9, 14, 15, 14, 9, 9, 10, 15, 17, 16, 11, 11, 12, 17, 18, 17, + 12, 12, 13, 18, 19, 18, 13, 13, 14, 19, 20, 19, 14, 14, 15, 20, 22, 21, 16, 16, 17, 22, 23, 22, + 17, 17, 18, 23, 24, 23, 18, 18, 19, 24, 25, 24, 19, 19, 20, 25, 27, 26, 21, 21, 22, 27, 28, 27, + 22, 22, 23, 28, 29, 28, 23, 23, 24, 29, 30, 29, 24, 24, 25, 30, 32, 31, 26, 26, 27, 32, 33, 32, + 27, 27, 28, 33, 34, 33, 28, 28, 29, 34, 35, 34, 29, 29, 30, 35, 37, 36, 31, 31, 32, 37, 38, 37, + 32, 32, 33, 38, 39, 38, 33, 33, 34, 39, 40, 39, 34, 34, 35, 40, 42, 41, 36, 36, 37, 42, 43, 42, + 37, 37, 38, 43, 44, 43, 38, 38, 39, 44, 45, 44, 39, 39, 40, 45, 47, 46, 41, 41, 42, 47, 48, 47, + 42, 42, 43, 48, 49, 48, 43, 43, 44, 49, 50, 49, 44, 44, 45, 50, 52, 51, 46, 46, 47, 52, 53, 52, + 47, 47, 48, 53, 54, 53, 48, 48, 49, 54, 55, 54, 49, 49, 50, 55, 57, 56, 51, 51, 52, 57, 58, 57, + 52, 52, 53, 58, 59, 58, 53, 53, 54, 59, 60, 59, 54, 54, 55, 60, 62, 61, 56, 56, 57, 62, 63, 62, + 57, 57, 58, 63, 64, 63, 58, 58, 59, 64, 65, 64, 59, 59, 60, 65, 67, 66, 61, 61, 62, 67, 68, 67, + 62, 62, 63, 68, 69, 68, 63, 63, 64, 69, 70, 69, 64, 64, 65, 70, 72, 71, 66, 66, 67, 72, 73, 72, + 67, 67, 68, 73, 74, 73, 68, 68, 69, 74, 75, 74, 69, 69, 70, 75, 77, 76, 71, 71, 72, 77, 78, 77, + 72, 72, 73, 78, 79, 78, 73, 73, 74, 79, 80, 79, 74, 74, 75, 80, 2, 1, 76, 76, 77, 2, 3, 2, 77, + 77, 78, 3, 4, 3, 78, 78, 79, 4, 5, 4, 79, 79, 80, 5, 85, 10, 5, 5, 81, 85, 86, 85, 81, 81, 82, + 86, 87, 86, 82, 82, 83, 87, 88, 87, 83, 83, 84, 88, 89, 15, 10, 10, 85, 89, 90, 89, 85, 85, 86, + 90, 91, 90, 86, 86, 87, 91, 92, 91, 87, 87, 88, 92, 93, 20, 15, 15, 89, 93, 94, 93, 89, 89, 90, + 94, 95, 94, 90, 90, 91, 95, 96, 95, 91, 91, 92, 96, 97, 25, 20, 20, 93, 97, 98, 97, 93, 93, 94, + 98, 99, 98, 94, 94, 95, 99, 100, 99, 95, 95, 96, 100, 101, 30, 25, 25, 97, 101, 102, 101, 97, + 97, 98, 102, 103, 102, 98, 98, 99, 103, 104, 103, 99, 99, 100, 104, 105, 35, 30, 30, 101, 105, + 106, 105, 101, 101, 102, 106, 107, 106, 102, 102, 103, 107, 108, 107, 103, 103, 104, 108, 109, + 40, 35, 35, 105, 109, 110, 109, 105, 105, 106, 110, 111, 110, 106, 106, 107, 111, 112, 111, + 107, 107, 108, 112, 113, 45, 40, 40, 109, 113, 114, 113, 109, 109, 110, 114, 115, 114, 110, + 110, 111, 115, 116, 115, 111, 111, 112, 116, 117, 50, 45, 45, 113, 117, 118, 117, 113, 113, + 114, 118, 119, 118, 114, 114, 115, 119, 120, 119, 115, 115, 116, 120, 121, 55, 50, 50, 117, + 121, 122, 121, 117, 117, 118, 122, 123, 122, 118, 118, 119, 123, 124, 123, 119, 119, 120, 124, + 125, 60, 55, 55, 121, 125, 126, 125, 121, 121, 122, 126, 127, 126, 122, 122, 123, 127, 128, + 127, 123, 123, 124, 128, 129, 65, 60, 60, 125, 129, 130, 129, 125, 125, 126, 130, 131, 130, + 126, 126, 127, 131, 132, 131, 127, 127, 128, 132, 133, 70, 65, 65, 129, 133, 134, 133, 129, + 129, 130, 134, 135, 134, 130, 130, 131, 135, 136, 135, 131, 131, 132, 136, 137, 75, 70, 70, + 133, 137, 138, 137, 133, 133, 134, 138, 139, 138, 134, 134, 135, 139, 140, 139, 135, 135, 136, + 140, 141, 80, 75, 75, 137, 141, 142, 141, 137, 137, 138, 142, 143, 142, 138, 138, 139, 143, + 144, 143, 139, 139, 140, 144, 81, 5, 80, 80, 141, 81, 82, 81, 141, 141, 142, 82, 83, 82, 142, + 142, 143, 83, 84, 83, 143, 143, 144, 84, 149, 88, 84, 84, 145, 149, 150, 149, 145, 145, 146, + 150, 151, 150, 146, 146, 147, 151, 152, 151, 147, 147, 148, 152, 153, 92, 88, 88, 149, 153, + 154, 153, 149, 149, 150, 154, 155, 154, 150, 150, 151, 155, 156, 155, 151, 151, 152, 156, 157, + 96, 92, 92, 153, 157, 158, 157, 153, 153, 154, 158, 159, 158, 154, 154, 155, 159, 160, 159, + 155, 155, 156, 160, 161, 100, 96, 96, 157, 161, 162, 161, 157, 157, 158, 162, 163, 162, 158, + 158, 159, 163, 164, 163, 159, 159, 160, 164, 165, 104, 100, 100, 161, 165, 166, 165, 161, 161, + 162, 166, 167, 166, 162, 162, 163, 167, 168, 167, 163, 163, 164, 168, 169, 108, 104, 104, 165, + 169, 170, 169, 165, 165, 166, 170, 171, 170, 166, 166, 167, 171, 172, 171, 167, 167, 168, 172, + 173, 112, 108, 108, 169, 173, 174, 173, 169, 169, 170, 174, 175, 174, 170, 170, 171, 175, 176, + 175, 171, 171, 172, 176, 177, 116, 112, 112, 173, 177, 178, 177, 173, 173, 174, 178, 179, 178, + 174, 174, 175, 179, 180, 179, 175, 175, 176, 180, 181, 120, 116, 116, 177, 181, 182, 181, 177, + 177, 178, 182, 183, 182, 178, 178, 179, 183, 184, 183, 179, 179, 180, 184, 185, 124, 120, 120, + 181, 185, 186, 185, 181, 181, 182, 186, 187, 186, 182, 182, 183, 187, 188, 187, 183, 183, 184, + 188, 189, 128, 124, 124, 185, 189, 190, 189, 185, 185, 186, 190, 191, 190, 186, 186, 187, 191, + 192, 191, 187, 187, 188, 192, 193, 132, 128, 128, 189, 193, 194, 193, 189, 189, 190, 194, 195, + 194, 190, 190, 191, 195, 196, 195, 191, 191, 192, 196, 197, 136, 132, 132, 193, 197, 198, 197, + 193, 193, 194, 198, 199, 198, 194, 194, 195, 199, 200, 199, 195, 195, 196, 200, 201, 140, 136, + 136, 197, 201, 202, 201, 197, 197, 198, 202, 203, 202, 198, 198, 199, 203, 204, 203, 199, 199, + 200, 204, 205, 144, 140, 140, 201, 205, 206, 205, 201, 201, 202, 206, 207, 206, 202, 202, 203, + 207, 208, 207, 203, 203, 204, 208, 145, 84, 144, 144, 205, 145, 146, 145, 205, 205, 206, 146, + 147, 146, 206, 206, 207, 147, 148, 147, 207, 207, 208, 148, 213, 152, 148, 148, 209, 213, 214, + 213, 209, 209, 210, 214, 215, 214, 210, 210, 211, 215, 212, 215, 211, 211, 212, 212, 216, 156, + 152, 152, 213, 216, 217, 216, 213, 213, 214, 217, 218, 217, 214, 214, 215, 218, 212, 218, 215, + 215, 212, 212, 219, 160, 156, 156, 216, 219, 220, 219, 216, 216, 217, 220, 221, 220, 217, 217, + 218, 221, 212, 221, 218, 218, 212, 212, 222, 164, 160, 160, 219, 222, 223, 222, 219, 219, 220, + 223, 224, 223, 220, 220, 221, 224, 212, 224, 221, 221, 212, 212, 225, 168, 164, 164, 222, 225, + 226, 225, 222, 222, 223, 226, 227, 226, 223, 223, 224, 227, 212, 227, 224, 224, 212, 212, 228, + 172, 168, 168, 225, 228, 229, 228, 225, 225, 226, 229, 230, 229, 226, 226, 227, 230, 212, 230, + 227, 227, 212, 212, 231, 176, 172, 172, 228, 231, 232, 231, 228, 228, 229, 232, 233, 232, 229, + 229, 230, 233, 212, 233, 230, 230, 212, 212, 234, 180, 176, 176, 231, 234, 235, 234, 231, 231, + 232, 235, 236, 235, 232, 232, 233, 236, 212, 236, 233, 233, 212, 212, 237, 184, 180, 180, 234, + 237, 238, 237, 234, 234, 235, 238, 239, 238, 235, 235, 236, 239, 212, 239, 236, 236, 212, 212, + 240, 188, 184, 184, 237, 240, 241, 240, 237, 237, 238, 241, 242, 241, 238, 238, 239, 242, 212, + 242, 239, 239, 212, 212, 243, 192, 188, 188, 240, 243, 244, 243, 240, 240, 241, 244, 245, 244, + 241, 241, 242, 245, 212, 245, 242, 242, 212, 212, 246, 196, 192, 192, 243, 246, 247, 246, 243, + 243, 244, 247, 248, 247, 244, 244, 245, 248, 212, 248, 245, 245, 212, 212, 249, 200, 196, 196, + 246, 249, 250, 249, 246, 246, 247, 250, 251, 250, 247, 247, 248, 251, 212, 251, 248, 248, 212, + 212, 252, 204, 200, 200, 249, 252, 253, 252, 249, 249, 250, 253, 254, 253, 250, 250, 251, 254, + 212, 254, 251, 251, 212, 212, 255, 208, 204, 204, 252, 255, 256, 255, 252, 252, 253, 256, 257, + 256, 253, 253, 254, 257, 212, 257, 254, 254, 212, 212, 209, 148, 208, 208, 255, 209, 210, 209, + 255, 255, 256, 210, 211, 210, 256, 256, 257, 211, 212, 211, 257, 257, 212, 212, 264, 263, 258, + 258, 259, 264, 265, 264, 259, 259, 260, 265, 266, 265, 260, 260, 261, 266, 267, 266, 261, 261, + 262, 267, 269, 268, 263, 263, 264, 269, 270, 269, 264, 264, 265, 270, 271, 270, 265, 265, 266, + 271, 272, 271, 266, 266, 267, 272, 274, 273, 268, 268, 269, 274, 275, 274, 269, 269, 270, 275, + 276, 275, 270, 270, 271, 276, 277, 276, 271, 271, 272, 277, 279, 278, 273, 273, 274, 279, 280, + 279, 274, 274, 275, 280, 281, 280, 275, 275, 276, 281, 282, 281, 276, 276, 277, 282, 284, 283, + 278, 278, 279, 284, 285, 284, 279, 279, 280, 285, 286, 285, 280, 280, 281, 286, 287, 286, 281, + 281, 282, 287, 289, 288, 283, 283, 284, 289, 290, 289, 284, 284, 285, 290, 291, 290, 285, 285, + 286, 291, 292, 291, 286, 286, 287, 292, 294, 293, 288, 288, 289, 294, 295, 294, 289, 289, 290, + 295, 296, 295, 290, 290, 291, 296, 297, 296, 291, 291, 292, 297, 259, 258, 293, 293, 294, 259, + 260, 259, 294, 294, 295, 260, 261, 260, 295, 295, 296, 261, 262, 261, 296, 296, 297, 262, 302, + 267, 262, 262, 298, 302, 303, 302, 298, 298, 299, 303, 304, 303, 299, 299, 300, 304, 305, 304, + 300, 300, 301, 305, 306, 272, 267, 267, 302, 306, 307, 306, 302, 302, 303, 307, 308, 307, 303, + 303, 304, 308, 309, 308, 304, 304, 305, 309, 310, 277, 272, 272, 306, 310, 311, 310, 306, 306, + 307, 311, 312, 311, 307, 307, 308, 312, 313, 312, 308, 308, 309, 313, 314, 282, 277, 277, 310, + 314, 315, 314, 310, 310, 311, 315, 316, 315, 311, 311, 312, 316, 317, 316, 312, 312, 313, 317, + 318, 287, 282, 282, 314, 318, 319, 318, 314, 314, 315, 319, 320, 319, 315, 315, 316, 320, 321, + 320, 316, 316, 317, 321, 322, 292, 287, 287, 318, 322, 323, 322, 318, 318, 319, 323, 324, 323, + 319, 319, 320, 324, 325, 324, 320, 320, 321, 325, 326, 297, 292, 292, 322, 326, 327, 326, 322, + 322, 323, 327, 328, 327, 323, 323, 324, 328, 329, 328, 324, 324, 325, 329, 298, 262, 297, 297, + 326, 298, 299, 298, 326, 326, 327, 299, 300, 299, 327, 327, 328, 300, 301, 300, 328, 328, 329, + 301, 336, 335, 330, 330, 331, 336, 337, 336, 331, 331, 332, 337, 338, 337, 332, 332, 333, 338, + 339, 338, 333, 333, 334, 339, 341, 340, 335, 335, 336, 341, 342, 341, 336, 336, 337, 342, 343, + 342, 337, 337, 338, 343, 344, 343, 338, 338, 339, 344, 346, 345, 340, 340, 341, 346, 347, 346, + 341, 341, 342, 347, 348, 347, 342, 342, 343, 348, 349, 348, 343, 343, 344, 349, 351, 350, 345, + 345, 346, 351, 352, 351, 346, 346, 347, 352, 353, 352, 347, 347, 348, 353, 354, 353, 348, 348, + 349, 354, 356, 355, 350, 350, 351, 356, 357, 356, 351, 351, 352, 357, 358, 357, 352, 352, 353, + 358, 359, 358, 353, 353, 354, 359, 361, 360, 355, 355, 356, 361, 362, 361, 356, 356, 357, 362, + 363, 362, 357, 357, 358, 363, 364, 363, 358, 358, 359, 364, 366, 365, 360, 360, 361, 366, 367, + 366, 361, 361, 362, 367, 368, 367, 362, 362, 363, 368, 369, 368, 363, 363, 364, 369, 331, 330, + 365, 365, 366, 331, 332, 331, 366, 366, 367, 332, 333, 332, 367, 367, 368, 333, 334, 333, 368, + 368, 369, 334, 374, 339, 334, 334, 370, 374, 375, 374, 370, 370, 371, 375, 376, 375, 371, 371, + 372, 376, 377, 376, 372, 372, 373, 377, 378, 344, 339, 339, 374, 378, 379, 378, 374, 374, 375, + 379, 380, 379, 375, 375, 376, 380, 381, 380, 376, 376, 377, 381, 382, 349, 344, 344, 378, 382, + 383, 382, 378, 378, 379, 383, 384, 383, 379, 379, 380, 384, 385, 384, 380, 380, 381, 385, 386, + 354, 349, 349, 382, 386, 387, 386, 382, 382, 383, 387, 388, 387, 383, 383, 384, 388, 389, 388, + 384, 384, 385, 389, 390, 359, 354, 354, 386, 390, 391, 390, 386, 386, 387, 391, 392, 391, 387, + 387, 388, 392, 393, 392, 388, 388, 389, 393, 394, 364, 359, 359, 390, 394, 395, 394, 390, 390, + 391, 395, 396, 395, 391, 391, 392, 396, 397, 396, 392, 392, 393, 397, 398, 369, 364, 364, 394, + 398, 399, 398, 394, 394, 395, 399, 400, 399, 395, 395, 396, 400, 401, 400, 396, 396, 397, 401, + 370, 334, 369, 369, 398, 370, 371, 370, 398, 398, 399, 371, 372, 371, 399, 399, 400, 372, 373, + 372, 400, 400, 401, 373, 407, 402, 402, 402, 403, 407, 408, 407, 403, 403, 404, 408, 409, 408, + 404, 404, 405, 409, 410, 409, 405, 405, 406, 410, 411, 402, 402, 402, 407, 411, 412, 411, 407, + 407, 408, 412, 413, 412, 408, 408, 409, 413, 414, 413, 409, 409, 410, 414, 415, 402, 402, 402, + 411, 415, 416, 415, 411, 411, 412, 416, 417, 416, 412, 412, 413, 417, 418, 417, 413, 413, 414, + 418, 419, 402, 402, 402, 415, 419, 420, 419, 415, 415, 416, 420, 421, 420, 416, 416, 417, 421, + 422, 421, 417, 417, 418, 422, 423, 402, 402, 402, 419, 423, 424, 423, 419, 419, 420, 424, 425, + 424, 420, 420, 421, 425, 426, 425, 421, 421, 422, 426, 427, 402, 402, 402, 423, 427, 428, 427, + 423, 423, 424, 428, 429, 428, 424, 424, 425, 429, 430, 429, 425, 425, 426, 430, 431, 402, 402, + 402, 427, 431, 432, 431, 427, 427, 428, 432, 433, 432, 428, 428, 429, 433, 434, 433, 429, 429, + 430, 434, 435, 402, 402, 402, 431, 435, 436, 435, 431, 431, 432, 436, 437, 436, 432, 432, 433, + 437, 438, 437, 433, 433, 434, 438, 439, 402, 402, 402, 435, 439, 440, 439, 435, 435, 436, 440, + 441, 440, 436, 436, 437, 441, 442, 441, 437, 437, 438, 442, 443, 402, 402, 402, 439, 443, 444, + 443, 439, 439, 440, 444, 445, 444, 440, 440, 441, 445, 446, 445, 441, 441, 442, 446, 447, 402, + 402, 402, 443, 447, 448, 447, 443, 443, 444, 448, 449, 448, 444, 444, 445, 449, 450, 449, 445, + 445, 446, 450, 451, 402, 402, 402, 447, 451, 452, 451, 447, 447, 448, 452, 453, 452, 448, 448, + 449, 453, 454, 453, 449, 449, 450, 454, 455, 402, 402, 402, 451, 455, 456, 455, 451, 451, 452, + 456, 457, 456, 452, 452, 453, 457, 458, 457, 453, 453, 454, 458, 459, 402, 402, 402, 455, 459, + 460, 459, 455, 455, 456, 460, 461, 460, 456, 456, 457, 461, 462, 461, 457, 457, 458, 462, 463, + 402, 402, 402, 459, 463, 464, 463, 459, 459, 460, 464, 465, 464, 460, 460, 461, 465, 466, 465, + 461, 461, 462, 466, 403, 402, 402, 402, 463, 403, 404, 403, 463, 463, 464, 404, 405, 404, 464, + 464, 465, 405, 406, 405, 465, 465, 466, 406, 471, 410, 406, 406, 467, 471, 472, 471, 467, 467, + 468, 472, 473, 472, 468, 468, 469, 473, 474, 473, 469, 469, 470, 474, 475, 414, 410, 410, 471, + 475, 476, 475, 471, 471, 472, 476, 477, 476, 472, 472, 473, 477, 478, 477, 473, 473, 474, 478, + 479, 418, 414, 414, 475, 479, 480, 479, 475, 475, 476, 480, 481, 480, 476, 476, 477, 481, 482, + 481, 477, 477, 478, 482, 483, 422, 418, 418, 479, 483, 484, 483, 479, 479, 480, 484, 485, 484, + 480, 480, 481, 485, 486, 485, 481, 481, 482, 486, 487, 426, 422, 422, 483, 487, 488, 487, 483, + 483, 484, 488, 489, 488, 484, 484, 485, 489, 490, 489, 485, 485, 486, 490, 491, 430, 426, 426, + 487, 491, 492, 491, 487, 487, 488, 492, 493, 492, 488, 488, 489, 493, 494, 493, 489, 489, 490, + 494, 495, 434, 430, 430, 491, 495, 496, 495, 491, 491, 492, 496, 497, 496, 492, 492, 493, 497, + 498, 497, 493, 493, 494, 498, 499, 438, 434, 434, 495, 499, 500, 499, 495, 495, 496, 500, 501, + 500, 496, 496, 497, 501, 502, 501, 497, 497, 498, 502, 503, 442, 438, 438, 499, 503, 504, 503, + 499, 499, 500, 504, 505, 504, 500, 500, 501, 505, 506, 505, 501, 501, 502, 506, 507, 446, 442, + 442, 503, 507, 508, 507, 503, 503, 504, 508, 509, 508, 504, 504, 505, 509, 510, 509, 505, 505, + 506, 510, 511, 450, 446, 446, 507, 511, 512, 511, 507, 507, 508, 512, 513, 512, 508, 508, 509, + 513, 514, 513, 509, 509, 510, 514, 515, 454, 450, 450, 511, 515, 516, 515, 511, 511, 512, 516, + 517, 516, 512, 512, 513, 517, 518, 517, 513, 513, 514, 518, 519, 458, 454, 454, 515, 519, 520, + 519, 515, 515, 516, 520, 521, 520, 516, 516, 517, 521, 522, 521, 517, 517, 518, 522, 523, 462, + 458, 458, 519, 523, 524, 523, 519, 519, 520, 524, 525, 524, 520, 520, 521, 525, 526, 525, 521, + 521, 522, 526, 527, 466, 462, 462, 523, 527, 528, 527, 523, 523, 524, 528, 529, 528, 524, 524, + 525, 529, 530, 529, 525, 525, 526, 530, 467, 406, 466, 466, 527, 467, 468, 467, 527, 527, 528, + 468, 469, 468, 528, 528, 529, 469, 470, 469, 529, 529, 530, 470u16, +]; diff --git a/examples/wgpu/wgpu_instancing/shaders/fs.wgsl b/examples/wgpu/wgpu_instancing/shaders/fs.wgsl new file mode 100644 index 000000000..306d23040 --- /dev/null +++ b/examples/wgpu/wgpu_instancing/shaders/fs.wgsl @@ -0,0 +1,15 @@ +struct FragmentOutput { + @location(0) f_color: vec4, +}; + +@fragment +fn main( + @location(0) normal: vec3, + @location(1) color: vec3, +) -> FragmentOutput { + let light: vec3 = vec3(0.0, 0.0, 1.0); + let brightness: f32 = dot(normalize(normal), normalize(light)); + let dark_color: vec3 = vec3(0.1, 0.1, 0.1) * color; + let out_color = vec4(mix(dark_color, color, vec3(brightness)), 1.0); + return FragmentOutput(out_color); +} diff --git a/examples/wgpu/wgpu_instancing/shaders/vs.wgsl b/examples/wgpu/wgpu_instancing/shaders/vs.wgsl new file mode 100644 index 000000000..dbf944694 --- /dev/null +++ b/examples/wgpu/wgpu_instancing/shaders/vs.wgsl @@ -0,0 +1,48 @@ +struct Data { + world: mat4x4, + view: mat4x4, + proj: mat4x4, +}; + +struct VertexOutput { + @location(0) out_normal: vec3, + @location(1) out_color: vec3, + @builtin(position) out_pos: vec4, +}; + +@group(0) @binding(0) +var uniforms: Data; + +fn custom_inverse(m: mat3x3) -> mat3x3 { + let determinant: f32 = determinant(m); + let invdet: f32 = 1.0 / determinant; + var minv: mat3x3; + minv[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invdet; + minv[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invdet; + minv[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invdet; + minv[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invdet; + minv[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invdet; + minv[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invdet; + minv[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invdet; + minv[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invdet; + minv[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invdet; + return minv; +} + +@vertex +fn main( + @location(0) pos: vec3, + @location(1) normal: vec3, + @location(2) mat0: vec4, + @location(3) mat1: vec4, + @location(4) mat2: vec4, + @location(5) mat3: vec4, + @location(6) color: vec3, +) -> VertexOutput { + let instance_transform: mat4x4 = mat4x4(mat0, mat1, mat2, mat3); + let worldview: mat4x4 = uniforms.view * uniforms.world * instance_transform; + let wv3: mat3x3 = mat3x3(worldview[0].xyz, worldview[1].xyz, worldview[2].xyz); + let out_normal: vec3 = transpose(custom_inverse(wv3)) * normal; + let out_pos: vec4 = uniforms.proj * worldview * vec4(pos, 1.0); + return VertexOutput(out_normal, color, out_pos); +} diff --git a/examples/wgpu/wgpu_instancing/wgpu_instancing.rs b/examples/wgpu/wgpu_instancing/wgpu_instancing.rs new file mode 100644 index 000000000..31f184954 --- /dev/null +++ b/examples/wgpu/wgpu_instancing/wgpu_instancing.rs @@ -0,0 +1,494 @@ +use nannou::prelude::*; +use std::cell::RefCell; +use std::sync::{Arc, Mutex}; + +mod data; + +/* Generates vertices on a subdivided isocahedron, normalized to 1. + * It is used for creating a sphere for which the vertices are spread more + * regularly than it would be with for instance polar coordinates (which is the case for UV map). + * See https://en.wikipedia.org/wiki/Geodesic_polyhedron + */ +fn make_geodesic_isocahedron(subdivisions: usize) -> Vec { + let sqrt5 = 5f32.sqrt(); + let phi = (1f32 + sqrt5) * 0.5f32; + let ratio = (10f32 + (2f32 * sqrt5)).sqrt() / (4f32 * phi); + let a = (1f32 / ratio) * 0.5f32; + let b = (1f32 / ratio) / (2f32 * phi); + + let mut points = vec![ + vec3(0f32, b, -a), + vec3(b, a, 0f32), + vec3(-b, a, 0f32), + vec3(0f32, b, a), + vec3(0f32, -b, a), + vec3(-a, 0f32, b), + vec3(0f32, -b, -a), + vec3(a, 0f32, -b), + vec3(a, 0f32, b), + vec3(-a, 0f32, -b), + vec3(b, -a, 0f32), + vec3(-b, -a, 0f32), + ]; + + let triangles = vec![ + [0, 1, 2], + [3, 2, 1], + [3, 4, 5], + [3, 8, 4], + [0, 6, 7], + [0, 9, 6], + [4, 10, 11], + [6, 11, 10], + [2, 5, 9], + [11, 9, 5], + [1, 7, 8], + [10, 8, 7], + [3, 5, 2], + [3, 1, 8], + [0, 2, 9], + [0, 7, 1], + [6, 9, 11], + [6, 10, 7], + [4, 11, 5], + [4, 8, 10], + ]; + + let missing_edges = vec![ + [1, 2], + [4, 5], + [6, 7], + [10, 11], + [5, 9], + [9, 2], + [5, 11], + [7, 8], + [8, 1], + [7, 10], + ]; + + points.reserve( + triangles.len() * subdivisions * (subdivisions + 1) / 2 + + missing_edges.len() * subdivisions, + ); + + for indices in triangles.iter() { + let p0 = points[indices[0]]; + let p1 = points[indices[1]]; + let p2 = points[indices[2]]; + + let step0 = (p1 - p0) / (subdivisions + 1) as f32; + let step1 = (p2 - p0) / (subdivisions + 1) as f32; + + for i in 1..subdivisions + 1 { + for j in 0..subdivisions + 1 - i { + let pt = p0 + i as f32 * step0 + j as f32 * step1; + points.push(pt.normalize()); + } + } + } + + for edge in missing_edges.iter() { + let p0 = points[edge[0]]; + let p1 = points[edge[1]]; + let step = (p1 - p0) / (subdivisions + 1) as f32; + for i in 1..subdivisions + 1 { + let pt = p0 + i as f32 * step; + points.push(pt.normalize()); + } + } + + points +} + +#[derive(Clone)] +struct Model { + graphics: Arc>, + sphere: Vec, +} + +struct Graphics { + vertex_buffer: wgpu::Buffer, + normal_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + uniform_buffer: wgpu::Buffer, + depth_texture: wgpu::Texture, + depth_texture_view: wgpu::TextureView, + bind_group: wgpu::BindGroup, + render_pipeline: wgpu::RenderPipeline, +} + +// The vertex type that we will use to represent a point on our triangle. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Vertex { + position: (f32, f32, f32), +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Normal { + normal: (f32, f32, f32), +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Uniforms { + world: Mat4, + view: Mat4, + proj: Mat4, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Instance { + transformation: Mat4, + color: [f32; 3], +} + +const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + +fn main() { + nannou::app(model).render(render).run(); +} + +fn model(app: &App) -> Model { + let w_id = app.new_window::().hdr(true).size(1024, 576).build(); + + // The gpu device associated with the window's swapchain + let window = app.window(w_id); + let device = window.device(); + let format = Frame::TEXTURE_FORMAT; + let msaa_samples = window.msaa_samples(); + let UVec2 { x: win_w, y: win_h } = window.size_pixels(); + + // Load shader modules. + let vs_desc = wgpu::include_wgsl!("shaders/vs.wgsl"); + let fs_desc = wgpu::include_wgsl!("shaders/fs.wgsl"); + let vs_mod = device.create_shader_module(vs_desc); + let fs_mod = device.create_shader_module(fs_desc); + + // Create the vertex, normal and index buffers. + let vertices_bytes = vertices_as_bytes(&data::VERTICES); + let normals_bytes = normals_as_bytes(&data::NORMALS); + let indices_bytes = indices_as_bytes(&data::INDICES); + let vertex_usage = wgpu::BufferUsages::VERTEX; + let index_usage = wgpu::BufferUsages::INDEX; + let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: vertices_bytes, + usage: vertex_usage, + }); + let normal_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: normals_bytes, + usage: vertex_usage, + }); + let index_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: indices_bytes, + usage: index_usage, + }); + + let sphere = make_geodesic_isocahedron(10); + println!("Number of points on the sphere: {}", sphere.len()); + + // Create the depth texture. + let depth_texture = create_depth_texture(&device, [win_w, win_h], DEPTH_FORMAT, msaa_samples); + let depth_texture_view = depth_texture.view().build(); + + // Create the uniform buffer. + let uniforms = create_uniforms(0.0, [win_w, win_h]); + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST; + let uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: uniforms_bytes, + usage, + }); + + // Create the render pipeline. + let bind_group_layout = create_bind_group_layout(&device); + let bind_group = create_bind_group(&device, &bind_group_layout, &uniform_buffer); + let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout); + let render_pipeline = create_render_pipeline( + &device, + &pipeline_layout, + &vs_mod, + &fs_mod, + format, + DEPTH_FORMAT, + msaa_samples, + ); + + let graphics = Arc::new(Mutex::new(Graphics { + vertex_buffer, + normal_buffer, + index_buffer, + uniform_buffer, + depth_texture, + depth_texture_view, + bind_group, + render_pipeline, + })); + + Model { graphics, sphere } +} + +fn make_instance( + orientation: Vec3, + offset: f32, + local_rotation: f32, + scale: f32, + color: [f32; 3], +) -> Instance { + let scale_m = Mat4::from_scale(Vec3::splat(scale)); + let local_rotation_m = Mat4::from_rotation_y(local_rotation); + let orientation_m = { + let up = Vec3::Y; + let cosine = orientation.dot(up); + if cosine > 0.999 { + Mat4::IDENTITY + } else if cosine < -0.999 { + Mat4::from_axis_angle(Vec3::X, std::f32::consts::PI) + } else { + Mat4::from_axis_angle( + up.cross(orientation).normalize(), + up.angle_between(orientation), + ) + } + }; + + let translation_m = Mat4::from_translation(offset * orientation); + + Instance { + transformation: translation_m * orientation_m * local_rotation_m * scale_m, + color, + } +} + +fn special_color(index: usize) -> [f32; 3] { + let value = 1.5f32 * (index as f32).sin() + 1f32; + if value < 1f32 { + [0.6f32, 0.6f32, 0.0f32] + } else if value < 2f32 { + [0.6f32, 0.0f32, 0.6f32] + } else { + [0.0f32, 0.6f32, 0.6f32] + } +} + +fn render(app: &RenderApp, model: &Model, mut frame: Frame) { + let mut g = model.graphics.lock().unwrap(); + + // If the window has changed size, recreate our depth texture to match. + let depth_size = g.depth_texture.size(); + let frame_size = frame.texture_size(); + let device = frame.device(); + if frame_size != depth_size { + let depth_format = g.depth_texture.format(); + let sample_count = frame.resolve_target_msaa_samples(); + g.depth_texture = create_depth_texture(&device, frame_size, depth_format, sample_count); + g.depth_texture_view = g.depth_texture.view().build(); + } + + let inner_sphere_instance_rotation = app.time(); + let outer_sphere_instance_rotation = 0.2f32 * app.time(); + let inner_sphere_radius = 35f32; + let outer_sphere_radius = 50f32; + let inner_sphere_scale = 0.04f32; + let outer_sphere_scale = 0.03f32; + + let instances: Vec<_> = model + .sphere + .iter() + .map(|direction| { + make_instance( + direction.clone(), + outer_sphere_radius, + outer_sphere_instance_rotation, + outer_sphere_scale, + [1f32, 1f32, 1f32], + ) + }) + .chain(model.sphere.iter().enumerate().map(|(i, direction)| { + make_instance( + direction.clone(), + inner_sphere_radius + 2f32 * (i as f32 + app.time()).sin().pow(4f32), + inner_sphere_instance_rotation, + inner_sphere_scale, + special_color(i), + ) + })) + .collect(); + + let instances_bytes = instances_as_bytes(&instances); + let usage = wgpu::BufferUsages::VERTEX; + let instance_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: instances_bytes, + usage, + }); + + // Update the uniforms (rotate around the teapot). + let world_rotation = 0.05f32 * app.time(); + let uniforms = create_uniforms(world_rotation, frame_size); + let uniforms_size = std::mem::size_of::() as wgpu::BufferAddress; + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::COPY_SRC; + let new_uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: uniforms_bytes, + usage, + }); + + let mut encoder = frame.command_encoder(); + encoder.copy_buffer_to_buffer(&new_uniform_buffer, 0, &g.uniform_buffer, 0, uniforms_size); + let mut render_pass = wgpu::RenderPassBuilder::new() + .color_attachment(frame.resolve_target_view().unwrap(), |color| color) + // We'll use a depth texture to assist with the order of rendering fragments based on depth. + .depth_stencil_attachment(&g.depth_texture_view, |depth| depth) + .begin(&mut encoder); + render_pass.set_bind_group(0, &g.bind_group, &[]); + render_pass.set_pipeline(&g.render_pipeline); + render_pass.set_vertex_buffer(0, g.vertex_buffer.slice(..)); + render_pass.set_vertex_buffer(1, g.normal_buffer.slice(..)); + render_pass.set_vertex_buffer(2, instance_buffer.slice(..)); + render_pass.set_index_buffer(g.index_buffer.slice(..), wgpu::IndexFormat::Uint16); + let index_range = 0..data::INDICES.len() as u32; + let start_vertex = 0; + let instance_range = 0..instances.len() as u32; + render_pass.draw_indexed(index_range, start_vertex, instance_range); +} + +fn create_uniforms(world_rotation: f32, [w, h]: [u32; 2]) -> Uniforms { + let world_rotation = Mat4::from_rotation_y(world_rotation); + let aspect_ratio = w as f32 / h as f32; + let fov_y = std::f32::consts::FRAC_PI_2; + let near = 0.01; + let far = 100.0; + let proj = Mat4::perspective_rh_gl(fov_y, aspect_ratio, near, far); + let eye = pt3(0.3, 0.3, 1.0); + let target = Point3::ZERO; + let up = Vec3::Y; + let view = Mat4::look_at_rh(eye, target, up); + let world_scale = Mat4::from_scale(Vec3::splat(0.015)); + Uniforms { + world: world_rotation, + view: (view * world_scale).into(), + proj: proj.into(), + } +} + +fn create_depth_texture( + device: &wgpu::Device, + size: [u32; 2], + depth_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::Texture { + wgpu::TextureBuilder::new() + .size(size) + .format(depth_format) + .usage(wgpu::TextureUsages::RENDER_ATTACHMENT) + .sample_count(sample_count) + .build(device) +} + +fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + wgpu::BindGroupLayoutBuilder::new() + .uniform_buffer(wgpu::ShaderStages::VERTEX, false) + .build(device) +} + +fn create_bind_group( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + uniform_buffer: &wgpu::Buffer, +) -> wgpu::BindGroup { + wgpu::BindGroupBuilder::new() + .buffer::(uniform_buffer, 0..1) + .build(device, layout) +} + +fn create_pipeline_layout( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, +) -> wgpu::PipelineLayout { + let desc = wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }; + device.create_pipeline_layout(&desc) +} + +fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + vs_mod: &wgpu::ShaderModule, + fs_mod: &wgpu::ShaderModule, + dst_format: wgpu::TextureFormat, + depth_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::RenderPipeline { + wgpu::RenderPipelineBuilder::from_layout(layout, vs_mod) + .fragment_shader(&fs_mod) + .color_format(dst_format) + .color_blend(wgpu::BlendComponent::REPLACE) + .alpha_blend(wgpu::BlendComponent::REPLACE) + .add_vertex_buffer::(&wgpu::vertex_attr_array![0 => Float32x3]) + .add_vertex_buffer::(&wgpu::vertex_attr_array![1 => Float32x3]) + // TODO: this can use the macro again when https://github.com/gfx-rs/wgpu/issues/836 is fixed + .add_instance_buffer::(&[ + wgpu::VertexAttribute { + shader_location: 2, + format: wgpu::VertexFormat::Float32x4, + offset: std::mem::size_of::<[f32; 4]>() as u64 * 0, + }, + wgpu::VertexAttribute { + shader_location: 3, + format: wgpu::VertexFormat::Float32x4, + offset: std::mem::size_of::<[f32; 4]>() as u64 * 1, + }, + wgpu::VertexAttribute { + shader_location: 4, + format: wgpu::VertexFormat::Float32x4, + offset: std::mem::size_of::<[f32; 4]>() as u64 * 2, + }, + wgpu::VertexAttribute { + shader_location: 5, + format: wgpu::VertexFormat::Float32x4, + offset: std::mem::size_of::<[f32; 4]>() as u64 * 3, + }, + wgpu::VertexAttribute { + shader_location: 6, + format: wgpu::VertexFormat::Float32x4, + offset: std::mem::size_of::<[f32; 4]>() as u64 * 4, + }, + ]) + .depth_format(depth_format) + .sample_count(sample_count) + .build(device) +} + +// See the `nannou::wgpu::bytes` documentation for why the following are necessary. + +fn vertices_as_bytes(data: &[Vertex]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn normals_as_bytes(data: &[Normal]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn indices_as_bytes(data: &[u16]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn uniforms_as_bytes(uniforms: &Uniforms) -> &[u8] { + unsafe { wgpu::bytes::from(uniforms) } +} + +fn instances_as_bytes(data: &[Instance]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} diff --git a/examples/wgpu/wgpu_teapot/data.rs b/examples/wgpu/wgpu_teapot/data.rs new file mode 100644 index 000000000..61aefab11 --- /dev/null +++ b/examples/wgpu/wgpu_teapot/data.rs @@ -0,0 +1,3354 @@ +use crate::{Normal, Vertex}; + +pub const VERTICES: [Vertex; 531] = [ + Vertex { + position: (0.0, 0.0, 0.0), + }, // dummy vector because in the original model indices + // start at 1 + Vertex { + position: (40.6266, 28.3457, -1.10804), + }, + Vertex { + position: (40.0714, 30.4443, -1.10804), + }, + Vertex { + position: (40.7155, 31.1438, -1.10804), + }, + Vertex { + position: (42.0257, 30.4443, -1.10804), + }, + Vertex { + position: (43.4692, 28.3457, -1.10804), + }, + Vertex { + position: (37.5425, 28.3457, 14.5117), + }, + Vertex { + position: (37.0303, 30.4443, 14.2938), + }, + Vertex { + position: (37.6244, 31.1438, 14.5466), + }, + Vertex { + position: (38.8331, 30.4443, 15.0609), + }, + Vertex { + position: (40.1647, 28.3457, 15.6274), + }, + Vertex { + position: (29.0859, 28.3457, 27.1468), + }, + Vertex { + position: (28.6917, 30.4443, 26.7527), + }, + Vertex { + position: (29.149, 31.1438, 27.2099), + }, + Vertex { + position: (30.0792, 30.4443, 28.1402), + }, + Vertex { + position: (31.1041, 28.3457, 29.165), + }, + Vertex { + position: (16.4508, 28.3457, 35.6034), + }, + Vertex { + position: (16.2329, 30.4443, 35.0912), + }, + Vertex { + position: (16.4857, 31.1438, 35.6853), + }, + Vertex { + position: (16.9999, 30.4443, 36.894), + }, + Vertex { + position: (17.5665, 28.3457, 38.2256), + }, + Vertex { + position: (0.831025, 28.3457, 38.6876), + }, + Vertex { + position: (0.831025, 30.4443, 38.1324), + }, + Vertex { + position: (0.831025, 31.1438, 38.7764), + }, + Vertex { + position: (0.831025, 30.4443, 40.0866), + }, + Vertex { + position: (0.831025, 28.3457, 41.5301), + }, + Vertex { + position: (-15.868, 28.3457, 35.6034), + }, + Vertex { + position: (-15.0262, 30.4443, 35.0912), + }, + Vertex { + position: (-14.9585, 31.1438, 35.6853), + }, + Vertex { + position: (-15.3547, 30.4443, 36.894), + }, + Vertex { + position: (-15.9044, 28.3457, 38.2256), + }, + Vertex { + position: (-28.3832, 28.3457, 27.1468), + }, + Vertex { + position: (-27.4344, 30.4443, 26.7527), + }, + Vertex { + position: (-27.6068, 31.1438, 27.2099), + }, + Vertex { + position: (-28.4322, 30.4443, 28.1402), + }, + Vertex { + position: (-29.4421, 28.3457, 29.165), + }, + Vertex { + position: (-36.2402, 28.3457, 14.5117), + }, + Vertex { + position: (-35.52, 30.4443, 14.2938), + }, + Vertex { + position: (-36.0073, 31.1438, 14.5466), + }, + Vertex { + position: (-37.1767, 30.4443, 15.0609), + }, + Vertex { + position: (-38.5027, 28.3457, 15.6274), + }, + Vertex { + position: (-38.9646, 28.3457, -1.10804), + }, + Vertex { + position: (-38.4094, 30.4443, -1.10804), + }, + Vertex { + position: (-39.0534, 31.1438, -1.10804), + }, + Vertex { + position: (-40.3636, 30.4443, -1.10804), + }, + Vertex { + position: (-41.8071, 28.3457, -1.10804), + }, + Vertex { + position: (-35.8804, 28.3457, -16.7278), + }, + Vertex { + position: (-35.3683, 30.4443, -16.5099), + }, + Vertex { + position: (-35.9624, 31.1438, -16.7627), + }, + Vertex { + position: (-37.1711, 30.4443, -17.2769), + }, + Vertex { + position: (-38.5027, 28.3457, -17.8435), + }, + Vertex { + position: (-27.4238, 28.3457, -29.3629), + }, + Vertex { + position: (-27.0297, 30.4443, -28.9687), + }, + Vertex { + position: (-27.4869, 31.1438, -29.426), + }, + Vertex { + position: (-28.4172, 30.4443, -30.3562), + }, + Vertex { + position: (-29.4421, 28.3457, -31.3811), + }, + Vertex { + position: (-14.7887, 28.3457, -37.8195), + }, + Vertex { + position: (-14.5708, 30.4443, -37.3073), + }, + Vertex { + position: (-14.8236, 31.1438, -37.9014), + }, + Vertex { + position: (-15.3379, 30.4443, -39.1101), + }, + Vertex { + position: (-15.9044, 28.3457, -40.4417), + }, + Vertex { + position: (0.831025, 28.3457, -40.9036), + }, + Vertex { + position: (0.831025, 30.4443, -40.3484), + }, + Vertex { + position: (0.831025, 31.1438, -40.9925), + }, + Vertex { + position: (0.831025, 30.4443, -42.3027), + }, + Vertex { + position: (0.831025, 28.3457, -43.7462), + }, + Vertex { + position: (16.4508, 28.3457, -37.8195), + }, + Vertex { + position: (16.2329, 30.4443, -37.3073), + }, + Vertex { + position: (16.4857, 31.1438, -37.9014), + }, + Vertex { + position: (16.9999, 30.4443, -39.1101), + }, + Vertex { + position: (17.5665, 28.3457, -40.4417), + }, + Vertex { + position: (29.0859, 28.3457, -29.3629), + }, + Vertex { + position: (28.6917, 30.4443, -28.9687), + }, + Vertex { + position: (29.149, 31.1438, -29.426), + }, + Vertex { + position: (30.0792, 30.4443, -30.3562), + }, + Vertex { + position: (31.1041, 28.3457, -31.3811), + }, + Vertex { + position: (37.5425, 28.3457, -16.7278), + }, + Vertex { + position: (37.0303, 30.4443, -16.5099), + }, + Vertex { + position: (37.6244, 31.1438, -16.7627), + }, + Vertex { + position: (38.8331, 30.4443, -17.2769), + }, + Vertex { + position: (40.1647, 28.3457, -17.8435), + }, + Vertex { + position: (48.6879, 17.1865, -1.10804), + }, + Vertex { + position: (53.2404, 6.22714, -1.10804), + }, + Vertex { + position: (56.4605, -4.33246, -1.10804), + }, + Vertex { + position: (57.6819, -14.2925, -1.10804), + }, + Vertex { + position: (44.979, 17.1865, 17.6758), + }, + Vertex { + position: (49.1787, 6.22714, 19.4626), + }, + Vertex { + position: (52.1492, -4.33246, 20.7265), + }, + Vertex { + position: (53.2759, -14.2925, 21.2059), + }, + Vertex { + position: (34.8094, 17.1865, 32.8703), + }, + Vertex { + position: (38.0417, 6.22714, 36.1026), + }, + Vertex { + position: (40.3279, -4.33246, 38.3889), + }, + Vertex { + position: (41.1951, -14.2925, 39.2561), + }, + Vertex { + position: (19.6148, 17.1865, 43.0399), + }, + Vertex { + position: (21.4017, 6.22714, 47.2396), + }, + Vertex { + position: (22.6656, -4.33246, 50.2101), + }, + Vertex { + position: (23.145, -14.2925, 51.3369), + }, + Vertex { + position: (0.831025, 17.1865, 46.7488), + }, + Vertex { + position: (0.831025, 6.22714, 51.3013), + }, + Vertex { + position: (0.831025, -4.33246, 54.5214), + }, + Vertex { + position: (0.831025, -14.2925, 55.7428), + }, + Vertex { + position: (-17.9528, 17.1865, 43.0399), + }, + Vertex { + position: (-19.7397, 6.22714, 47.2396), + }, + Vertex { + position: (-21.0035, -4.33246, 50.2101), + }, + Vertex { + position: (-21.4829, -14.2925, 51.3369), + }, + Vertex { + position: (-33.1474, 17.1865, 32.8703), + }, + Vertex { + position: (-36.3796, 6.22714, 36.1026), + }, + Vertex { + position: (-38.6659, -4.33246, 38.3889), + }, + Vertex { + position: (-39.5331, -14.2925, 39.2561), + }, + Vertex { + position: (-43.3169, 17.1865, 17.6758), + }, + Vertex { + position: (-47.5166, 6.22714, 19.4626), + }, + Vertex { + position: (-50.4871, -4.33246, 20.7265), + }, + Vertex { + position: (-51.6139, -14.2925, 21.2059), + }, + Vertex { + position: (-47.0258, 17.1865, -1.10804), + }, + Vertex { + position: (-51.5784, 6.22714, -1.10804), + }, + Vertex { + position: (-54.7984, -4.33246, -1.10804), + }, + Vertex { + position: (-56.0198, -14.2925, -1.10804), + }, + Vertex { + position: (-43.3169, 17.1865, -19.8919), + }, + Vertex { + position: (-47.5166, 6.22714, -21.6787), + }, + Vertex { + position: (-50.4871, -4.33246, -22.9426), + }, + Vertex { + position: (-51.6139, -14.2925, -23.422), + }, + Vertex { + position: (-33.1474, 17.1865, -35.0864), + }, + Vertex { + position: (-36.3796, 6.22714, -38.3187), + }, + Vertex { + position: (-38.6659, -4.33246, -40.6049), + }, + Vertex { + position: (-39.5331, -14.2925, -41.4721), + }, + Vertex { + position: (-17.9528, 17.1865, -45.256), + }, + Vertex { + position: (-19.7397, 6.22714, -49.4557), + }, + Vertex { + position: (-21.0035, -4.33246, -52.4262), + }, + Vertex { + position: (-21.4829, -14.2925, -53.5529), + }, + Vertex { + position: (0.831025, 17.1865, -48.9649), + }, + Vertex { + position: (0.831025, 6.22714, -53.5174), + }, + Vertex { + position: (0.831025, -4.33246, -56.7375), + }, + Vertex { + position: (0.831025, -14.2925, -57.9589), + }, + Vertex { + position: (19.6148, 17.1865, -45.256), + }, + Vertex { + position: (21.4017, 6.22714, -49.4557), + }, + Vertex { + position: (22.6656, -4.33246, -52.4262), + }, + Vertex { + position: (23.145, -14.2925, -53.5529), + }, + Vertex { + position: (34.8094, 17.1865, -35.0864), + }, + Vertex { + position: (38.0417, 6.22714, -38.3187), + }, + Vertex { + position: (40.3279, -4.33246, -40.6049), + }, + Vertex { + position: (41.1951, -14.2925, -41.4721), + }, + Vertex { + position: (44.979, 17.1865, -19.8919), + }, + Vertex { + position: (49.1787, 6.22714, -21.6787), + }, + Vertex { + position: (52.1492, -4.33246, -22.9426), + }, + Vertex { + position: (53.2759, -14.2925, -23.422), + }, + Vertex { + position: (55.4611, -22.7202, -1.10804), + }, + Vertex { + position: (50.5755, -28.9493, -1.10804), + }, + Vertex { + position: (45.6899, -33.1798, -1.10804), + }, + Vertex { + position: (43.4692, -35.6115, -1.10804), + }, + Vertex { + position: (51.2273, -22.7202, 20.3343), + }, + Vertex { + position: (46.7203, -28.9493, 18.4167), + }, + Vertex { + position: (42.2133, -33.1798, 16.4991), + }, + Vertex { + position: (40.1647, -35.6115, 15.6274), + }, + Vertex { + position: (39.6184, -22.7202, 37.6793), + }, + Vertex { + position: (36.1496, -28.9493, 34.2106), + }, + Vertex { + position: (32.6808, -33.1798, 30.7418), + }, + Vertex { + position: (31.1041, -35.6115, 29.165), + }, + Vertex { + position: (22.2733, -22.7202, 49.2882), + }, + Vertex { + position: (20.3557, -28.9493, 44.7813), + }, + Vertex { + position: (18.4381, -33.1798, 40.2743), + }, + Vertex { + position: (17.5665, -35.6115, 38.2256), + }, + Vertex { + position: (0.831025, -22.7202, 53.5221), + }, + Vertex { + position: (0.831025, -28.9493, 48.6365), + }, + Vertex { + position: (0.831025, -33.1798, 43.7508), + }, + Vertex { + position: (0.831025, -35.6115, 41.5301), + }, + Vertex { + position: (-20.6113, -22.7202, 49.2882), + }, + Vertex { + position: (-18.6937, -28.9493, 44.7813), + }, + Vertex { + position: (-16.7761, -33.1798, 40.2743), + }, + Vertex { + position: (-15.9044, -35.6115, 38.2256), + }, + Vertex { + position: (-37.9564, -22.7202, 37.6793), + }, + Vertex { + position: (-34.4876, -28.9493, 34.2106), + }, + Vertex { + position: (-31.0188, -33.1798, 30.7418), + }, + Vertex { + position: (-29.4421, -35.6115, 29.165), + }, + Vertex { + position: (-49.5653, -22.7202, 20.3343), + }, + Vertex { + position: (-45.0583, -28.9493, 18.4167), + }, + Vertex { + position: (-40.5513, -33.1798, 16.4991), + }, + Vertex { + position: (-38.5027, -35.6115, 15.6274), + }, + Vertex { + position: (-53.7991, -22.7202, -1.10804), + }, + Vertex { + position: (-48.9135, -28.9493, -1.10804), + }, + Vertex { + position: (-44.0279, -33.1798, -1.10804), + }, + Vertex { + position: (-41.8071, -35.6115, -1.10804), + }, + Vertex { + position: (-49.5653, -22.7202, -22.5504), + }, + Vertex { + position: (-45.0583, -28.9493, -20.6327), + }, + Vertex { + position: (-40.5513, -33.1798, -18.7151), + }, + Vertex { + position: (-38.5027, -35.6115, -17.8435), + }, + Vertex { + position: (-37.9564, -22.7202, -39.8954), + }, + Vertex { + position: (-34.4876, -28.9493, -36.4266), + }, + Vertex { + position: (-31.0188, -33.1798, -32.9578), + }, + Vertex { + position: (-29.4421, -35.6115, -31.3811), + }, + Vertex { + position: (-20.6113, -22.7202, -51.5043), + }, + Vertex { + position: (-18.6937, -28.9493, -46.9973), + }, + Vertex { + position: (-16.7761, -33.1798, -42.4903), + }, + Vertex { + position: (-15.9044, -35.6115, -40.4417), + }, + Vertex { + position: (0.831025, -22.7202, -55.7382), + }, + Vertex { + position: (0.831025, -28.9493, -50.8525), + }, + Vertex { + position: (0.831025, -33.1798, -45.9669), + }, + Vertex { + position: (0.831025, -35.6115, -43.7462), + }, + Vertex { + position: (22.2733, -22.7202, -51.5043), + }, + Vertex { + position: (20.3557, -28.9493, -46.9973), + }, + Vertex { + position: (18.4381, -33.1798, -42.4903), + }, + Vertex { + position: (17.5665, -35.6115, -40.4417), + }, + Vertex { + position: (39.6184, -22.7202, -39.8954), + }, + Vertex { + position: (36.1496, -28.9493, -36.4266), + }, + Vertex { + position: (32.6808, -33.1798, -32.9578), + }, + Vertex { + position: (31.1041, -35.6115, -31.3811), + }, + Vertex { + position: (51.2273, -22.7202, -22.5504), + }, + Vertex { + position: (46.7203, -28.9493, -20.6327), + }, + Vertex { + position: (42.2133, -33.1798, -18.7151), + }, + Vertex { + position: (40.1647, -35.6115, -17.8435), + }, + Vertex { + position: (42.5031, -37.1772, -1.10804), + }, + Vertex { + position: (37.3399, -38.5429, -1.10804), + }, + Vertex { + position: (24.5818, -39.5089, -1.10804), + }, + Vertex { + position: (0.831025, -39.8754, -1.10804), + }, + Vertex { + position: (39.2736, -37.1772, 15.2483), + }, + Vertex { + position: (34.5105, -38.5429, 13.2217), + }, + Vertex { + position: (22.7411, -39.5089, 8.21414), + }, + Vertex { + position: (30.4182, -37.1772, 28.4792), + }, + Vertex { + position: (26.7523, -38.5429, 24.8133), + }, + Vertex { + position: (17.6941, -39.5089, 15.755), + }, + Vertex { + position: (17.1873, -37.1772, 37.3345), + }, + Vertex { + position: (15.1608, -38.5429, 32.5714), + }, + Vertex { + position: (10.1532, -39.5089, 20.8021), + }, + Vertex { + position: (0.831025, -37.1772, 40.5641), + }, + Vertex { + position: (0.831025, -38.5429, 35.4009), + }, + Vertex { + position: (0.831025, -39.5089, 22.6427), + }, + Vertex { + position: (-15.5253, -37.1772, 37.3345), + }, + Vertex { + position: (-13.4987, -38.5429, 32.5714), + }, + Vertex { + position: (-8.49115, -39.5089, 20.8021), + }, + Vertex { + position: (-28.7562, -37.1772, 28.4792), + }, + Vertex { + position: (-25.0903, -38.5429, 24.8133), + }, + Vertex { + position: (-16.032, -39.5089, 15.755), + }, + Vertex { + position: (-37.6115, -37.1772, 15.2483), + }, + Vertex { + position: (-32.8484, -38.5429, 13.2217), + }, + Vertex { + position: (-21.0791, -39.5089, 8.21414), + }, + Vertex { + position: (-40.8411, -37.1772, -1.10804), + }, + Vertex { + position: (-35.6779, -38.5429, -1.10804), + }, + Vertex { + position: (-22.9198, -39.5089, -1.10804), + }, + Vertex { + position: (-37.6115, -37.1772, -17.4643), + }, + Vertex { + position: (-32.8484, -38.5429, -15.4378), + }, + Vertex { + position: (-21.0791, -39.5089, -10.4302), + }, + Vertex { + position: (-28.7562, -37.1772, -30.6952), + }, + Vertex { + position: (-25.0903, -38.5429, -27.0294), + }, + Vertex { + position: (-16.032, -39.5089, -17.9711), + }, + Vertex { + position: (-15.5253, -37.1772, -39.5506), + }, + Vertex { + position: (-13.4987, -38.5429, -34.7875), + }, + Vertex { + position: (-8.49115, -39.5089, -23.0181), + }, + Vertex { + position: (0.831025, -37.1772, -42.7802), + }, + Vertex { + position: (0.831025, -38.5429, -37.6169), + }, + Vertex { + position: (0.831025, -39.5089, -24.8588), + }, + Vertex { + position: (17.1873, -37.1772, -39.5506), + }, + Vertex { + position: (15.1608, -38.5429, -34.7875), + }, + Vertex { + position: (10.1532, -39.5089, -23.0181), + }, + Vertex { + position: (30.4182, -37.1772, -30.6952), + }, + Vertex { + position: (26.7523, -38.5429, -27.0294), + }, + Vertex { + position: (17.6941, -39.5089, -17.9711), + }, + Vertex { + position: (39.2736, -37.1772, -17.4643), + }, + Vertex { + position: (34.5105, -38.5429, -15.4378), + }, + Vertex { + position: (22.7411, -39.5089, -10.4302), + }, + Vertex { + position: (-44.6497, 17.6861, -1.10804), + }, + Vertex { + position: (-57.9297, 17.5862, -1.10804), + }, + Vertex { + position: (-67.7453, 16.8867, -1.10804), + }, + Vertex { + position: (-73.8301, 14.9879, -1.10804), + }, + Vertex { + position: (-75.9176, 11.2904, -1.10804), + }, + Vertex { + position: (-44.2055, 18.6855, 3.68876), + }, + Vertex { + position: (-58.3252, 18.5699, 3.68876), + }, + Vertex { + position: (-68.6891, 17.7611, 3.68876), + }, + Vertex { + position: (-75.0724, 15.5657, 3.68876), + }, + Vertex { + position: (-77.2501, 11.2904, 3.68876), + }, + Vertex { + position: (-43.2284, 20.884, 5.28769), + }, + Vertex { + position: (-59.1955, 20.7341, 5.28769), + }, + Vertex { + position: (-70.7655, 19.6848, 5.28769), + }, + Vertex { + position: (-77.8053, 16.8367, 5.28769), + }, + Vertex { + position: (-80.1814, 11.2904, 5.28769), + }, + Vertex { + position: (-42.2513, 23.0825, 3.68876), + }, + Vertex { + position: (-60.0657, 22.8983, 3.68876), + }, + Vertex { + position: (-72.8419, 21.6085, 3.68876), + }, + Vertex { + position: (-80.5381, 18.1077, 3.68876), + }, + Vertex { + position: (-83.1128, 11.2904, 3.68876), + }, + Vertex { + position: (-41.8071, 24.0819, -1.10804), + }, + Vertex { + position: (-60.4613, 23.882, -1.10804), + }, + Vertex { + position: (-73.7857, 22.4829, -1.10804), + }, + Vertex { + position: (-81.7804, 18.6855, -1.10804), + }, + Vertex { + position: (-84.4453, 11.2904, -1.10804), + }, + Vertex { + position: (-42.2513, 23.0825, -5.90483), + }, + Vertex { + position: (-60.0657, 22.8983, -5.90483), + }, + Vertex { + position: (-72.8419, 21.6085, -5.90483), + }, + Vertex { + position: (-80.5381, 18.1077, -5.90483), + }, + Vertex { + position: (-83.1128, 11.2904, -5.90483), + }, + Vertex { + position: (-43.2284, 20.884, -7.50376), + }, + Vertex { + position: (-59.1955, 20.7341, -7.50376), + }, + Vertex { + position: (-70.7655, 19.6848, -7.50376), + }, + Vertex { + position: (-77.8053, 16.8367, -7.50376), + }, + Vertex { + position: (-80.1814, 11.2904, -7.50376), + }, + Vertex { + position: (-44.2055, 18.6855, -5.90483), + }, + Vertex { + position: (-58.3252, 18.5699, -5.90483), + }, + Vertex { + position: (-68.6891, 17.7611, -5.90483), + }, + Vertex { + position: (-75.0724, 15.5657, -5.90483), + }, + Vertex { + position: (-77.2501, 11.2904, -5.90483), + }, + Vertex { + position: (-74.8073, 5.4943, -1.10804), + }, + Vertex { + position: (-71.2985, -1.50103, -1.10804), + }, + Vertex { + position: (-65.1248, -8.49634, -1.10804), + }, + Vertex { + position: (-56.0198, -14.2925, -1.10804), + }, + Vertex { + position: (-76.0183, 4.93477, 3.68876), + }, + Vertex { + position: (-72.159, -2.35462, 3.68876), + }, + Vertex { + position: (-65.4267, -9.55033, 3.68876), + }, + Vertex { + position: (-55.5757, -15.6249, 3.68876), + }, + Vertex { + position: (-78.6824, 3.70383, 5.28769), + }, + Vertex { + position: (-74.0522, -4.23253, 5.28769), + }, + Vertex { + position: (-66.0909, -11.8691, 5.28769), + }, + Vertex { + position: (-54.5986, -18.5563, 5.28769), + }, + Vertex { + position: (-81.3466, 2.47288, 3.68876), + }, + Vertex { + position: (-75.9454, -6.11044, 3.68876), + }, + Vertex { + position: (-66.755, -14.1878, 3.68876), + }, + Vertex { + position: (-53.6214, -21.4877, 3.68876), + }, + Vertex { + position: (-82.5576, 1.91336, -1.10804), + }, + Vertex { + position: (-76.8059, -6.96404, -1.10804), + }, + Vertex { + position: (-67.0569, -15.2418, -1.10804), + }, + Vertex { + position: (-53.1773, -22.8201, -1.10804), + }, + Vertex { + position: (-81.3466, 2.47288, -5.90483), + }, + Vertex { + position: (-75.9454, -6.11044, -5.90483), + }, + Vertex { + position: (-66.755, -14.1878, -5.90483), + }, + Vertex { + position: (-53.6214, -21.4877, -5.90483), + }, + Vertex { + position: (-78.6824, 3.70383, -7.50376), + }, + Vertex { + position: (-74.0522, -4.23253, -7.50376), + }, + Vertex { + position: (-66.0909, -11.8691, -7.50376), + }, + Vertex { + position: (-54.5986, -18.5563, -7.50376), + }, + Vertex { + position: (-76.0183, 4.93477, -5.90483), + }, + Vertex { + position: (-72.159, -2.35462, -5.90483), + }, + Vertex { + position: (-65.4267, -9.55033, -5.90483), + }, + Vertex { + position: (-55.5757, -15.6249, -5.90483), + }, + Vertex { + position: (49.1543, 0.630882, -1.10804), + }, + Vertex { + position: (62.7896, 3.76212, -1.10804), + }, + Vertex { + position: (68.6967, 11.2904, -1.10804), + }, + Vertex { + position: (71.939, 20.4176, -1.10804), + }, + Vertex { + position: (77.5797, 28.3457, -1.10804), + }, + Vertex { + position: (49.1543, -3.03333, 9.4449), + }, + Vertex { + position: (63.8305, 1.04519, 8.42059), + }, + Vertex { + position: (70.0292, 9.70814, 6.1671), + }, + Vertex { + position: (73.5629, 19.8451, 3.91361), + }, + Vertex { + position: (80.2446, 28.3457, 2.88929), + }, + Vertex { + position: (49.1543, -11.0946, 12.9626), + }, + Vertex { + position: (66.1207, -4.93206, 11.5968), + }, + Vertex { + position: (72.9605, 6.22714, 8.59214), + }, + Vertex { + position: (77.1355, 18.5855, 5.58749), + }, + Vertex { + position: (86.1073, 28.3457, 4.22173), + }, + Vertex { + position: (49.1543, -19.1559, 9.4449), + }, + Vertex { + position: (68.4108, -10.9093, 8.42059), + }, + Vertex { + position: (75.8919, 2.74614, 6.1671), + }, + Vertex { + position: (80.7081, 17.326, 3.91361), + }, + Vertex { + position: (91.97, 28.3457, 2.88929), + }, + Vertex { + position: (49.1543, -22.8201, -1.10804), + }, + Vertex { + position: (69.4518, -13.6262, -1.10804), + }, + Vertex { + position: (77.2244, 1.16386, -1.10804), + }, + Vertex { + position: (82.3321, 16.7534, -1.10804), + }, + Vertex { + position: (94.6349, 28.3457, -1.10804), + }, + Vertex { + position: (49.1543, -19.1559, -11.661), + }, + Vertex { + position: (68.4108, -10.9093, -10.6367), + }, + Vertex { + position: (75.8919, 2.74614, -8.38317), + }, + Vertex { + position: (80.7081, 17.326, -6.12968), + }, + Vertex { + position: (91.97, 28.3457, -5.10536), + }, + Vertex { + position: (49.1543, -11.0946, -15.1786), + }, + Vertex { + position: (66.1207, -4.93206, -13.8129), + }, + Vertex { + position: (72.9605, 6.22714, -10.8082), + }, + Vertex { + position: (77.1355, 18.5855, -7.80356), + }, + Vertex { + position: (86.1073, 28.3457, -6.4378), + }, + Vertex { + position: (49.1543, -3.03333, -11.661), + }, + Vertex { + position: (63.8305, 1.04519, -10.6367), + }, + Vertex { + position: (70.0292, 9.70814, -8.38317), + }, + Vertex { + position: (73.5629, 19.8451, -6.12968), + }, + Vertex { + position: (80.2446, 28.3457, -5.10536), + }, + Vertex { + position: (79.6227, 29.5449, -1.10804), + }, + Vertex { + position: (81.1329, 29.9446, -1.10804), + }, + Vertex { + position: (81.577, 29.5449, -1.10804), + }, + Vertex { + position: (80.4222, 28.3457, -1.10804), + }, + Vertex { + position: (82.4767, 29.6034, 2.63946), + }, + Vertex { + position: (83.8116, 30.0383, 2.08983), + }, + Vertex { + position: (83.8515, 29.6268, 1.54019), + }, + Vertex { + position: (82.1988, 28.3457, 1.29036), + }, + Vertex { + position: (88.7555, 29.7322, 3.88862), + }, + Vertex { + position: (89.7049, 30.2444, 3.15578), + }, + Vertex { + position: (88.8555, 29.8072, 2.42294), + }, + Vertex { + position: (86.1073, 28.3457, 2.08983), + }, + Vertex { + position: (95.0343, 29.8611, 2.63946), + }, + Vertex { + position: (95.5982, 30.4505, 2.08983), + }, + Vertex { + position: (93.8594, 29.9875, 1.54019), + }, + Vertex { + position: (90.0158, 28.3457, 1.29036), + }, + Vertex { + position: (97.8883, 29.9196, -1.10804), + }, + Vertex { + position: (98.2769, 30.5442, -1.10804), + }, + Vertex { + position: (96.1339, 30.0695, -1.10804), + }, + Vertex { + position: (91.7924, 28.3457, -1.10804), + }, + Vertex { + position: (95.0343, 29.8611, -4.85553), + }, + Vertex { + position: (95.5982, 30.4505, -4.3059), + }, + Vertex { + position: (93.8594, 29.9875, -3.75626), + }, + Vertex { + position: (90.0158, 28.3457, -3.50643), + }, + Vertex { + position: (88.7555, 29.7322, -6.10469), + }, + Vertex { + position: (89.7049, 30.2444, -5.37185), + }, + Vertex { + position: (88.8555, 29.8072, -4.63901), + }, + Vertex { + position: (86.1073, 28.3457, -4.3059), + }, + Vertex { + position: (82.4767, 29.6034, -4.85553), + }, + Vertex { + position: (83.8116, 30.0383, -4.3059), + }, + Vertex { + position: (83.8515, 29.6268, -3.75626), + }, + Vertex { + position: (82.1988, 28.3457, -3.50643), + }, + Vertex { + position: (0.831025, 49.6647, -1.10804), + }, + Vertex { + position: (10.5134, 48.2657, -1.10804), + }, + Vertex { + position: (10.0693, 44.868, -1.10804), + }, + Vertex { + position: (6.42728, 40.6708, -1.10804), + }, + Vertex { + position: (6.51611, 36.8733, -1.10804), + }, + Vertex { + position: (9.76642, 48.2657, 2.70243), + }, + Vertex { + position: (9.35632, 44.868, 2.52698), + }, + Vertex { + position: (5.9947, 40.6708, 1.09187), + }, + Vertex { + position: (6.07552, 36.8733, 1.12336), + }, + Vertex { + position: (7.71453, 48.2657, 5.77547), + }, + Vertex { + position: (7.39819, 44.868, 5.45913), + }, + Vertex { + position: (4.80736, 40.6708, 2.8683), + }, + Vertex { + position: (4.86744, 36.8733, 2.92838), + }, + Vertex { + position: (4.64149, 48.2657, 7.82736), + }, + Vertex { + position: (4.46604, 44.868, 7.41726), + }, + Vertex { + position: (3.03093, 40.6708, 4.05564), + }, + Vertex { + position: (3.06242, 36.8733, 4.13646), + }, + Vertex { + position: (0.831025, 48.2657, 8.57438), + }, + Vertex { + position: (0.831025, 44.868, 8.13023), + }, + Vertex { + position: (0.831025, 40.6708, 4.48822), + }, + Vertex { + position: (0.831025, 36.8733, 4.57705), + }, + Vertex { + position: (-2.97944, 48.2657, 7.82736), + }, + Vertex { + position: (-2.80399, 44.868, 7.41726), + }, + Vertex { + position: (-1.36888, 40.6708, 4.05564), + }, + Vertex { + position: (-1.40037, 36.8733, 4.13646), + }, + Vertex { + position: (-6.05248, 48.2657, 5.77547), + }, + Vertex { + position: (-5.73614, 44.868, 5.45913), + }, + Vertex { + position: (-3.14531, 40.6708, 2.8683), + }, + Vertex { + position: (-3.20539, 36.8733, 2.92838), + }, + Vertex { + position: (-8.10437, 48.2657, 2.70243), + }, + Vertex { + position: (-7.69427, 44.868, 2.52698), + }, + Vertex { + position: (-4.33265, 40.6708, 1.09187), + }, + Vertex { + position: (-4.41347, 36.8733, 1.12336), + }, + Vertex { + position: (-8.85139, 48.2657, -1.10804), + }, + Vertex { + position: (-8.40724, 44.868, -1.10804), + }, + Vertex { + position: (-4.76523, 40.6708, -1.10804), + }, + Vertex { + position: (-4.85406, 36.8733, -1.10804), + }, + Vertex { + position: (-8.10437, 48.2657, -4.9185), + }, + Vertex { + position: (-7.69427, 44.868, -4.74305), + }, + Vertex { + position: (-4.33265, 40.6708, -3.30794), + }, + Vertex { + position: (-4.41347, 36.8733, -3.33943), + }, + Vertex { + position: (-6.05248, 48.2657, -7.99154), + }, + Vertex { + position: (-5.73614, 44.868, -7.6752), + }, + Vertex { + position: (-3.14531, 40.6708, -5.08437), + }, + Vertex { + position: (-3.20539, 36.8733, -5.14445), + }, + Vertex { + position: (-2.97944, 48.2657, -10.0434), + }, + Vertex { + position: (-2.80399, 44.868, -9.63333), + }, + Vertex { + position: (-1.36888, 40.6708, -6.27171), + }, + Vertex { + position: (-1.40037, 36.8733, -6.35253), + }, + Vertex { + position: (0.831025, 48.2657, -10.7904), + }, + Vertex { + position: (0.831025, 44.868, -10.3463), + }, + Vertex { + position: (0.831025, 40.6708, -6.70429), + }, + Vertex { + position: (0.831025, 36.8733, -6.79312), + }, + Vertex { + position: (4.64149, 48.2657, -10.0434), + }, + Vertex { + position: (4.46604, 44.868, -9.63333), + }, + Vertex { + position: (3.03093, 40.6708, -6.27171), + }, + Vertex { + position: (3.06242, 36.8733, -6.35253), + }, + Vertex { + position: (7.71453, 48.2657, -7.99154), + }, + Vertex { + position: (7.39819, 44.868, -7.6752), + }, + Vertex { + position: (4.80736, 40.6708, -5.08437), + }, + Vertex { + position: (4.86744, 36.8733, -5.14445), + }, + Vertex { + position: (9.76642, 48.2657, -4.9185), + }, + Vertex { + position: (9.35632, 44.868, -4.74305), + }, + Vertex { + position: (5.9947, 40.6708, -3.30794), + }, + Vertex { + position: (6.07552, 36.8733, -3.33943), + }, + Vertex { + position: (13.8001, 34.3417, -1.10804), + }, + Vertex { + position: (24.282, 32.6095, -1.10804), + }, + Vertex { + position: (33.6979, 30.8773, -1.10804), + }, + Vertex { + position: (37.7841, 28.3457, -1.10804), + }, + Vertex { + position: (12.795, 34.3417, 3.98234), + }, + Vertex { + position: (22.4646, 32.6095, 8.09647), + }, + Vertex { + position: (31.1507, 30.8773, 11.7922), + }, + Vertex { + position: (34.9202, 28.3457, 13.396), + }, + Vertex { + position: (10.0391, 34.3417, 8.10003), + }, + Vertex { + position: (17.4812, 32.6095, 15.5422), + }, + Vertex { + position: (24.1665, 30.8773, 22.2275), + }, + Vertex { + position: (27.0677, 28.3457, 25.1286), + }, + Vertex { + position: (5.9214, 34.3417, 10.856), + }, + Vertex { + position: (10.0355, 32.6095, 20.5255), + }, + Vertex { + position: (13.7313, 30.8773, 29.2117), + }, + Vertex { + position: (15.3351, 28.3457, 32.9812), + }, + Vertex { + position: (0.831025, 34.3417, 11.8611), + }, + Vertex { + position: (0.831025, 32.6095, 22.3429), + }, + Vertex { + position: (0.831025, 30.8773, 31.7589), + }, + Vertex { + position: (0.831025, 28.3457, 35.845), + }, + Vertex { + position: (-4.25935, 34.3417, 10.856), + }, + Vertex { + position: (-8.37348, 32.6095, 20.5255), + }, + Vertex { + position: (-12.0692, 30.8773, 29.2117), + }, + Vertex { + position: (-13.673, 28.3457, 32.9812), + }, + Vertex { + position: (-8.37704, 34.3417, 8.10003), + }, + Vertex { + position: (-15.8192, 32.6095, 15.5422), + }, + Vertex { + position: (-22.5045, 30.8773, 22.2275), + }, + Vertex { + position: (-25.4056, 28.3457, 25.1286), + }, + Vertex { + position: (-11.133, 34.3417, 3.98234), + }, + Vertex { + position: (-20.8025, 32.6095, 8.09647), + }, + Vertex { + position: (-29.4887, 30.8773, 11.7922), + }, + Vertex { + position: (-33.2582, 28.3457, 13.396), + }, + Vertex { + position: (-12.1381, 34.3417, -1.10804), + }, + Vertex { + position: (-22.62, 32.6095, -1.10804), + }, + Vertex { + position: (-32.0359, 30.8773, -1.10804), + }, + Vertex { + position: (-36.122, 28.3457, -1.10804), + }, + Vertex { + position: (-11.133, 34.3417, -6.19841), + }, + Vertex { + position: (-20.8025, 32.6095, -10.3125), + }, + Vertex { + position: (-29.4887, 30.8773, -14.0083), + }, + Vertex { + position: (-33.2582, 28.3457, -15.6121), + }, + Vertex { + position: (-8.37704, 34.3417, -10.3161), + }, + Vertex { + position: (-15.8192, 32.6095, -17.7582), + }, + Vertex { + position: (-22.5045, 30.8773, -24.4435), + }, + Vertex { + position: (-25.4056, 28.3457, -27.3447), + }, + Vertex { + position: (-4.25935, 34.3417, -13.072), + }, + Vertex { + position: (-8.37348, 32.6095, -22.7416), + }, + Vertex { + position: (-12.0692, 30.8773, -31.4277), + }, + Vertex { + position: (-13.673, 28.3457, -35.1972), + }, + Vertex { + position: (0.831025, 34.3417, -14.0771), + }, + Vertex { + position: (0.831025, 32.6095, -24.559), + }, + Vertex { + position: (0.831025, 30.8773, -33.9749), + }, + Vertex { + position: (0.831025, 28.3457, -38.0611), + }, + Vertex { + position: (5.9214, 34.3417, -13.072), + }, + Vertex { + position: (10.0355, 32.6095, -22.7416), + }, + Vertex { + position: (13.7313, 30.8773, -31.4277), + }, + Vertex { + position: (15.3351, 28.3457, -35.1972), + }, + Vertex { + position: (10.0391, 34.3417, -10.3161), + }, + Vertex { + position: (17.4812, 32.6095, -17.7582), + }, + Vertex { + position: (24.1665, 30.8773, -24.4435), + }, + Vertex { + position: (27.0677, 28.3457, -27.3447), + }, + Vertex { + position: (12.795, 34.3417, -6.19841), + }, + Vertex { + position: (22.4646, 32.6095, -10.3125), + }, + Vertex { + position: (31.1507, 30.8773, -14.0083), + }, + Vertex { + position: (34.9202, 28.3457, -15.6121), + }, +]; + +pub const NORMALS: [Normal; 531] = [ + Normal { + normal: (0.0, 0.0, 0.0), + }, // dummy vector because in the original model indices + // start at 1 + Normal { + normal: (-0.966742, -0.255752, 0.0), + }, + Normal { + normal: (-0.966824, 0.255443, 0.0), + }, + Normal { + normal: (-0.092052, 0.995754, 0.0), + }, + Normal { + normal: (0.68205, 0.731305, 0.0), + }, + Normal { + normal: (0.870301, 0.492521, -0.0), + }, + Normal { + normal: (-0.893014, -0.256345, -0.369882), + }, + Normal { + normal: (-0.893437, 0.255997, -0.369102), + }, + Normal { + normal: (-0.0838771, 0.995843, -0.0355068), + }, + Normal { + normal: (0.629724, 0.73186, 0.260439), + }, + Normal { + normal: (0.803725, 0.49337, 0.332584), + }, + Normal { + normal: (-0.683407, -0.256729, -0.683407), + }, + Normal { + normal: (-0.683531, 0.256067, -0.683531), + }, + Normal { + normal: (-0.0649249, 0.995776, -0.0649248), + }, + Normal { + normal: (0.481398, 0.732469, 0.481398), + }, + Normal { + normal: (0.614804, 0.493997, 0.614804), + }, + Normal { + normal: (-0.369882, -0.256345, -0.893014), + }, + Normal { + normal: (-0.369102, 0.255997, -0.893437), + }, + Normal { + normal: (-0.0355067, 0.995843, -0.0838772), + }, + Normal { + normal: (0.260439, 0.73186, 0.629724), + }, + Normal { + normal: (0.332584, 0.49337, 0.803725), + }, + Normal { + normal: (-0.00284834, -0.257863, -0.966177), + }, + Normal { + normal: (-0.00192311, 0.254736, -0.967009), + }, + Normal { + normal: (-0.000266114, 0.995734, -0.0922702), + }, + Normal { + normal: (0.0, 0.731295, 0.682061), + }, + Normal { + normal: (0.0, 0.492521, 0.870301), + }, + Normal { + normal: (0.379058, -0.3593, -0.852771), + }, + Normal { + normal: (0.37711, 0.149086, -0.914091), + }, + Normal { + normal: (0.0275022, 0.992081, -0.122551), + }, + Normal { + normal: (-0.26101, 0.726762, 0.635367), + }, + Normal { + normal: (-0.332485, 0.492546, 0.804271), + }, + Normal { + normal: (0.663548, -0.410791, -0.625264), + }, + Normal { + normal: (0.712664, 0.0737216, -0.697621), + }, + Normal { + normal: (0.0997268, 0.987509, -0.121984), + }, + Normal { + normal: (-0.48732, 0.723754, 0.488568), + }, + Normal { + normal: (-0.615242, 0.492602, 0.615484), + }, + Normal { + normal: (0.880028, -0.332908, -0.338709), + }, + Normal { + normal: (0.917276, 0.167113, -0.361493), + }, + Normal { + normal: (0.113584, 0.992365, -0.0480695), + }, + Normal { + normal: (-0.63415, 0.727508, 0.261889), + }, + Normal { + normal: (-0.804126, 0.492634, 0.332705), + }, + Normal { + normal: (0.96669, -0.255738, 0.0104537), + }, + Normal { + normal: (0.967442, 0.252962, 0.00810329), + }, + Normal { + normal: (0.0934365, 0.995624, 0.00128063), + }, + Normal { + normal: (-0.682167, 0.731196, -0.00034353), + }, + Normal { + normal: (-0.870322, 0.492483, -0.0), + }, + Normal { + normal: (0.893014, -0.256345, 0.369882), + }, + Normal { + normal: (0.893437, 0.255997, 0.369102), + }, + Normal { + normal: (0.0838768, 0.995843, 0.0355066), + }, + Normal { + normal: (-0.629724, 0.73186, -0.260439), + }, + Normal { + normal: (-0.803725, 0.49337, -0.332584), + }, + Normal { + normal: (0.683407, -0.256729, 0.683407), + }, + Normal { + normal: (0.683531, 0.256067, 0.683531), + }, + Normal { + normal: (0.0649249, 0.995776, 0.0649249), + }, + Normal { + normal: (-0.481398, 0.732469, -0.481398), + }, + Normal { + normal: (-0.614804, 0.493997, -0.614804), + }, + Normal { + normal: (0.369882, -0.256345, 0.893014), + }, + Normal { + normal: (0.369102, 0.255997, 0.893437), + }, + Normal { + normal: (0.0355067, 0.995843, 0.083877), + }, + Normal { + normal: (-0.260439, 0.73186, -0.629724), + }, + Normal { + normal: (-0.332584, 0.49337, -0.803725), + }, + Normal { + normal: (0.0, -0.255752, 0.966742), + }, + Normal { + normal: (0.0, 0.255443, 0.966824), + }, + Normal { + normal: (0.0, 0.995754, 0.092052), + }, + Normal { + normal: (0.0, 0.731305, -0.68205), + }, + Normal { + normal: (-0.0, 0.492521, -0.870301), + }, + Normal { + normal: (-0.369882, -0.256345, 0.893014), + }, + Normal { + normal: (-0.369102, 0.255996, 0.893437), + }, + Normal { + normal: (-0.0355068, 0.995843, 0.0838771), + }, + Normal { + normal: (0.260439, 0.73186, -0.629724), + }, + Normal { + normal: (0.332584, 0.49337, -0.803725), + }, + Normal { + normal: (-0.683407, -0.256729, 0.683407), + }, + Normal { + normal: (-0.683531, 0.256067, 0.683531), + }, + Normal { + normal: (-0.0649249, 0.995776, 0.064925), + }, + Normal { + normal: (0.481398, 0.732469, -0.481398), + }, + Normal { + normal: (0.614804, 0.493997, -0.614804), + }, + Normal { + normal: (-0.893014, -0.256345, 0.369882), + }, + Normal { + normal: (-0.893437, 0.255997, 0.369102), + }, + Normal { + normal: (-0.0838767, 0.995843, 0.0355066), + }, + Normal { + normal: (0.629724, 0.73186, -0.260439), + }, + Normal { + normal: (0.803725, 0.49337, -0.332584), + }, + Normal { + normal: (0.915321, 0.402725, 0.0), + }, + Normal { + normal: (0.941808, 0.336151, -0.0), + }, + Normal { + normal: (0.97869, 0.205342, 0.0), + }, + Normal { + normal: (0.997804, -0.0662397, 0.0), + }, + Normal { + normal: (0.845438, 0.403546, 0.349835), + }, + Normal { + normal: (0.869996, 0.336859, 0.360047), + }, + Normal { + normal: (0.904193, 0.205791, 0.37428), + }, + Normal { + normal: (0.921879, -0.0663697, 0.381752), + }, + Normal { + normal: (0.646802, 0.404096, 0.646802), + }, + Normal { + normal: (0.665655, 0.337351, 0.665655), + }, + Normal { + normal: (0.691923, 0.20612, 0.691923), + }, + Normal { + normal: (0.705542, -0.0664796, 0.705543), + }, + Normal { + normal: (0.349835, 0.403546, 0.845438), + }, + Normal { + normal: (0.360047, 0.336859, 0.869996), + }, + Normal { + normal: (0.37428, 0.205791, 0.904193), + }, + Normal { + normal: (0.381752, -0.0663697, 0.921879), + }, + Normal { + normal: (-0.0, 0.402725, 0.915321), + }, + Normal { + normal: (0.0, 0.336151, 0.941808), + }, + Normal { + normal: (-0.0, 0.205342, 0.97869), + }, + Normal { + normal: (-0.0, -0.0662397, 0.997804), + }, + Normal { + normal: (-0.349835, 0.403546, 0.845438), + }, + Normal { + normal: (-0.360047, 0.336859, 0.869996), + }, + Normal { + normal: (-0.37428, 0.205791, 0.904193), + }, + Normal { + normal: (-0.381752, -0.0663697, 0.921879), + }, + Normal { + normal: (-0.646802, 0.404096, 0.646802), + }, + Normal { + normal: (-0.665655, 0.337351, 0.665655), + }, + Normal { + normal: (-0.691923, 0.20612, 0.691923), + }, + Normal { + normal: (-0.705543, -0.0664796, 0.705543), + }, + Normal { + normal: (-0.845438, 0.403546, 0.349835), + }, + Normal { + normal: (-0.869996, 0.336859, 0.360047), + }, + Normal { + normal: (-0.904193, 0.205791, 0.37428), + }, + Normal { + normal: (-0.921879, -0.0663697, 0.381752), + }, + Normal { + normal: (-0.915321, 0.402725, -0.0), + }, + Normal { + normal: (-0.941808, 0.336151, -0.0), + }, + Normal { + normal: (-0.97869, 0.205342, -0.0), + }, + Normal { + normal: (-0.997804, -0.0662397, -0.0), + }, + Normal { + normal: (-0.845438, 0.403546, -0.349835), + }, + Normal { + normal: (-0.869996, 0.336859, -0.360047), + }, + Normal { + normal: (-0.904193, 0.205791, -0.37428), + }, + Normal { + normal: (-0.921879, -0.0663697, -0.381752), + }, + Normal { + normal: (-0.646802, 0.404096, -0.646802), + }, + Normal { + normal: (-0.665655, 0.337351, -0.665655), + }, + Normal { + normal: (-0.691923, 0.20612, -0.691923), + }, + Normal { + normal: (-0.705542, -0.0664796, -0.705543), + }, + Normal { + normal: (-0.349835, 0.403546, -0.845438), + }, + Normal { + normal: (-0.360047, 0.336859, -0.869996), + }, + Normal { + normal: (-0.37428, 0.205791, -0.904193), + }, + Normal { + normal: (-0.381752, -0.0663697, -0.921879), + }, + Normal { + normal: (0.0, 0.402725, -0.915321), + }, + Normal { + normal: (-0.0, 0.336151, -0.941808), + }, + Normal { + normal: (0.0, 0.205342, -0.97869), + }, + Normal { + normal: (0.0, -0.0662397, -0.997804), + }, + Normal { + normal: (0.349835, 0.403546, -0.845438), + }, + Normal { + normal: (0.360047, 0.336859, -0.869996), + }, + Normal { + normal: (0.37428, 0.205791, -0.904193), + }, + Normal { + normal: (0.381752, -0.0663697, -0.921879), + }, + Normal { + normal: (0.646802, 0.404096, -0.646802), + }, + Normal { + normal: (0.665655, 0.337351, -0.665655), + }, + Normal { + normal: (0.691923, 0.20612, -0.691923), + }, + Normal { + normal: (0.705543, -0.0664796, -0.705542), + }, + Normal { + normal: (0.845438, 0.403546, -0.349835), + }, + Normal { + normal: (0.869996, 0.336859, -0.360047), + }, + Normal { + normal: (0.904193, 0.205791, -0.37428), + }, + Normal { + normal: (0.921879, -0.0663697, -0.381752), + }, + Normal { + normal: (0.900182, -0.435513, -0.0), + }, + Normal { + normal: (0.729611, -0.683863, -0.0), + }, + Normal { + normal: (0.693951, -0.720022, -0.0), + }, + Normal { + normal: (0.79395, -0.607984, 0.0), + }, + Normal { + normal: (0.831437, -0.43618, 0.344179), + }, + Normal { + normal: (0.673512, -0.684665, 0.278594), + }, + Normal { + normal: (0.640399, -0.720924, 0.264874), + }, + Normal { + normal: (0.732949, -0.608996, 0.303166), + }, + Normal { + normal: (0.636092, -0.436777, 0.636092), + }, + Normal { + normal: (0.514965, -0.685289, 0.514965), + }, + Normal { + normal: (0.489651, -0.721446, 0.489651), + }, + Normal { + normal: (0.560555, -0.609554, 0.560555), + }, + Normal { + normal: (0.344179, -0.43618, 0.831437), + }, + Normal { + normal: (0.278594, -0.684665, 0.673512), + }, + Normal { + normal: (0.264874, -0.720924, 0.640399), + }, + Normal { + normal: (0.303166, -0.608996, 0.732949), + }, + Normal { + normal: (0.0, -0.435513, 0.900182), + }, + Normal { + normal: (-0.0, -0.683863, 0.729611), + }, + Normal { + normal: (0.0, -0.720022, 0.693951), + }, + Normal { + normal: (-0.0, -0.607984, 0.79395), + }, + Normal { + normal: (-0.344179, -0.43618, 0.831437), + }, + Normal { + normal: (-0.278594, -0.684665, 0.673512), + }, + Normal { + normal: (-0.264874, -0.720924, 0.640399), + }, + Normal { + normal: (-0.303166, -0.608996, 0.732949), + }, + Normal { + normal: (-0.636092, -0.436777, 0.636092), + }, + Normal { + normal: (-0.514965, -0.685289, 0.514965), + }, + Normal { + normal: (-0.489651, -0.721446, 0.489651), + }, + Normal { + normal: (-0.560555, -0.609554, 0.560555), + }, + Normal { + normal: (-0.831437, -0.43618, 0.344179), + }, + Normal { + normal: (-0.673512, -0.684665, 0.278595), + }, + Normal { + normal: (-0.640399, -0.720924, 0.264874), + }, + Normal { + normal: (-0.732949, -0.608996, 0.303166), + }, + Normal { + normal: (-0.900182, -0.435513, -0.0), + }, + Normal { + normal: (-0.729611, -0.683863, -0.0), + }, + Normal { + normal: (-0.693951, -0.720022, 0.0), + }, + Normal { + normal: (-0.79395, -0.607983, -0.0), + }, + Normal { + normal: (-0.831437, -0.43618, -0.344179), + }, + Normal { + normal: (-0.673512, -0.684665, -0.278594), + }, + Normal { + normal: (-0.640399, -0.720924, -0.264874), + }, + Normal { + normal: (-0.732949, -0.608996, -0.303166), + }, + Normal { + normal: (-0.636092, -0.436777, -0.636092), + }, + Normal { + normal: (-0.514965, -0.685289, -0.514965), + }, + Normal { + normal: (-0.489651, -0.721446, -0.489651), + }, + Normal { + normal: (-0.560555, -0.609554, -0.560555), + }, + Normal { + normal: (-0.344179, -0.43618, -0.831437), + }, + Normal { + normal: (-0.278594, -0.684665, -0.673512), + }, + Normal { + normal: (-0.264874, -0.720924, -0.640399), + }, + Normal { + normal: (-0.303166, -0.608996, -0.732949), + }, + Normal { + normal: (-0.0, -0.435513, -0.900182), + }, + Normal { + normal: (0.0, -0.683863, -0.729611), + }, + Normal { + normal: (-0.0, -0.720022, -0.693951), + }, + Normal { + normal: (0.0, -0.607984, -0.79395), + }, + Normal { + normal: (0.344179, -0.43618, -0.831437), + }, + Normal { + normal: (0.278594, -0.684665, -0.673512), + }, + Normal { + normal: (0.264874, -0.720924, -0.640399), + }, + Normal { + normal: (0.303167, -0.608996, -0.732949), + }, + Normal { + normal: (0.636092, -0.436777, -0.636092), + }, + Normal { + normal: (0.514965, -0.685289, -0.514965), + }, + Normal { + normal: (0.489651, -0.721446, -0.489651), + }, + Normal { + normal: (0.560555, -0.609554, -0.560555), + }, + Normal { + normal: (0.831437, -0.43618, -0.344179), + }, + Normal { + normal: (0.673512, -0.684665, -0.278595), + }, + Normal { + normal: (0.640399, -0.720924, -0.264874), + }, + Normal { + normal: (0.732949, -0.608996, -0.303166), + }, + Normal { + normal: (0.62386, -0.781536, 0.0), + }, + Normal { + normal: (0.177291, -0.984159, -0.0), + }, + Normal { + normal: (0.0492072, -0.998789, 0.0), + }, + Normal { + normal: (0.0, -1.0, -0.0), + }, + Normal { + normal: (0.576229, -0.781801, 0.238217), + }, + Normal { + normal: (0.163629, -0.984208, 0.0675273), + }, + Normal { + normal: (0.0454217, -0.998792, 0.0187357), + }, + Normal { + normal: (0.440416, -0.782348, 0.440416), + }, + Normal { + normal: (0.124903, -0.984276, 0.124903), + }, + Normal { + normal: (0.0346621, -0.998798, 0.0346621), + }, + Normal { + normal: (0.238217, -0.781801, 0.576229), + }, + Normal { + normal: (0.0675273, -0.984208, 0.163629), + }, + Normal { + normal: (0.0187357, -0.998792, 0.0454217), + }, + Normal { + normal: (-0.0, -0.781536, 0.62386), + }, + Normal { + normal: (0.0, -0.984159, 0.177291), + }, + Normal { + normal: (-0.0, -0.998789, 0.0492072), + }, + Normal { + normal: (-0.238216, -0.781801, 0.576229), + }, + Normal { + normal: (-0.0675273, -0.984208, 0.163629), + }, + Normal { + normal: (-0.0187357, -0.998792, 0.0454217), + }, + Normal { + normal: (-0.440416, -0.782348, 0.440416), + }, + Normal { + normal: (-0.124903, -0.984276, 0.124903), + }, + Normal { + normal: (-0.0346621, -0.998798, 0.0346621), + }, + Normal { + normal: (-0.576229, -0.781801, 0.238217), + }, + Normal { + normal: (-0.163629, -0.984208, 0.0675273), + }, + Normal { + normal: (-0.0454217, -0.998792, 0.0187357), + }, + Normal { + normal: (-0.62386, -0.781536, -0.0), + }, + Normal { + normal: (-0.177291, -0.984159, 0.0), + }, + Normal { + normal: (-0.0492072, -0.998789, -0.0), + }, + Normal { + normal: (-0.576229, -0.781801, -0.238217), + }, + Normal { + normal: (-0.163629, -0.984208, -0.0675273), + }, + Normal { + normal: (-0.0454217, -0.998792, -0.0187357), + }, + Normal { + normal: (-0.440416, -0.782348, -0.440416), + }, + Normal { + normal: (-0.124903, -0.984276, -0.124903), + }, + Normal { + normal: (-0.0346621, -0.998798, -0.0346621), + }, + Normal { + normal: (-0.238217, -0.781801, -0.576229), + }, + Normal { + normal: (-0.0675273, -0.984208, -0.163629), + }, + Normal { + normal: (-0.0187357, -0.998792, -0.0454217), + }, + Normal { + normal: (0.0, -0.781536, -0.62386), + }, + Normal { + normal: (-0.0, -0.984159, -0.177291), + }, + Normal { + normal: (0.0, -0.998789, -0.0492072), + }, + Normal { + normal: (0.238217, -0.781801, -0.576229), + }, + Normal { + normal: (0.0675273, -0.984208, -0.163629), + }, + Normal { + normal: (0.0187357, -0.998792, -0.0454217), + }, + Normal { + normal: (0.440416, -0.782348, -0.440416), + }, + Normal { + normal: (0.124903, -0.984276, -0.124903), + }, + Normal { + normal: (0.0346621, -0.998798, -0.0346621), + }, + Normal { + normal: (0.576229, -0.781801, -0.238217), + }, + Normal { + normal: (0.163629, -0.984208, -0.0675273), + }, + Normal { + normal: (0.0454217, -0.998792, -0.0187357), + }, + Normal { + normal: (0.00778619, -0.99997, -0.000215809), + }, + Normal { + normal: (0.0391385, -0.999233, -0.000988567), + }, + Normal { + normal: (0.179511, -0.983746, -0.00436856), + }, + Normal { + normal: (0.6123, -0.790556, -0.0104598), + }, + Normal { + normal: (0.986152, -0.165707, -0.00666949), + }, + Normal { + normal: (0.00703893, -0.812495, 0.582926), + }, + Normal { + normal: (0.0361273, -0.837257, 0.545614), + }, + Normal { + normal: (0.161845, -0.810421, 0.563048), + }, + Normal { + normal: (0.482365, -0.595148, 0.642746), + }, + Normal { + normal: (0.73872, -0.114593, 0.664199), + }, + Normal { + normal: (-0.00190867, 0.162121, 0.986769), + }, + Normal { + normal: (0.0027616, 0.0171073, 0.99985), + }, + Normal { + normal: (0.0105326, 0.0733989, 0.997247), + }, + Normal { + normal: (-0.0660406, 0.130069, 0.989303), + }, + Normal { + normal: (-0.0944272, 0.0165946, 0.995393), + }, + Normal { + normal: (-0.009203, 0.871509, 0.490293), + }, + Normal { + normal: (-0.0486064, 0.840609, 0.539457), + }, + Normal { + normal: (-0.223298, 0.802881, 0.552739), + }, + Normal { + normal: (-0.596365, 0.559971, 0.575135), + }, + Normal { + normal: (-0.803337, 0.0682361, 0.591602), + }, + Normal { + normal: (-0.0105609, 0.999944, 0.000103364), + }, + Normal { + normal: (-0.0587986, 0.99827, 0.000709759), + }, + Normal { + normal: (-0.28071, 0.959787, 0.00326876), + }, + Normal { + normal: (-0.749723, 0.661738, 0.0042684), + }, + Normal { + normal: (-0.997351, 0.0727144, 0.00205923), + }, + Normal { + normal: (-0.00879197, 0.871493, -0.49033), + }, + Normal { + normal: (-0.0464937, 0.841178, -0.538756), + }, + Normal { + normal: (-0.217909, 0.806807, -0.549161), + }, + Normal { + normal: (-0.597291, 0.560026, -0.574121), + }, + Normal { + normal: (-0.804, 0.0629127, -0.591291), + }, + Normal { + normal: (-0.00180555, 0.161691, -0.98684), + }, + Normal { + normal: (0.00203087, 0.014555, -0.999892), + }, + Normal { + normal: (0.00921499, 0.0600698, -0.998152), + }, + Normal { + normal: (-0.0593333, 0.113865, -0.991723), + }, + Normal { + normal: (-0.0868992, 0.0122903, -0.996141), + }, + Normal { + normal: (0.00641779, -0.812379, -0.583094), + }, + Normal { + normal: (0.0337833, -0.837512, -0.545373), + }, + Normal { + normal: (0.157112, -0.811947, -0.56219), + }, + Normal { + normal: (0.484407, -0.589365, -0.646528), + }, + Normal { + normal: (0.73887, -0.10132, -0.666187), + }, + Normal { + normal: (0.946512, 0.32265, -0.0033571), + }, + Normal { + normal: (0.82583, 0.56387, -0.00745213), + }, + Normal { + normal: (0.650011, 0.759893, -0.00693681), + }, + Normal { + normal: (0.532429, 0.846458, -0.00524544), + }, + Normal { + normal: (0.725608, 0.259351, 0.637362), + }, + Normal { + normal: (0.645945, 0.461988, 0.607719), + }, + Normal { + normal: (0.531614, 0.63666, 0.558615), + }, + Normal { + normal: (0.424964, 0.681717, 0.59554), + }, + Normal { + normal: (-0.0495616, -0.019755, 0.998576), + }, + Normal { + normal: (-0.0378162, -0.0356243, 0.99865), + }, + Normal { + normal: (-0.0379139, -0.0365122, 0.998614), + }, + Normal { + normal: (-0.168854, -0.297946, 0.93953), + }, + Normal { + normal: (-0.742342, -0.299166, 0.599523), + }, + Normal { + normal: (-0.619602, -0.529406, 0.579503), + }, + Normal { + normal: (-0.483708, -0.685761, 0.543837), + }, + Normal { + normal: (-0.445293, -0.794355, 0.413176), + }, + Normal { + normal: (-0.926513, -0.376257, 0.00199587), + }, + Normal { + normal: (-0.75392, -0.656952, 0.00431723), + }, + Normal { + normal: (-0.566224, -0.824244, 0.00346105), + }, + Normal { + normal: (-0.481804, -0.876277, 0.00185047), + }, + Normal { + normal: (-0.744675, -0.294424, -0.598977), + }, + Normal { + normal: (-0.621949, -0.528114, -0.578165), + }, + Normal { + normal: (-0.481171, -0.68834, -0.542828), + }, + Normal { + normal: (-0.438055, -0.797035, -0.415744), + }, + Normal { + normal: (-0.0443368, -0.0170558, -0.998871), + }, + Normal { + normal: (-0.0261761, -0.0281665, -0.99926), + }, + Normal { + normal: (-0.0252939, -0.0283323, -0.999278), + }, + Normal { + normal: (-0.157482, -0.289392, -0.944167), + }, + Normal { + normal: (0.728244, 0.25241, -0.637142), + }, + Normal { + normal: (0.647055, 0.459725, -0.608254), + }, + Normal { + normal: (0.522994, 0.640657, -0.562171), + }, + Normal { + normal: (0.409978, 0.682857, -0.604669), + }, + Normal { + normal: (-0.230787, 0.972982, -0.00652338), + }, + Normal { + normal: (-0.548936, 0.835863, -0.00151111), + }, + Normal { + normal: (-0.875671, 0.482807, 0.00989278), + }, + Normal { + normal: (-0.877554, 0.479097, 0.0190923), + }, + Normal { + normal: (-0.69619, 0.717439, 0.024497), + }, + Normal { + normal: (-0.152878, 0.687211, 0.71019), + }, + Normal { + normal: (-0.316721, 0.63775, 0.702113), + }, + Normal { + normal: (-0.601067, 0.471452, 0.64533), + }, + Normal { + normal: (-0.635889, 0.44609, 0.6298), + }, + Normal { + normal: (-0.435746, 0.601008, 0.670011), + }, + Normal { + normal: (0.111112, -0.0850694, 0.99016), + }, + Normal { + normal: (0.22331, 0.00654036, 0.974726), + }, + Normal { + normal: (0.190097, 0.154964, 0.969458), + }, + Normal { + normal: (0.00527077, 0.189482, 0.98187), + }, + Normal { + normal: (-0.0117518, 0.246688, 0.969024), + }, + Normal { + normal: (0.343906, -0.722796, 0.599412), + }, + Normal { + normal: (0.572489, -0.567656, 0.591627), + }, + Normal { + normal: (0.787436, -0.256459, 0.560512), + }, + Normal { + normal: (0.647097, -0.306374, 0.698141), + }, + Normal { + normal: (0.427528, -0.499343, 0.753576), + }, + Normal { + normal: (0.410926, -0.911668, 0.00128446), + }, + Normal { + normal: (0.67152, -0.740986, -0.000899122), + }, + Normal { + normal: (0.922026, -0.38706, -0.00725269), + }, + Normal { + normal: (0.84691, -0.531556, -0.0138542), + }, + Normal { + normal: (0.535925, -0.8442, -0.0105045), + }, + Normal { + normal: (0.341188, -0.722822, -0.600931), + }, + Normal { + normal: (0.578664, -0.561139, -0.591838), + }, + Normal { + normal: (0.784869, -0.25102, -0.566542), + }, + Normal { + normal: (0.642681, -0.302257, -0.70399), + }, + Normal { + normal: (0.418589, -0.500042, -0.758117), + }, + Normal { + normal: (0.115806, -0.0791394, -0.990114), + }, + Normal { + normal: (0.232811, 0.0125652, -0.972441), + }, + Normal { + normal: (0.206662, 0.153601, -0.96628), + }, + Normal { + normal: (0.0244996, 0.161443, -0.986578), + }, + Normal { + normal: (0.00338193, 0.211115, -0.977455), + }, + Normal { + normal: (-0.134912, 0.687491, -0.713551), + }, + Normal { + normal: (-0.31954, 0.633073, -0.705062), + }, + Normal { + normal: (-0.603902, 0.461442, -0.649903), + }, + Normal { + normal: (-0.631816, 0.437169, -0.640072), + }, + Normal { + normal: (-0.424306, 0.612706, -0.66675), + }, + Normal { + normal: (-0.4258, 0.904753, 0.0108049), + }, + Normal { + normal: (0.0220472, 0.999756, 0.00162273), + }, + Normal { + normal: (0.999599, 0.0258705, 0.0115556), + }, + Normal { + normal: (0.709585, -0.704553, 0.00967183), + }, + Normal { + normal: (-0.259858, 0.791936, 0.552549), + }, + Normal { + normal: (0.00953916, 0.99972, -0.0216718), + }, + Normal { + normal: (0.410156, 0.332912, -0.849083), + }, + Normal { + normal: (0.541523, -0.54862, -0.637), + }, + Normal { + normal: (0.0463104, 0.455224, 0.889172), + }, + Normal { + normal: (-0.0106883, 0.988794, 0.148901), + }, + Normal { + normal: (-0.0443756, 0.682947, -0.729118), + }, + Normal { + normal: (0.122825, 0.00923214, -0.992385), + }, + Normal { + normal: (0.481839, -0.180439, 0.85748), + }, + Normal { + normal: (0.455272, 0.736752, 0.499925), + }, + Normal { + normal: (-0.220542, 0.907193, -0.358276), + }, + Normal { + normal: (-0.23592, 0.657249, -0.715797), + }, + Normal { + normal: (0.728092, -0.685302, -0.0155853), + }, + Normal { + normal: (0.888739, 0.45811, -0.0166791), + }, + Normal { + normal: (-0.260097, 0.965582, 0.000800195), + }, + Normal { + normal: (-0.371612, 0.928378, -0.00441745), + }, + Normal { + normal: (0.480166, -0.17836, -0.858853), + }, + Normal { + normal: (0.488103, 0.716801, -0.497947), + }, + Normal { + normal: (-0.222004, 0.905399, 0.361893), + }, + Normal { + normal: (-0.235405, 0.66318, 0.710477), + }, + Normal { + normal: (0.0587203, 0.437704, -0.8972), + }, + Normal { + normal: (0.00132612, 0.986459, -0.164003), + }, + Normal { + normal: (-0.0441901, 0.681677, 0.730317), + }, + Normal { + normal: (0.138801, -0.0341896, 0.98973), + }, + Normal { + normal: (-0.25889, 0.797206, -0.54538), + }, + Normal { + normal: (0.0122703, 0.999739, 0.0192865), + }, + Normal { + normal: (0.39863, 0.35489, 0.845663), + }, + Normal { + normal: (0.537564, -0.5814, 0.610737), + }, + Normal { + normal: (-0.0, 1.0, 0.0), + }, + Normal { + normal: (0.82454, 0.565804, 0.0), + }, + Normal { + normal: (0.917701, -0.397272, 0.0), + }, + Normal { + normal: (0.935269, -0.353939, 0.000112842), + }, + Normal { + normal: (0.780712, 0.624891, 0.0), + }, + Normal { + normal: (0.762641, 0.565035, 0.314825), + }, + Normal { + normal: (0.847982, -0.397998, 0.350034), + }, + Normal { + normal: (0.864141, -0.355261, 0.356441), + }, + Normal { + normal: (0.720991, 0.625625, 0.297933), + }, + Normal { + normal: (0.583357, 0.565165, 0.583338), + }, + Normal { + normal: (0.648485, -0.398726, 0.648448), + }, + Normal { + normal: (0.660872, -0.355894, 0.660748), + }, + Normal { + normal: (0.551862, 0.62529, 0.55178), + }, + Normal { + normal: (0.314824, 0.565051, 0.762629), + }, + Normal { + normal: (0.350045, -0.397976, 0.847988), + }, + Normal { + normal: (0.356474, -0.3552, 0.864153), + }, + Normal { + normal: (0.297983, 0.625515, 0.721067), + }, + Normal { + normal: (-0.0, 0.565804, 0.82454), + }, + Normal { + normal: (-0.0, -0.397272, 0.917701), + }, + Normal { + normal: (-0.000112839, -0.353939, 0.935269), + }, + Normal { + normal: (-0.0, 0.624891, 0.780712), + }, + Normal { + normal: (-0.314825, 0.565035, 0.762641), + }, + Normal { + normal: (-0.350034, -0.397998, 0.847982), + }, + Normal { + normal: (-0.356441, -0.355261, 0.864141), + }, + Normal { + normal: (-0.297933, 0.625625, 0.720991), + }, + Normal { + normal: (-0.583338, 0.565165, 0.583357), + }, + Normal { + normal: (-0.648448, -0.398726, 0.648485), + }, + Normal { + normal: (-0.660748, -0.355894, 0.660872), + }, + Normal { + normal: (-0.55178, 0.62529, 0.551862), + }, + Normal { + normal: (-0.762629, 0.565051, 0.314824), + }, + Normal { + normal: (-0.847988, -0.397976, 0.350045), + }, + Normal { + normal: (-0.864153, -0.3552, 0.356474), + }, + Normal { + normal: (-0.721067, 0.625515, 0.297983), + }, + Normal { + normal: (-0.82454, 0.565804, -0.0), + }, + Normal { + normal: (-0.917701, -0.397272, -0.0), + }, + Normal { + normal: (-0.935269, -0.353939, -0.000112839), + }, + Normal { + normal: (-0.780712, 0.624891, -0.0), + }, + Normal { + normal: (-0.76264, 0.565035, -0.314825), + }, + Normal { + normal: (-0.847982, -0.397998, -0.350034), + }, + Normal { + normal: (-0.864141, -0.355261, -0.356441), + }, + Normal { + normal: (-0.720991, 0.625625, -0.297933), + }, + Normal { + normal: (-0.583357, 0.565165, -0.583338), + }, + Normal { + normal: (-0.648485, -0.398726, -0.648448), + }, + Normal { + normal: (-0.660872, -0.355894, -0.660748), + }, + Normal { + normal: (-0.551862, 0.62529, -0.55178), + }, + Normal { + normal: (-0.314824, 0.565051, -0.762629), + }, + Normal { + normal: (-0.350045, -0.397976, -0.847988), + }, + Normal { + normal: (-0.356474, -0.3552, -0.864153), + }, + Normal { + normal: (-0.297983, 0.625515, -0.721067), + }, + Normal { + normal: (0.0, 0.565804, -0.82454), + }, + Normal { + normal: (0.0, -0.397272, -0.917701), + }, + Normal { + normal: (0.000112839, -0.353939, -0.935269), + }, + Normal { + normal: (0.0, 0.624891, -0.780712), + }, + Normal { + normal: (0.314825, 0.565035, -0.762641), + }, + Normal { + normal: (0.350034, -0.397998, -0.847982), + }, + Normal { + normal: (0.356441, -0.355261, -0.864141), + }, + Normal { + normal: (0.297933, 0.625625, -0.720991), + }, + Normal { + normal: (0.583338, 0.565165, -0.583357), + }, + Normal { + normal: (0.648448, -0.398726, -0.648485), + }, + Normal { + normal: (0.660748, -0.355894, -0.660872), + }, + Normal { + normal: (0.55178, 0.62529, -0.551862), + }, + Normal { + normal: (0.762629, 0.565051, -0.314824), + }, + Normal { + normal: (0.847988, -0.397976, -0.350045), + }, + Normal { + normal: (0.864153, -0.3552, -0.356474), + }, + Normal { + normal: (0.721067, 0.625515, -0.297983), + }, + Normal { + normal: (0.236584, 0.971611, 0.0), + }, + Normal { + normal: (0.173084, 0.984907, -0.0), + }, + Normal { + normal: (0.379703, 0.925108, 0.0), + }, + Normal { + normal: (0.526673, 0.850068, 0.0), + }, + Normal { + normal: (0.217978, 0.971775, 0.0902162), + }, + Normal { + normal: (0.15959, 0.984977, 0.0659615), + }, + Normal { + normal: (0.350498, 0.925312, 0.14474), + }, + Normal { + normal: (0.48559, 0.850653, 0.201474), + }, + Normal { + normal: (0.166631, 0.971838, 0.166631), + }, + Normal { + normal: (0.121908, 0.985026, 0.121908), + }, + Normal { + normal: (0.267668, 0.925585, 0.267668), + }, + Normal { + normal: (0.371315, 0.851029, 0.371315), + }, + Normal { + normal: (0.0902162, 0.971775, 0.217978), + }, + Normal { + normal: (0.0659615, 0.984977, 0.15959), + }, + Normal { + normal: (0.14474, 0.925312, 0.350498), + }, + Normal { + normal: (0.201474, 0.850653, 0.48559), + }, + Normal { + normal: (-0.0, 0.971611, 0.236584), + }, + Normal { + normal: (0.0, 0.984907, 0.173084), + }, + Normal { + normal: (0.0, 0.925108, 0.379703), + }, + Normal { + normal: (0.0, 0.850068, 0.526673), + }, + Normal { + normal: (-0.0902162, 0.971775, 0.217978), + }, + Normal { + normal: (-0.0659615, 0.984977, 0.15959), + }, + Normal { + normal: (-0.14474, 0.925312, 0.350498), + }, + Normal { + normal: (-0.201474, 0.850653, 0.48559), + }, + Normal { + normal: (-0.166631, 0.971838, 0.166631), + }, + Normal { + normal: (-0.121908, 0.985026, 0.121908), + }, + Normal { + normal: (-0.267668, 0.925585, 0.267668), + }, + Normal { + normal: (-0.371315, 0.851029, 0.371315), + }, + Normal { + normal: (-0.217978, 0.971775, 0.0902162), + }, + Normal { + normal: (-0.15959, 0.984977, 0.0659615), + }, + Normal { + normal: (-0.350498, 0.925312, 0.14474), + }, + Normal { + normal: (-0.48559, 0.850653, 0.201474), + }, + Normal { + normal: (-0.236583, 0.971611, -0.0), + }, + Normal { + normal: (-0.173084, 0.984907, 0.0), + }, + Normal { + normal: (-0.379703, 0.925108, -0.0), + }, + Normal { + normal: (-0.526673, 0.850068, 0.0), + }, + Normal { + normal: (-0.217978, 0.971775, -0.0902162), + }, + Normal { + normal: (-0.15959, 0.984977, -0.0659615), + }, + Normal { + normal: (-0.350498, 0.925312, -0.14474), + }, + Normal { + normal: (-0.48559, 0.850653, -0.201474), + }, + Normal { + normal: (-0.166631, 0.971838, -0.166631), + }, + Normal { + normal: (-0.121908, 0.985026, -0.121908), + }, + Normal { + normal: (-0.267668, 0.925585, -0.267668), + }, + Normal { + normal: (-0.371315, 0.851029, -0.371315), + }, + Normal { + normal: (-0.0902162, 0.971775, -0.217978), + }, + Normal { + normal: (-0.0659615, 0.984977, -0.15959), + }, + Normal { + normal: (-0.14474, 0.925312, -0.350498), + }, + Normal { + normal: (-0.201474, 0.850653, -0.485589), + }, + Normal { + normal: (0.0, 0.971611, -0.236584), + }, + Normal { + normal: (-0.0, 0.984907, -0.173084), + }, + Normal { + normal: (-0.0, 0.925108, -0.379703), + }, + Normal { + normal: (-0.0, 0.850068, -0.526673), + }, + Normal { + normal: (0.0902162, 0.971775, -0.217978), + }, + Normal { + normal: (0.0659615, 0.984977, -0.15959), + }, + Normal { + normal: (0.14474, 0.925312, -0.350498), + }, + Normal { + normal: (0.201474, 0.850653, -0.48559), + }, + Normal { + normal: (0.166631, 0.971838, -0.166631), + }, + Normal { + normal: (0.121908, 0.985026, -0.121908), + }, + Normal { + normal: (0.267668, 0.925585, -0.267668), + }, + Normal { + normal: (0.371315, 0.851029, -0.371315), + }, + Normal { + normal: (0.217978, 0.971775, -0.0902162), + }, + Normal { + normal: (0.15959, 0.984977, -0.0659615), + }, + Normal { + normal: (0.350498, 0.925312, -0.14474), + }, + Normal { + normal: (0.48559, 0.850653, -0.201474), + }, +]; + +pub const INDICES: [u16; 3072] = [ + 7, 6, 1, 1, 2, 7, 8, 7, 2, 2, 3, 8, 9, 8, 3, 3, 4, 9, 10, 9, 4, 4, 5, 10, 12, 11, 6, 6, 7, 12, + 13, 12, 7, 7, 8, 13, 14, 13, 8, 8, 9, 14, 15, 14, 9, 9, 10, 15, 17, 16, 11, 11, 12, 17, 18, 17, + 12, 12, 13, 18, 19, 18, 13, 13, 14, 19, 20, 19, 14, 14, 15, 20, 22, 21, 16, 16, 17, 22, 23, 22, + 17, 17, 18, 23, 24, 23, 18, 18, 19, 24, 25, 24, 19, 19, 20, 25, 27, 26, 21, 21, 22, 27, 28, 27, + 22, 22, 23, 28, 29, 28, 23, 23, 24, 29, 30, 29, 24, 24, 25, 30, 32, 31, 26, 26, 27, 32, 33, 32, + 27, 27, 28, 33, 34, 33, 28, 28, 29, 34, 35, 34, 29, 29, 30, 35, 37, 36, 31, 31, 32, 37, 38, 37, + 32, 32, 33, 38, 39, 38, 33, 33, 34, 39, 40, 39, 34, 34, 35, 40, 42, 41, 36, 36, 37, 42, 43, 42, + 37, 37, 38, 43, 44, 43, 38, 38, 39, 44, 45, 44, 39, 39, 40, 45, 47, 46, 41, 41, 42, 47, 48, 47, + 42, 42, 43, 48, 49, 48, 43, 43, 44, 49, 50, 49, 44, 44, 45, 50, 52, 51, 46, 46, 47, 52, 53, 52, + 47, 47, 48, 53, 54, 53, 48, 48, 49, 54, 55, 54, 49, 49, 50, 55, 57, 56, 51, 51, 52, 57, 58, 57, + 52, 52, 53, 58, 59, 58, 53, 53, 54, 59, 60, 59, 54, 54, 55, 60, 62, 61, 56, 56, 57, 62, 63, 62, + 57, 57, 58, 63, 64, 63, 58, 58, 59, 64, 65, 64, 59, 59, 60, 65, 67, 66, 61, 61, 62, 67, 68, 67, + 62, 62, 63, 68, 69, 68, 63, 63, 64, 69, 70, 69, 64, 64, 65, 70, 72, 71, 66, 66, 67, 72, 73, 72, + 67, 67, 68, 73, 74, 73, 68, 68, 69, 74, 75, 74, 69, 69, 70, 75, 77, 76, 71, 71, 72, 77, 78, 77, + 72, 72, 73, 78, 79, 78, 73, 73, 74, 79, 80, 79, 74, 74, 75, 80, 2, 1, 76, 76, 77, 2, 3, 2, 77, + 77, 78, 3, 4, 3, 78, 78, 79, 4, 5, 4, 79, 79, 80, 5, 85, 10, 5, 5, 81, 85, 86, 85, 81, 81, 82, + 86, 87, 86, 82, 82, 83, 87, 88, 87, 83, 83, 84, 88, 89, 15, 10, 10, 85, 89, 90, 89, 85, 85, 86, + 90, 91, 90, 86, 86, 87, 91, 92, 91, 87, 87, 88, 92, 93, 20, 15, 15, 89, 93, 94, 93, 89, 89, 90, + 94, 95, 94, 90, 90, 91, 95, 96, 95, 91, 91, 92, 96, 97, 25, 20, 20, 93, 97, 98, 97, 93, 93, 94, + 98, 99, 98, 94, 94, 95, 99, 100, 99, 95, 95, 96, 100, 101, 30, 25, 25, 97, 101, 102, 101, 97, + 97, 98, 102, 103, 102, 98, 98, 99, 103, 104, 103, 99, 99, 100, 104, 105, 35, 30, 30, 101, 105, + 106, 105, 101, 101, 102, 106, 107, 106, 102, 102, 103, 107, 108, 107, 103, 103, 104, 108, 109, + 40, 35, 35, 105, 109, 110, 109, 105, 105, 106, 110, 111, 110, 106, 106, 107, 111, 112, 111, + 107, 107, 108, 112, 113, 45, 40, 40, 109, 113, 114, 113, 109, 109, 110, 114, 115, 114, 110, + 110, 111, 115, 116, 115, 111, 111, 112, 116, 117, 50, 45, 45, 113, 117, 118, 117, 113, 113, + 114, 118, 119, 118, 114, 114, 115, 119, 120, 119, 115, 115, 116, 120, 121, 55, 50, 50, 117, + 121, 122, 121, 117, 117, 118, 122, 123, 122, 118, 118, 119, 123, 124, 123, 119, 119, 120, 124, + 125, 60, 55, 55, 121, 125, 126, 125, 121, 121, 122, 126, 127, 126, 122, 122, 123, 127, 128, + 127, 123, 123, 124, 128, 129, 65, 60, 60, 125, 129, 130, 129, 125, 125, 126, 130, 131, 130, + 126, 126, 127, 131, 132, 131, 127, 127, 128, 132, 133, 70, 65, 65, 129, 133, 134, 133, 129, + 129, 130, 134, 135, 134, 130, 130, 131, 135, 136, 135, 131, 131, 132, 136, 137, 75, 70, 70, + 133, 137, 138, 137, 133, 133, 134, 138, 139, 138, 134, 134, 135, 139, 140, 139, 135, 135, 136, + 140, 141, 80, 75, 75, 137, 141, 142, 141, 137, 137, 138, 142, 143, 142, 138, 138, 139, 143, + 144, 143, 139, 139, 140, 144, 81, 5, 80, 80, 141, 81, 82, 81, 141, 141, 142, 82, 83, 82, 142, + 142, 143, 83, 84, 83, 143, 143, 144, 84, 149, 88, 84, 84, 145, 149, 150, 149, 145, 145, 146, + 150, 151, 150, 146, 146, 147, 151, 152, 151, 147, 147, 148, 152, 153, 92, 88, 88, 149, 153, + 154, 153, 149, 149, 150, 154, 155, 154, 150, 150, 151, 155, 156, 155, 151, 151, 152, 156, 157, + 96, 92, 92, 153, 157, 158, 157, 153, 153, 154, 158, 159, 158, 154, 154, 155, 159, 160, 159, + 155, 155, 156, 160, 161, 100, 96, 96, 157, 161, 162, 161, 157, 157, 158, 162, 163, 162, 158, + 158, 159, 163, 164, 163, 159, 159, 160, 164, 165, 104, 100, 100, 161, 165, 166, 165, 161, 161, + 162, 166, 167, 166, 162, 162, 163, 167, 168, 167, 163, 163, 164, 168, 169, 108, 104, 104, 165, + 169, 170, 169, 165, 165, 166, 170, 171, 170, 166, 166, 167, 171, 172, 171, 167, 167, 168, 172, + 173, 112, 108, 108, 169, 173, 174, 173, 169, 169, 170, 174, 175, 174, 170, 170, 171, 175, 176, + 175, 171, 171, 172, 176, 177, 116, 112, 112, 173, 177, 178, 177, 173, 173, 174, 178, 179, 178, + 174, 174, 175, 179, 180, 179, 175, 175, 176, 180, 181, 120, 116, 116, 177, 181, 182, 181, 177, + 177, 178, 182, 183, 182, 178, 178, 179, 183, 184, 183, 179, 179, 180, 184, 185, 124, 120, 120, + 181, 185, 186, 185, 181, 181, 182, 186, 187, 186, 182, 182, 183, 187, 188, 187, 183, 183, 184, + 188, 189, 128, 124, 124, 185, 189, 190, 189, 185, 185, 186, 190, 191, 190, 186, 186, 187, 191, + 192, 191, 187, 187, 188, 192, 193, 132, 128, 128, 189, 193, 194, 193, 189, 189, 190, 194, 195, + 194, 190, 190, 191, 195, 196, 195, 191, 191, 192, 196, 197, 136, 132, 132, 193, 197, 198, 197, + 193, 193, 194, 198, 199, 198, 194, 194, 195, 199, 200, 199, 195, 195, 196, 200, 201, 140, 136, + 136, 197, 201, 202, 201, 197, 197, 198, 202, 203, 202, 198, 198, 199, 203, 204, 203, 199, 199, + 200, 204, 205, 144, 140, 140, 201, 205, 206, 205, 201, 201, 202, 206, 207, 206, 202, 202, 203, + 207, 208, 207, 203, 203, 204, 208, 145, 84, 144, 144, 205, 145, 146, 145, 205, 205, 206, 146, + 147, 146, 206, 206, 207, 147, 148, 147, 207, 207, 208, 148, 213, 152, 148, 148, 209, 213, 214, + 213, 209, 209, 210, 214, 215, 214, 210, 210, 211, 215, 212, 215, 211, 211, 212, 212, 216, 156, + 152, 152, 213, 216, 217, 216, 213, 213, 214, 217, 218, 217, 214, 214, 215, 218, 212, 218, 215, + 215, 212, 212, 219, 160, 156, 156, 216, 219, 220, 219, 216, 216, 217, 220, 221, 220, 217, 217, + 218, 221, 212, 221, 218, 218, 212, 212, 222, 164, 160, 160, 219, 222, 223, 222, 219, 219, 220, + 223, 224, 223, 220, 220, 221, 224, 212, 224, 221, 221, 212, 212, 225, 168, 164, 164, 222, 225, + 226, 225, 222, 222, 223, 226, 227, 226, 223, 223, 224, 227, 212, 227, 224, 224, 212, 212, 228, + 172, 168, 168, 225, 228, 229, 228, 225, 225, 226, 229, 230, 229, 226, 226, 227, 230, 212, 230, + 227, 227, 212, 212, 231, 176, 172, 172, 228, 231, 232, 231, 228, 228, 229, 232, 233, 232, 229, + 229, 230, 233, 212, 233, 230, 230, 212, 212, 234, 180, 176, 176, 231, 234, 235, 234, 231, 231, + 232, 235, 236, 235, 232, 232, 233, 236, 212, 236, 233, 233, 212, 212, 237, 184, 180, 180, 234, + 237, 238, 237, 234, 234, 235, 238, 239, 238, 235, 235, 236, 239, 212, 239, 236, 236, 212, 212, + 240, 188, 184, 184, 237, 240, 241, 240, 237, 237, 238, 241, 242, 241, 238, 238, 239, 242, 212, + 242, 239, 239, 212, 212, 243, 192, 188, 188, 240, 243, 244, 243, 240, 240, 241, 244, 245, 244, + 241, 241, 242, 245, 212, 245, 242, 242, 212, 212, 246, 196, 192, 192, 243, 246, 247, 246, 243, + 243, 244, 247, 248, 247, 244, 244, 245, 248, 212, 248, 245, 245, 212, 212, 249, 200, 196, 196, + 246, 249, 250, 249, 246, 246, 247, 250, 251, 250, 247, 247, 248, 251, 212, 251, 248, 248, 212, + 212, 252, 204, 200, 200, 249, 252, 253, 252, 249, 249, 250, 253, 254, 253, 250, 250, 251, 254, + 212, 254, 251, 251, 212, 212, 255, 208, 204, 204, 252, 255, 256, 255, 252, 252, 253, 256, 257, + 256, 253, 253, 254, 257, 212, 257, 254, 254, 212, 212, 209, 148, 208, 208, 255, 209, 210, 209, + 255, 255, 256, 210, 211, 210, 256, 256, 257, 211, 212, 211, 257, 257, 212, 212, 264, 263, 258, + 258, 259, 264, 265, 264, 259, 259, 260, 265, 266, 265, 260, 260, 261, 266, 267, 266, 261, 261, + 262, 267, 269, 268, 263, 263, 264, 269, 270, 269, 264, 264, 265, 270, 271, 270, 265, 265, 266, + 271, 272, 271, 266, 266, 267, 272, 274, 273, 268, 268, 269, 274, 275, 274, 269, 269, 270, 275, + 276, 275, 270, 270, 271, 276, 277, 276, 271, 271, 272, 277, 279, 278, 273, 273, 274, 279, 280, + 279, 274, 274, 275, 280, 281, 280, 275, 275, 276, 281, 282, 281, 276, 276, 277, 282, 284, 283, + 278, 278, 279, 284, 285, 284, 279, 279, 280, 285, 286, 285, 280, 280, 281, 286, 287, 286, 281, + 281, 282, 287, 289, 288, 283, 283, 284, 289, 290, 289, 284, 284, 285, 290, 291, 290, 285, 285, + 286, 291, 292, 291, 286, 286, 287, 292, 294, 293, 288, 288, 289, 294, 295, 294, 289, 289, 290, + 295, 296, 295, 290, 290, 291, 296, 297, 296, 291, 291, 292, 297, 259, 258, 293, 293, 294, 259, + 260, 259, 294, 294, 295, 260, 261, 260, 295, 295, 296, 261, 262, 261, 296, 296, 297, 262, 302, + 267, 262, 262, 298, 302, 303, 302, 298, 298, 299, 303, 304, 303, 299, 299, 300, 304, 305, 304, + 300, 300, 301, 305, 306, 272, 267, 267, 302, 306, 307, 306, 302, 302, 303, 307, 308, 307, 303, + 303, 304, 308, 309, 308, 304, 304, 305, 309, 310, 277, 272, 272, 306, 310, 311, 310, 306, 306, + 307, 311, 312, 311, 307, 307, 308, 312, 313, 312, 308, 308, 309, 313, 314, 282, 277, 277, 310, + 314, 315, 314, 310, 310, 311, 315, 316, 315, 311, 311, 312, 316, 317, 316, 312, 312, 313, 317, + 318, 287, 282, 282, 314, 318, 319, 318, 314, 314, 315, 319, 320, 319, 315, 315, 316, 320, 321, + 320, 316, 316, 317, 321, 322, 292, 287, 287, 318, 322, 323, 322, 318, 318, 319, 323, 324, 323, + 319, 319, 320, 324, 325, 324, 320, 320, 321, 325, 326, 297, 292, 292, 322, 326, 327, 326, 322, + 322, 323, 327, 328, 327, 323, 323, 324, 328, 329, 328, 324, 324, 325, 329, 298, 262, 297, 297, + 326, 298, 299, 298, 326, 326, 327, 299, 300, 299, 327, 327, 328, 300, 301, 300, 328, 328, 329, + 301, 336, 335, 330, 330, 331, 336, 337, 336, 331, 331, 332, 337, 338, 337, 332, 332, 333, 338, + 339, 338, 333, 333, 334, 339, 341, 340, 335, 335, 336, 341, 342, 341, 336, 336, 337, 342, 343, + 342, 337, 337, 338, 343, 344, 343, 338, 338, 339, 344, 346, 345, 340, 340, 341, 346, 347, 346, + 341, 341, 342, 347, 348, 347, 342, 342, 343, 348, 349, 348, 343, 343, 344, 349, 351, 350, 345, + 345, 346, 351, 352, 351, 346, 346, 347, 352, 353, 352, 347, 347, 348, 353, 354, 353, 348, 348, + 349, 354, 356, 355, 350, 350, 351, 356, 357, 356, 351, 351, 352, 357, 358, 357, 352, 352, 353, + 358, 359, 358, 353, 353, 354, 359, 361, 360, 355, 355, 356, 361, 362, 361, 356, 356, 357, 362, + 363, 362, 357, 357, 358, 363, 364, 363, 358, 358, 359, 364, 366, 365, 360, 360, 361, 366, 367, + 366, 361, 361, 362, 367, 368, 367, 362, 362, 363, 368, 369, 368, 363, 363, 364, 369, 331, 330, + 365, 365, 366, 331, 332, 331, 366, 366, 367, 332, 333, 332, 367, 367, 368, 333, 334, 333, 368, + 368, 369, 334, 374, 339, 334, 334, 370, 374, 375, 374, 370, 370, 371, 375, 376, 375, 371, 371, + 372, 376, 377, 376, 372, 372, 373, 377, 378, 344, 339, 339, 374, 378, 379, 378, 374, 374, 375, + 379, 380, 379, 375, 375, 376, 380, 381, 380, 376, 376, 377, 381, 382, 349, 344, 344, 378, 382, + 383, 382, 378, 378, 379, 383, 384, 383, 379, 379, 380, 384, 385, 384, 380, 380, 381, 385, 386, + 354, 349, 349, 382, 386, 387, 386, 382, 382, 383, 387, 388, 387, 383, 383, 384, 388, 389, 388, + 384, 384, 385, 389, 390, 359, 354, 354, 386, 390, 391, 390, 386, 386, 387, 391, 392, 391, 387, + 387, 388, 392, 393, 392, 388, 388, 389, 393, 394, 364, 359, 359, 390, 394, 395, 394, 390, 390, + 391, 395, 396, 395, 391, 391, 392, 396, 397, 396, 392, 392, 393, 397, 398, 369, 364, 364, 394, + 398, 399, 398, 394, 394, 395, 399, 400, 399, 395, 395, 396, 400, 401, 400, 396, 396, 397, 401, + 370, 334, 369, 369, 398, 370, 371, 370, 398, 398, 399, 371, 372, 371, 399, 399, 400, 372, 373, + 372, 400, 400, 401, 373, 407, 402, 402, 402, 403, 407, 408, 407, 403, 403, 404, 408, 409, 408, + 404, 404, 405, 409, 410, 409, 405, 405, 406, 410, 411, 402, 402, 402, 407, 411, 412, 411, 407, + 407, 408, 412, 413, 412, 408, 408, 409, 413, 414, 413, 409, 409, 410, 414, 415, 402, 402, 402, + 411, 415, 416, 415, 411, 411, 412, 416, 417, 416, 412, 412, 413, 417, 418, 417, 413, 413, 414, + 418, 419, 402, 402, 402, 415, 419, 420, 419, 415, 415, 416, 420, 421, 420, 416, 416, 417, 421, + 422, 421, 417, 417, 418, 422, 423, 402, 402, 402, 419, 423, 424, 423, 419, 419, 420, 424, 425, + 424, 420, 420, 421, 425, 426, 425, 421, 421, 422, 426, 427, 402, 402, 402, 423, 427, 428, 427, + 423, 423, 424, 428, 429, 428, 424, 424, 425, 429, 430, 429, 425, 425, 426, 430, 431, 402, 402, + 402, 427, 431, 432, 431, 427, 427, 428, 432, 433, 432, 428, 428, 429, 433, 434, 433, 429, 429, + 430, 434, 435, 402, 402, 402, 431, 435, 436, 435, 431, 431, 432, 436, 437, 436, 432, 432, 433, + 437, 438, 437, 433, 433, 434, 438, 439, 402, 402, 402, 435, 439, 440, 439, 435, 435, 436, 440, + 441, 440, 436, 436, 437, 441, 442, 441, 437, 437, 438, 442, 443, 402, 402, 402, 439, 443, 444, + 443, 439, 439, 440, 444, 445, 444, 440, 440, 441, 445, 446, 445, 441, 441, 442, 446, 447, 402, + 402, 402, 443, 447, 448, 447, 443, 443, 444, 448, 449, 448, 444, 444, 445, 449, 450, 449, 445, + 445, 446, 450, 451, 402, 402, 402, 447, 451, 452, 451, 447, 447, 448, 452, 453, 452, 448, 448, + 449, 453, 454, 453, 449, 449, 450, 454, 455, 402, 402, 402, 451, 455, 456, 455, 451, 451, 452, + 456, 457, 456, 452, 452, 453, 457, 458, 457, 453, 453, 454, 458, 459, 402, 402, 402, 455, 459, + 460, 459, 455, 455, 456, 460, 461, 460, 456, 456, 457, 461, 462, 461, 457, 457, 458, 462, 463, + 402, 402, 402, 459, 463, 464, 463, 459, 459, 460, 464, 465, 464, 460, 460, 461, 465, 466, 465, + 461, 461, 462, 466, 403, 402, 402, 402, 463, 403, 404, 403, 463, 463, 464, 404, 405, 404, 464, + 464, 465, 405, 406, 405, 465, 465, 466, 406, 471, 410, 406, 406, 467, 471, 472, 471, 467, 467, + 468, 472, 473, 472, 468, 468, 469, 473, 474, 473, 469, 469, 470, 474, 475, 414, 410, 410, 471, + 475, 476, 475, 471, 471, 472, 476, 477, 476, 472, 472, 473, 477, 478, 477, 473, 473, 474, 478, + 479, 418, 414, 414, 475, 479, 480, 479, 475, 475, 476, 480, 481, 480, 476, 476, 477, 481, 482, + 481, 477, 477, 478, 482, 483, 422, 418, 418, 479, 483, 484, 483, 479, 479, 480, 484, 485, 484, + 480, 480, 481, 485, 486, 485, 481, 481, 482, 486, 487, 426, 422, 422, 483, 487, 488, 487, 483, + 483, 484, 488, 489, 488, 484, 484, 485, 489, 490, 489, 485, 485, 486, 490, 491, 430, 426, 426, + 487, 491, 492, 491, 487, 487, 488, 492, 493, 492, 488, 488, 489, 493, 494, 493, 489, 489, 490, + 494, 495, 434, 430, 430, 491, 495, 496, 495, 491, 491, 492, 496, 497, 496, 492, 492, 493, 497, + 498, 497, 493, 493, 494, 498, 499, 438, 434, 434, 495, 499, 500, 499, 495, 495, 496, 500, 501, + 500, 496, 496, 497, 501, 502, 501, 497, 497, 498, 502, 503, 442, 438, 438, 499, 503, 504, 503, + 499, 499, 500, 504, 505, 504, 500, 500, 501, 505, 506, 505, 501, 501, 502, 506, 507, 446, 442, + 442, 503, 507, 508, 507, 503, 503, 504, 508, 509, 508, 504, 504, 505, 509, 510, 509, 505, 505, + 506, 510, 511, 450, 446, 446, 507, 511, 512, 511, 507, 507, 508, 512, 513, 512, 508, 508, 509, + 513, 514, 513, 509, 509, 510, 514, 515, 454, 450, 450, 511, 515, 516, 515, 511, 511, 512, 516, + 517, 516, 512, 512, 513, 517, 518, 517, 513, 513, 514, 518, 519, 458, 454, 454, 515, 519, 520, + 519, 515, 515, 516, 520, 521, 520, 516, 516, 517, 521, 522, 521, 517, 517, 518, 522, 523, 462, + 458, 458, 519, 523, 524, 523, 519, 519, 520, 524, 525, 524, 520, 520, 521, 525, 526, 525, 521, + 521, 522, 526, 527, 466, 462, 462, 523, 527, 528, 527, 523, 523, 524, 528, 529, 528, 524, 524, + 525, 529, 530, 529, 525, 525, 526, 530, 467, 406, 466, 466, 527, 467, 468, 467, 527, 527, 528, + 468, 469, 468, 528, 528, 529, 469, 470, 469, 529, 529, 530, 470u16, +]; diff --git a/examples/wgpu/wgpu_teapot/shaders/fs.wgsl b/examples/wgpu/wgpu_teapot/shaders/fs.wgsl new file mode 100644 index 000000000..6a5079bbc --- /dev/null +++ b/examples/wgpu/wgpu_teapot/shaders/fs.wgsl @@ -0,0 +1,9 @@ +@fragment +fn main(@location(0) normal: vec3) -> @location(0) vec4 { + let light: vec3 = vec3(0.0, 0.0, 1.0); + let color: vec3 = vec3(1.0); + let brightness: f32 = dot(normalize(normal), normalize(light)); + let dark_color: vec3 = vec3(0.1) * color; + let out_color = vec4(mix(dark_color, color, vec3(brightness)), 1.0); + return out_color; +} diff --git a/examples/wgpu/wgpu_teapot/shaders/vs.wgsl b/examples/wgpu/wgpu_teapot/shaders/vs.wgsl new file mode 100644 index 000000000..856e1f018 --- /dev/null +++ b/examples/wgpu/wgpu_teapot/shaders/vs.wgsl @@ -0,0 +1,41 @@ +struct Data { + world: mat4x4, + view: mat4x4, + proj: mat4x4, +}; + +struct VertexOutput { + @location(0) normal: vec3, + @builtin(position) pos: vec4, +}; + +@group(0) @binding(0) +var uniforms: Data; + +fn custom_inverse(m: mat3x3) -> mat3x3 { + let determinant: f32 = determinant(m); + let invdet: f32 = 1.0 / determinant; + var minv: mat3x3; + minv[0][0] = (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * invdet; + minv[0][1] = (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * invdet; + minv[0][2] = (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * invdet; + minv[1][0] = (m[1][2] * m[2][0] - m[1][0] * m[2][2]) * invdet; + minv[1][1] = (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * invdet; + minv[1][2] = (m[1][0] * m[0][2] - m[0][0] * m[1][2]) * invdet; + minv[2][0] = (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * invdet; + minv[2][1] = (m[2][0] * m[0][1] - m[0][0] * m[2][1]) * invdet; + minv[2][2] = (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * invdet; + return minv; +} + +@vertex +fn main( + @location(0) pos: vec3, + @location(1) normal: vec3, +) -> VertexOutput { + let worldview: mat4x4 = uniforms.view * uniforms.world; + let wv3: mat3x3 = mat3x3(worldview[0].xyz, worldview[1].xyz, worldview[2].xyz); + let out_normal: vec3 = transpose(custom_inverse(wv3)) * normal; + let out_pos: vec4 = uniforms.proj * worldview * vec4(pos, 1.0); + return VertexOutput(out_normal, out_pos); +} diff --git a/examples/wgpu/wgpu_teapot/wgpu_teapot.rs b/examples/wgpu/wgpu_teapot/wgpu_teapot.rs new file mode 100644 index 000000000..e40299aad --- /dev/null +++ b/examples/wgpu/wgpu_teapot/wgpu_teapot.rs @@ -0,0 +1,271 @@ +use nannou::prelude::*; +use std::sync::{Arc, Mutex}; + +mod data; + +#[derive(Clone)] +struct Model { + graphics: Arc>, +} + +struct Graphics { + vertex_buffer: wgpu::Buffer, + normal_buffer: wgpu::Buffer, + index_buffer: wgpu::Buffer, + uniform_buffer: wgpu::Buffer, + depth_texture: wgpu::Texture, + depth_texture_view: wgpu::TextureView, + bind_group: wgpu::BindGroup, + render_pipeline: wgpu::RenderPipeline, +} + +// The vertex type that we will use to represent a point on our triangle. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct Vertex { + position: (f32, f32, f32), +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Normal { + normal: (f32, f32, f32), +} + +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Uniforms { + world: Mat4, + view: Mat4, + proj: Mat4, +} + +const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + +fn main() { + nannou::app(model).render(render).run(); +} + +fn model(app: &App) -> Model { + let w_id = app.new_window::().hdr(true).size(1024, 576).build(); + + // The gpu device associated with the window's swapchain + let window = app.window(w_id); + let device = window.device(); + let format = Frame::TEXTURE_FORMAT; + let msaa_samples = window.msaa_samples(); + let UVec2 { x: win_w, y: win_h } = window.size_pixels(); + + // Load shader modules. + let vs_desc = wgpu::include_wgsl!("shaders/vs.wgsl"); + let fs_desc = wgpu::include_wgsl!("shaders/fs.wgsl"); + let vs_mod = device.create_shader_module(vs_desc); + let fs_mod = device.create_shader_module(fs_desc); + + // Create the vertex, normal and index buffers. + let vertices_bytes = vertices_as_bytes(&data::VERTICES); + let normals_bytes = normals_as_bytes(&data::NORMALS); + let indices_bytes = indices_as_bytes(&data::INDICES); + let vertex_usage = wgpu::BufferUsages::VERTEX; + let index_usage = wgpu::BufferUsages::INDEX; + let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: vertices_bytes, + usage: vertex_usage, + }); + let normal_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: normals_bytes, + usage: vertex_usage, + }); + let index_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: indices_bytes, + usage: index_usage, + }); + + // Create the depth texture. + let depth_texture = create_depth_texture(&device, [win_w, win_h], DEPTH_FORMAT, msaa_samples); + let depth_texture_view = depth_texture.view().build(); + + // Create the uniform buffer. + let uniforms = create_uniforms(0.0, [win_w, win_h]); + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST; + let uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: uniforms_bytes, + usage, + }); + + // Create the render pipeline. + let bind_group_layout = create_bind_group_layout(&device); + let bind_group = create_bind_group(&device, &bind_group_layout, &uniform_buffer); + let pipeline_layout = create_pipeline_layout(&device, &bind_group_layout); + let render_pipeline = create_render_pipeline( + &device, + &pipeline_layout, + &vs_mod, + &fs_mod, + format, + DEPTH_FORMAT, + msaa_samples, + ); + + let graphics = Arc::new(Mutex::new(Graphics { + vertex_buffer, + normal_buffer, + index_buffer, + uniform_buffer, + depth_texture, + depth_texture_view, + bind_group, + render_pipeline, + })); + + Model { graphics } +} + +fn render(app: &RenderApp, model: &Model, frame: Frame) { + let mut g = model.graphics.lock().unwrap(); + + // If the window has changed size, recreate our depth texture to match. + let depth_size = g.depth_texture.size(); + let frame_size = frame.texture_size(); + let device = frame.device(); + if frame_size != depth_size { + let depth_format = g.depth_texture.format(); + let sample_count = frame.resolve_target_msaa_samples(); + g.depth_texture = create_depth_texture(&device, frame_size, depth_format, sample_count); + g.depth_texture_view = g.depth_texture.view().build(); + } + + // Update the uniforms (rotate around the teapot). + let rotation = app.time(); + let uniforms = create_uniforms(rotation, frame_size); + let uniforms_size = std::mem::size_of::() as wgpu::BufferAddress; + let uniforms_bytes = uniforms_as_bytes(&uniforms); + let usage = wgpu::BufferUsages::COPY_SRC; + let new_uniform_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: uniforms_bytes, + usage, + }); + + let mut encoder = frame.command_encoder(); + encoder.copy_buffer_to_buffer(&new_uniform_buffer, 0, &g.uniform_buffer, 0, uniforms_size); + let mut render_pass = wgpu::RenderPassBuilder::new() + .color_attachment(frame.resolve_target_view().unwrap(), |color| color) + // We'll use a depth texture to assist with the order of rendering fragments based on depth. + .depth_stencil_attachment(&g.depth_texture_view, |depth| depth) + .begin(&mut encoder); + render_pass.set_bind_group(0, &g.bind_group, &[]); + render_pass.set_pipeline(&g.render_pipeline); + render_pass.set_vertex_buffer(0, g.vertex_buffer.slice(..)); + render_pass.set_vertex_buffer(1, g.normal_buffer.slice(..)); + render_pass.set_index_buffer(g.index_buffer.slice(..), wgpu::IndexFormat::Uint16); + let index_range = 0..data::INDICES.len() as u32; + let start_vertex = 0; + let instance_range = 0..1; + render_pass.draw_indexed(index_range, start_vertex, instance_range); +} + +fn create_uniforms(rotation: f32, [w, h]: [u32; 2]) -> Uniforms { + let rotation = Mat4::from_rotation_y(rotation); + let aspect_ratio = w as f32 / h as f32; + let fov_y = std::f32::consts::FRAC_PI_2; + let near = 0.01; + let far = 100.0; + let proj = Mat4::perspective_rh_gl(fov_y, aspect_ratio, near, far); + let eye = pt3(0.3, 0.3, 1.0); + let target = Point3::ZERO; + let up = Vec3::Y; + let view = Mat4::look_at_rh(eye, target, up); + let scale = Mat4::from_scale(Vec3::splat(0.01)); + Uniforms { + world: rotation, + view: (view * scale).into(), + proj: proj.into(), + } +} + +fn create_depth_texture( + device: &wgpu::Device, + size: [u32; 2], + depth_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::Texture { + wgpu::TextureBuilder::new() + .size(size) + .format(depth_format) + .usage(wgpu::TextureUsages::RENDER_ATTACHMENT) + .sample_count(sample_count) + .build(device) +} + +fn create_bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout { + wgpu::BindGroupLayoutBuilder::new() + .uniform_buffer(wgpu::ShaderStages::VERTEX, false) + .build(device) +} + +fn create_bind_group( + device: &wgpu::Device, + layout: &wgpu::BindGroupLayout, + uniform_buffer: &wgpu::Buffer, +) -> wgpu::BindGroup { + wgpu::BindGroupBuilder::new() + .buffer::(uniform_buffer, 0..1) + .build(device, layout) +} + +fn create_pipeline_layout( + device: &wgpu::Device, + bind_group_layout: &wgpu::BindGroupLayout, +) -> wgpu::PipelineLayout { + let desc = wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bind_group_layout], + push_constant_ranges: &[], + }; + device.create_pipeline_layout(&desc) +} + +fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + vs_mod: &wgpu::ShaderModule, + fs_mod: &wgpu::ShaderModule, + dst_format: wgpu::TextureFormat, + depth_format: wgpu::TextureFormat, + sample_count: u32, +) -> wgpu::RenderPipeline { + wgpu::RenderPipelineBuilder::from_layout(layout, vs_mod) + .fragment_shader(&fs_mod) + .color_format(dst_format) + .color_blend(wgpu::BlendComponent::REPLACE) + .alpha_blend(wgpu::BlendComponent::REPLACE) + .add_vertex_buffer::(&wgpu::vertex_attr_array![0 => Float32x3]) + .add_vertex_buffer::(&wgpu::vertex_attr_array![1 => Float32x3]) + .depth_format(depth_format) + .sample_count(sample_count) + .build(device) +} + +// See the `nannou::wgpu::bytes` documentation for why the following are necessary. + +fn vertices_as_bytes(data: &[Vertex]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn normals_as_bytes(data: &[Normal]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn indices_as_bytes(data: &[u16]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} + +fn uniforms_as_bytes(uniforms: &Uniforms) -> &[u8] { + unsafe { wgpu::bytes::from(uniforms) } +} diff --git a/examples/wgpu/wgpu_triangle/shaders/fs.wgsl b/examples/wgpu/wgpu_triangle/shaders/fs.wgsl new file mode 100644 index 000000000..cf27bb563 --- /dev/null +++ b/examples/wgpu/wgpu_triangle/shaders/fs.wgsl @@ -0,0 +1,4 @@ +@fragment +fn main() -> @location(0) vec4 { + return vec4(1.0, 0.0, 0.0, 1.0); +} diff --git a/examples/wgpu/wgpu_triangle/shaders/vs.wgsl b/examples/wgpu/wgpu_triangle/shaders/vs.wgsl new file mode 100644 index 000000000..24ec5ee10 --- /dev/null +++ b/examples/wgpu/wgpu_triangle/shaders/vs.wgsl @@ -0,0 +1,4 @@ +@vertex +fn main(@location(0) pos: vec2) -> @builtin(position) vec4 { + return vec4(pos, 0.0, 1.0); +} diff --git a/examples/wgpu/wgpu_triangle/wgpu_triangle.rs b/examples/wgpu/wgpu_triangle/wgpu_triangle.rs new file mode 100644 index 000000000..254c46ed7 --- /dev/null +++ b/examples/wgpu/wgpu_triangle/wgpu_triangle.rs @@ -0,0 +1,111 @@ +//! A simple demonstration on how to create and draw with a custom wgpu render pipeline in nannou! +//! +//! The aim of this example is not to show the simplest way of drawing a triangle in nannou, but +//! rather provide a reference on how to get started creating your own rendering pipeline from +//! scratch. While nannou's provided graphics-y APIs can do a lot of things quite efficiently, +//! writing a custom pipeline that does only exactly what you need it to can sometimes result in +//! better performance. + +use nannou::prelude::*; +use std::sync::Arc; + +#[derive(Clone)] +struct Model { + bind_group: Arc, + render_pipeline: Arc, + vertex_buffer: Arc, +} + +// The vertex type that we will use to represent a point on our triangle. +#[repr(C)] +#[derive(Clone, Copy)] +struct Vertex { + position: [f32; 2], +} + +// The vertices that make up our triangle. +const VERTICES: [Vertex; 3] = [ + Vertex { + position: [-0.5, -0.25], + }, + Vertex { + position: [0.0, 0.5], + }, + Vertex { + position: [0.25, -0.1], + }, +]; + +fn main() { + nannou::app(model).render(render).run(); +} + +fn model(app: &App) -> Model { + let w_id = app.new_window::().hdr(true).size(512, 512).build(); + + // The gpu device associated with the window's swapchain + let window = app.window(w_id); + let device = window.device(); + let format = Frame::TEXTURE_FORMAT; + let sample_count = window.msaa_samples(); + + // Load shader modules. + let vs_desc = wgpu::include_wgsl!("shaders/vs.wgsl"); + let fs_desc = wgpu::include_wgsl!("shaders/fs.wgsl"); + let vs_mod = device.create_shader_module(vs_desc); + let fs_mod = device.create_shader_module(fs_desc); + + // Create the vertex buffer. + let vertices_bytes = vertices_as_bytes(&VERTICES[..]); + let usage = wgpu::BufferUsages::VERTEX; + let vertex_buffer = device.create_buffer_init(&BufferInitDescriptor { + label: None, + contents: vertices_bytes, + usage, + }); + + // Create the render pipeline. + let bind_group_layout = wgpu::BindGroupLayoutBuilder::new().build(&device); + let bind_group = wgpu::BindGroupBuilder::new().build(&device, &bind_group_layout); + let pipeline_layout = wgpu::create_pipeline_layout(&device, None, &[&bind_group_layout], &[]); + let render_pipeline = wgpu::RenderPipelineBuilder::from_layout(&pipeline_layout, &vs_mod) + .fragment_shader(&fs_mod) + .color_format(format) + .add_vertex_buffer::(&wgpu::vertex_attr_array![0 => Float32x2]) + .sample_count(sample_count) + .build(&device); + + Model { + bind_group: Arc::new(bind_group), + vertex_buffer: Arc::new(vertex_buffer), + render_pipeline: Arc::new(render_pipeline), + } +} + +// Draw the state of your `Model` into the given `Frame` here. +fn render(_app: &RenderApp, model: &Model, frame: Frame) { + // Using this we will encode commands that will be submitted to the GPU. + let mut encoder = frame.command_encoder(); + + // The render pass can be thought of a single large command consisting of sub commands. Here we + // begin a render pass that outputs to the frame's texture. Then we add sub-commands for + // setting the bind group, render pipeline, vertex buffers and then finally drawing. + let mut render_pass = wgpu::RenderPassBuilder::new() + .color_attachment(frame.resolve_target_view().unwrap(), |color| color) + .begin(&mut encoder); + render_pass.set_bind_group(0, &model.bind_group, &[]); + render_pass.set_pipeline(&model.render_pipeline); + render_pass.set_vertex_buffer(0, model.vertex_buffer.slice(..)); + + // We want to draw the whole range of vertices, and we're only drawing one instance of them. + let vertex_range = 0..VERTICES.len() as u32; + let instance_range = 0..1; + render_pass.draw(vertex_range, instance_range); + + // Now we're done! The commands we added will be submitted after `view` completes. +} + +// See the `nannou::wgpu::bytes` documentation for why this is necessary. +fn vertices_as_bytes(data: &[Vertex]) -> &[u8] { + unsafe { wgpu::bytes::from_slice(data) } +} diff --git a/nannou/Cargo.toml b/nannou/Cargo.toml index 3548e49f0..b1ba20e93 100644 --- a/nannou/Cargo.toml +++ b/nannou/Cargo.toml @@ -22,6 +22,7 @@ getrandom = "0.2.3" instant = "0.1.9" lyon = "1.0" nannou_core = { version ="0.19.0", path = "../nannou_core", features = ["std"] } +nannou_wgpu = { version = "0.19.0", path = "../nannou_wgpu", features = ["capturer"]} noise = "0.7" notosans = { version = "0.1", optional = true } num_cpus = "1" @@ -32,13 +33,14 @@ serde_json = { workspace = true, optional = true } toml = { workspace = true, optional = true } walkdir = "2" web-sys = { version = "0.3.64", optional = true } +wgpu = { workspace = true } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tokio = { version = "1", features = ["full"]} -image = { version = "0.25", features = ["default"] } +image = { workspace = true, features = ["default"] } [target.'cfg(target_arch = "wasm32")'.dependencies] tokio = { version = "1", features = ["rt"]} -image = { version = "0.25", features = [], default-features = false } +image = { workspace = true, features = [], default-features = false } [features] default = ["notosans"] diff --git a/nannou/src/app.rs b/nannou/src/app.rs index 2b2de18ea..a8c654d4a 100644 --- a/nannou/src/app.rs +++ b/nannou/src/app.rs @@ -31,6 +31,8 @@ use bevy::reflect::{ ApplyError, DynamicTypePath, GetTypeRegistration, ReflectMut, ReflectOwned, ReflectRef, TypeInfo, }; +use bevy::render::extract_resource::{extract_resource, ExtractResource}; +use bevy::render::render_graph::ViewNodeRunner; use bevy::window::{ExitCondition, PrimaryWindow, WindowClosed, WindowFocused, WindowResized}; use bevy::winit::{UpdateMode, WinitEvent, WinitSettings}; #[cfg(feature = "egui")] @@ -47,10 +49,12 @@ use bevy_nannou::prelude::render::ExtendedNannouMaterial; use bevy_nannou::prelude::{draw, DrawHolder}; use bevy_nannou::NannouPlugin; -use crate::prelude::bevy_asset::io::AssetSource; +use crate::frame::{Frame, FramePlugin}; use crate::prelude::bevy_ecs::system::SystemState; +use crate::prelude::bevy_render::extract_component::ExtractComponentPlugin; use crate::prelude::render::NannouMesh; use crate::prelude::NannouMaterialPlugin; +use crate::render::{NannouRenderNode, RenderApp, RenderPlugin}; use crate::window::WindowUserFunctions; use crate::{camera, geom, light, window}; @@ -72,6 +76,9 @@ pub type SketchViewFn = fn(&App); /// The user function type allowing them to consume the `model` when the application exits. pub type ExitFn = fn(&App, Model); +/// The user function type for rendering their model to the surface of a single window. +pub type RenderFn = fn(&RenderApp, &Model, Frame); + /// The **App**'s view function. enum View { /// A view function allows for viewing the user's model. @@ -96,6 +103,7 @@ pub struct Builder { config: Config, event: Option>, update: Option>, + render: Option>, default_view: Option>, exit: Option>, } @@ -132,7 +140,7 @@ fn default_model(_: &App) {} /// - A map of channels for submitting user input updates to active **Ui**s. pub struct App<'w> { current_view: Option, - resourece_world: Rc>>, + resource_world: Rc>>, component_world: Rc>>, window_count: AtomicUsize, } @@ -146,6 +154,20 @@ struct EventFnRes(Option>); #[derive(Resource, Deref, DerefMut)] struct UpdateFnRes(Option>); +#[derive(Resource, Deref, DerefMut)] +pub(crate) struct RenderFnRes(Option>); + +impl ExtractResource for RenderFnRes +where + M: Clone + Send + Sync + 'static, +{ + type Source = Self; + + fn extract_resource(source: &Self::Source) -> Self { + RenderFnRes(source.0.clone()) + } +} + #[derive(Resource, Deref, DerefMut)] struct ViewFnRes(Option>); @@ -163,6 +185,17 @@ struct Config { #[derive(Resource, Deref, DerefMut)] pub struct ModelHolder(pub M); +impl ExtractResource for ModelHolder +where + M: Clone + Send + Sync + 'static, +{ + type Source = Self; + + fn extract_resource(source: &Self::Source) -> Self { + ModelHolder(source.0.clone()) + } +} + #[derive(Resource)] struct CreateDefaultWindow; @@ -221,6 +254,7 @@ where config: Config::default(), event: None, update: None, + render: None, default_view: None, exit: None, } @@ -258,6 +292,17 @@ where self } + pub fn render(mut self, render: RenderFn) -> Self + where + M: Send + Sync + Clone + 'static, + ViewNodeRunner>: FromWorld, + { + self.render = Some(render); + self.app + .add_plugins((RenderPlugin::::default(), FramePlugin)); + self + } + /// Tell the app that you would like it to create a single, simple, default window just before /// it calls your model function. /// @@ -365,6 +410,7 @@ where .insert_resource(ModelFnRes(self.model)) .insert_resource(EventFnRes(self.event)) .insert_resource(UpdateFnRes(self.update)) + .insert_resource(RenderFnRes(self.render)) .insert_resource(ViewFnRes(self.default_view)) .insert_resource(ExitFnRes(self.exit)) .add_systems(Startup, startup::) @@ -650,19 +696,19 @@ impl<'w> App<'w> { App { current_view: None, - resourece_world: Rc::new(RefCell::new(world)), + resource_world: Rc::new(RefCell::new(world)), component_world: Rc::new(RefCell::new(world)), window_count: window_count.into(), } } pub(crate) fn resource_world(&self) -> std::cell::Ref<'_, World> { - let world = self.resourece_world.borrow(); + let world = self.resource_world.borrow(); std::cell::Ref::map(world, |world| unsafe { world.world() }) } pub(crate) fn resource_world_mut(&self) -> RefMut<'_, World> { - let world = unsafe { self.resourece_world.borrow_mut() }; + let world = unsafe { self.resource_world.borrow_mut() }; RefMut::map(world, |world| unsafe { world.world_mut() }) } @@ -676,18 +722,6 @@ impl<'w> App<'w> { RefMut::map(world, |world| unsafe { world.world_mut() }) } - /// Retreive a mutable reference to the `App`'s world. - /// - /// WARNING: This should be used with extreme caution as it can lead to undefined behavior. - /// This is only safe to use if you are certain that the world is not being accessed by any - /// other part of the application. - /// - /// Applications that wish to make greater use of the ECS should consider using the Bevy ECS - /// API directly. - pub unsafe fn unsafe_world_mut(&self) -> &'w mut World { - self.resourece_world.borrow_mut().world_mut() - } - /// Returns the list of all the monitors available on the system. pub fn available_monitors(&self) -> Vec<()> { // Bevy doesn't expose this right now but could be nice @@ -846,7 +880,10 @@ impl<'w> App<'w> { /// Produce the [App]'s [DrawHolder] API for drawing geometry and text with colors and textures. pub fn draw(&self) -> draw::Draw { - let window_id = self.window_id(); + let window_id = match self.current_view { + Some(window_id) => window_id, + None => self.window_id(), + }; let world = self.component_world(); let draw = world.entity(window_id).get::(); draw.unwrap().0.clone() @@ -929,7 +966,7 @@ fn get_app_and_state<'w, 's, S: SystemParam + 'static>( ) -> (App<'w>, ::Item<'w, 's>) { state.update_archetypes(world); let app = App::new(world); - let param = unsafe { state.get_unchecked_manual(*app.resourece_world.borrow_mut()) }; + let param = unsafe { state.get_unchecked_manual(*app.resource_world.borrow_mut()) }; (app, param) } diff --git a/nannou/src/frame.rs b/nannou/src/frame.rs new file mode 100644 index 000000000..d67278fa5 --- /dev/null +++ b/nannou/src/frame.rs @@ -0,0 +1,223 @@ +use bevy::ecs::entity::EntityHashMap; +use bevy::prelude::*; +use bevy::render::render_resource::Extent3d; +use bevy::render::renderer::{RenderContext, RenderDevice}; +use bevy::render::view::{ExtractedView, ExtractedWindows, ViewTarget}; +use bevy::render::{Extract, RenderApp}; +use nannou_core::geom; +use std::cell::RefCell; +use std::ops::Deref; + +pub struct FramePlugin; + +impl Plugin for FramePlugin { + fn build(&self, app: &mut App) { + if let Some(render_app) = app.get_sub_app_mut(RenderApp) { + render_app + .init_resource::() + .add_systems(ExtractSchedule, extract_scale_factors); + } + } +} + +fn extract_scale_factors( + mut window_scale_factors: ResMut, + windows_q: Extract>, +) { + window_scale_factors.clear(); + for (entity, window) in windows_q.iter() { + window_scale_factors.insert(entity, window.scale_factor()); + } +} + +#[derive(Resource, Deref, DerefMut, Default)] +struct ExtractedWindowsScaleFactor(EntityHashMap); + +pub struct Frame<'a, 'w> { + window_id: Entity, + world: &'w World, + view_target: &'w ViewTarget, + extracted_windows: &'w ExtractedWindows, + extracted_view: &'w ExtractedView, + render_device: &'w RenderDevice, + render_context: RefCell<&'a mut RenderContext<'w>>, +} + +impl<'a, 'w> Frame<'a, 'w> { + pub const TEXTURE_FORMAT: wgpu::TextureFormat = + nannou_wgpu::RenderPipelineBuilder::DEFAULT_COLOR_FORMAT; + + pub(crate) fn new( + world: &'w World, + view_target_id: Entity, + view_target: &'w ViewTarget, + extracted_windows: &'w ExtractedWindows, + extracted_view: &'w ExtractedView, + render_context: &'a mut RenderContext<'w>, + ) -> Self { + let render_device = world.resource::(); + Frame { + window_id: view_target_id, + world, + view_target, + render_device, + render_context: RefCell::new(render_context), + extracted_windows, + extracted_view, + } + } + + /// Access the command encoder in order to encode commands that will be submitted to the swap + /// chain queue at the end of the call to **view**. + pub fn command_encoder(&self) -> std::cell::RefMut { + std::cell::RefMut::map(self.render_context.borrow_mut(), |x| x.command_encoder()) + } + + /// The `Id` of the window whose wgpu surface is associated with this frame. + pub fn window_id(&self) -> Entity { + self.window_id + } + + /// A **Rect** representing the full surface of the frame. + /// + /// The returned **Rect** is equivalent to the result of calling **Window::rect** on the window + /// associated with this **Frame**. + pub fn rect(&self) -> geom::Rect { + let window = self.extracted_windows.windows.get(&self.window_id).unwrap(); + let scale_factor = self.world.resource::(); + let scale_factor = scale_factor.get(&self.window_id).unwrap(); + let scale_factor = *scale_factor as f32; + let [width, height] = [window.physical_width, window.physical_height]; + geom::Rect::from_x_y_w_h( + 0.0, + 0.0, + width as f32 / scale_factor, + height as f32 / scale_factor, + ) + } + + /// The `nth` frame for the associated window since the application started. + /// + /// E.g. the first frame yielded will return `0`, the second will return `1`, and so on. + pub fn nth(&self) -> u64 { + todo!() + } + + /// The swap chain texture that will be the target for drawing this frame. + pub fn swap_chain_texture(&self) -> &wgpu::TextureView { + self.view_target.out_texture() + } + + /// The texture format of the frame's swap chain texture. + pub fn swap_chain_texture_format(&self) -> wgpu::TextureFormat { + self.view_target.out_texture_format() + } + + /// The device and queue on which the swap chain was created and which will be used to submit + /// the **RawFrame**'s encoded commands. + /// + /// This refers to the same **DeviceQueuePair** as held by the window associated with this + /// frame. + pub fn device(&self) -> &wgpu::Device { + self.render_device.wgpu_device() + } + + /// The texture to which all graphics should be drawn this frame. + /// + /// This is **not** the swapchain texture, but rather an intermediary linear sRGBA image. This + /// intermediary image is used in order to: + /// + /// - Ensure consistent MSAA resolve behaviour across platforms. + /// - Avoid the need for multiple implicit conversions to and from linear sRGBA for each + /// graphics pipeline render pass that is used. + /// - Allow for the user's rendered image to persist between frames. + /// + /// The exact format of the texture is equal to `Frame::TEXTURE_FORMAT`. + /// + /// If the number of MSAA samples specified is greater than `1` (which it is by default if + /// supported by the platform), this will be a multisampled texture. After the **view** + /// function returns, this texture will be resolved to a non-multisampled linear sRGBA texture. + /// After the texture has been resolved if necessary, it will then be used as a shader input + /// within a graphics pipeline used to draw the swapchain texture. + pub fn texture(&self) -> &wgpu::Texture { + self.view_target.main_texture() + } + + /// A full view into the frame's texture. + /// + /// See `texture` for details. + pub fn texture_view(&self) -> &wgpu::TextureView { + self.view_target.main_texture_view() + } + + /// Returns the resolve target texture in the case that MSAA is enabled. + pub fn resolve_target(&self) -> Option<&wgpu::Texture> { + self.view_target.sampled_main_texture().map(|x| x.deref()) + } + + /// Returns the resolve target texture view in the case that MSAA is enabled. + pub fn resolve_target_view(&self) -> Option<&wgpu::TextureView> { + self.view_target + .sampled_main_texture_view() + .map(|x| x.deref()) + } + + pub fn resolve_target_msaa_samples(&self) -> u32 { + self.view_target + .sampled_main_texture() + .map(|x| x.sample_count()) + .unwrap_or(1) + } + + /// The color format of the `Frame`'s intermediary linear sRGBA texture (equal to + /// `Frame::TEXTURE_FORMAT`). + pub fn texture_format(&self) -> wgpu::TextureFormat { + self.view_target.main_texture_format() + } + + /// The number of MSAA samples of the `Frame`'s intermediary linear sRGBA texture. + pub fn texture_msaa_samples(&self) -> u32 { + self.view_target.main_texture().sample_count() + } + + /// The size of the frame's texture in pixels. + pub fn texture_size(&self) -> [u32; 2] { + let Extent3d { width, height, .. } = self.view_target.main_texture().size(); + [width, height] + } + + /// Short-hand for constructing a `wgpu::RenderPassColorAttachment` for use within a + /// render pass that targets this frame's texture. The returned descriptor's `attachment` will + /// the same `wgpu::TextureView` returned by the `Frame::texture` method. + /// + /// Note that this method will not perform any resolving. In the case that `msaa_samples` is + /// greater than `1`, a render pass will be automatically added after the `view` completes and + /// before the texture is drawn to the swapchain. + pub fn color_attachment_descriptor(&self) -> wgpu::RenderPassColorAttachment { + self.view_target.get_color_attachment() + } + + /// Clear the texture with the given color. + pub fn clear(&mut self, color: C) + where + C: Into, + { + let linear_color = color.into().to_linear(); + let view = self.view_target.main_texture_view(); + let mut render_ctx = self.render_context.borrow_mut(); + render_ctx.begin_tracked_render_pass(wgpu::RenderPassDescriptor { + label: Some("nannou_frame_clear"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(linear_color.into()), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + } +} diff --git a/nannou/src/lib.rs b/nannou/src/lib.rs index d3e463d15..c2fdccacd 100644 --- a/nannou/src/lib.rs +++ b/nannou/src/lib.rs @@ -24,6 +24,7 @@ pub use self::app::App; pub mod app; mod camera; +mod frame; pub mod geom; pub mod image; #[cfg(feature = "serde")] @@ -31,9 +32,12 @@ pub mod io; mod light; pub mod noise; pub mod prelude; +mod render; pub mod time; mod window; +pub use nannou_wgpu as wgpu; + /// Begin building the `App`. /// /// The `model` argument is the function that the App will call to initialise your Model. diff --git a/nannou/src/prelude.rs b/nannou/src/prelude.rs index dced60aa3..347c93687 100644 --- a/nannou/src/prelude.rs +++ b/nannou/src/prelude.rs @@ -4,9 +4,14 @@ pub use bevy::asset as bevy_asset; pub use bevy::ecs as bevy_ecs; pub use bevy::reflect as bevy_reflect; pub use bevy::render as bevy_render; +pub use bevy::tasks::*; #[cfg(feature = "egui")] pub use bevy_egui::egui; +pub use crate::frame::*; +pub use crate::render::*; +pub use crate::wgpu; +pub use crate::wgpu::util::{BufferInitDescriptor, DeviceExt}; pub use bevy_nannou::prelude::*; pub use nannou_core::prelude::*; diff --git a/nannou/src/render.rs b/nannou/src/render.rs new file mode 100644 index 000000000..a6e412d75 --- /dev/null +++ b/nannou/src/render.rs @@ -0,0 +1,138 @@ +use crate::app::{ModelHolder, RenderFnRes}; +use crate::frame::Frame; +use crate::prelude::bevy_render::extract_resource::extract_resource; +use bevy::core_pipeline::core_3d::graph::{Core3d, Node3d}; +use bevy::ecs::query::QueryItem; +pub use bevy::prelude::*; +use bevy::render::render_graph::{ + NodeRunError, RenderGraphApp, RenderGraphContext, RenderLabel, ViewNode, ViewNodeRunner, +}; +use bevy::render::renderer::RenderContext; +use bevy::render::view::{ExtractedView, ExtractedWindows, ViewTarget}; +use std::ops::Deref; + +pub(crate) struct RenderPlugin(std::marker::PhantomData); + +impl Default for RenderPlugin +where + M: Send + Sync + Clone + 'static, +{ + fn default() -> Self { + Self(std::marker::PhantomData) + } +} + +impl Plugin for RenderPlugin +where + M: Send + Sync + Clone + 'static, +{ + fn build(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(bevy::render::RenderApp) else { + return; + }; + + render_app.add_systems( + ExtractSchedule, + ( + extract_resource::>, + extract_resource::>, + ), + ); + } + + fn finish(&self, app: &mut App) { + let Some(render_app) = app.get_sub_app_mut(bevy::render::RenderApp) else { + return; + }; + + render_app + .add_render_graph_node::>>( + Core3d, + NannouRenderNodeLabel, + ) + .add_render_graph_edges( + Core3d, + ( + Node3d::MainTransparentPass, + NannouRenderNodeLabel, + Node3d::EndMainPass, + ), + ); + } +} + +pub struct RenderApp<'w> { + current_view: Option, + world: &'w World, +} + +impl<'w> RenderApp<'w> { + pub fn new(world: &'w World) -> Self { + Self { + current_view: None, + world, + } + } + + /// Get the elapsed seconds since startup. + pub fn time(&self) -> f32 { + let time = self.world.resource::