diff --git a/Cargo.toml b/Cargo.toml index 085a899e..8edefc97 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bevy_gaussian_splatting" description = "bevy gaussian splatting render pipeline plugin" -version = "2.0.2" +version = "2.1.0" edition = "2021" authors = ["mosure "] license = "MIT" @@ -114,6 +114,7 @@ viewer = [ # "bevy_transform_gizmo", "bevy/multi-threaded", # bevy screenshot functionality requires bevy/multi-threaded as of 0.12.1 "clap", + "bevy/bevy_ui", ] web = [ @@ -128,13 +129,14 @@ web = [ ] webgl2 = ["bevy/webgl2"] +webgpu = ["bevy/webgpu"] [dependencies] -bevy_args = { version = "1.2.0", optional = true } -bevy-inspector-egui = { version = "0.22", optional = true } +bevy_args = { version = "1.3.0", optional = true } +bevy-inspector-egui = { version = "0.23", optional = true } bevy_mod_picking = { version = "0.17", optional = true } -bevy_panorbit_camera = { version = "0.12", optional = true } +bevy_panorbit_camera = { version = "0.14", optional = true } bevy_transform_gizmo = { version = "0.10", optional = true } bincode2 = { version = "2.0", optional = true } byte-unit = { version = "5.0", optional = true } @@ -152,7 +154,7 @@ rayon = { version = "1.8", optional = true } serde = "1.0" static_assertions = "1.1" typenum = "1.17.0" -wgpu = "0.17.1" +wgpu = "0.19.1" [target.'cfg(target_arch = "wasm32")'.dependencies] @@ -161,7 +163,7 @@ wasm-bindgen = "0.2.89" [dependencies.bevy] -version = "0.12" +version = "0.13.0" default-features = false features = [ "bevy_asset", diff --git a/README.md b/README.md index 0b0c580c..78309bcd 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,8 @@ fn setup_gaussian_cloud( | `bevy_gaussian_splatting` | `bevy` | | :-- | :-- | -| `0.4 - 1.0` | `0.12` | +| `2.1` | `0.13` | +| `0.4 - 2.0` | `0.12` | | `0.1 - 0.3` | `0.11` | ## projects using this plugin diff --git a/examples/headless.rs b/examples/headless.rs index 0943ccfb..ca6770f9 100644 --- a/examples/headless.rs +++ b/examples/headless.rs @@ -10,10 +10,6 @@ use bevy::{ render::renderer::RenderDevice, }; use bevy_args::BevyArgsPlugin; -use bevy_panorbit_camera::{ - PanOrbitCamera, - PanOrbitCameraPlugin, -}; use bevy_gaussian_splatting::{ GaussianCloud, @@ -31,7 +27,7 @@ mod frame_capture { use bevy::prelude::*; use bevy::render::render_asset::RenderAssets; - use bevy::render::render_graph::{self, NodeRunError, RenderGraph, RenderGraphContext}; + use bevy::render::render_graph::{self, NodeRunError, RenderGraph, RenderGraphContext, RenderLabel}; use bevy::render::renderer::{RenderContext, RenderDevice, RenderQueue}; use bevy::render::{Extract, RenderApp}; @@ -77,7 +73,8 @@ mod frame_capture { } } - pub const IMAGE_COPY: &str = "image_copy"; + #[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] + pub struct ImageCopyLabel; pub struct ImageCopyPlugin; impl Plugin for ImageCopyPlugin { @@ -90,9 +87,9 @@ mod frame_capture { let mut graph = render_app.world.get_resource_mut::().unwrap(); - graph.add_node(IMAGE_COPY, ImageCopyDriver); + graph.add_node(ImageCopyLabel, ImageCopyDriver); - graph.add_node_edge(IMAGE_COPY, bevy::render::main_graph::node::CAMERA_DRIVER); + graph.add_node_edge(ImageCopyLabel, bevy::render::graph::CameraDriverLabel); } } @@ -171,7 +168,7 @@ mod frame_capture { .create_command_encoder(&CommandEncoderDescriptor::default()); let block_dimensions = src_image.texture_format.block_dimensions(); - let block_size = src_image.texture_format.block_size(None).unwrap(); + let block_size = src_image.texture_format.block_copy_size(None).unwrap(); let padded_bytes_per_row = RenderDevice::align_copy_bytes_per_row( (src_image.size.x as usize / block_dimensions.0 as usize) diff --git a/src/gaussian/cloud.rs b/src/gaussian/cloud.rs index ebbadcef..54add7a3 100644 --- a/src/gaussian/cloud.rs +++ b/src/gaussian/cloud.rs @@ -2,12 +2,8 @@ use rand::{ seq::SliceRandom, Rng, }; -use std::iter::FromIterator; -use bevy::{ - prelude::*, - reflect::TypeUuid, -}; +use bevy::prelude::*; use serde::{ Deserialize, Serialize, @@ -52,11 +48,9 @@ use crate::gaussian::f16::{ Default, PartialEq, Reflect, - TypeUuid, Serialize, Deserialize, )] -#[uuid = "ac2f08eb-bc32-aabb-ff21-51571ea332d5"] pub struct GaussianCloud { pub position_visibility: Vec, @@ -77,11 +71,10 @@ pub struct GaussianCloud { Default, PartialEq, Reflect, - TypeUuid, + TypePath, Serialize, Deserialize, )] -#[uuid = "ac2f08eb-bc32-aabb-ff21-51571ea332d5"] pub struct GaussianCloud { pub position_visibility: Vec, diff --git a/src/morph/particle.rs b/src/morph/particle.rs index bb9a068e..944f4e84 100644 --- a/src/morph/particle.rs +++ b/src/morph/particle.rs @@ -11,12 +11,14 @@ use bevy::{ load_internal_asset, LoadState, }, - core_pipeline::core_3d::CORE_3D, + core_pipeline::core_3d::graph::{ + Core3d, + Node3d, + }, ecs::system::{ lifetimeless::SRes, SystemParamItem, }, - reflect::TypeUuid, render::{ Extract, render_asset::{ @@ -24,12 +26,12 @@ use bevy::{ RenderAsset, RenderAssets, RenderAssetPlugin, + RenderAssetUsages, }, render_resource::{ BindGroup, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, @@ -111,13 +113,13 @@ impl Plugin for ParticleBehaviorPlugin { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_graph_node::( - CORE_3D, + Core3d, node::MORPH, ) .add_render_graph_edge( - CORE_3D, + Core3d, node::MORPH, - bevy::core_pipeline::core_3d::graph::node::PREPASS, + Node3d::Prepass, ); render_app @@ -170,24 +172,19 @@ pub struct GpuParticleBehaviorBuffers { } impl RenderAsset for ParticleBehaviors { - type ExtractedAsset = ParticleBehaviors; type PreparedAsset = GpuParticleBehaviorBuffers; type Param = SRes; - fn extract_asset(&self) -> Self::ExtractedAsset { - self.clone() - } - fn prepare_asset( - particle_behaviors: Self::ExtractedAsset, + self, render_device: &mut SystemParamItem, - ) -> Result> { - let particle_behavior_count = particle_behaviors.0.len() as u32; + ) -> Result> { + let particle_behavior_count = self.0.len() as u32; let particle_behavior_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { label: Some("particle behavior buffer"), contents: bytemuck::cast_slice( - particle_behaviors.0.as_slice() + self.0.as_slice() ), usage: BufferUsages::VERTEX | BufferUsages::COPY_DST | BufferUsages::STORAGE, }); @@ -197,6 +194,10 @@ impl RenderAsset for ParticleBehaviors { particle_behavior_buffer, }) } + + fn asset_usage(&self) -> RenderAssetUsages { + RenderAssetUsages::RENDER_WORLD + } } @@ -211,9 +212,9 @@ impl FromWorld for ParticleBehaviorPipeline { let render_device = render_world.resource::(); let gaussian_cloud_pipeline = render_world.resource::(); - let particle_behavior_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("gaussian_cloud_particle_behavior_layout"), - entries: &[ + let particle_behavior_layout = render_device.create_bind_group_layout( + Some("gaussian_cloud_particle_behavior_layout"), + &[ BindGroupLayoutEntry { binding: 7, visibility: ShaderStages::COMPUTE, @@ -225,7 +226,7 @@ impl FromWorld for ParticleBehaviorPipeline { count: None, }, ], - }); + ); let shader_defs = shader_defs(GaussianCloudPipelineKey::default()); let pipeline_cache = render_world.resource::(); @@ -453,11 +454,9 @@ impl Default for ParticleBehavior { Default, PartialEq, Reflect, - TypeUuid, Serialize, Deserialize, )] -#[uuid = "ac2f08eb-6463-2131-6772-51571ea332d5"] pub struct ParticleBehaviors(pub Vec); diff --git a/src/morph/wavelet.rs b/src/morph/wavelet.rs deleted file mode 100644 index 7cb9d7cf..00000000 --- a/src/morph/wavelet.rs +++ /dev/null @@ -1,22 +0,0 @@ -// #[derive( -// Asset, -// Clone, -// Debug, -// PartialEq, -// Reflect, -// TypeUuid, -// Serialize, -// Deserialize, -// )] -// #[uuid = "ac2f08eb-7543-2346-ff21-51571ea332d5"] -// pub struct MorphGaussianCurve { -// pub indicies: Vec, -// pub keyframe_timestamps: Vec, -// pub keyframes: Vec, -// } - -// pub struct MorphGaussianWavelet { -// pub indicies: Vec, -// pub keyframe_timestamps: Vec, -// pub coefficients: Vec, -// } diff --git a/src/morph/wavelet.wgsl b/src/morph/wavelet.wgsl deleted file mode 100644 index c0102e6f..00000000 --- a/src/morph/wavelet.wgsl +++ /dev/null @@ -1,8 +0,0 @@ - -// struct WaveletBehavior { -// @location(0) index: u32, -// @location(1) wavelet: array, -// } - -// // wavelet behavior -// @group(4) @binding(1) var morph_wavelets: array; diff --git a/src/query/select.rs b/src/query/select.rs index 015c88dd..0eb66b25 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,5 +1,3 @@ -use std::iter::FromIterator; - use bevy::{ prelude::*, asset::LoadState, diff --git a/src/render/mod.rs b/src/render/mod.rs index 0e0136a2..e59d1156 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,35 +1,36 @@ use std::hash::Hash; use bevy::{ - prelude::*, asset::{ load_internal_asset, LoadState, }, core_pipeline::core_3d::Transparent3d, ecs::{ + query::ROQueryItem, system::{ lifetimeless::*, SystemParamItem, - }, - query::ROQueryItem, + } }, + prelude::*, render::{ Extract, extract_component::{ + ComponentUniforms, DynamicUniformIndex, UniformComponentPlugin, - ComponentUniforms, }, globals::{ - GlobalsUniform, GlobalsBuffer, + GlobalsUniform, }, render_asset::{ PrepareAssetError, RenderAsset, - RenderAssets, RenderAssetPlugin, + RenderAssetUsages, + RenderAssets, }, render_phase::{ AddRenderCommand, @@ -43,16 +44,16 @@ use bevy::{ }, render_resource::*, renderer::RenderDevice, - Render, - RenderApp, - RenderSet, view::{ ExtractedView, ViewUniform, - ViewUniforms, ViewUniformOffset, + ViewUniforms, }, - }, + Render, + RenderApp, + RenderSet, + } }; use crate::{ @@ -200,27 +201,22 @@ pub struct GpuGaussianCloud { pub debug_gpu: GaussianCloud, } impl RenderAsset for GaussianCloud { - type ExtractedAsset = GaussianCloud; type PreparedAsset = GpuGaussianCloud; type Param = SRes; - fn extract_asset(&self) -> Self::ExtractedAsset { - self.clone() - } - fn prepare_asset( - gaussian_cloud: Self::ExtractedAsset, + self, render_device: &mut SystemParamItem, - ) -> Result> { - let count = gaussian_cloud.len(); + ) -> Result> { + let count = self.len(); let draw_indirect_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { label: Some("draw indirect buffer"), - contents: wgpu::util::DrawIndirect { + contents: wgpu::util::DrawIndirectArgs { vertex_count: 4, instance_count: count as u32, - base_vertex: 0, - base_instance: 0, + first_vertex: 0, + first_instance: 0, }.as_bytes(), usage: BufferUsages::INDIRECT | BufferUsages::COPY_DST | BufferUsages::STORAGE | BufferUsages::COPY_SRC, }); @@ -232,14 +228,18 @@ impl RenderAsset for GaussianCloud { draw_indirect_buffer, #[cfg(feature = "packed")] - packed: packed::prepare_cloud(render_device, &gaussian_cloud), + packed: packed::prepare_cloud(render_device, &self), #[cfg(feature = "buffer_storage")] - planar: planar::prepare_cloud(render_device, &gaussian_cloud), + planar: planar::prepare_cloud(render_device, &self), #[cfg(feature = "debug_gpu")] debug_gpu: gaussian_cloud, }) } + + fn asset_usage(&self) -> RenderAssetUsages { + RenderAssetUsages::default() + } } #[cfg(feature = "buffer_storage")] @@ -366,14 +366,14 @@ impl FromWorld for GaussianCloudPipeline { }, ]; - let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("gaussian_view_layout"), - entries: &view_layout_entries, - }); + let view_layout = render_device.create_bind_group_layout( + Some("gaussian_view_layout"), + &view_layout_entries, + ); - let gaussian_uniform_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("gaussian_uniform_layout"), - entries: &[ + let gaussian_uniform_layout = render_device.create_bind_group_layout( + Some("gaussian_uniform_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -385,7 +385,7 @@ impl FromWorld for GaussianCloudPipeline { count: None, }, ], - }); + ); #[cfg(not(feature = "morph_particles"))] let read_only = true; @@ -397,12 +397,12 @@ impl FromWorld for GaussianCloudPipeline { #[cfg(all(feature = "buffer_storage", not(feature = "packed")))] let gaussian_cloud_layout = planar::get_bind_group_layout(render_device, read_only); #[cfg(feature = "buffer_texture")] - let gaussian_cloud_layout = texture::get_bind_group_layout(&render_device, read_only); + let gaussian_cloud_layout = texture::get_bind_group_layout(render_device, read_only); #[cfg(feature = "buffer_storage")] - let sorted_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("sorted_layout"), - entries: &[ + let sorted_layout = render_device.create_bind_group_layout( + Some("sorted_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::VERTEX_FRAGMENT, @@ -414,9 +414,9 @@ impl FromWorld for GaussianCloudPipeline { count: None, }, ], - }); + ); #[cfg(feature = "buffer_texture")] - let sorted_layout = texture::get_sorted_bind_group_layout(&render_device); + let sorted_layout = texture::get_sorted_bind_group_layout(render_device); GaussianCloudPipeline { gaussian_cloud_layout, @@ -900,20 +900,20 @@ pub fn queue_gaussian_view_bind_groups( pub struct SetGaussianViewBindGroup; impl RenderCommand

