initial ui pass

This commit is contained in:
Carter Anderson 2020-01-08 19:17:11 -08:00
parent edd0bca622
commit eb1233d9f0
15 changed files with 329 additions and 18 deletions

View file

@ -168,10 +168,17 @@ fn main() {
let cube = Mesh::load(MeshType::Cube);
let plane = Mesh::load(MeshType::Plane{ size: 24.5 });
let quad = Mesh::load(MeshType::Quad {
north_west: math::vec2(100.0, 200.0),
north_east: math::vec2(200.0, 200.0),
south_west: math::vec2(100.0, 100.0),
south_east: math::vec2(200.0, 100.0),
});
let mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
let _cube_handle = mesh_storage.add(cube, "cube");
let plane_handle = mesh_storage.add(plane, "plane");
let quad_handle = mesh_storage.add(quad, "quad");
world.resources.insert(mesh_storage);
let transform_system_bundle = transform_system_bundle::build(&mut world);
@ -254,6 +261,7 @@ fn main() {
far: 1000.0,
aspect_ratio: 1.0,
}),
ActiveCamera,
LocalToWorld(Mat4::look_at_rh(
Vec3::new(6.0, -40.0, 20.0),
Vec3::new(0.0, 0.0, 0.0),
@ -262,6 +270,31 @@ fn main() {
)
]);
world.insert((), vec![
// camera
(
Camera::new(CameraType::Orthographic {
left: 0.0,
right: 0.0,
bottom: 0.0,
top: 0.0,
near: 0.0,
far: 1.0,
}),
ActiveCamera2d,
)
]);
world.insert((), vec![
// camera
(
quad_handle,
Mesh2d,
)
]);
let mut rng = StdRng::from_entropy();
for _ in 0 .. 70000 {
create_person(&mut world, _cube_handle.clone(),

View file

@ -22,12 +22,14 @@ impl Application {
fn add_default_passes(&mut self) {
self.render_graph.add_render_resource_manager(Box::new(render_resources::MaterialResourceManager));
self.render_graph.add_render_resource_manager(Box::new(render_resources::LightResourceManager::new(10)));
self.render_graph.add_render_resource_manager(Box::new(render_resources::CameraResourceManager));
self.render_graph.add_render_resource_manager(Box::new(render_resources::GlobalResourceManager));
self.render_graph.add_render_resource_manager(Box::new(render_resources::Global2dResourceManager));
let depth_format = wgpu::TextureFormat::Depth32Float;
self.render_graph.set_pass("forward", Box::new(ForwardPass::new(depth_format)));
self.render_graph.set_pipeline("forward", "forward", Box::new(ForwardPipeline::new()));
self.render_graph.set_pipeline("forward", "forward_instanced", Box::new(ForwardInstancedPipeline::new(depth_format)));
self.render_graph.set_pipeline("forward", "ui", Box::new(UiPipeline::new()));
}
fn update(&mut self) {

View file

@ -1,12 +1,23 @@
use crate::math::Mat4;
pub struct ActiveCamera;
pub struct ActiveCamera2d;
pub enum CameraType {
Projection {
fov: f32,
aspect_ratio: f32,
near: f32,
far: f32
}
},
Orthographic {
left: f32,
right: f32,
bottom: f32,
top: f32,
near: f32,
far: f32,
},
}
pub struct Camera {
@ -26,18 +37,29 @@ impl Camera {
match &mut self.camera_type {
CameraType::Projection { aspect_ratio, fov, near, far } => {
*aspect_ratio = width as f32 / height as f32;
self.view_matrix = get_projection_matrix(*fov, *aspect_ratio, *near, *far)
self.view_matrix = get_perspective_projection_matrix(*fov, *aspect_ratio, *near, *far)
},
CameraType::Orthographic { left, right, bottom, top, near, far} => {
*right = width as f32;
*top = height as f32;
self.view_matrix = get_orthographic_projection_matrix(*left, *right, *bottom, *top, *near, *far)
}
}
}
}
pub fn get_projection_matrix(fov: f32, aspect_ratio: f32, near: f32, far: f32) -> Mat4 {
pub fn get_perspective_projection_matrix(fov: f32, aspect_ratio: f32, near: f32, far: f32) -> Mat4 {
let projection = Mat4::perspective_rh_gl(fov, aspect_ratio, near, far);
opengl_to_wgpu_matrix() * projection
}
pub fn get_orthographic_projection_matrix(left: f32, right: f32, bottom: f32, top: f32, near: f32, far: f32) -> Mat4 {
let projection = Mat4::orthographic_rh_gl(left, right, bottom, top, near, far);
opengl_to_wgpu_matrix() * projection
}
pub fn opengl_to_wgpu_matrix() -> Mat4 {
Mat4::from_cols_array(&[
1.0, 0.0, 0.0, 0.0,

View file

@ -20,7 +20,7 @@ pub struct LightRaw {
impl LightRaw {
pub fn from(light: &Light, transform: &math::Mat4, translation: &Translation) -> LightRaw {
let proj = camera::get_projection_matrix(light.fov, 1.0, light.depth.start, light.depth.end) * *transform;
let proj = camera::get_perspective_projection_matrix(light.fov, 1.0, light.depth.start, light.depth.end) * *transform;
let (x, y, z) = translation.0.into();
LightRaw {
proj: proj.to_cols_array_2d(),

View file

@ -1,12 +1,21 @@
use crate::{vertex::Vertex, asset::Asset};
use crate::{vertex::Vertex, asset::Asset, math::*};
use wgpu::{Buffer, Device};
use zerocopy::AsBytes;
// TODO: this is pretty dirty. work out a cleaner way to distinguish between 3d and 2d meshes
pub struct Mesh2d;
pub enum MeshType {
Cube,
Plane {
size: f32
},
Quad {
north_west: Vec2,
north_east: Vec2,
south_west: Vec2,
south_east: Vec2,
}
}
pub struct Mesh {
@ -33,6 +42,7 @@ impl Asset<MeshType> for Mesh {
let (vertices, indices) = match descriptor {
MeshType::Cube => create_cube(),
MeshType::Plane { size } => create_plane(size),
MeshType::Quad { north_west, north_east, south_west, south_east } => create_quad(north_west, north_east, south_west, south_east),
};
Mesh {
@ -44,6 +54,18 @@ impl Asset<MeshType> for Mesh {
}
}
pub fn create_quad(north_west: Vec2, north_east: Vec2, south_west: Vec2, south_east: Vec2) -> (Vec<Vertex>, Vec<u16>) {
let vertex_data = [
Vertex::from(([south_west.x(), south_west.y(), 0.0], [0.0, 0.0, 1.0])),
Vertex::from(([north_west.x(), north_west.y(), 0.0], [0.0, 0.0, 1.0])),
Vertex::from(([north_east.x(), north_east.y(), 0.0], [0.0, 0.0, 1.0])),
Vertex::from(([south_east.x(), south_east.y(), 0.0], [0.0, 0.0, 1.0])),
];
let index_data: &[u16] = &[ 0, 1, 2, 0, 2, 3 ];
return (vertex_data.to_vec(), index_data.to_vec());
}
pub fn create_cube() -> (Vec<Vertex>, Vec<u16>) {
let vertex_data = [
// top (0, 0, 1)
@ -98,6 +120,7 @@ pub fn create_plane(size: f32) -> (Vec<Vertex>, Vec<u16>) {
Vertex::from(([-size, size, 0.0], [0.0, 0.0, 1.0])),
];
// TODO: make sure this order is correct
let index_data: &[u16] = &[0, 1, 2, 2, 1, 3];
(vertex_data.to_vec(), index_data.to_vec())

View file

@ -127,7 +127,7 @@ impl Pipeline for ForwardPipeline {
let mut mesh_query =
<(Read<Material>, Read<Handle<Mesh>>)>::query()
.filter(!component::<Instanced>());
for (entity, mesh) in mesh_query.iter_immutable(world) {
for (material, mesh) in mesh_query.iter_immutable(world) {
let current_mesh_id = *mesh.id.read().unwrap();
let mut should_load_mesh = last_mesh_id == None;
@ -144,7 +144,7 @@ impl Pipeline for ForwardPipeline {
}
if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]);
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1);
};

View file

@ -147,10 +147,10 @@ impl Pipeline for ForwardShadowPassNew {
pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]);
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
for (entity, mesh) in mesh_query.iter_immutable(world) {
for (material, mesh) in mesh_query.iter_immutable(world) {
if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]);
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1);

View file

@ -3,8 +3,10 @@ mod forward;
mod forward_shadow;
mod forward_instanced;
mod shadow;
mod ui;
pub use forward::{ForwardUniforms, ForwardPipeline, ForwardPass};
pub use forward_shadow::{ForwardShadowPassNew};
pub use forward_instanced::ForwardInstancedPipeline;
pub use shadow::ShadowPass;
pub use shadow::ShadowPass;
pub use ui::UiPipeline;

View file

@ -146,11 +146,11 @@ impl Pipeline for ShadowPipeline {
.resources
.get_mut::<AssetStorage<Mesh, MeshType>>()
.unwrap();
for (entity, mesh) in mesh_query.iter_immutable(world) {
for (material, mesh) in mesh_query.iter_immutable(world) {
if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_bind_group(1, entity.bind_group.as_ref().unwrap(), &[]);
pass.set_bind_group(1, material.bind_group.as_ref().unwrap(), &[]);
pass.set_index_buffer(&mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
pass.draw_indexed(0..mesh_asset.indices.len() as u32, 0, 0..1);

149
src/render/passes/ui/mod.rs Normal file
View file

@ -0,0 +1,149 @@
use crate::{render::*, asset::*, render::mesh::*};
use legion::prelude::*;
use wgpu::SwapChainOutput;
pub struct UiPipeline {
pub pipeline: Option<wgpu::RenderPipeline>,
pub depth_format: wgpu::TextureFormat,
pub bind_group: Option<wgpu::BindGroup>,
}
impl UiPipeline {
pub fn new() -> Self {
UiPipeline {
pipeline: None,
bind_group: None,
depth_format: wgpu::TextureFormat::Depth32Float
}
}
}
impl Pipeline for UiPipeline {
fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) {
let vs_bytes = shader::load_glsl(
include_str!("ui.vert"),
shader::ShaderStage::Vertex,
);
let fs_bytes = shader::load_glsl(
include_str!("ui.frag"),
shader::ShaderStage::Fragment,
);
let bind_group_layout =
render_graph.device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
bindings: &[
wgpu::BindGroupLayoutBinding {
binding: 0, // global_2d
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
ty: wgpu::BindingType::UniformBuffer { dynamic: false },
},
],
});
self.bind_group = Some({
let global_2d_uniform_buffer = render_graph.get_uniform_buffer(render_resources::GLOBAL_2D_UNIFORM_BUFFER_NAME).unwrap();
// Create bind group
render_graph.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
bindings: &[
wgpu::Binding {
binding: 0,
resource: global_2d_uniform_buffer.get_binding_resource(),
},
],
})
});
let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout],
});
let vertex_buffer_descriptor = get_vertex_buffer_descriptor();
let vs_module = render_graph.device.create_shader_module(&vs_bytes);
let fs_module = render_graph.device.create_shader_module(&fs_bytes);
self.pipeline = Some(render_graph.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: render_graph.swap_chain_descriptor.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: &[vertex_buffer_descriptor],
sample_count: 1,
sample_mask: !0,
alpha_to_coverage_enabled: false,
}));
}
fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) {
pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]);
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
let mut last_mesh_id = None;
let mut mesh_query =
<(Read<Handle<Mesh>>, Read<Mesh2d>)>::query()
.filter(!component::<Instanced>());
for (mesh, _) in mesh_query.iter_immutable(world) {
let current_mesh_id = *mesh.id.read().unwrap();
let mut should_load_mesh = last_mesh_id == None;
if let Some(last) = last_mesh_id {
should_load_mesh = last != current_mesh_id;
}
if should_load_mesh {
if let Some(mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
mesh_asset.setup_buffers(&render_graph.device);
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
pass.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
};
}
if let Some(ref mesh_asset) = mesh_storage.get(*mesh.id.read().unwrap()) {
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. 1);
};
last_mesh_id = Some(current_mesh_id);
}
}
fn resize(&mut self, _: &RenderGraphData) {
}
fn get_pipeline(&self) -> &wgpu::RenderPipeline {
self.pipeline.as_ref().unwrap()
}
}

View file

@ -0,0 +1,10 @@
#version 450
layout(location = 0) in vec3 v_Normal;
layout(location = 1) in vec4 v_Position;
layout(location = 0) out vec4 o_Target;
void main() {
o_Target = vec4(1.0, 0.0, 0.0, 1.0);
}

View file

@ -0,0 +1,17 @@
#version 450
layout(location = 0) in vec4 a_Pos;
layout(location = 1) in vec4 a_Normal;
layout(location = 0) out vec3 v_Normal;
layout(location = 1) out vec4 v_Position;
layout(set = 0, binding = 0) uniform Globals {
mat4 u_ViewProj;
};
void main() {
v_Normal = vec3(a_Normal.xyz);
v_Position = vec4(a_Pos);
gl_Position = u_ViewProj * v_Position;
}

View file

@ -0,0 +1,51 @@
use crate::{render::*, math};
use legion::prelude::*;
use std::mem;
use zerocopy::{AsBytes, FromBytes};
pub const GLOBAL_2D_UNIFORM_BUFFER_NAME: &str = "global_2d";
#[repr(C)]
#[derive(Clone, Copy, AsBytes, FromBytes)]
pub struct Global2dUniforms {
pub projection_matrix: [[f32; 4]; 4],
}
pub struct Global2dResourceManager;
impl RenderResourceManager for Global2dResourceManager {
fn initialize(&self, render_graph: &mut RenderGraphData, _: &mut World) {
let uniform_size = mem::size_of::<Global2dUniforms>() as wgpu::BufferAddress;
let ui_uniforms = Global2dUniforms {
projection_matrix: math::Mat4::identity().to_cols_array_2d(),
};
let buffer = render_graph.device.create_buffer_with_data(
ui_uniforms.as_bytes(),
wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST,
);
let uniform_buffer = UniformBuffer {
buffer: buffer,
size: uniform_size,
};
render_graph.set_uniform_buffer(GLOBAL_2D_UNIFORM_BUFFER_NAME, uniform_buffer);
}
fn update<'a>(&mut self, _render_graph: &mut RenderGraphData, _encoder: &'a mut wgpu::CommandEncoder, _world: &mut World) {
}
fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) {
for (mut camera, _) in <(Write<Camera>, Read<ActiveCamera2d>)>::query().iter(world) {
camera.update(render_graph.swap_chain_descriptor.width, render_graph.swap_chain_descriptor.height);
let camera_matrix: [[f32; 4]; 4] = camera.view_matrix.to_cols_array_2d();
let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64;
let temp_camera_buffer =
render_graph.device.create_buffer_with_data(camera_matrix.as_bytes(), wgpu::BufferUsage::COPY_SRC);
let global_2d_uniform_buffer = render_graph.get_uniform_buffer(GLOBAL_2D_UNIFORM_BUFFER_NAME).unwrap();
encoder.copy_buffer_to_buffer(&temp_camera_buffer, 0, &global_2d_uniform_buffer.buffer, 0, matrix_size);
}
}
}

View file

@ -6,9 +6,9 @@ use zerocopy::AsBytes;
pub const FORWARD_UNIFORM_BUFFER_NAME: &str = "forward";
pub struct CameraResourceManager;
pub struct GlobalResourceManager;
impl RenderResourceManager for CameraResourceManager {
impl RenderResourceManager for GlobalResourceManager {
fn initialize(&self, render_graph: &mut RenderGraphData, world: &mut World) {
let light_count = <Read<Light>>::query().iter_immutable(world).count();
let forward_uniforms = ForwardUniforms {
@ -32,7 +32,7 @@ impl RenderResourceManager for CameraResourceManager {
}
fn resize<'a>(&self, render_graph: &mut RenderGraphData, encoder: &'a mut wgpu::CommandEncoder, world: &mut World) {
for (mut camera, local_to_world) in <(Write<Camera>, Read<LocalToWorld>)>::query().iter(world) {
for (mut camera, local_to_world, _) in <(Write<Camera>, Read<LocalToWorld>, Read<ActiveCamera>)>::query().iter(world) {
camera.update(render_graph.swap_chain_descriptor.width, render_graph.swap_chain_descriptor.height);
let camera_matrix: [[f32; 4]; 4] = (camera.view_matrix * local_to_world.0).to_cols_array_2d();
let matrix_size = mem::size_of::<[[f32; 4]; 4]>() as u64;

View file

@ -1,7 +1,9 @@
mod light_resource_manager;
mod camera_resource_manager;
mod global_resource_manager;
mod global_2d_resource_manager;
mod material_resource_manager;
pub use light_resource_manager::*;
pub use camera_resource_manager::*;
pub use global_resource_manager::*;
pub use global_2d_resource_manager::*;
pub use material_resource_manager::*;