From cd60778d462f427e1c5d6ab27bda27c4e4c6162b Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 30 Nov 2019 17:42:27 -0800 Subject: [PATCH] use wgpu example as base --- Cargo.toml | 12 +- examples/simple.rs | 19 +- src/application.rs | 851 ++++++++++++++++++++++++++++---- src/lib.rs | 2 + src/render/bake/bake.frag | 4 + src/render/bake/bake.vert | 16 + src/render/forward/forward.frag | 62 +++ src/render/forward/forward.vert | 22 + src/render/lib.rs | 0 src/shader.frag | 7 - src/shader.frag.spv | Bin 352 -> 0 bytes src/shader.vert | 15 - src/shader.vert.spv | Bin 904 -> 0 bytes src/temp.rs | 126 +++++ src/vertex.rs | 97 ++++ 15 files changed, 1098 insertions(+), 135 deletions(-) create mode 100644 src/render/bake/bake.frag create mode 100644 src/render/bake/bake.vert create mode 100644 src/render/forward/forward.frag create mode 100644 src/render/forward/forward.vert create mode 100644 src/render/lib.rs delete mode 100644 src/shader.frag delete mode 100644 src/shader.frag.spv delete mode 100644 src/shader.vert delete mode 100644 src/shader.vert.spv create mode 100644 src/temp.rs create mode 100644 src/vertex.rs diff --git a/Cargo.toml b/Cargo.toml index 7785b69f4e..4ad3a922f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,8 +5,12 @@ authors = ["Carter Anderson "] edition = "2018" [dependencies] -# legion = { git = "https://github.com/TomGillen/legion.git" } -legion = { git = "https://github.com/jaynus/legion.git" } +legion = { git = "https://github.com/TomGillen/legion.git" } nalgebra = "0.18" -wgpu = "0.4.0" -winit = "0.20.0-alpha4" \ No newline at end of file +wgpu = { git = "https://github.com/gfx-rs/wgpu-rs.git", rev = "44fa1bc2fa208fa92f80944253e0da56cb7ac1fe"} +winit = "0.20.0-alpha4" +glsl-to-spirv = "0.1" +cgmath = "0.17" +zerocopy = "0.2" +log = "0.4" +env_logger = "0.7" \ No newline at end of file diff --git a/examples/simple.rs b/examples/simple.rs index 93ce194016..df72902b34 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,18 +1,21 @@ -use legion::prelude::*; use bevy::{Application, Transform}; - +use legion::prelude::*; struct SimpleApp; -impl Application for SimpleApp { - fn update(&self) {} -} - fn main() { - let app = SimpleApp {}; + Application::run(); // Create a world to store our entities let universe = Universe::new(); let mut world = universe.create_world(); world.insert((), vec![(Transform::new(),)]); - app.start(); + + // Create a query which finds all `Position` and `Velocity` components + let mut query = Read::::query(); + + + // // Iterate through all entities that match the query in the world + for mut trans in query.iter(&mut world) { + // println!("{} hi", trans.global); + } } diff --git a/src/application.rs b/src/application.rs index deb84aaf7f..c25cef7fb0 100644 --- a/src/application.rs +++ b/src/application.rs @@ -1,26 +1,712 @@ use winit::{ event, + event::WindowEvent, event_loop::{ControlFlow, EventLoop}, }; -pub trait Application { - fn start(&self) { - let event_loop = EventLoop::new(); +use zerocopy::{AsBytes, FromBytes}; - let (_window, size, surface) = { - let window = winit::window::Window::new(&event_loop).unwrap(); - let size = window.inner_size().to_physical(window.hidpi_factor()); +use std::rc::Rc; +use std::mem; - let surface = wgpu::Surface::create(&window); - (window, size, surface) +use crate::temp::*; +use crate::vertex::*; + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(unused)] +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.0, + 0.0, 0.0, 0.5, 1.0, +); + +#[allow(dead_code)] +pub fn cast_slice(data: &[T]) -> &[u8] { + use std::mem::size_of; + use std::slice::from_raw_parts; + + unsafe { from_raw_parts(data.as_ptr() as *const u8, data.len() * size_of::()) } +} + +pub struct Application +{ + entities: Vec, + lights: Vec, + lights_are_dirty: bool, + shadow_pass: Pass, + forward_pass: Pass, + forward_depth: wgpu::TextureView, + light_uniform_buf: wgpu::Buffer, +} + +impl Application { + const MAX_LIGHTS: usize = 10; + const SHADOW_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + const SHADOW_SIZE: wgpu::Extent3d = wgpu::Extent3d { + width: 512, + height: 512, + depth: 1, + }; + const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth32Float; + + fn init( + sc_desc: &wgpu::SwapChainDescriptor, + device: &wgpu::Device, + ) -> (Self, Option) + { + let vertex_size = mem::size_of::(); + let (cube_vertex_data, cube_index_data) = create_cube(); + let cube_vertex_buf = Rc::new( + device.create_buffer_with_data(cube_vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX), + ); + + let cube_index_buf = Rc::new( + device.create_buffer_with_data(cube_index_data.as_bytes(), wgpu::BufferUsage::INDEX), + ); + + let (plane_vertex_data, plane_index_data) = create_plane(7); + let plane_vertex_buf = + device.create_buffer_with_data(plane_vertex_data.as_bytes(), wgpu::BufferUsage::VERTEX); + + let plane_index_buf = + device.create_buffer_with_data(plane_index_data.as_bytes(), wgpu::BufferUsage::INDEX); + + let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; + let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + size: entity_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + let local_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + + let mut entities = vec![{ + use cgmath::SquareMatrix; + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &local_bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &plane_uniform_buf, + range: 0 .. entity_uniform_size, + }, + }], + }); + Entity { + mx_world: cgmath::Matrix4::identity(), + rotation_speed: 0.0, + color: wgpu::Color::WHITE, + vertex_buf: Rc::new(plane_vertex_buf), + index_buf: Rc::new(plane_index_buf), + index_count: plane_index_data.len(), + bind_group, + uniform_buf: plane_uniform_buf, + } + }]; + + struct CubeDesc { + offset: cgmath::Vector3, + angle: f32, + scale: f32, + rotation: f32, + } + let cube_descs = [ + CubeDesc { + offset: cgmath::vec3(-2.0, -2.0, 2.0), + angle: 10.0, + scale: 0.7, + rotation: 0.1, + }, + CubeDesc { + offset: cgmath::vec3(2.0, -2.0, 2.0), + angle: 50.0, + scale: 1.3, + rotation: 0.2, + }, + CubeDesc { + offset: cgmath::vec3(-2.0, 2.0, 2.0), + angle: 140.0, + scale: 1.1, + rotation: 0.3, + }, + CubeDesc { + offset: cgmath::vec3(2.0, 2.0, 2.0), + angle: 210.0, + scale: 0.9, + rotation: 0.4, + }, + ]; + + for cube in &cube_descs { + use cgmath::{Decomposed, Deg, InnerSpace, Quaternion, Rotation3}; + + let transform = Decomposed { + disp: cube.offset.clone(), + rot: Quaternion::from_axis_angle(cube.offset.normalize(), Deg(cube.angle)), + scale: cube.scale, + }; + let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + size: entity_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + entities.push(Entity { + mx_world: cgmath::Matrix4::from(transform), + rotation_speed: cube.rotation, + color: wgpu::Color::GREEN, + vertex_buf: Rc::clone(&cube_vertex_buf), + index_buf: Rc::clone(&cube_index_buf), + index_count: cube_index_data.len(), + bind_group: device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &local_bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0 .. entity_uniform_size, + }, + }], + }), + uniform_buf, + }); + } + + // Create other resources + let shadow_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, + lod_min_clamp: -100.0, + lod_max_clamp: 100.0, + compare_function: wgpu::CompareFunction::LessEqual, + }); + + let shadow_texture = device.create_texture(&wgpu::TextureDescriptor { + size: Self::SHADOW_SIZE, + array_layer_count: Self::MAX_LIGHTS as u32, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::SHADOW_FORMAT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, + }); + let shadow_view = shadow_texture.create_default_view(); + + let mut shadow_target_views = (0 .. 2) + .map(|i| { + Some(shadow_texture.create_view(&wgpu::TextureViewDescriptor { + format: Self::SHADOW_FORMAT, + dimension: wgpu::TextureViewDimension::D2, + aspect: wgpu::TextureAspect::All, + base_mip_level: 0, + level_count: 1, + base_array_layer: i as u32, + array_layer_count: 1, + })) + }) + .collect::>(); + let lights = vec![ + Light { + pos: cgmath::Point3::new(7.0, -5.0, 10.0), + color: wgpu::Color { + r: 0.5, + g: 1.0, + b: 0.5, + a: 1.0, + }, + fov: 60.0, + depth: 1.0 .. 20.0, + target_view: shadow_target_views[0].take().unwrap(), + }, + Light { + pos: cgmath::Point3::new(-5.0, 7.0, 10.0), + color: wgpu::Color { + r: 1.0, + g: 0.5, + b: 0.5, + a: 1.0, + }, + fov: 45.0, + depth: 1.0 .. 20.0, + target_view: shadow_target_views[1].take().unwrap(), + }, + ]; + let light_uniform_size = + (Self::MAX_LIGHTS * mem::size_of::()) as wgpu::BufferAddress; + let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + size: light_uniform_size, + usage: wgpu::BufferUsage::UNIFORM + | wgpu::BufferUsage::COPY_SRC + | wgpu::BufferUsage::COPY_DST, + }); + + let vb_desc = wgpu::VertexBufferDescriptor { + stride: vertex_size as wgpu::BufferAddress, + step_mode: wgpu::InputStepMode::Vertex, + attributes: &[ + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Char4, + offset: 0, + shader_location: 0, + }, + wgpu::VertexAttributeDescriptor { + format: wgpu::VertexFormat::Char4, + offset: 4 * 1, + shader_location: 1, + }, + ], }; - let adapter = wgpu::Adapter::request(&wgpu::RequestAdapterOptions { - power_preference: wgpu::PowerPreference::Default, - backends: wgpu::BackendBit::PRIMARY, - }) - .unwrap(); + let shadow_pass = { + // Create pipeline layout + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[wgpu::BindGroupLayoutBinding { + binding: 0, // global + visibility: wgpu::ShaderStage::VERTEX, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }], + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout, &local_bind_group_layout], + }); + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + size: uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + }); + + // Create bind group + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0 .. uniform_size, + }, + }], + }); + + // Create the render pipeline + let vs_bytes = + load_glsl(include_str!("render/bake/bake.vert"), ShaderStage::Vertex); + let fs_bytes = + load_glsl(include_str!("render/bake/bake.frag"), ShaderStage::Fragment); + let vs_module = device.create_shader_module(&vs_bytes); + let fs_module = device.create_shader_module(&fs_bytes); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &pipeline_layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::Back, + depth_bias: 2, // corresponds to bilinear filtering + depth_bias_slope_scale: 2.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[], + depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { + format: Self::SHADOW_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::LessEqual, + stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[vb_desc.clone()], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + Pass { + pipeline, + bind_group, + uniform_buf, + } + }; + + let forward_pass = { + // Create pipeline layout + let bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + bindings: &[ + wgpu::BindGroupLayoutBinding { + binding: 0, // global + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + wgpu::BindGroupLayoutBinding { + binding: 1, // lights + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { dynamic: false }, + }, + wgpu::BindGroupLayoutBinding { + binding: 2, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::SampledTexture { + multisampled: false, + dimension: wgpu::TextureViewDimension::D2Array, + }, + }, + wgpu::BindGroupLayoutBinding { + binding: 3, + visibility: wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::Sampler, + }, + ], + }); + let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + bind_group_layouts: &[&bind_group_layout, &local_bind_group_layout], + }); + + let mx_total = generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let forward_uniforms = ForwardUniforms { + proj: *mx_total.as_ref(), + num_lights: [lights.len() as u32, 0, 0, 0], + }; + let uniform_size = mem::size_of::() as wgpu::BufferAddress; + let uniform_buf = device.create_buffer_with_data( + forward_uniforms.as_bytes(), + wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + ); + + // Create bind group + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &bind_group_layout, + bindings: &[ + wgpu::Binding { + binding: 0, + resource: wgpu::BindingResource::Buffer { + buffer: &uniform_buf, + range: 0 .. uniform_size, + }, + }, + wgpu::Binding { + binding: 1, + resource: wgpu::BindingResource::Buffer { + buffer: &light_uniform_buf, + range: 0 .. light_uniform_size, + }, + }, + wgpu::Binding { + binding: 2, + resource: wgpu::BindingResource::TextureView(&shadow_view), + }, + wgpu::Binding { + binding: 3, + resource: wgpu::BindingResource::Sampler(&shadow_sampler), + }, + ], + }); + + // Create the render pipeline + let vs_bytes = + load_glsl(include_str!("render/forward/forward.vert"), ShaderStage::Vertex); + let fs_bytes = + load_glsl(include_str!("render/forward/forward.frag"), ShaderStage::Fragment); + + let vs_module = device.create_shader_module(&vs_bytes); + let fs_module = device.create_shader_module(&fs_bytes); + + let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { + layout: &pipeline_layout, + vertex_stage: wgpu::ProgrammableStageDescriptor { + module: &vs_module, + entry_point: "main", + }, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), + rasterization_state: Some(wgpu::RasterizationStateDescriptor { + front_face: wgpu::FrontFace::Ccw, + cull_mode: wgpu::CullMode::Back, + depth_bias: 0, + depth_bias_slope_scale: 0.0, + depth_bias_clamp: 0.0, + }), + primitive_topology: wgpu::PrimitiveTopology::TriangleList, + color_states: &[wgpu::ColorStateDescriptor { + format: sc_desc.format, + color_blend: wgpu::BlendDescriptor::REPLACE, + alpha_blend: wgpu::BlendDescriptor::REPLACE, + write_mask: wgpu::ColorWrite::ALL, + }], + depth_stencil_state: Some(wgpu::DepthStencilStateDescriptor { + format: Self::DEPTH_FORMAT, + depth_write_enabled: true, + depth_compare: wgpu::CompareFunction::Less, + stencil_front: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_back: wgpu::StencilStateFaceDescriptor::IGNORE, + stencil_read_mask: 0, + stencil_write_mask: 0, + }), + index_format: wgpu::IndexFormat::Uint16, + vertex_buffers: &[vb_desc], + sample_count: 1, + sample_mask: !0, + alpha_to_coverage_enabled: false, + }); + + Pass { + pipeline, + bind_group, + uniform_buf, + } + }; + + let depth_texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: sc_desc.width, + height: sc_desc.height, + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); + + let this = Application { + entities, + lights, + lights_are_dirty: true, + shadow_pass, + forward_pass, + forward_depth: depth_texture.create_default_view(), + light_uniform_buf, + }; + (this, None) + } + + fn resize( + &mut self, + sc_desc: &wgpu::SwapChainDescriptor, + device: &wgpu::Device, + ) -> Option + { + let command_buf = { + let mx_total = generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_ref: &[f32; 16] = mx_total.as_ref(); + let temp_buf = + device.create_buffer_with_data(mx_ref.as_bytes(), wgpu::BufferUsage::COPY_SRC); + + let mut encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + encoder.copy_buffer_to_buffer(&temp_buf, 0, &self.forward_pass.uniform_buf, 0, 64); + encoder.finish() + }; + + let depth_texture = device.create_texture(&wgpu::TextureDescriptor { + size: wgpu::Extent3d { + width: sc_desc.width, + height: sc_desc.height, + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: Self::DEPTH_FORMAT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + }); + self.forward_depth = depth_texture.create_default_view(); + + Some(command_buf) + } + + fn update(&mut self, event: WindowEvent) + { + } + + fn render( + &mut self, + frame: &wgpu::SwapChainOutput, + device: &wgpu::Device, + ) -> wgpu::CommandBuffer + { + let mut encoder = + device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); + + { + let size = mem::size_of::(); + let temp_buf_data = device + .create_buffer_mapped(self.entities.len() * size, wgpu::BufferUsage::COPY_SRC); + + // FIXME: Align and use `LayoutVerified` + for (entity, slot) in self + .entities + .iter_mut() + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + if entity.rotation_speed != 0.0 { + let rotation = + cgmath::Matrix4::from_angle_x(cgmath::Deg(entity.rotation_speed)); + entity.mx_world = entity.mx_world * rotation; + } + slot.copy_from_slice( + EntityUniforms { + model: entity.mx_world.into(), + color: [ + entity.color.r as f32, + entity.color.g as f32, + entity.color.b as f32, + entity.color.a as f32, + ], + } + .as_bytes(), + ); + } + + let temp_buf = temp_buf_data.finish(); + + for (i, entity) in self.entities.iter().enumerate() { + encoder.copy_buffer_to_buffer( + &temp_buf, + (i * size) as wgpu::BufferAddress, + &entity.uniform_buf, + 0, + size as wgpu::BufferAddress, + ); + } + } + + if self.lights_are_dirty { + self.lights_are_dirty = false; + let size = mem::size_of::(); + let total_size = size * self.lights.len(); + let temp_buf_data = + device.create_buffer_mapped(total_size, wgpu::BufferUsage::COPY_SRC); + // FIXME: Align and use `LayoutVerified` + for (light, slot) in self + .lights + .iter() + .zip(temp_buf_data.data.chunks_exact_mut(size)) + { + slot.copy_from_slice(light.to_raw().as_bytes()); + } + encoder.copy_buffer_to_buffer( + &temp_buf_data.finish(), + 0, + &self.light_uniform_buf, + 0, + total_size as wgpu::BufferAddress, + ); + } + + for (i, light) in self.lights.iter().enumerate() { + // The light uniform buffer already has the projection, + // let's just copy it over to the shadow uniform buffer. + encoder.copy_buffer_to_buffer( + &self.light_uniform_buf, + (i * mem::size_of::()) as wgpu::BufferAddress, + &self.shadow_pass.uniform_buf, + 0, + 64, + ); + + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &light.target_view, + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + clear_stencil: 0, + }), + }); + pass.set_pipeline(&self.shadow_pass.pipeline); + pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); + + for entity in &self.entities { + pass.set_bind_group(1, &entity.bind_group, &[]); + pass.set_index_buffer(&entity.index_buf, 0); + pass.set_vertex_buffers(0, &[(&entity.vertex_buf, 0)]); + pass.draw_indexed(0 .. entity.index_count as u32, 0, 0 .. 1); + } + } + + // forward pass + { + let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { + attachment: &frame.view, + resolve_target: None, + load_op: wgpu::LoadOp::Clear, + store_op: wgpu::StoreOp::Store, + clear_color: wgpu::Color { + r: 0.1, + g: 0.2, + b: 0.3, + a: 1.0, + }, + }], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &self.forward_depth, + depth_load_op: wgpu::LoadOp::Clear, + depth_store_op: wgpu::StoreOp::Store, + stencil_load_op: wgpu::LoadOp::Clear, + stencil_store_op: wgpu::StoreOp::Store, + clear_depth: 1.0, + clear_stencil: 0, + }), + }); + pass.set_pipeline(&self.forward_pass.pipeline); + pass.set_bind_group(0, &self.forward_pass.bind_group, &[]); + + for entity in &self.entities { + pass.set_bind_group(1, &entity.bind_group, &[]); + pass.set_index_buffer(&entity.index_buf, 0); + pass.set_vertex_buffers(0, &[(&entity.vertex_buf, 0)]); + pass.draw_indexed(0 .. entity.index_count as u32, 0, 0 .. 1); + } + } + + encoder.finish() + } + + #[allow(dead_code)] + pub fn run() { + env_logger::init(); + let event_loop = EventLoop::new(); + log::info!("Initializing the window..."); + + let adapter = wgpu::Adapter::request( + &wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::Default, + }, + wgpu::BackendBit::PRIMARY, + ) + .unwrap(); + let (device, mut queue) = adapter.request_device(&wgpu::DeviceDescriptor { extensions: wgpu::Extensions { anisotropic_filtering: false, @@ -28,67 +714,31 @@ pub trait Application { limits: wgpu::Limits::default(), }); - let vs = include_bytes!("shader.vert.spv"); - let vs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap()); - - let fs = include_bytes!("shader.frag.spv"); - let fs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap()); - - let bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[] }); - let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &bind_group_layout, - bindings: &[], - }); - let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - bind_group_layouts: &[&bind_group_layout], - }); - - let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - layout: &pipeline_layout, - vertex_stage: wgpu::ProgrammableStageDescriptor { - module: &vs_module, - entry_point: "main", - }, - fragment_stage: Some(wgpu::ProgrammableStageDescriptor { - module: &fs_module, - entry_point: "main", - }), - rasterization_state: Some(wgpu::RasterizationStateDescriptor { - front_face: wgpu::FrontFace::Ccw, - cull_mode: wgpu::CullMode::None, - depth_bias: 0, - depth_bias_slope_scale: 0.0, - depth_bias_clamp: 0.0, - }), - primitive_topology: wgpu::PrimitiveTopology::TriangleList, - color_states: &[wgpu::ColorStateDescriptor { - format: wgpu::TextureFormat::Bgra8UnormSrgb, - color_blend: wgpu::BlendDescriptor::REPLACE, - alpha_blend: wgpu::BlendDescriptor::REPLACE, - write_mask: wgpu::ColorWrite::ALL, - }], - depth_stencil_state: None, - index_format: wgpu::IndexFormat::Uint16, - vertex_buffers: &[], - sample_count: 1, - sample_mask: !0, - alpha_to_coverage_enabled: false, - }); - - let mut swap_chain = device.create_swap_chain( - &surface, - &wgpu::SwapChainDescriptor { - usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, - format: wgpu::TextureFormat::Bgra8UnormSrgb, - width: size.width.round() as u32, - height: size.height.round() as u32, - present_mode: wgpu::PresentMode::Vsync, - }, - ); - + let (_window, hidpi_factor, size, surface) = { + let window = winit::window::Window::new(&event_loop).unwrap(); + window.set_title("bevy"); + let hidpi_factor = window.hidpi_factor(); + let size = window.inner_size().to_physical(hidpi_factor); + let surface = wgpu::Surface::create(&window); + (window, hidpi_factor, size, surface) + }; + + let mut sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + format: wgpu::TextureFormat::Bgra8UnormSrgb, + width: size.width.round() as u32, + height: size.height.round() as u32, + present_mode: wgpu::PresentMode::Vsync, + }; + let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); + + log::info!("Initializing the example..."); + let (mut example, init_command_buf) = Application::init(&sc_desc, &device); + if let Some(command_buf) = init_command_buf { + queue.submit(&[command_buf]); + } + + log::info!("Entering render loop..."); event_loop.run(move |event, _, control_flow| { *control_flow = if cfg!(feature = "metal-auto-capture") { ControlFlow::Exit @@ -96,8 +746,22 @@ pub trait Application { ControlFlow::Poll }; match event { + event::Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + let physical = size.to_physical(hidpi_factor); + log::info!("Resizing to {:?}", physical); + sc_desc.width = physical.width.round() as u32; + sc_desc.height = physical.height.round() as u32; + swap_chain = device.create_swap_chain(&surface, &sc_desc); + let command_buf = example.resize(&sc_desc, &device); + if let Some(command_buf) = command_buf { + queue.submit(&[command_buf]); + } + } event::Event::WindowEvent { event, .. } => match event { - event::WindowEvent::KeyboardInput { + WindowEvent::KeyboardInput { input: event::KeyboardInput { virtual_keycode: Some(event::VirtualKeyCode::Escape), @@ -106,37 +770,22 @@ pub trait Application { }, .. } - | event::WindowEvent::CloseRequested => { + | WindowEvent::CloseRequested => { *control_flow = ControlFlow::Exit; } - _ => {} + _ => { + example.update(event); + } }, event::Event::EventsCleared => { - let frame = swap_chain.get_next_texture(); - let mut encoder = - device.create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }); - { - let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { - attachment: &frame.view, - resolve_target: None, - load_op: wgpu::LoadOp::Clear, - store_op: wgpu::StoreOp::Store, - clear_color: wgpu::Color::GREEN, - }], - depth_stencil_attachment: None, - }); - rpass.set_pipeline(&render_pipeline); - rpass.set_bind_group(0, &bind_group, &[]); - rpass.draw(0..3, 0..1); - } - - queue.submit(&[encoder.finish()]); + let frame = swap_chain + .get_next_texture() + .expect("Timeout when acquiring next swap chain texture"); + let command_buf = example.render(&frame, &device); + queue.submit(&[command_buf]); } _ => (), } - }); + }); } - - fn update(&self); -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1512568422..90d6d3e58c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,7 @@ mod transform; mod application; +mod vertex; +mod temp; pub use transform::Transform; pub use application::Application; \ No newline at end of file diff --git a/src/render/bake/bake.frag b/src/render/bake/bake.frag new file mode 100644 index 0000000000..f0bcb49bf9 --- /dev/null +++ b/src/render/bake/bake.frag @@ -0,0 +1,4 @@ +#version 450 + +void main() { +} diff --git a/src/render/bake/bake.vert b/src/render/bake/bake.vert new file mode 100644 index 0000000000..e4426b7455 --- /dev/null +++ b/src/render/bake/bake.vert @@ -0,0 +1,16 @@ +#version 450 + +layout(location = 0) in ivec4 a_Pos; + +layout(set = 0, binding = 0) uniform Globals { + mat4 u_ViewProj; +}; + +layout(set = 1, binding = 0) uniform Entity { + mat4 u_World; + vec4 u_Color; +}; + +void main() { + gl_Position = u_ViewProj * u_World * vec4(a_Pos); +} diff --git a/src/render/forward/forward.frag b/src/render/forward/forward.frag new file mode 100644 index 0000000000..fdd587ae6d --- /dev/null +++ b/src/render/forward/forward.frag @@ -0,0 +1,62 @@ +#version 450 + +const int MAX_LIGHTS = 10; + +layout(location = 0) in vec3 v_Normal; +layout(location = 1) in vec4 v_Position; + +layout(location = 0) out vec4 o_Target; + +struct Light { + mat4 proj; + vec4 pos; + vec4 color; +}; + +layout(set = 0, binding = 0) uniform Globals { + mat4 u_ViewProj; + uvec4 u_NumLights; +}; +layout(set = 0, binding = 1) uniform Lights { + Light u_Lights[MAX_LIGHTS]; +}; +layout(set = 0, binding = 2) uniform texture2DArray t_Shadow; +layout(set = 0, binding = 3) uniform samplerShadow s_Shadow; + +layout(set = 1, binding = 0) uniform Entity { + mat4 u_World; + vec4 u_Color; +}; + +float fetch_shadow(int light_id, vec4 homogeneous_coords) { + if (homogeneous_coords.w <= 0.0) { + return 1.0; + } + // compute texture coordinates for shadow lookup + vec4 light_local = vec4( + (homogeneous_coords.xy/homogeneous_coords.w + 1.0) / 2.0, + light_id, + homogeneous_coords.z / homogeneous_coords.w + ); + // do the lookup, using HW PCF and comparison + return texture(sampler2DArrayShadow(t_Shadow, s_Shadow), light_local); +} + +void main() { + vec3 normal = normalize(v_Normal); + vec3 ambient = vec3(0.05, 0.05, 0.05); + // accumulate color + vec3 color = ambient; + for (int i=0; i{0_MDl2 z&V`Ng!;+L!No6(kh_>=5QccB>*PEZsrPesC^-YKl-R>WRNeXqBx`>v59)9mJ_w0mknd~dA z&!5~gt&QOJR)KV0zIZKgX-t><>cAfBhU+ix^)24x@VqNZOkTje!+kgY+&8!b;(Zb8 diff --git a/src/shader.vert b/src/shader.vert deleted file mode 100644 index ac6dcc7c32..0000000000 --- a/src/shader.vert +++ /dev/null @@ -1,15 +0,0 @@ -#version 450 - -out gl_PerVertex { - vec4 gl_Position; -}; - -const vec2 positions[3] = vec2[3]( - vec2(0.0, -0.5), - vec2(0.5, 0.5), - vec2(-0.5, 0.5) -); - -void main() { - gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); -} diff --git a/src/shader.vert.spv b/src/shader.vert.spv deleted file mode 100644 index 9a3f5994b71471f4f282bdb2299e70ce2ebd9d62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 904 zcmYk4OD}^_5QdLdTa;4wyN_alhy@}M8mp365Q(i++DH@Hgf1-oGl^eiBk?@nMV#i% z%)Il?oH^4kpR1KZ7zm{>6t+Whsv!pxLOB#;+qk~F-hb=2_79H^R8&Gf7OEMi(lZEN znw_rx2v`7lemU$H!UBr_ngYFt$UQwj+_Ycs+pqohJ0Wbs>znJnb^4uNm->9%SKeCt zlTQk-x-F{<{FdQ6hRw(4HvT1?_jt;Q2@QJ5Ia`CN>}75TOu@>p$I~a8S^Oeg1m@8D zVq@R4n)Z^5V1}`7$Nr~j>^|gXh`lEQtR(EF@hHB>-eXvMJA?WPHUb{?#^b<#%fu5{ zYvjyZTLqpho=n2eJ$9jX3aF9KG}HK;dZw8nkP{gUl{9v?Y@P@|gpa!UO+4Rg%`tCqH}2je{|!^XdY8TZ2GpJrJHsOI z{&UpkocV$Z?_C9QYScT!8j!z5<386@4)e!tq?~WM;WqE90k!7bZv?!@`L}@If&aC0 L7_0wbD<|L=@_;WL diff --git a/src/temp.rs b/src/temp.rs new file mode 100644 index 0000000000..e5527a9a75 --- /dev/null +++ b/src/temp.rs @@ -0,0 +1,126 @@ +pub use std::rc::Rc; +pub use std::ops::Range; +use zerocopy::{AsBytes, FromBytes}; + +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.0, + 0.0, + 0.0, + 0.5, + 1.0, +); + +pub struct Entity { + pub mx_world: cgmath::Matrix4, + pub rotation_speed: f32, + pub color: wgpu::Color, + pub vertex_buf: Rc, + pub index_buf: Rc, + pub index_count: usize, + pub bind_group: wgpu::BindGroup, + pub uniform_buf: wgpu::Buffer, +} + +pub struct Light { + pub pos: cgmath::Point3, + pub color: wgpu::Color, + pub fov: f32, + pub depth: Range, + pub target_view: wgpu::TextureView, +} + +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct LightRaw { + pub proj: [[f32; 4]; 4], + pub pos: [f32; 4], + pub color: [f32; 4], +} + +impl Light { + pub fn to_raw(&self) -> LightRaw { + use cgmath::{Deg, EuclideanSpace, Matrix4, PerspectiveFov, Point3, Vector3}; + + let mx_view = Matrix4::look_at(self.pos, Point3::origin(), Vector3::unit_z()); + let projection = PerspectiveFov { + fovy: Deg(self.fov).into(), + aspect: 1.0, + near: self.depth.start, + far: self.depth.end, + }; + let mx_view_proj = OPENGL_TO_WGPU_MATRIX * + cgmath::Matrix4::from(projection.to_perspective()) * mx_view; + LightRaw { + proj: *mx_view_proj.as_ref(), + pos: [self.pos.x, self.pos.y, self.pos.z, 1.0], + color: [ + self.color.r as f32, + self.color.g as f32, + self.color.b as f32, + 1.0, + ], + } + } +} + +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct ForwardUniforms { + pub proj: [[f32; 4]; 4], + pub num_lights: [u32; 4], +} + +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct EntityUniforms { + pub model: [[f32; 4]; 4], + pub color: [f32; 4], +} + +#[repr(C)] +pub struct ShadowUniforms { + pub proj: [[f32; 4]; 4], +} + +pub struct Pass { + pub pipeline: wgpu::RenderPipeline, + pub bind_group: wgpu::BindGroup, + pub uniform_buf: wgpu::Buffer, +} + +pub enum ShaderStage { + Vertex, + Fragment, + Compute, +} + +pub fn load_glsl(code: &str, stage: ShaderStage) -> Vec { + let ty = match stage { + ShaderStage::Vertex => glsl_to_spirv::ShaderType::Vertex, + ShaderStage::Fragment => glsl_to_spirv::ShaderType::Fragment, + ShaderStage::Compute => glsl_to_spirv::ShaderType::Compute, + }; + + wgpu::read_spirv(glsl_to_spirv::compile(&code, ty).unwrap()).unwrap() +} + +pub fn generate_matrix(aspect_ratio: f32) -> cgmath::Matrix4 { + let mx_projection = cgmath::perspective(cgmath::Deg(45f32), aspect_ratio, 1.0, 20.0); + let mx_view = cgmath::Matrix4::look_at( + cgmath::Point3::new(3.0f32, -10.0, 6.0), + cgmath::Point3::new(0f32, 0.0, 0.0), + cgmath::Vector3::unit_z(), + ); + OPENGL_TO_WGPU_MATRIX * mx_projection * mx_view +} diff --git a/src/vertex.rs b/src/vertex.rs new file mode 100644 index 0000000000..80e4435d7d --- /dev/null +++ b/src/vertex.rs @@ -0,0 +1,97 @@ +use zerocopy::{AsBytes, FromBytes}; + +#[repr(C)] +#[derive(Clone, Copy, AsBytes, FromBytes)] +pub struct Vertex { + pub pos: [i8; 4], + pub normal: [i8; 4], +} + +pub fn vertex(pos: [i8; 3], nor: [i8; 3]) -> Vertex { + Vertex { + pos: [pos[0], pos[1], pos[2], 1], + normal: [nor[0], nor[1], nor[2], 0], + } +} + +pub fn create_cube() -> (Vec, Vec) { + let vertex_data = [ + // top (0, 0, 1) + vertex([-1, -1, 1], [0, 0, 1]), + vertex([1, -1, 1], [0, 0, 1]), + vertex([1, 1, 1], [0, 0, 1]), + vertex([-1, 1, 1], [0, 0, 1]), + // bottom (0, 0, -1) + vertex([-1, 1, -1], [0, 0, -1]), + vertex([1, 1, -1], [0, 0, -1]), + vertex([1, -1, -1], [0, 0, -1]), + vertex([-1, -1, -1], [0, 0, -1]), + // right (1, 0, 0) + vertex([1, -1, -1], [1, 0, 0]), + vertex([1, 1, -1], [1, 0, 0]), + vertex([1, 1, 1], [1, 0, 0]), + vertex([1, -1, 1], [1, 0, 0]), + // left (-1, 0, 0) + vertex([-1, -1, 1], [-1, 0, 0]), + vertex([-1, 1, 1], [-1, 0, 0]), + vertex([-1, 1, -1], [-1, 0, 0]), + vertex([-1, -1, -1], [-1, 0, 0]), + // front (0, 1, 0) + vertex([1, 1, -1], [0, 1, 0]), + vertex([-1, 1, -1], [0, 1, 0]), + vertex([-1, 1, 1], [0, 1, 0]), + vertex([1, 1, 1], [0, 1, 0]), + // back (0, -1, 0) + vertex([1, -1, 1], [0, -1, 0]), + vertex([-1, -1, 1], [0, -1, 0]), + vertex([-1, -1, -1], [0, -1, 0]), + vertex([1, -1, -1], [0, -1, 0]), + ]; + + let index_data: &[u16] = &[ + 0, 1, 2, 2, 3, 0, // top + 4, 5, 6, 6, 7, 4, // bottom + 8, 9, 10, 10, 11, 8, // right + 12, 13, 14, 14, 15, 12, // left + 16, 17, 18, 18, 19, 16, // front + 20, 21, 22, 22, 23, 20, // back + ]; + + (vertex_data.to_vec(), index_data.to_vec()) +} + +pub fn create_plane(size: i8) -> (Vec, Vec) { + let vertex_data = [ + vertex([size, -size, 0], [0, 0, 1]), + vertex([size, size, 0], [0, 0, 1]), + vertex([-size, -size, 0], [0, 0, 1]), + vertex([-size, size, 0], [0, 0, 1]), + ]; + + let index_data: &[u16] = &[0, 1, 2, 2, 1, 3]; + + (vertex_data.to_vec(), index_data.to_vec()) +} + +pub fn create_texels(size: usize) -> Vec { + use std::iter; + + (0 .. size * size) + .flat_map(|id| { + // get high five for recognizing this ;) + let cx = 3.0 * (id % size) as f32 / (size - 1) as f32 - 2.0; + let cy = 2.0 * (id / size) as f32 / (size - 1) as f32 - 1.0; + let (mut x, mut y, mut count) = (cx, cy, 0); + while count < 0xFF && x * x + y * y < 4.0 { + let old_x = x; + x = x * x - y * y + cx; + y = 2.0 * old_x * y + cy; + count += 1; + } + iter::once(0xFF - (count * 5) as u8) + .chain(iter::once(0xFF - (count * 15) as u8)) + .chain(iter::once(0xFF - (count * 50) as u8)) + .chain(iter::once(1)) + }) + .collect() +} \ No newline at end of file