for SetGaussianViewBindGroup { type Param = (); - type ViewWorldQuery = ( + type ViewQuery = ( Read, Read, ); - type ItemWorldQuery = (); + type ItemQuery = (); #[inline] fn render<'w>( _item: &P, (view_uniform, gaussian_view_bind_group): ROQueryItem< 'w, - Self::ViewWorldQuery, + Self::ViewQuery, >, - _entity: (), + _entity: Option<()>, _: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -931,14 +931,14 @@ impl RenderCommand

for SetGaussianViewBindGroup pub struct SetGaussianUniformBindGroup; impl RenderCommand

for SetGaussianUniformBindGroup { type Param = SRes; - type ViewWorldQuery = (); - type ItemWorldQuery = Read>; + type ViewQuery = (); + type ItemQuery = Read>; #[inline] fn render<'w>( _item: &P, _view: (), - gaussian_cloud_index: ROQueryItem, + gaussian_cloud_index: Option>, bind_groups: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { @@ -946,7 +946,7 @@ impl RenderCommand

for SetGaussianUniformBindGr let bind_group = bind_groups.base_bind_group.as_ref().expect("bind group not initialized"); let mut set_bind_group = |indices: &[u32]| pass.set_bind_group(I, bind_group, indices); - let gaussian_cloud_index = gaussian_cloud_index.index(); + let gaussian_cloud_index = gaussian_cloud_index.unwrap().index(); set_bind_group(&[gaussian_cloud_index]); RenderCommandResult::Success @@ -956,8 +956,8 @@ impl RenderCommand

for SetGaussianUniformBindGr pub struct DrawGaussianInstanced; impl RenderCommand

for DrawGaussianInstanced { type Param = SRes>; - type ViewWorldQuery = (); - type ItemWorldQuery = ( + type ViewQuery = (); + type ItemQuery = ( Read>, Read, ); @@ -966,16 +966,15 @@ impl RenderCommand

for DrawGaussianInstanced { fn render<'w>( _item: &P, _view: (), - ( - handle, - bind_groups, - ): ( + entity: Option<( &'w Handle, &'w GaussianCloudBindGroup, - ), + )>, gaussian_clouds: SystemParamItem<'w, '_, Self::Param>, pass: &mut TrackedRenderPass<'w>, ) -> RenderCommandResult { + let (handle, bind_groups) = entity.expect("gaussian cloud entity not found"); + let gpu_gaussian_cloud = match gaussian_clouds.into_inner().get(handle) { Some(gpu_gaussian_cloud) => gpu_gaussian_cloud, None => return RenderCommandResult::Failure, diff --git a/src/render/packed.rs b/src/render/packed.rs index e8b3e7aa..7efcc1b7 100644 --- a/src/render/packed.rs +++ b/src/render/packed.rs @@ -3,7 +3,6 @@ use bevy::render::{ BindGroup, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, @@ -56,9 +55,9 @@ pub fn get_bind_group_layout( render_device: &RenderDevice, read_only: bool ) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("packed_gaussian_cloud_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("packed_gaussian_cloud_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -70,7 +69,7 @@ pub fn get_bind_group_layout( count: None, }, ], - }) + ) } diff --git a/src/render/planar.rs b/src/render/planar.rs index b41d47c0..3e87624d 100644 --- a/src/render/planar.rs +++ b/src/render/planar.rs @@ -146,9 +146,9 @@ pub fn get_bind_group_layout( render_device: &RenderDevice, read_only: bool ) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("planar_f16_gaussian_cloud_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("planar_f16_gaussian_cloud_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -180,7 +180,7 @@ pub fn get_bind_group_layout( count: None, }, ], - }) + ) } @@ -189,9 +189,9 @@ pub fn get_bind_group_layout( render_device: &RenderDevice, read_only: bool ) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("planar_f32_gaussian_cloud_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("planar_f32_gaussian_cloud_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -233,7 +233,7 @@ pub fn get_bind_group_layout( count: None, }, ], - }) + ) } diff --git a/src/render/texture.rs b/src/render/texture.rs index 2bbff4ce..0a5fb260 100644 --- a/src/render/texture.rs +++ b/src/render/texture.rs @@ -1,34 +1,14 @@ use bevy::{ - prelude::*, - asset::LoadState, - ecs::query::QueryItem, - render::{ + asset::LoadState, ecs::query::QueryItem, prelude::*, render::{ extract_component::{ ExtractComponent, ExtractComponentPlugin, - }, - Render, - RenderApp, - RenderSet, - render_asset::RenderAssets, - render_resource::{ - BindGroup, - BindGroupLayout, - BindGroupLayoutDescriptor, - BindGroupLayoutEntry, - BindGroupEntry, - BindingType, - BindingResource, - Extent3d, - TextureDimension, - TextureFormat, - TextureSampleType, - TextureUsages, - TextureViewDimension, - ShaderStages, - }, - renderer::RenderDevice, - }, + }, render_asset::{ + RenderAssetUsages, RenderAssets + }, render_resource::{ + BindGroup, BindGroupEntry, BindGroupLayout, BindGroupLayoutEntry, BindingResource, BindingType, Extent3d, ShaderStages, TextureDimension, TextureFormat, TextureSampleType, TextureUsages, TextureViewDimension + }, renderer::RenderDevice, Render, RenderApp, RenderSet + } }; use static_assertions::assert_cfg; @@ -95,12 +75,12 @@ pub struct TextureBuffers { } impl ExtractComponent for TextureBuffers { - type Query = &'static Self; + type QueryData = &'static Self; - type Filter = (); + type QueryFilter = (); type Out = Self; - fn extract_component(texture_buffers: QueryItem<'_, Self::Query>) -> Option { + fn extract_component(texture_buffers: QueryItem<'_, Self::QueryData>) -> Option { texture_buffers.clone().into() } } @@ -141,6 +121,8 @@ pub fn queue_gpu_texture_buffers( &TextureBuffers, )>, ) { + // TODO: verify gpu_images are loaded + for (entity, texture_buffers,) in clouds.iter() { #[cfg(feature = "f16")] let bind_group = render_device.create_bind_group( @@ -219,13 +201,15 @@ fn queue_textures( asset_server: Res, gaussian_cloud_res: Res>, mut images: ResMut>, - clouds: Query<( - Entity, - &Handle, + clouds: Query< + ( + Entity, + &Handle, + ), Without, - )>, + >, ) { - for (entity, cloud_handle, _) in clouds.iter() { + for (entity, cloud_handle) in clouds.iter() { if Some(LoadState::Loading) == asset_server.get_load_state(cloud_handle){ continue; } @@ -248,6 +232,7 @@ fn queue_textures( TextureDimension::D2, bytemuck::cast_slice(cloud.position_visibility.as_slice()).to_vec(), TextureFormat::Rgba32Float, + RenderAssetUsages::default(), // TODO: if there are no CPU image derived features, set to render only ); position_visibility.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING; let position_visibility = images.add(position_visibility); @@ -280,6 +265,7 @@ fn queue_textures( TextureDimension::D2, bytemuck::cast_slice(planar_spherical_harmonics.as_slice()).to_vec(), TextureFormat::Rgba32Uint, + RenderAssetUsages::default(), ); spherical_harmonics.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING; let spherical_harmonics = images.add(spherical_harmonics); @@ -291,6 +277,7 @@ fn queue_textures( TextureDimension::D2, bytemuck::cast_slice(cloud.covariance_3d_opacity_packed128.as_slice()).to_vec(), TextureFormat::Rgba32Uint, + RenderAssetUsages::default(), ); covariance_3d_opacity.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING; let covariance_3d_opacity = images.add(covariance_3d_opacity); @@ -309,6 +296,7 @@ fn queue_textures( TextureDimension::D2, bytemuck::cast_slice(cloud.rotation_scale_opacity_packed128.as_slice()).to_vec(), TextureFormat::Rgba32Uint, + RenderAssetUsages::default(), ); rotation_scale_opacity.texture_descriptor.usage = TextureUsages::COPY_DST | TextureUsages::TEXTURE_BINDING; let rotation_scale_opacity = images.add(rotation_scale_opacity); @@ -339,9 +327,9 @@ fn queue_textures( pub fn get_sorted_bind_group_layout( render_device: &RenderDevice, ) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("texture_sorted_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("texture_sorted_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -353,7 +341,7 @@ pub fn get_sorted_bind_group_layout( count: None, }, ], - }) + ) } @@ -368,9 +356,9 @@ pub fn get_bind_group_layout( TextureViewDimension::D2Array }; - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("texture_f16_gaussian_cloud_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("texture_f16_gaussian_cloud_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -404,7 +392,7 @@ pub fn get_bind_group_layout( count: None, }, ], - }) + ) } @@ -413,9 +401,9 @@ pub fn get_bind_group_layout( render_device: &RenderDevice, read_only: bool ) -> BindGroupLayout { - render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("texture_f32_gaussian_cloud_layout"), - entries: &[ + render_device.create_bind_group_layout( + Some("texture_f32_gaussian_cloud_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::all(), @@ -457,5 +445,5 @@ pub fn get_bind_group_layout( count: None, }, ], - }) + ) } diff --git a/src/sort/mod.rs b/src/sort/mod.rs index e44baf1f..2143cd6c 100644 --- a/src/sort/mod.rs +++ b/src/sort/mod.rs @@ -5,12 +5,12 @@ use bevy::{ lifetimeless::SRes, SystemParamItem, }, - reflect::TypeUuid, render::{ render_resource::*, render_asset::{ RenderAsset, RenderAssetPlugin, + RenderAssetUsages, PrepareAssetError, }, renderer::RenderDevice, @@ -131,6 +131,7 @@ fn update_textures_on_change( AssetEvent::Added { id: _ } => {}, AssetEvent::Removed { id: _ } => {}, AssetEvent::LoadedWithDependencies { id: _ } => {}, + AssetEvent::Unused { id: _ } => {}, } } } @@ -142,12 +143,14 @@ fn auto_insert_sorted_entries( asset_server: Res, gaussian_clouds_res: Res>, mut sorted_entries_res: ResMut>, - gaussian_clouds: Query<( - Entity, - &Handle, - &GaussianCloudSettings, - Without>, - )>, + gaussian_clouds: Query< + ( + Entity, + &Handle, + &GaussianCloudSettings, + ), + Without> + >, #[cfg(feature = "buffer_texture")] mut images: ResMut>, @@ -156,7 +159,6 @@ fn auto_insert_sorted_entries( entity, gaussian_cloud_handle, _settings, - _, ) in gaussian_clouds.iter() { // // TODO: specialize vertex shader for sort mode (e.g. draw_indirect but no sort indirection) // if settings.sort_mode == SortMode::None { @@ -199,6 +201,7 @@ fn auto_insert_sorted_entries( TextureDimension::D2, bytemuck::cast_slice(sorted.as_slice()).to_vec(), TextureFormat::Rg32Uint, + RenderAssetUsages::default(), )), sorted, }); @@ -233,9 +236,7 @@ pub struct SortEntry { Default, PartialEq, Reflect, - TypeUuid, )] -#[uuid = "ac2f08eb-fa13-ccdd-ea11-51571ea332d5"] pub struct SortedEntries { pub sorted: Vec, @@ -244,34 +245,33 @@ pub struct SortedEntries { } impl RenderAsset for SortedEntries { - type ExtractedAsset = SortedEntries; type PreparedAsset = GpuSortedEntry; type Param = SRes; - fn extract_asset(&self) -> Self::ExtractedAsset { - self.clone() - } - fn prepare_asset( - sorted_entries: Self::ExtractedAsset, + self, render_device: &mut SystemParamItem, - ) -> Result> { + ) -> Result> { let sorted_entry_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { label: Some("sorted_entry_buffer"), - contents: bytemuck::cast_slice(sorted_entries.sorted.as_slice()), + contents: bytemuck::cast_slice(self.sorted.as_slice()), usage: BufferUsages::COPY_SRC | BufferUsages::COPY_DST | BufferUsages::STORAGE, }); - let count = sorted_entries.sorted.len(); + let count = self.sorted.len(); Ok(GpuSortedEntry { sorted_entry_buffer, count, #[cfg(feature = "buffer_texture")] - texture: sorted_entries.texture, + texture: self.texture, }) } + + fn asset_usage(&self) -> RenderAssetUsages { + RenderAssetUsages::default() + } } diff --git a/src/sort/radix.rs b/src/sort/radix.rs index 85003014..cd85112a 100644 --- a/src/sort/radix.rs +++ b/src/sort/radix.rs @@ -6,14 +6,16 @@ use bevy::{ load_internal_asset, LoadState, }, - core_pipeline::core_3d::CORE_3D, + core_pipeline::core_3d::graph::{ + Core3d, + Node3d, + }, render::{ render_asset::RenderAssets, render_resource::{ BindGroup, BindGroupEntry, BindGroupLayout, - BindGroupLayoutDescriptor, BindGroupLayoutEntry, BindingResource, BindingType, @@ -40,6 +42,7 @@ use bevy::{ NodeRunError, RenderGraphApp, RenderGraphContext, + RenderLabel, }, Render, RenderApp, @@ -81,9 +84,9 @@ assert_cfg!( const RADIX_SHADER_HANDLE: Handle = Handle::weak_from_u128(6234673214); const TEMPORAL_SORT_SHADER_HANDLE: Handle = Handle::weak_from_u128(1634543224); -pub mod node { - pub const RADIX_SORT: &str = "radix_sort"; -} +#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)] +pub struct RadixSortLabel; + #[derive(Default)] pub struct RadixSortPlugin; @@ -107,13 +110,13 @@ impl Plugin for RadixSortPlugin { if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { render_app .add_render_graph_node::( - CORE_3D, - node::RADIX_SORT, + Core3d, + RadixSortLabel, ) .add_render_graph_edge( - CORE_3D, - node::RADIX_SORT, - bevy::core_pipeline::core_3d::graph::node::PREPASS, + Core3d, + RadixSortLabel, + Node3d::Prepass, ); render_app @@ -139,6 +142,7 @@ impl Plugin for RadixSortPlugin { #[derive(Resource, Default)] pub struct RadixSortBuffers { + // TODO: use a more ECS-friendly approach pub asset_map: HashMap< AssetId, GpuRadixBuffers, @@ -256,14 +260,14 @@ impl FromWorld for RadixSortPipeline { ty: BindingType::Buffer { ty: BufferBindingType::Storage { read_only: false }, has_dynamic_offset: false, - min_binding_size: BufferSize::new(std::mem::size_of::() as u64), + min_binding_size: BufferSize::new(std::mem::size_of::() as u64), }, count: None, }; - let radix_sort_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { - label: Some("radix_sort_layout"), - entries: &[ + let radix_sort_layout = render_device.create_bind_group_layout( + Some("radix_sort_layout"), + &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::COMPUTE, @@ -298,7 +302,7 @@ impl FromWorld for RadixSortPipeline { count: None, }, ], - }); + ); let sorting_layout = vec![ gaussian_cloud_pipeline.view_layout.clone(), diff --git a/tests/gpu/_harness.rs b/tests/gpu/_harness.rs index f96e9834..75b466ca 100644 --- a/tests/gpu/_harness.rs +++ b/tests/gpu/_harness.rs @@ -25,7 +25,6 @@ pub fn test_harness_app( DefaultPlugins .set(WindowPlugin { primary_window: Some(Window { - fit_canvas_to_parent: false, mode: bevy::window::WindowMode::Windowed, present_mode: bevy::window::PresentMode::AutoVsync, prevent_default_event_handling: false, diff --git a/tests/gpu/radix.rs b/tests/gpu/radix.rs index 4740d763..fcd5c4c8 100644 --- a/tests/gpu/radix.rs +++ b/tests/gpu/radix.rs @@ -10,10 +10,11 @@ use bevy::{ prelude::*, core::FrameCount, core_pipeline::{ - core_3d::{ - CORE_3D, - Transparent3d, + core_3d::graph::{ + Core3d, + Node3d, }, + Transparent3d, tonemapping::Tonemapping, }, render::{ diff --git a/tools/compare_aabb_obb.rs b/tools/compare_aabb_obb.rs index 5777208f..da1f1122 100644 --- a/tools/compare_aabb_obb.rs +++ b/tools/compare_aabb_obb.rs @@ -1,7 +1,6 @@ use bevy::{ prelude::*, app::AppExit, - core::Name, core_pipeline::tonemapping::Tonemapping, }; use bevy_args::{ @@ -112,7 +111,6 @@ fn compare_aabb_obb_app() { .set(ImagePlugin::default_nearest()) .set(WindowPlugin { primary_window: Some(Window { - fit_canvas_to_parent: false, mode: bevy::window::WindowMode::Windowed, present_mode: bevy::window::PresentMode::AutoVsync, prevent_default_event_handling: false, @@ -142,7 +140,7 @@ fn compare_aabb_obb_app() { } pub fn esc_close( - keys: Res>, + keys: Res>, mut exit: EventWriter ) { if keys.just_pressed(KeyCode::Escape) { diff --git a/viewer/viewer.rs b/viewer/viewer.rs index fa3bc1f1..e3d101ac 100644 --- a/viewer/viewer.rs +++ b/viewer/viewer.rs @@ -4,10 +4,7 @@ use std::path::PathBuf; use bevy::{ prelude::*, app::AppExit, - core::{ - Name, - FrameCount, - }, + core::FrameCount, core_pipeline::tonemapping::Tonemapping, diagnostic::{ DiagnosticsStore, @@ -88,7 +85,7 @@ fn setup_gaussian_cloud( tonemapping: Tonemapping::None, ..default() }, - PanOrbitCamera{ + PanOrbitCamera { allow_upside_down: true, orbit_smoothness: 0.0, pan_smoothness: 0.0, @@ -198,7 +195,7 @@ fn example_app() { #[cfg(not(target_arch = "wasm32"))] let primary_window = Some(Window { - fit_canvas_to_parent: false, + canvas: Some("#bevy".to_string()), mode: bevy::window::WindowMode::Windowed, prevent_default_event_handling: false, resolution: (config.width, config.height).into(), @@ -276,12 +273,12 @@ fn example_app() { pub fn press_s_screenshot( - keys: Res>, + keys: Res>, main_window: Query>, mut screenshot_manager: ResMut, current_frame: Res, ) { - if keys.just_pressed(KeyCode::S) { + if keys.just_pressed(KeyCode::KeyS) { if let Ok(window_entity) = main_window.get_single() { let images_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("screenshots"); std::fs::create_dir_all(&images_dir).unwrap(); @@ -299,7 +296,7 @@ pub fn press_s_screenshot( } pub fn press_esc_close( - keys: Res>, + keys: Res>, mut exit: EventWriter ) { if keys.just_pressed(KeyCode::Escape) { @@ -309,10 +306,10 @@ pub fn press_esc_close( #[cfg(feature = "query_select")] fn press_i_invert_selection( - keys: Res>, + keys: Res>, mut select_inverse_events: EventWriter, ) { - if keys.just_pressed(KeyCode::I) { + if keys.just_pressed(KeyCode::KeyI) { log("inverting selection"); select_inverse_events.send(InvertSelectionEvent); } @@ -320,10 +317,10 @@ fn press_i_invert_selection( #[cfg(feature = "query_select")] fn press_o_save_selection( - keys: Res>, + keys: Res>, mut select_inverse_events: EventWriter, ) { - if keys.just_pressed(KeyCode::O) { + if keys.just_pressed(KeyCode::KeyO) { log("saving selection"); select_inverse_events.send(SaveSelectionEvent); } @@ -366,7 +363,7 @@ fn fps_update_system( mut query: Query<&mut Text, With>, ) { for mut text in &mut query { - if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) { + if let Some(fps) = diagnostics.get(&FrameTimeDiagnosticsPlugin::FPS) { if let Some(value) = fps.smoothed() { text.sections[1].value = format!("{value:.2}"); } diff --git a/www/index.html b/www/index.html index 4007d9e5..d05d4ed5 100644 --- a/www/index.html +++ b/www/index.html @@ -20,4 +20,7 @@ // Disable right-click context menu document.addEventListener('contextmenu', event => event.preventDefault()); + + +