mirror of
https://github.com/bevyengine/bevy
synced 2024-11-21 12:13:25 +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 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);
|
||||
|
@ -287,16 +280,37 @@ fn main() {
|
|||
]);
|
||||
|
||||
world.insert((), vec![
|
||||
|
||||
// camera
|
||||
(
|
||||
quad_handle,
|
||||
Mesh2d,
|
||||
Rect {
|
||||
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();
|
||||
for _ in 0 .. 70000 {
|
||||
for _ in 0 .. 5 {
|
||||
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)));
|
||||
}
|
||||
|
|
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 render_resources;
|
||||
pub mod passes;
|
||||
pub mod instancing;
|
||||
|
||||
mod light;
|
||||
mod render_graph;
|
||||
mod material;
|
||||
mod rect;
|
||||
|
||||
pub use light::*;
|
||||
pub use shader::*;
|
||||
|
@ -14,6 +16,7 @@ pub use render_graph::*;
|
|||
pub use material::*;
|
||||
pub use mesh::*;
|
||||
pub use camera::*;
|
||||
pub use rect::*;
|
||||
|
||||
use std::mem;
|
||||
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 std::mem;
|
||||
use zerocopy::AsBytes;
|
||||
use wgpu::{Device, SwapChainOutput};
|
||||
|
||||
pub struct InstanceBufferInfo {
|
||||
pub buffer: wgpu::Buffer,
|
||||
pub instance_count: usize,
|
||||
pub mesh_id: usize,
|
||||
}
|
||||
|
||||
pub struct ForwardInstancedPipeline {
|
||||
pub pipeline: Option<wgpu::RenderPipeline>,
|
||||
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 zerocopy::{AsBytes, FromBytes};
|
||||
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 pipeline: Option<wgpu::RenderPipeline>,
|
||||
pub depth_format: wgpu::TextureFormat,
|
||||
pub quad: Option<Handle<Mesh>>,
|
||||
pub bind_group: Option<wgpu::BindGroup>,
|
||||
}
|
||||
|
||||
|
@ -13,13 +24,48 @@ impl UiPipeline {
|
|||
UiPipeline {
|
||||
pipeline: None,
|
||||
bind_group: None,
|
||||
quad: None,
|
||||
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 {
|
||||
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(
|
||||
include_str!("ui.vert"),
|
||||
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 {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
});
|
||||
|
||||
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 fs_module = render_graph.device.create_shader_module(&fs_bytes);
|
||||
|
@ -101,7 +186,7 @@ impl Pipeline for UiPipeline {
|
|||
stencil_write_mask: 0,
|
||||
}),
|
||||
index_format: wgpu::IndexFormat::Uint16,
|
||||
vertex_buffers: &[vertex_buffer_descriptor],
|
||||
vertex_buffers: &[vertex_buffer_descriptor, instance_buffer_descriptor],
|
||||
sample_count: 1,
|
||||
sample_mask: !0,
|
||||
alpha_to_coverage_enabled: false,
|
||||
|
@ -109,34 +194,18 @@ impl Pipeline for UiPipeline {
|
|||
}
|
||||
|
||||
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(), &[]);
|
||||
|
||||
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);
|
||||
for instance_buffer_info in instance_buffer_infos.as_ref().unwrap().iter() {
|
||||
if let Some(mesh_asset) = mesh_storage.get(instance_buffer_info.mesh_id) {
|
||||
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)]);
|
||||
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);
|
||||
};
|
||||
|
||||
last_mesh_id = Some(current_mesh_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#version 450
|
||||
|
||||
layout(location = 0) in vec3 v_Normal;
|
||||
layout(location = 1) in vec4 v_Position;
|
||||
layout(location = 0) in vec4 v_Color;
|
||||
|
||||
layout(location = 0) out vec4 o_Target;
|
||||
|
||||
void main() {
|
||||
o_Target = vec4(1.0, 0.0, 0.0, 1.0);
|
||||
o_Target = v_Color;
|
||||
}
|
||||
|
|
|
@ -1,17 +1,24 @@
|
|||
#version 450
|
||||
|
||||
// vertex attributes
|
||||
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;
|
||||
// instanced attributes (RectData)
|
||||
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 {
|
||||
mat4 u_ViewProj;
|
||||
};
|
||||
|
||||
void main() {
|
||||
v_Normal = vec3(a_Normal.xyz);
|
||||
v_Position = vec4(a_Pos);
|
||||
gl_Position = u_ViewProj * v_Position;
|
||||
v_Color = a_RectColor;
|
||||
vec4 position = a_Pos * vec4(a_RectDimensions, 0.0, 1.0);
|
||||
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