mirror of
https://github.com/bevyengine/bevy
synced 2024-11-24 21:53:07 +00:00
batched rect rendering
This commit is contained in:
parent
eb1233d9f0
commit
aeeb85b7b0
8 changed files with 162 additions and 54 deletions
|
@ -168,17 +168,10 @@ fn main() {
|
||||||
|
|
||||||
let cube = Mesh::load(MeshType::Cube);
|
let cube = Mesh::load(MeshType::Cube);
|
||||||
let plane = Mesh::load(MeshType::Plane{ size: 24.5 });
|
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 mut mesh_storage = AssetStorage::<Mesh, MeshType>::new();
|
||||||
|
|
||||||
let _cube_handle = mesh_storage.add(cube, "cube");
|
let _cube_handle = mesh_storage.add(cube, "cube");
|
||||||
let plane_handle = mesh_storage.add(plane, "plane");
|
let plane_handle = mesh_storage.add(plane, "plane");
|
||||||
let quad_handle = mesh_storage.add(quad, "quad");
|
|
||||||
world.resources.insert(mesh_storage);
|
world.resources.insert(mesh_storage);
|
||||||
|
|
||||||
let transform_system_bundle = transform_system_bundle::build(&mut world);
|
let transform_system_bundle = transform_system_bundle::build(&mut world);
|
||||||
|
@ -287,16 +280,37 @@ fn main() {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
world.insert((), vec![
|
world.insert((), vec![
|
||||||
|
|
||||||
// camera
|
|
||||||
(
|
(
|
||||||
quad_handle,
|
Rect {
|
||||||
Mesh2d,
|
position: math::vec2(75.0, 75.0),
|
||||||
|
dimensions: math::vec2(100.0, 100.0),
|
||||||
|
color: math::vec4(0.0, 1.0, 0.0, 1.0),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
world.insert((), vec![
|
||||||
|
(
|
||||||
|
Rect {
|
||||||
|
position: math::vec2(50.0, 50.0),
|
||||||
|
dimensions: math::vec2(100.0, 100.0),
|
||||||
|
color: math::vec4(1.0, 0.0, 0.0, 1.0),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
|
||||||
|
world.insert((), vec![
|
||||||
|
(
|
||||||
|
Rect {
|
||||||
|
position: math::vec2(100.0, 100.0),
|
||||||
|
dimensions: math::vec2(100.0, 100.0),
|
||||||
|
color: math::vec4(0.0, 0.0, 1.0, 1.0),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let mut rng = StdRng::from_entropy();
|
let mut rng = StdRng::from_entropy();
|
||||||
for _ in 0 .. 70000 {
|
for _ in 0 .. 5 {
|
||||||
create_person(&mut world, _cube_handle.clone(),
|
create_person(&mut world, _cube_handle.clone(),
|
||||||
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)));
|
Translation::new(rng.gen_range(-50.0, 50.0), 0.0, rng.gen_range(-50.0, 50.0)));
|
||||||
}
|
}
|
||||||
|
|
5
src/render/instancing.rs
Normal file
5
src/render/instancing.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub struct InstanceBufferInfo {
|
||||||
|
pub buffer: wgpu::Buffer,
|
||||||
|
pub instance_count: usize,
|
||||||
|
pub mesh_id: usize,
|
||||||
|
}
|
|
@ -3,10 +3,12 @@ pub mod shader;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
pub mod render_resources;
|
pub mod render_resources;
|
||||||
pub mod passes;
|
pub mod passes;
|
||||||
|
pub mod instancing;
|
||||||
|
|
||||||
mod light;
|
mod light;
|
||||||
mod render_graph;
|
mod render_graph;
|
||||||
mod material;
|
mod material;
|
||||||
|
mod rect;
|
||||||
|
|
||||||
pub use light::*;
|
pub use light::*;
|
||||||
pub use shader::*;
|
pub use shader::*;
|
||||||
|
@ -14,6 +16,7 @@ pub use render_graph::*;
|
||||||
pub use material::*;
|
pub use material::*;
|
||||||
pub use mesh::*;
|
pub use mesh::*;
|
||||||
pub use camera::*;
|
pub use camera::*;
|
||||||
|
pub use rect::*;
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use crate::vertex::Vertex;
|
use crate::vertex::Vertex;
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
use crate::{render::*, asset::*, render::mesh::*, LocalToWorld};
|
use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, LocalToWorld};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use zerocopy::AsBytes;
|
use zerocopy::AsBytes;
|
||||||
use wgpu::{Device, SwapChainOutput};
|
use wgpu::{Device, SwapChainOutput};
|
||||||
|
|
||||||
pub struct InstanceBufferInfo {
|
|
||||||
pub buffer: wgpu::Buffer,
|
|
||||||
pub instance_count: usize,
|
|
||||||
pub mesh_id: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ForwardInstancedPipeline {
|
pub struct ForwardInstancedPipeline {
|
||||||
pub pipeline: Option<wgpu::RenderPipeline>,
|
pub pipeline: Option<wgpu::RenderPipeline>,
|
||||||
pub depth_format: wgpu::TextureFormat,
|
pub depth_format: wgpu::TextureFormat,
|
||||||
|
|
|
@ -1,10 +1,21 @@
|
||||||
use crate::{render::*, asset::*, render::mesh::*};
|
use crate::{render::{*, instancing::InstanceBufferInfo}, asset::*, render::mesh::*, math};
|
||||||
use legion::prelude::*;
|
use legion::prelude::*;
|
||||||
|
use zerocopy::{AsBytes, FromBytes};
|
||||||
use wgpu::SwapChainOutput;
|
use wgpu::SwapChainOutput;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone, Copy, AsBytes, FromBytes)]
|
||||||
|
pub struct RectData {
|
||||||
|
pub position: [f32; 2],
|
||||||
|
pub dimensions: [f32; 2],
|
||||||
|
pub color: [f32; 4],
|
||||||
|
pub z_index: f32,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UiPipeline {
|
pub struct UiPipeline {
|
||||||
pub pipeline: Option<wgpu::RenderPipeline>,
|
pub pipeline: Option<wgpu::RenderPipeline>,
|
||||||
pub depth_format: wgpu::TextureFormat,
|
pub depth_format: wgpu::TextureFormat,
|
||||||
|
pub quad: Option<Handle<Mesh>>,
|
||||||
pub bind_group: Option<wgpu::BindGroup>,
|
pub bind_group: Option<wgpu::BindGroup>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,13 +24,48 @@ impl UiPipeline {
|
||||||
UiPipeline {
|
UiPipeline {
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
bind_group: None,
|
bind_group: None,
|
||||||
|
quad: None,
|
||||||
depth_format: wgpu::TextureFormat::Depth32Float
|
depth_format: wgpu::TextureFormat::Depth32Float
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_rect_buffers(&self, device: &wgpu::Device, world: &World) -> Vec<InstanceBufferInfo> {
|
||||||
|
let mut rect_query = <Read<Rect>>::query();
|
||||||
|
let rect_count = rect_query.iter_immutable(world).count();
|
||||||
|
|
||||||
|
let mut data = Vec::with_capacity(rect_count);
|
||||||
|
// TODO: this probably isn't the best way to handle z-ordering
|
||||||
|
let mut z = 0.9999;
|
||||||
|
for rect in rect_query.iter_immutable(world)
|
||||||
|
{
|
||||||
|
data.push(RectData {
|
||||||
|
position: rect.position.into(),
|
||||||
|
dimensions: rect.dimensions.into(),
|
||||||
|
color: rect.color.into(),
|
||||||
|
z_index: z,
|
||||||
|
});
|
||||||
|
|
||||||
|
z -= 0.0001;
|
||||||
|
}
|
||||||
|
|
||||||
|
let buffer = device
|
||||||
|
.create_buffer_with_data(data.as_bytes(), wgpu::BufferUsage::COPY_SRC | wgpu::BufferUsage::VERTEX);
|
||||||
|
|
||||||
|
let mesh_id = *self.quad.as_ref().unwrap().id.read().unwrap();
|
||||||
|
|
||||||
|
let mut instance_buffer_infos = Vec::new();
|
||||||
|
instance_buffer_infos.push(InstanceBufferInfo {
|
||||||
|
mesh_id: mesh_id,
|
||||||
|
buffer: buffer,
|
||||||
|
instance_count: rect_count,
|
||||||
|
});
|
||||||
|
|
||||||
|
instance_buffer_infos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pipeline for UiPipeline {
|
impl Pipeline for UiPipeline {
|
||||||
fn initialize(&mut self, render_graph: &mut RenderGraphData, _: &mut World) {
|
fn initialize(&mut self, render_graph: &mut RenderGraphData, world: &mut World) {
|
||||||
let vs_bytes = shader::load_glsl(
|
let vs_bytes = shader::load_glsl(
|
||||||
include_str!("ui.vert"),
|
include_str!("ui.vert"),
|
||||||
shader::ShaderStage::Vertex,
|
shader::ShaderStage::Vertex,
|
||||||
|
@ -56,11 +102,50 @@ impl Pipeline for UiPipeline {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
|
||||||
|
|
||||||
|
let quad = Mesh::load(MeshType::Quad {
|
||||||
|
north_west: math::vec2(-0.5, 0.5),
|
||||||
|
north_east: math::vec2(0.5, 0.5),
|
||||||
|
south_west: math::vec2(-0.5, -0.5),
|
||||||
|
south_east: math::vec2(0.5, -0.5),
|
||||||
|
});
|
||||||
|
self.quad = Some(mesh_storage.add(quad, "ui_quad"));
|
||||||
|
}
|
||||||
|
|
||||||
let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
let pipeline_layout = render_graph.device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
bind_group_layouts: &[&bind_group_layout],
|
bind_group_layouts: &[&bind_group_layout],
|
||||||
});
|
});
|
||||||
|
|
||||||
let vertex_buffer_descriptor = get_vertex_buffer_descriptor();
|
let vertex_buffer_descriptor = get_vertex_buffer_descriptor();
|
||||||
|
let rect_data_size = mem::size_of::<RectData>();
|
||||||
|
let instance_buffer_descriptor = wgpu::VertexBufferDescriptor {
|
||||||
|
stride: rect_data_size as wgpu::BufferAddress,
|
||||||
|
step_mode: wgpu::InputStepMode::Instance,
|
||||||
|
attributes: &[
|
||||||
|
wgpu::VertexAttributeDescriptor {
|
||||||
|
format: wgpu::VertexFormat::Float2,
|
||||||
|
offset: 0,
|
||||||
|
shader_location: 2,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttributeDescriptor {
|
||||||
|
format: wgpu::VertexFormat::Float2,
|
||||||
|
offset: 2 * 4,
|
||||||
|
shader_location: 3,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttributeDescriptor {
|
||||||
|
format: wgpu::VertexFormat::Float4,
|
||||||
|
offset: 4 * 4,
|
||||||
|
shader_location: 4,
|
||||||
|
},
|
||||||
|
wgpu::VertexAttributeDescriptor {
|
||||||
|
format: wgpu::VertexFormat::Float,
|
||||||
|
offset: 8 * 4,
|
||||||
|
shader_location: 5,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
let vs_module = render_graph.device.create_shader_module(&vs_bytes);
|
let vs_module = render_graph.device.create_shader_module(&vs_bytes);
|
||||||
let fs_module = render_graph.device.create_shader_module(&fs_bytes);
|
let fs_module = render_graph.device.create_shader_module(&fs_bytes);
|
||||||
|
@ -101,7 +186,7 @@ impl Pipeline for UiPipeline {
|
||||||
stencil_write_mask: 0,
|
stencil_write_mask: 0,
|
||||||
}),
|
}),
|
||||||
index_format: wgpu::IndexFormat::Uint16,
|
index_format: wgpu::IndexFormat::Uint16,
|
||||||
vertex_buffers: &[vertex_buffer_descriptor],
|
vertex_buffers: &[vertex_buffer_descriptor, instance_buffer_descriptor],
|
||||||
sample_count: 1,
|
sample_count: 1,
|
||||||
sample_mask: !0,
|
sample_mask: !0,
|
||||||
alpha_to_coverage_enabled: false,
|
alpha_to_coverage_enabled: false,
|
||||||
|
@ -109,35 +194,19 @@ impl Pipeline for UiPipeline {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) {
|
fn render(&mut self, render_graph: &RenderGraphData, pass: &mut wgpu::RenderPass, _: &SwapChainOutput, world: &mut World) {
|
||||||
|
let instance_buffer_infos = Some(self.create_rect_buffers(&render_graph.device, world));
|
||||||
pass.set_bind_group(0, self.bind_group.as_ref().unwrap(), &[]);
|
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 mesh_storage = world.resources.get_mut::<AssetStorage<Mesh, MeshType>>().unwrap();
|
||||||
let mut last_mesh_id = None;
|
for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
|
||||||
let mut mesh_query =
|
if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) {
|
||||||
<(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);
|
mesh_asset.setup_buffers(&render_graph.device);
|
||||||
pass.set_index_buffer(mesh_asset.index_buffer.as_ref().unwrap(), 0);
|
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.set_vertex_buffers(0, &[(&mesh_asset.vertex_buffer.as_ref().unwrap(), 0)]);
|
||||||
|
pass.set_vertex_buffers(1, &[(&instance_buffer_info.buffer, 0)]);
|
||||||
|
pass.draw_indexed(0 .. mesh_asset.indices.len() as u32, 0, 0 .. instance_buffer_info.instance_count as u32);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
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 resize(&mut self, _: &RenderGraphData) {
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec3 v_Normal;
|
layout(location = 0) in vec4 v_Color;
|
||||||
layout(location = 1) in vec4 v_Position;
|
|
||||||
|
|
||||||
layout(location = 0) out vec4 o_Target;
|
layout(location = 0) out vec4 o_Target;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
o_Target = vec4(1.0, 0.0, 0.0, 1.0);
|
o_Target = v_Color;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,24 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
// vertex attributes
|
||||||
layout(location = 0) in vec4 a_Pos;
|
layout(location = 0) in vec4 a_Pos;
|
||||||
layout(location = 1) in vec4 a_Normal;
|
layout(location = 1) in vec4 a_Normal;
|
||||||
|
|
||||||
layout(location = 0) out vec3 v_Normal;
|
// instanced attributes (RectData)
|
||||||
layout(location = 1) out vec4 v_Position;
|
layout (location = 2) in vec2 a_RectPosition;
|
||||||
|
layout (location = 3) in vec2 a_RectDimensions;
|
||||||
|
layout (location = 4) in vec4 a_RectColor;
|
||||||
|
layout (location = 5) in float a_RectZIndex;
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 v_Color;
|
||||||
|
|
||||||
layout(set = 0, binding = 0) uniform Globals {
|
layout(set = 0, binding = 0) uniform Globals {
|
||||||
mat4 u_ViewProj;
|
mat4 u_ViewProj;
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
v_Normal = vec3(a_Normal.xyz);
|
v_Color = a_RectColor;
|
||||||
v_Position = vec4(a_Pos);
|
vec4 position = a_Pos * vec4(a_RectDimensions, 0.0, 1.0);
|
||||||
gl_Position = u_ViewProj * v_Position;
|
position = position + vec4(a_RectPosition, -a_RectZIndex, 0.0);
|
||||||
|
gl_Position = u_ViewProj * position;
|
||||||
}
|
}
|
||||||
|
|
17
src/render/rect.rs
Normal file
17
src/render/rect.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
use crate::math::{Vec2, Vec4};
|
||||||
|
|
||||||
|
pub struct Rect {
|
||||||
|
pub position: Vec2,
|
||||||
|
pub dimensions: Vec2,
|
||||||
|
pub color: Vec4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rect {
|
||||||
|
pub fn new(position: Vec2, dimensions: Vec2, color: Vec4) -> Self {
|
||||||
|
Rect {
|
||||||
|
position,
|
||||||
|
dimensions,
|
||||||
|
color,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue