update mesh on gpu when it changes

This commit is contained in:
Carter Anderson 2020-05-16 00:21:04 -07:00
parent 5d0d3d28c7
commit fcc0a6303b
14 changed files with 173 additions and 95 deletions

View file

@ -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 {

View file

@ -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);
self.events.send(AssetEvent::Created { handle });
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();
self.events.send(AssetEvent::Created { handle });
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>>()

View file

@ -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) => {

View file

@ -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);
}
}

View file

@ -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;
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 (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,
);
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,
);
}
}
},
)

View file

@ -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),

View file

@ -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();

View file

@ -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()

View file

@ -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

View file

@ -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),

View file

@ -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()

View file

@ -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()

View file

@ -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()

View file

@ -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()