mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
update mesh on gpu when it changes
This commit is contained in:
parent
5d0d3d28c7
commit
fcc0a6303b
14 changed files with 173 additions and 95 deletions
|
@ -143,7 +143,7 @@ impl AssetServer {
|
|||
let loader = resources.get::<Box<dyn AssetLoader<T>>>().unwrap();
|
||||
let asset = loader.load_from_file(&asset_path)?;
|
||||
let handle = Handle::from(handle_id);
|
||||
assets.add_with_handle(handle, asset);
|
||||
assets.set(handle, asset);
|
||||
assets.set_path(handle, &asset_path.path);
|
||||
Ok(handle)
|
||||
} else {
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::collections::HashMap;
|
|||
|
||||
pub enum AssetEvent<T> {
|
||||
Created { handle: Handle<T> },
|
||||
Modified { handle: Handle<T> },
|
||||
}
|
||||
|
||||
pub struct Assets<T> {
|
||||
|
@ -40,15 +41,26 @@ impl<T> Assets<T> {
|
|||
handle
|
||||
}
|
||||
|
||||
pub fn add_with_handle(&mut self, handle: Handle<T>, asset: T) {
|
||||
pub fn set(&mut self, handle: Handle<T>, asset: T) {
|
||||
let exists = self.assets.contains_key(&handle.id);
|
||||
self.assets.insert(handle.id, asset);
|
||||
|
||||
if exists {
|
||||
self.events.send(AssetEvent::Modified { handle });
|
||||
} else {
|
||||
self.events.send(AssetEvent::Created { handle });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_default(&mut self, asset: T) -> Handle<T> {
|
||||
let exists = self.assets.contains_key(&DEFAULT_HANDLE_ID);
|
||||
self.assets.insert(DEFAULT_HANDLE_ID, asset);
|
||||
let handle = Handle::default();
|
||||
if exists {
|
||||
self.events.send(AssetEvent::Modified { handle });
|
||||
} else {
|
||||
self.events.send(AssetEvent::Created { handle });
|
||||
}
|
||||
handle
|
||||
}
|
||||
|
||||
|
@ -111,7 +123,7 @@ impl AddAsset for AppBuilder {
|
|||
{
|
||||
self.init_resource::<Assets<T>>()
|
||||
.add_system_to_stage(
|
||||
stage::EVENT_UPDATE,
|
||||
stage::POST_UPDATE,
|
||||
Assets::<T>::asset_event_system.system(),
|
||||
)
|
||||
.add_event::<AssetEvent<T>>()
|
||||
|
|
|
@ -53,7 +53,7 @@ pub fn update_asset_storage_system<T>(
|
|||
match asset_channel.receiver.try_recv() {
|
||||
Ok(result) => {
|
||||
let asset = result.result.unwrap();
|
||||
assets.add_with_handle(result.handle, asset);
|
||||
assets.set(result.handle, asset);
|
||||
assets.set_path(result.handle, &result.path.path);
|
||||
}
|
||||
Err(TryRecvError::Empty) => {
|
||||
|
|
|
@ -73,7 +73,6 @@ impl AppPlugin for RenderPlugin {
|
|||
|
||||
app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE)
|
||||
.add_stage_after(RENDER_RESOURCE_STAGE, RENDER_STAGE)
|
||||
// resources
|
||||
.add_asset::<Mesh>()
|
||||
.add_asset::<Texture>()
|
||||
.add_asset::<Shader>()
|
||||
|
@ -86,12 +85,9 @@ impl AppPlugin for RenderPlugin {
|
|||
.init_resource::<VertexBufferDescriptors>()
|
||||
.init_resource::<EntityRenderResourceAssignments>()
|
||||
.init_resource::<EntitiesWaitingForAssets>()
|
||||
// core systems
|
||||
.add_system(entity_render_resource_assignments_system())
|
||||
.init_system_to_stage(stage::POST_UPDATE, camera::camera_update_system)
|
||||
.add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system())
|
||||
.add_system_to_stage(stage::PRE_UPDATE, EntitiesWaitingForAssets::clear_system.system())
|
||||
// render resource provider systems
|
||||
.init_system_to_stage(RENDER_RESOURCE_STAGE, mesh_resource_provider_system);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,16 @@ use crate::{
|
|||
state_descriptors::{IndexFormat, PrimitiveTopology},
|
||||
VertexBufferDescriptor, VertexBufferDescriptors, VertexFormat,
|
||||
},
|
||||
render_resource::{BufferInfo, BufferUsage, RenderResourceAssignments, EntitiesWaitingForAssets},
|
||||
render_resource::{BufferInfo, BufferUsage, EntitiesWaitingForAssets},
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
shader::AsUniforms,
|
||||
Renderable, Vertex,
|
||||
};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_app::Events;
|
||||
use bevy_asset::{AssetEvent, Assets, Handle};
|
||||
use glam::*;
|
||||
use legion::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
use std::{borrow::Cow, collections::HashSet};
|
||||
use thiserror::Error;
|
||||
use zerocopy::AsBytes;
|
||||
|
||||
|
@ -170,41 +171,50 @@ pub mod shape {
|
|||
use crate::pipeline::state_descriptors::PrimitiveTopology;
|
||||
use glam::*;
|
||||
|
||||
pub struct Cube;
|
||||
pub struct Cube {
|
||||
pub size: f32,
|
||||
}
|
||||
|
||||
impl Default for Cube {
|
||||
fn default() -> Self {
|
||||
Cube { size: 1.0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Cube> for Mesh {
|
||||
fn from(_: Cube) -> Self {
|
||||
fn from(cube: Cube) -> Self {
|
||||
let size = cube.size;
|
||||
let vertices = &[
|
||||
// top (0., 0., 1.)
|
||||
([-1., -1., 1.], [0., 0., 1.], [0., 0.]),
|
||||
([1., -1., 1.], [0., 0., 1.], [1., 0.]),
|
||||
([1., 1., 1.], [0., 0., 1.], [1., 1.]),
|
||||
([-1., 1., 1.], [0., 0., 1.], [0., 1.]),
|
||||
// bottom (0., 0., -1.)
|
||||
([-1., 1., -1.], [0., 0., -1.], [1., 0.]),
|
||||
([1., 1., -1.], [0., 0., -1.], [0., 0.]),
|
||||
([1., -1., -1.], [0., 0., -1.], [0., 1.]),
|
||||
([-1., -1., -1.], [0., 0., -1.], [1., 1.]),
|
||||
// right (1., 0., 0.)
|
||||
([1., -1., -1.], [1., 0., 0.], [0., 0.]),
|
||||
([1., 1., -1.], [1., 0., 0.], [1., 0.]),
|
||||
([1., 1., 1.], [1., 0., 0.], [1., 1.]),
|
||||
([1., -1., 1.], [1., 0., 0.], [0., 1.]),
|
||||
// left (-1., 0., 0.)
|
||||
([-1., -1., 1.], [-1., 0., 0.], [1., 0.]),
|
||||
([-1., 1., 1.], [-1., 0., 0.], [0., 0.]),
|
||||
([-1., 1., -1.], [-1., 0., 0.], [0., 1.]),
|
||||
([-1., -1., -1.], [-1., 0., 0.], [1., 1.]),
|
||||
// front (0., 1., 0.)
|
||||
([1., 1., -1.], [0., 1., 0.], [1., 0.]),
|
||||
([-1., 1., -1.], [0., 1., 0.], [0., 0.]),
|
||||
([-1., 1., 1.], [0., 1., 0.], [0., 1.]),
|
||||
([1., 1., 1.], [0., 1., 0.], [1., 1.]),
|
||||
// back (0., -1., 0.)
|
||||
([1., -1., 1.], [0., -1., 0.], [0., 0.]),
|
||||
([-1., -1., 1.], [0., -1., 0.], [1., 0.]),
|
||||
([-1., -1., -1.], [0., -1., 0.], [1., 1.]),
|
||||
([1., -1., -1.], [0., -1., 0.], [0., 1.]),
|
||||
// top (0., 0., size)
|
||||
([-size, -size, size], [0., 0., size], [0., 0.]),
|
||||
([size, -size, size], [0., 0., size], [size, 0.]),
|
||||
([size, size, size], [0., 0., size], [size, size]),
|
||||
([-size, size, size], [0., 0., size], [0., size]),
|
||||
// bottom (0., 0., -size)
|
||||
([-size, size, -size], [0., 0., -size], [size, 0.]),
|
||||
([size, size, -size], [0., 0., -size], [0., 0.]),
|
||||
([size, -size, -size], [0., 0., -size], [0., size]),
|
||||
([-size, -size, -size], [0., 0., -size], [size, size]),
|
||||
// right (size, 0., 0.)
|
||||
([size, -size, -size], [size, 0., 0.], [0., 0.]),
|
||||
([size, size, -size], [size, 0., 0.], [size, 0.]),
|
||||
([size, size, size], [size, 0., 0.], [size, size]),
|
||||
([size, -size, size], [size, 0., 0.], [0., size]),
|
||||
// left (-size, 0., 0.)
|
||||
([-size, -size, size], [-size, 0., 0.], [size, 0.]),
|
||||
([-size, size, size], [-size, 0., 0.], [0., 0.]),
|
||||
([-size, size, -size], [-size, 0., 0.], [0., size]),
|
||||
([-size, -size, -size], [-size, 0., 0.], [size, size]),
|
||||
// front (0., size, 0.)
|
||||
([size, size, -size], [0., size, 0.], [size, 0.]),
|
||||
([-size, size, -size], [0., size, 0.], [0., 0.]),
|
||||
([-size, size, size], [0., size, 0.], [0., size]),
|
||||
([size, size, size], [0., size, 0.], [size, size]),
|
||||
// back (0., -size, 0.)
|
||||
([size, -size, size], [0., -size, 0.], [0., 0.]),
|
||||
([-size, -size, size], [0., -size, 0.], [size, 0.]),
|
||||
([-size, -size, -size], [0., -size, 0.], [size, size]),
|
||||
([size, -size, -size], [0., -size, 0.], [0., size]),
|
||||
];
|
||||
|
||||
let mut positions = Vec::new();
|
||||
|
@ -310,45 +320,32 @@ pub mod shape {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn mesh_specializer_system() -> Box<dyn Schedulable> {
|
||||
SystemBuilder::new("mesh_specializer")
|
||||
.read_resource::<Assets<Mesh>>()
|
||||
.with_query(
|
||||
<(Read<Handle<Mesh>>, Write<Renderable>)>::query()
|
||||
.filter(changed::<Handle<Mesh>>() | changed::<Renderable>()),
|
||||
)
|
||||
.build(|_, world, meshes, query| {
|
||||
for (mesh_handle, mut renderable) in query.iter_mut(world) {
|
||||
if let Some(mesh) = meshes.get(&mesh_handle) {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.primitive_topology = mesh.primitive_topology;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_mesh_resource(
|
||||
render_resources: &dyn RenderResourceContext,
|
||||
render_resource_assignments: &mut RenderResourceAssignments,
|
||||
renderable: &mut Renderable,
|
||||
vertex_buffer_descriptor: &VertexBufferDescriptor,
|
||||
entities_waiting_for_assets: &EntitiesWaitingForAssets,
|
||||
entity: Entity,
|
||||
handle: Handle<Mesh>,
|
||||
meshes: &Assets<Mesh>,
|
||||
mesh_changed: bool,
|
||||
) {
|
||||
log::trace!("setup mesh for {:?}", render_resource_assignments.id);
|
||||
log::trace!(
|
||||
"setup mesh for {:?}",
|
||||
renderable.render_resource_assignments.id
|
||||
);
|
||||
let index_format = IndexFormat::Uint16;
|
||||
let (vertex_buffer, index_buffer) = if let Some(vertex_buffer) =
|
||||
render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
|
||||
let (vertex_buffer, index_buffer) = if mesh_changed
|
||||
|| render_resources
|
||||
.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
|
||||
.is_none()
|
||||
{
|
||||
(
|
||||
vertex_buffer,
|
||||
render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX),
|
||||
)
|
||||
} else {
|
||||
if let Some(mesh_asset) = meshes.get(&handle) {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.primitive_topology = mesh_asset.primitive_topology;
|
||||
|
||||
let vertex_bytes = mesh_asset
|
||||
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
|
||||
.unwrap();
|
||||
|
@ -377,35 +374,108 @@ fn setup_mesh_resource(
|
|||
entities_waiting_for_assets.add(entity);
|
||||
return;
|
||||
}
|
||||
} else if let Some(vertex_buffer) =
|
||||
render_resources.get_asset_resource(handle, VERTEX_BUFFER_ASSET_INDEX)
|
||||
{
|
||||
(
|
||||
vertex_buffer,
|
||||
render_resources.get_asset_resource(handle, INDEX_BUFFER_ASSET_INDEX),
|
||||
)
|
||||
} else {
|
||||
panic!("This should never be reached. The current 'if let' limitations make this case required.")
|
||||
};
|
||||
|
||||
render_resource_assignments.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.set_vertex_buffer("Vertex", vertex_buffer, index_buffer);
|
||||
}
|
||||
|
||||
pub fn mesh_resource_provider_system(resources: &mut Resources) -> Box<dyn Schedulable> {
|
||||
let mut vertex_buffer_descriptors = resources.get_mut::<VertexBufferDescriptors>().unwrap();
|
||||
let mesh_events = resources.get::<Events<AssetEvent<Mesh>>>().unwrap();
|
||||
let mut mesh_event_reader = mesh_events.get_reader();
|
||||
// TODO: allow pipelines to specialize on vertex_buffer_descriptor and index_format
|
||||
let vertex_buffer_descriptor = Vertex::get_vertex_buffer_descriptor().unwrap();
|
||||
vertex_buffer_descriptors.set(vertex_buffer_descriptor.clone());
|
||||
SystemBuilder::new("mesh_resource_provider")
|
||||
.read_resource::<RenderResources>()
|
||||
.read_resource::<Assets<Mesh>>()
|
||||
.read_resource::<EntitiesWaitingForAssets>()
|
||||
.read_resource::<Events<AssetEvent<Mesh>>>()
|
||||
.with_query(<(Read<Handle<Mesh>>, Write<Renderable>)>::query())
|
||||
.build(
|
||||
move |_, world, (render_resource_context, meshes, entities_waiting_for_assets), query| {
|
||||
move |_,
|
||||
world,
|
||||
(render_resource_context, meshes, mesh_events),
|
||||
query| {
|
||||
let render_resources = &*render_resource_context.context;
|
||||
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
|
||||
for (entity, (handle, mut renderable)) in query.iter_entities_mut(world) {
|
||||
setup_mesh_resource(
|
||||
render_resources,
|
||||
&mut renderable.render_resource_assignments,
|
||||
&vertex_buffer_descriptor,
|
||||
entities_waiting_for_assets,
|
||||
entity,
|
||||
*handle,
|
||||
&meshes,
|
||||
let changed_meshes = mesh_event_reader
|
||||
.iter(&mesh_events)
|
||||
.map(|e| match e {
|
||||
AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
|
||||
Some(handle)
|
||||
}
|
||||
})
|
||||
.filter(|h| h.is_some())
|
||||
.map(|h| *h.unwrap())
|
||||
.collect::<HashSet<Handle<Mesh>>>();
|
||||
|
||||
for changed_mesh_handle in changed_meshes.iter() {
|
||||
if let Some(mesh) = meshes.get(changed_mesh_handle) {
|
||||
let vertex_bytes = mesh
|
||||
.get_vertex_buffer_bytes(&vertex_buffer_descriptor)
|
||||
.unwrap();
|
||||
// TODO: use a staging buffer here
|
||||
let vertex_buffer = render_resources.create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::VERTEX,
|
||||
..Default::default()
|
||||
},
|
||||
&vertex_bytes,
|
||||
);
|
||||
|
||||
let index_bytes = mesh.get_index_buffer_bytes(IndexFormat::Uint16).unwrap();
|
||||
let index_buffer = render_resources.create_buffer_with_data(
|
||||
BufferInfo {
|
||||
buffer_usage: BufferUsage::INDEX,
|
||||
..Default::default()
|
||||
},
|
||||
&index_bytes,
|
||||
);
|
||||
|
||||
render_resources.set_asset_resource(
|
||||
*changed_mesh_handle,
|
||||
vertex_buffer,
|
||||
VERTEX_BUFFER_ASSET_INDEX,
|
||||
);
|
||||
render_resources.set_asset_resource(
|
||||
*changed_mesh_handle,
|
||||
index_buffer,
|
||||
INDEX_BUFFER_ASSET_INDEX,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: remove this once batches are pipeline specific and deprecate assigned_meshes draw target
|
||||
for (handle, mut renderable) in query.iter_mut(world) {
|
||||
if let Some(mesh) = meshes.get(&handle) {
|
||||
renderable
|
||||
.render_resource_assignments
|
||||
.pipeline_specialization
|
||||
.primitive_topology = mesh.primitive_topology;
|
||||
}
|
||||
|
||||
if let Some(vertex_buffer) =
|
||||
render_resources.get_asset_resource(*handle, VERTEX_BUFFER_ASSET_INDEX)
|
||||
{
|
||||
let index_buffer =
|
||||
render_resources.get_asset_resource(*handle, INDEX_BUFFER_ASSET_INDEX);
|
||||
|
||||
renderable.render_resource_assignments.set_vertex_buffer(
|
||||
"Vertex",
|
||||
vertex_buffer,
|
||||
index_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -48,7 +48,7 @@ impl AppPlugin for UiPlugin {
|
|||
render_graph.add_ui_graph(resources);
|
||||
|
||||
let mut meshes = resources.get_mut::<Assets<Mesh>>().unwrap();
|
||||
meshes.add_with_handle(
|
||||
meshes.set(
|
||||
QUAD_HANDLE,
|
||||
Mesh::from(Quad {
|
||||
size: Vec2::new(1.0, 1.0),
|
||||
|
|
|
@ -78,7 +78,7 @@ impl UiRenderGraphBuilder for RenderGraph {
|
|||
.unwrap();
|
||||
let mut pipelines = resources.get_mut::<Assets<PipelineDescriptor>>().unwrap();
|
||||
let mut shaders = resources.get_mut::<Assets<Shader>>().unwrap();
|
||||
pipelines.add_with_handle(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
|
||||
pipelines.set(UI_PIPELINE_HANDLE, build_ui_pipeline(&mut shaders));
|
||||
let main_pass: &mut PassNode = self
|
||||
.get_node_mut(base_render_graph::node::MAIN_PASS)
|
||||
.unwrap();
|
||||
|
|
|
@ -21,7 +21,7 @@ fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
let cube_material_handle = materials.add(StandardMaterial {
|
||||
albedo: Color::rgb(0.5, 0.4, 0.3),
|
||||
..Default::default()
|
||||
|
|
|
@ -14,7 +14,7 @@ fn setup(
|
|||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
// create a cube and a plane mesh
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 }));
|
||||
|
||||
// create materials for our cube and plane
|
||||
|
|
|
@ -30,7 +30,7 @@ fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
let plane_handle = meshes.add(Mesh::from(shape::Plane { size: 10.0 }));
|
||||
let cube_material_handle = materials.add(StandardMaterial {
|
||||
albedo: Color::rgb(0.5, 0.4, 0.3),
|
||||
|
|
|
@ -14,7 +14,7 @@ fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
let cube_material_handle = materials.add(StandardMaterial {
|
||||
albedo: Color::rgb(0.5, 0.4, 0.3),
|
||||
..Default::default()
|
||||
|
|
|
@ -65,7 +65,7 @@ fn setup(
|
|||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
let cube_material_handle = materials.add(StandardMaterial {
|
||||
albedo: Color::rgb(0.5, 0.4, 0.3),
|
||||
..Default::default()
|
||||
|
|
|
@ -68,7 +68,7 @@ fn setup(
|
|||
let material = materials.add(MyMaterial {
|
||||
color: Color::rgb(0.0, 0.8, 0.0),
|
||||
});
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
|
||||
command_buffer
|
||||
.build()
|
||||
|
|
|
@ -84,7 +84,7 @@ fn setup(
|
|||
always_red: true,
|
||||
});
|
||||
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube));
|
||||
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 1.0 }));
|
||||
|
||||
command_buffer
|
||||
.build()
|
||||
|
|
Loading…
Reference in a new issue