diff --git a/src/cube.rs b/src/cube.rs index e01a166..0a55491 100644 --- a/src/cube.rs +++ b/src/cube.rs @@ -1,63 +1,61 @@ use crate::vertex::Vertex; +#[rustfmt::skip] pub const VERTICES: &[Vertex] = &[ - Vertex { - position: [-0.5, -0.5, -0.5], - texture_coordinates: [0.0, 0.0], - }, // 0 - Vertex { - position: [-0.5, -0.5, 0.5], - texture_coordinates: [0.0, 1.0], - }, // 1 - Vertex { - position: [-0.5, 0.5, 0.5], - texture_coordinates: [1.0, 1.0], - }, // 2 - Vertex { - position: [-0.5, 0.5, -0.5], - texture_coordinates: [1.0, 0.0], - }, // 3 - Vertex { - position: [0.5, -0.5, -0.5], - texture_coordinates: [1.0, 1.0], - }, // 4 - Vertex { - position: [0.5, -0.5, 0.5], - texture_coordinates: [1.0, 0.0], - }, // 5 - Vertex { - position: [0.5, 0.5, 0.5], - texture_coordinates: [0.0, 0.0], - }, // 6 - Vertex { - position: [0.5, 0.5, -0.5], - texture_coordinates: [0.0, 1.0], - }, // 7 + // Left + Vertex { position: [-1.0, -1.0, -1.0], texture_coordinates: [1.0, 1.0], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [-1.0, -1.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [-1.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [-1.0, 0.0, 0.0] }, + Vertex { position: [-1.0, 1.0, -1.0], texture_coordinates: [1.0, 0.0], normal: [-1.0, 0.0, 0.0] }, + + // Right + Vertex { position: [ 1.0, -1.0, -1.0], texture_coordinates: [0.0, 1.0], normal: [ 1.0, 0.0, 0.0] }, + Vertex { position: [ 1.0, -1.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 1.0, 0.0, 0.0] }, + Vertex { position: [ 1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.0], normal: [ 1.0, 0.0, 0.0] }, + Vertex { position: [ 1.0, 1.0, -1.0], texture_coordinates: [0.0, 0.0], normal: [ 1.0, 0.0, 0.0] }, + + // Back + Vertex { position: [-1.0, -1.0, -1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 0.0, -1.0] }, + Vertex { position: [-1.0, 1.0, -1.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 0.0, -1.0] }, + Vertex { position: [ 1.0, 1.0, -1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, -1.0] }, + Vertex { position: [ 1.0, -1.0, -1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 0.0, -1.0] }, + + // Front + Vertex { position: [-1.0, -1.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 0.0, 1.0] }, + Vertex { position: [-1.0, 1.0, 1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 0.0, 1.0] }, + Vertex { position: [ 1.0, 1.0, 1.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 0.0, 1.0] }, + Vertex { position: [ 1.0, -1.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 0.0, 1.0] }, + + // Bottom + Vertex { position: [-1.0, -1.0, -1.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, -1.0, 0.0] }, + Vertex { position: [-1.0, -1.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, -1.0, 0.0] }, + Vertex { position: [ 1.0, -1.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, -1.0, 0.0] }, + Vertex { position: [ 1.0, -1.0, -1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, -1.0, 0.0] }, + + // Top + Vertex { position: [ -1.0, 1.0, -1.0], texture_coordinates: [0.0, 0.0], normal: [ 0.0, 1.0, 0.0] }, + Vertex { position: [ -1.0, 1.0, 1.0], texture_coordinates: [0.0, 1.0], normal: [ 0.0, 1.0, 0.0] }, + Vertex { position: [ 1.0, 1.0, 1.0], texture_coordinates: [1.0, 1.0], normal: [ 0.0, 1.0, 0.0] }, + Vertex { position: [ 1.0, 1.0, -1.0], texture_coordinates: [1.0, 0.0], normal: [ 0.0, 1.0, 0.0] }, ]; #[rustfmt::skip] pub const INDICES: &[u16] = &[ - // left - 0, 1, 2, - 0, 2, 3, + 2, 0, 1, + 3, 0, 2, - // bottom - 1, 0, 4, - 1, 4, 5, + 5, 4, 6, + 6, 4, 7, - // right - 5, 7, 6, - 5, 4, 7, + 10, 8, 9, + 11, 8, 10, - // top - 3, 2, 6, - 3, 6, 7, + 13, 12, 14, + 14, 12, 15, - // front - 2, 1, 5, - 2, 5, 6, + 16, 18, 17, + 16, 19, 18, - // back - 0, 3, 7, - 0, 7, 4, + 20, 21, 22, + 20, 22, 23, ]; diff --git a/src/instance.rs b/src/instance.rs new file mode 100644 index 0000000..5b2b833 --- /dev/null +++ b/src/instance.rs @@ -0,0 +1,53 @@ +pub struct Instance { + pub position: cgmath::Vector3, + pub rotation: cgmath::Quaternion, +} + +#[repr(C)] +#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] +pub struct InstanceRaw { + model: [[f32; 4]; 4], +} + +impl Instance { + pub fn to_raw(&self) -> InstanceRaw { + let position = cgmath::Matrix4::from_translation(self.position); + let rotation = cgmath::Matrix4::from(self.rotation); + + InstanceRaw { + model: (position * rotation).into(), + } + } +} + +impl InstanceRaw { + pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + use std::mem; + wgpu::VertexBufferLayout { + array_stride: mem::size_of::() as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Instance, + attributes: &[ + wgpu::VertexAttribute { + offset: 0, + shader_location: 5, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 4]>() as wgpu::BufferAddress, + shader_location: 6, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 8]>() as wgpu::BufferAddress, + shader_location: 7, + format: wgpu::VertexFormat::Float32x4, + }, + wgpu::VertexAttribute { + offset: mem::size_of::<[f32; 12]>() as wgpu::BufferAddress, + shader_location: 8, + format: wgpu::VertexFormat::Float32x4, + }, + ], + } + } +} diff --git a/src/light.rs b/src/light.rs index 66e6a38..a01471e 100644 --- a/src/light.rs +++ b/src/light.rs @@ -1,7 +1,7 @@ #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct Light { - position: [f32; 3], - _padding: u32, - color: [f32; 3], + pub position: [f32; 3], + pub _padding: u32, + pub color: [f32; 3], } diff --git a/src/main.rs b/src/main.rs index a540c87..b36a4d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,7 @@ mod camera; mod cube; +mod instance; +mod light; mod state; mod texture; mod uniforms; @@ -7,6 +9,7 @@ mod vertex; use std::time::Instant; use winit::{ + dpi::{PhysicalSize, Size}, event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::WindowBuilder, @@ -18,7 +21,11 @@ fn main() { env_logger::init(); let event_loop = EventLoop::new(); let window = WindowBuilder::new() - .with_title("\u{1f980}\u{1f980}\u{1f980}\u{1f980}\u{1f980}") + .with_title(r#"minecrab"#) + .with_inner_size(Size::Physical(PhysicalSize { + width: 1280, + height: 720, + })) .build(&event_loop) .unwrap(); diff --git a/src/shader.wgsl b/src/shader.wgsl index 83e53b3..22e567f 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,28 +1,60 @@ [[block]] struct Uniforms { - view_proj: mat4x4; + view_position: vec4; + view_projection: mat4x4; +}; + +[[block]] +struct Light { + position: vec3; + color: vec3; }; [[group(1), binding(0)]] var uniforms: Uniforms; +[[group(2), binding(0)]] +var light: Light; + struct VertexInput { [[location(0)]] position: vec3; [[location(1)]] texture_coordinates: vec2; + [[location(2)]] normal: vec3; }; struct VertexOutput { [[builtin(position)]] clip_position: vec4; [[location(0)]] texture_coordinates: vec2; + [[location(1)]] world_normal: vec3; + [[location(2)]] world_position: vec3; }; +struct InstanceInput { + [[location(5)]] model_matrix_0: vec4; + [[location(6)]] model_matrix_1: vec4; + [[location(7)]] model_matrix_2: vec4; + [[location(8)]] model_matrix_3: vec4; +}; + + [[stage(vertex)]] -fn main( - model: VertexInput, -) -> VertexOutput { +fn main(model: VertexInput, instance: InstanceInput) -> VertexOutput { + let model_matrix = mat4x4( + instance.model_matrix_0, + instance.model_matrix_1, + instance.model_matrix_2, + instance.model_matrix_3, + ); + var out: VertexOutput; out.texture_coordinates = model.texture_coordinates; - out.clip_position = uniforms.view_proj * vec4(model.position, 1.0); + out.world_normal = model.normal; + + var world_position: vec4 = model_matrix * vec4(model.position, 1.0); + out.world_position = world_position.xyz; + + out.clip_position = uniforms.view_projection * model_matrix * vec4(model.position, 1.0); + return out; } @@ -34,5 +66,21 @@ var s_diffuse: sampler; [[stage(fragment)]] fn main(in: VertexOutput) -> [[location(0)]] vec4 { - return textureSample(t_diffuse, s_diffuse, in.texture_coordinates); + let object_color: vec4 = textureSample(t_diffuse, s_diffuse, in.texture_coordinates); + + let ambient_strength = 0.2; + let ambient_color = light.color * ambient_strength; + + let light_direction = normalize(light.position - in.world_position); + let view_direction = normalize(uniforms.view_position.xyz - in.world_position); + let half_direction = normalize(view_direction + light_direction); + + let diffuse_strength = max(dot(in.world_normal, light_direction), 0.0); + let diffuse_color = light.color * diffuse_strength; + + let specular_strength = pow(max(dot(in.world_normal, half_direction), 0.0), 32.0); + let specular_color = specular_strength * light.color; + + let result = (ambient_color + diffuse_color + specular_color) * object_color.xyz; + return vec4(result, object_color.a); } diff --git a/src/state.rs b/src/state.rs index 95f3717..ee2ea12 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,7 +1,23 @@ +use cgmath::Rotation3; use wgpu::util::DeviceExt; use winit::{event::WindowEvent, window::Window}; -use crate::{camera::Camera, cube, texture::Texture, uniforms::Uniforms, vertex::Vertex}; +use crate::{ + camera::Camera, + cube, + instance::{Instance, InstanceRaw}, + light::Light, + texture::Texture, + uniforms::Uniforms, + vertex::Vertex, +}; + +const NUM_INSTANCES_PER_ROW: u32 = 10; +const INSTANCE_DISPLACEMENT: cgmath::Vector3 = cgmath::Vector3::new( + NUM_INSTANCES_PER_ROW as f32 * 1.5, + 0.0, + NUM_INSTANCES_PER_ROW as f32 * 1.5, +); pub struct State { pub render_surface: wgpu::Surface, @@ -18,9 +34,72 @@ pub struct State { pub _uniforms: Uniforms, pub _camera: Camera, pub uniform_bind_group: wgpu::BindGroup, + pub instances: Vec, + pub instance_buffer: wgpu::Buffer, + depth_texture: Texture, + light: Light, + light_buffer: wgpu::Buffer, + light_bind_group: wgpu::BindGroup, } impl State { + fn create_render_pipeline( + device: &wgpu::Device, + layout: &wgpu::PipelineLayout, + color_format: wgpu::TextureFormat, + depth_format: Option, + vertex_layouts: &[wgpu::VertexBufferLayout], + shader: wgpu::ShaderModuleDescriptor, + ) -> wgpu::RenderPipeline { + let shader = device.create_shader_module(&shader); + + device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: Some("Render Pipeline"), + layout: Some(&layout), + vertex: wgpu::VertexState { + module: &shader, + entry_point: "main", + buffers: vertex_layouts, + }, + fragment: Some(wgpu::FragmentState { + module: &shader, + entry_point: "main", + targets: &[wgpu::ColorTargetState { + format: color_format, + blend: Some(wgpu::BlendState { + alpha: wgpu::BlendComponent::REPLACE, + color: wgpu::BlendComponent::REPLACE, + }), + write_mask: wgpu::ColorWrite::ALL, + }], + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: Some(wgpu::Face::Back), + // Setting this to anything other than Fill requires Features::NON_FILL_POLYGON_MODE + polygon_mode: wgpu::PolygonMode::Fill, + // Requires Features::DEPTH_CLAMPING + clamp_depth: false, + // Requires Features::CONSERVATIVE_RASTERIZATION + conservative: false, + }, + depth_stencil: depth_format.map(|format| wgpu::DepthStencilState { + format, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), + multisample: wgpu::MultisampleState { + count: 1, + mask: !0, + alpha_to_coverage_enabled: false, + }, + }) + } + pub async fn new(window: &Window) -> Self { let size = window.inner_size(); @@ -53,14 +132,14 @@ impl State { .unwrap(), width: size.width, height: size.height, - present_mode: wgpu::PresentMode::Immediate, + present_mode: wgpu::PresentMode::Fifo, }; let swap_chain = render_device.create_swap_chain(&render_surface, &swap_chain_descriptor); let dirt_diffuse_texture = Texture::from_bytes( &render_device, &queue, - include_bytes!("../assets/block/dirt.png"), + include_bytes!("../assets/block/cobblestone.png"), "dirt_diffuse", ) .unwrap(); @@ -106,15 +185,15 @@ impl State { ], }); - let shader = render_device.create_shader_module(&wgpu::ShaderModuleDescriptor { + let shader = wgpu::ShaderModuleDescriptor { label: Some("shader"), flags: wgpu::ShaderFlags::all(), source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), - }); + }; let aspect = swap_chain_descriptor.width as f32 / swap_chain_descriptor.height as f32; let camera = Camera { - eye: (0.0, 1.0, 2.0).into(), // position the camera one unit up and 2 units back + eye: (0.0, 5.0, 10.0).into(), // position the camera one unit up and 2 units back target: (0.0, 0.0, 0.0).into(), // have it look at the origin up: cgmath::Vector3::unit_y(), aspect, @@ -136,7 +215,7 @@ impl State { render_device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, - visibility: wgpu::ShaderStage::VERTEX, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, ty: wgpu::BindingType::Buffer { ty: wgpu::BufferBindingType::Uniform, has_dynamic_offset: false, @@ -147,50 +226,62 @@ impl State { label: Some("uniform_bind_group_layout"), }); + let light = Light { + position: [5.0, 5.0, 5.0], + _padding: 0, + color: [1.0, 1.0, 1.0], + }; + + // We'll want to update our lights position, so we use COPY_DST + let light_buffer = render_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("light_buffer"), + contents: bytemuck::cast_slice(&[light]), + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + let light_bind_group_layout = + render_device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: None, + }); + + let light_bind_group = render_device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &light_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: light_buffer.as_entire_binding(), + }], + label: None, + }); + let render_pipeline_layout = render_device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("render_pipeline_layout"), - bind_group_layouts: &[&texture_bind_group_layout, &uniform_bind_group_layout], + bind_group_layouts: &[ + &texture_bind_group_layout, + &uniform_bind_group_layout, + &light_bind_group_layout, + ], push_constant_ranges: &[], }); - let render_pipeline = - render_device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("render_pipeline"), - layout: Some(&render_pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "main", - buffers: &[Vertex::desc()], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "main", - targets: &[wgpu::ColorTargetState { - format: swap_chain_descriptor.format, - blend: Some(wgpu::BlendState { - color: wgpu::BlendComponent::REPLACE, - alpha: wgpu::BlendComponent::REPLACE, - }), - write_mask: wgpu::ColorWrite::ALL, - }], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: Some(wgpu::Face::Back), - polygon_mode: wgpu::PolygonMode::Fill, - clamp_depth: false, - conservative: false, - }, - depth_stencil: None, - multisample: wgpu::MultisampleState { - count: 1, - mask: !0, - alpha_to_coverage_enabled: false, - }, - }); + let render_pipeline = Self::create_render_pipeline( + &render_device, + &render_pipeline_layout, + swap_chain_descriptor.format, + Some(Texture::DEPTH_FORMAT), + &[Vertex::desc(), InstanceRaw::desc()], + shader, + ); let vertex_buffer = render_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("vertex_buffer"), @@ -213,6 +304,35 @@ impl State { label: Some("uniform_bind_group"), }); + let instances = (0..NUM_INSTANCES_PER_ROW) + .flat_map(|z| { + (0..NUM_INSTANCES_PER_ROW).map(move |x| { + let position = cgmath::Vector3 { + x: x as f32 * 3.0, + y: 0.0, + z: z as f32 * 3.0, + } - INSTANCE_DISPLACEMENT; + + let rotation = cgmath::Quaternion::from_axis_angle( + cgmath::Vector3::unit_z(), + cgmath::Deg(0.0), + ); + + Instance { position, rotation } + }) + }) + .collect::>(); + + let instance_data = instances.iter().map(Instance::to_raw).collect::>(); + let instance_buffer = render_device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Instance Buffer"), + contents: bytemuck::cast_slice(&instance_data), + usage: wgpu::BufferUsage::VERTEX, + }); + + let depth_texture = + Texture::create_depth_texture(&render_device, &swap_chain_descriptor, "depth_texture"); + Self { render_surface, render_device, @@ -228,6 +348,12 @@ impl State { _camera: camera, uniform_bind_group, texture_bind_group, + instances, + instance_buffer, + depth_texture, + light, + light_buffer, + light_bind_group, } } @@ -236,6 +362,13 @@ impl State { self.size = new_size; self.swap_chain_descriptor.width = new_size.width; self.swap_chain_descriptor.height = new_size.height; + + self.depth_texture = Texture::create_depth_texture( + &self.render_device, + &self.swap_chain_descriptor, + "depth_texture", + ); + self.swap_chain = self .render_device .create_swap_chain(&self.render_surface, &self.swap_chain_descriptor); @@ -246,7 +379,15 @@ impl State { false } - pub fn update(&mut self) {} + pub fn update(&mut self) { + let old_position: cgmath::Vector3<_> = self.light.position.into(); + self.light.position = + (cgmath::Quaternion::from_axis_angle((0.0, 1.0, 0.0).into(), cgmath::Deg(1.0)) + * old_position) + .into(); + self.queue + .write_buffer(&self.light_buffer, 0, bytemuck::cast_slice(&[self.light])); + } pub fn render(&mut self) -> Result<(), wgpu::SwapChainError> { let frame = self.swap_chain.get_current_frame()?.output; @@ -264,22 +405,32 @@ impl State { view: &frame.view, resolve_target: None, ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color::BLACK), + load: wgpu::LoadOp::Clear(wgpu::Color::BLUE), store: true, }, }], - depth_stencil_attachment: None, + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }), }); render_pass.set_pipeline(&self.render_pipeline); render_pass.set_bind_group(0, &self.texture_bind_group, &[]); render_pass.set_bind_group(1, &self.uniform_bind_group, &[]); + render_pass.set_bind_group(2, &self.light_bind_group, &[]); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); + render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); + render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); - render_pass.draw_indexed(0..self.num_indices, 0, 0..1); + render_pass.draw_indexed(0..self.num_indices, 0, 0..self.instances.len() as _); } self.queue.submit(std::iter::once(render_encoder.finish())); diff --git a/src/texture.rs b/src/texture.rs index 7773b91..04cb238 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -1,5 +1,7 @@ use std::num::NonZeroU32; +use image::EncodableLayout; + pub struct Texture { pub texture: wgpu::Texture, pub sampler: wgpu::Sampler, @@ -7,6 +9,50 @@ pub struct Texture { } impl Texture { + pub const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + + pub fn create_depth_texture( + device: &wgpu::Device, + swap_chain_descriptor: &wgpu::SwapChainDescriptor, + label: &str, + ) -> Self { + let size = wgpu::Extent3d { + width: swap_chain_descriptor.width, + height: swap_chain_descriptor.height, + depth_or_array_layers: 1, + }; + + let texture = device.create_texture(&wgpu::TextureDescriptor { + label: Some(label), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsage::RENDER_ATTACHMENT | wgpu::TextureUsage::SAMPLED, + }); + + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + let sampler = device.create_sampler(&wgpu::SamplerDescriptor { + address_mode_u: wgpu::AddressMode::ClampToEdge, + address_mode_v: wgpu::AddressMode::ClampToEdge, + address_mode_w: wgpu::AddressMode::ClampToEdge, + mag_filter: wgpu::FilterMode::Linear, + min_filter: wgpu::FilterMode::Linear, + mipmap_filter: wgpu::FilterMode::Nearest, + compare: Some(wgpu::CompareFunction::LessEqual), // 5. + lod_min_clamp: -100.0, + lod_max_clamp: 100.0, + ..Default::default() + }); + + Self { + texture, + sampler, + view, + } + } + pub fn from_bytes( device: &wgpu::Device, queue: &wgpu::Queue, @@ -14,7 +60,7 @@ impl Texture { label: &str, ) -> anyhow::Result { let image = image::load_from_memory(bytes)?; - let rgba = image.as_rgba8().unwrap(); + let rgba = image.into_rgba8(); let (width, height) = rgba.dimensions(); let texture_size = wgpu::Extent3d { @@ -39,7 +85,7 @@ impl Texture { mip_level: 0, origin: wgpu::Origin3d::ZERO, }, - rgba, + rgba.as_bytes(), wgpu::ImageDataLayout { offset: 0, bytes_per_row: NonZeroU32::new(4 * width), diff --git a/src/uniforms.rs b/src/uniforms.rs index 1e0ef39..6d1d14c 100644 --- a/src/uniforms.rs +++ b/src/uniforms.rs @@ -5,19 +5,20 @@ use crate::camera::Camera; #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] pub struct Uniforms { - // We can't use cgmath with bytemuck directly so we'll have - // to convert the Matrix4 into a 4x4 f32 array + view_position: [f32; 4], view_projection: [[f32; 4]; 4], } impl Uniforms { pub fn new() -> Self { Self { + view_position: [0.0; 4], view_projection: cgmath::Matrix4::identity().into(), } } pub fn update_view_proj(&mut self, camera: &Camera) { + self.view_position = camera.eye.to_homogeneous().into(); self.view_projection = camera.build_view_projection_matrix().into(); } } diff --git a/src/vertex.rs b/src/vertex.rs index 367ca1b..3b1edc8 100644 --- a/src/vertex.rs +++ b/src/vertex.rs @@ -5,6 +5,7 @@ use std::mem::size_of; pub struct Vertex { pub position: [f32; 3], pub texture_coordinates: [f32; 2], + pub normal: [f32; 3], } impl Vertex { @@ -23,6 +24,11 @@ impl Vertex { shader_location: 1, format: wgpu::VertexFormat::Float32x2, }, + wgpu::VertexAttribute { + offset: size_of::<[f32; 3 + 2]>() as wgpu::BufferAddress, + shader_location: 2, + format: wgpu::VertexFormat::Float32x3, + }, ], } }