diff --git a/src/camera.rs b/src/camera.rs index 33a64a0..588bfe9 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -22,12 +22,8 @@ impl Camera { } } -#[rustfmt::skip] pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 0.5, 0.5, - 0.0, 0.0, 0.0, 1.0, + 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0, ); unsafe impl bytemuck::Pod for CameraUniform {} diff --git a/src/main.rs b/src/main.rs index 7e14655..c085dac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ +use crate::model::parse_obj; use bytemuck::bytes_of; +use image::EncodableLayout; use std::collections::BTreeMap; use std::sync::Arc; +use tobj::LoadOptions; use tracing::info; use wgpu::util::DeviceExt; -use wgpu::{ - Backends, BufferUsages, FragmentState, IndexFormat, Instance, InstanceDescriptor, - PipelineCompilationOptions, -}; +use wgpu::{Backends, BufferUsages, Device, FragmentState, IndexFormat, Instance, InstanceDescriptor, PipelineCompilationOptions}; use winit::application::ApplicationHandler; use winit::event::{ElementState, MouseButton}; use winit::event_loop::{ActiveEventLoop, EventLoop}; @@ -15,6 +15,7 @@ use winit::platform::android::activity::AndroidApp; use winit::window::{Window, WindowAttributes, WindowId}; use zlog::LogLevel; use zlog::config::LoggerConfig; + pub mod camera; pub mod model; pub mod texture; @@ -39,10 +40,14 @@ struct WgpuRenderer<'surface> { vertex_buffer: wgpu::Buffer, index_buffer: wgpu::Buffer, diffuse_bind_group: wgpu::BindGroup, + + depth_texture: wgpu::Texture, + depth_texture_view: wgpu::TextureView, camera: camera::Camera, camera_uniform: camera::CameraUniform, camera_buffer: wgpu::Buffer, camera_bind_group: wgpu::BindGroup, + index_count: u32, } impl WgpuRenderer<'_> { @@ -65,17 +70,24 @@ impl WgpuRenderer<'_> { store: wgpu::StoreOp::Store, }, })], - depth_stencil_attachment: None, - timestamp_writes: None, + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.depth_texture_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), occlusion_query_set: None, + timestamp_writes: None, }); rpass.set_pipeline(&self.render_pipeline); - rpass.set_bind_group(0, &self.diffuse_bind_group, &[]); + rpass.set_bind_group(0, &self.diffuse_bind_group, &[]); rpass.set_bind_group(1, &self.camera_bind_group, &[]); rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); rpass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32); - rpass.draw_indexed(0..INDICIES.len() as u32, 0, 0..1); + rpass.draw_indexed(0..self.index_count, 0, 0..1); } self.queue.submit(Some(encoder.finish())); surface_texture.present() @@ -160,6 +172,8 @@ impl Vertex { } } static ICON: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/Badge.png")); +static PUMPKIN: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/Pumpkin.obj")); + impl WgpuState { fn new() -> Self { let backends = Backends::PRIMARY; @@ -277,7 +291,13 @@ impl WgpuState { unclipped_depth: false, conservative: false, }, - depth_stencil: None, + depth_stencil: Some(wgpu::DepthStencilState { + format: wgpu::TextureFormat::Depth32Float, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil: wgpu::StencilState::default(), + bias: wgpu::DepthBiasState::default(), + }), multisample: wgpu::MultisampleState { count: 1, mask: !0, @@ -314,16 +334,33 @@ impl WgpuState { }; surface.configure(&device, &surface_config); + let pumpkin = tobj::load_obj("Pumpkin.obj", &tobj::GPU_LOAD_OPTIONS).unwrap(); + let (vertices, indices) = parse_obj(&pumpkin.0); + let (depth_texture, depth_texture_view) = + create_depth_texture(&device, surface_config.width, surface_config.height); + let materials = pumpkin.1.unwrap(); + let diffuse_texture = texture::Texture::from_bytes(&device, &queue, ICON, "zenyx-icon").unwrap(); + let model = tobj::load_obj_buf( + &mut PUMPKIN.as_bytes(), + &LoadOptions { + triangulate: true, + single_index: true, + ..Default::default() + }, + |_| Ok(Default::default()), + ) + .unwrap(); + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Vertex buffer"), - contents: bytemuck::cast_slice(VERTICES.as_ref()), + contents: bytemuck::cast_slice(vertices.as_ref()), usage: BufferUsages::VERTEX, }); let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Index buffer"), - contents: bytemuck::cast_slice(&INDICIES), + contents: bytemuck::cast_slice(indices.as_ref()), usage: BufferUsages::INDEX, }); @@ -352,7 +389,7 @@ impl WgpuState { aspect: surface_config.width as f32 / surface_config.height as f32, fovy: 45.0, znear: 0.1, - zfar: 100.0, + zfar: 1000.0, }; let mut camera_uniform = camera::CameraUniform::default(); @@ -374,10 +411,12 @@ impl WgpuState { }); let render_pipeline = device.create_render_pipeline(&pipeline_descriptor); + WgpuRenderer { surface, surface_config, diffuse_bind_group, + depth_texture, render_pipeline, device, vertex_buffer, @@ -387,9 +426,40 @@ impl WgpuState { camera_uniform, camera_buffer, camera_bind_group, + index_count: indices.len() as u32, + depth_texture_view, } } + } + +fn create_depth_texture( + device: &wgpu::Device, + width: u32, + height: u32, +) -> (wgpu::Texture, wgpu::TextureView) { + let size = wgpu::Extent3d { + width, + height, + depth_or_array_layers: 1, + }; + + let desc = wgpu::TextureDescriptor { + label: Some("Depth Texture"), + size, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Depth32Float, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING, + view_formats: &[], + }; + + let texture = device.create_texture(&desc); + let view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + (texture, view) +} + static VERTICES: [Vertex; 4] = { [ Vertex { @@ -465,6 +535,9 @@ impl ApplicationHandler for App<'_> { let mut new_config = window_ctx.renderer.surface_config.clone(); new_config.width = size.width; new_config.height = size.height; + let (depth_texture, depth_view) = create_depth_texture(&window_ctx.renderer.device, size.width, size.height); + window_ctx.renderer.depth_texture = depth_texture; + window_ctx.renderer.depth_texture_view = depth_view; window_ctx .renderer diff --git a/src/model.rs b/src/model.rs index 542b391..d64f875 100644 --- a/src/model.rs +++ b/src/model.rs @@ -1,4 +1,8 @@ +use crate::Vertex; use crate::texture::Texture; +use cgmath::{Vector2, Vector3, Zero}; +use tobj::Model; + pub struct Material { pub name: String, pub diffuse_texture: Texture, @@ -12,3 +16,42 @@ pub struct Mesh { pub num_elements: u32, pub material: usize, } + +pub fn parse_obj(obj: &Vec) -> (Vec, Vec) { + let mut combined_vertices = Vec::new(); + let mut combined_indices = Vec::new(); + let mut vertex_offset = 0; + + for object in obj { + let mesh: &_ = &object.mesh; + let vertices: Vec = (0..mesh.positions.len() / 3) + .map(|i| Vertex { + position: Vector3::from([ + mesh.positions[i * 3], + mesh.positions[i * 3 + 1], + mesh.positions[i * 3 + 2], + ]), + color: cgmath::Vector3::from([1.0, 1.0, 1.0]), + normal: if !mesh.normals.is_empty() { + Vector3::from([ + mesh.normals[i * 3], + mesh.normals[i * 3 + 1], + mesh.normals[i * 3 + 2], + ]) + } else { + Vector3::zero() + }, + tex_coords: if !mesh.texcoords.is_empty() { + Vector2::from([mesh.texcoords[i * 2], mesh.texcoords[i * 2 + 1]]) + } else { + Vector2::zero() + }, + }) + .collect(); + combined_vertices.extend(vertices); + combined_indices.extend(mesh.indices.iter().map(|&index| index + vertex_offset)); + vertex_offset += (mesh.positions.len() as u32) / 3; + } + + (combined_vertices, combined_indices) +}