From a51495d7a43309aad3b7cb234cfa58bbc7f6a6c2 Mon Sep 17 00:00:00 2001 From: hacknus Date: Wed, 20 May 2026 11:41:27 +0200 Subject: [PATCH 1/2] bump to bevy 0.19 and version 5.0.0 --- CHANGELOG.MD | 2 +- Cargo.toml | 8 +-- README.md | 1 + examples/bevy_egui.rs | 30 ++++++---- src/bevy_voxel_plot.rs | 123 +++++++++++++++++++++++------------------ 5 files changed, 92 insertions(+), 72 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index 0b4c8b6..ced6467 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -6,7 +6,7 @@ All notable changes to the `bevy voxel plot` crate will be documented in this fi ### Added: -* ... +* Update to bevy 0.19 # 4.0.0 - 6.4.2026 diff --git a/Cargo.toml b/Cargo.toml index ee4ad19..61cccf7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_voxel_plot" -version = "4.0.0" +version = "5.0.0" edition = "2021" authors = ["Linus Leo Stöckli"] repository = "https://github.com/hacknus/bevy_voxel_plot" @@ -13,9 +13,9 @@ homepage = "https://github.com/hacknus/bevy_voxel_plot" license = "Apache-2.0" [dependencies] -bevy = "0.18" +bevy = "0.19.0-rc.1" bytemuck = "1.25" [dev-dependencies] -bevy_panorbit_camera = { version = "0.34" } -bevy_egui = { version = "0.39" } +bevy_panorbit_camera = { git = "https://github.com/hacknus/bevy_panorbit_camera", branch = "bevy_0.19" } +bevy_egui = { git = "https://github.com/taboky-dev/bevy_egui.git", rev = "d34a47e" } diff --git a/README.md b/README.md index f76f8c3..d3e126c 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ low alpha. | bevy | bevy_voxel_plot | |------|-----------------| +| 0.19 | 5.0 | | 0.18 | 4.0 | | 0.17 | 3.0 | | 0.16 | 2.0 | diff --git a/examples/bevy_egui.rs b/examples/bevy_egui.rs index f417fa1..0559bf9 100644 --- a/examples/bevy_egui.rs +++ b/examples/bevy_egui.rs @@ -217,18 +217,24 @@ pub fn update_gui( let height = 500.0; if let Ok(ctx) = contexts.ctx_mut() { - egui::CentralPanel::default().show(ctx, |ui| { - show_plot( - &mut meshes, - &cube_preview_texture_id, - width, - height, - ui, - &mut query, - &mut opacity_threshold, - &mut cam_input, - ) - }); + let available = ctx.content_rect(); + egui::Area::new(egui::Id::new("bevy_egui_central_panel")) + .fixed_pos(available.min) + .show(ctx, |ui| { + ui.set_min_size(available.size()); + egui::CentralPanel::default().show_inside(ui, |ui| { + show_plot( + &mut meshes, + &cube_preview_texture_id, + width, + height, + ui, + &mut query, + &mut opacity_threshold, + &mut cam_input, + ) + }); + }); } } fn show_plot( diff --git a/src/bevy_voxel_plot.rs b/src/bevy_voxel_plot.rs index 262e415..c00a5b5 100644 --- a/src/bevy_voxel_plot.rs +++ b/src/bevy_voxel_plot.rs @@ -8,8 +8,10 @@ //! It's generally recommended to try the built-in instancing before going with this approach. use bevy::asset::{load_internal_asset, uuid_handle}; +use bevy::core_pipeline::core_3d::TransparentSortingInfo3d; use bevy::mesh::{MeshVertexBufferLayoutRef, VertexBufferLayout}; use bevy::pbr::SetMeshViewBindingArrayBindGroup; +use bevy::render::sync_component::SyncComponent; use bevy::render::RenderSystems; use bevy::{ core_pipeline::core_3d::Transparent3d, @@ -18,10 +20,12 @@ use bevy::{ system::{lifetimeless::*, SystemParamItem}, }, pbr::{ - MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, + self, MeshInputUniform, MeshPipeline, MeshPipelineKey, MeshPipelineSystems, MeshUniform, + RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, ViewKeyCache, }, prelude::*, render::{ + batching::gpu_preprocessing::BatchedInstanceBuffers, extract_component::{ExtractComponent, ExtractComponentPlugin}, mesh::{allocator::MeshAllocator, RenderMesh, RenderMeshBufferInfo}, render_asset::RenderAssets, @@ -33,11 +37,18 @@ use bevy::{ renderer::RenderDevice, sync_world::MainEntity, view::ExtractedView, - Render, RenderApp, + Render, RenderApp, RenderStartup, }, }; use bytemuck::{Pod, Zeroable}; +impl SyncComponent<()> for CameraPosition { + type Target = (); +} +impl SyncComponent<()> for InstanceMaterialData { + type Target = (); +} + /// Component holding per-instance data for custom rendering. #[derive(Component)] pub struct InstanceMaterialData { @@ -69,6 +80,10 @@ impl Plugin for VoxelMaterialPlugin { app.sub_app_mut(RenderApp) .add_render_command::() .init_resource::>() + .add_systems( + RenderStartup, + init_custom_pipeline.after(MeshPipelineSystems), + ) .add_systems( Render, ( @@ -84,9 +99,22 @@ impl Plugin for VoxelMaterialPlugin { ); } - fn finish(&self, app: &mut App) { - app.sub_app_mut(RenderApp).init_resource::(); + fn finish(&self, _app: &mut App) {} +} + +fn init_custom_pipeline( + mut commands: Commands, + custom_pipeline: Option>, + mesh_pipeline: Res, +) { + if custom_pipeline.is_some() { + return; } + + commands.insert_resource(CustomPipeline { + shader: SHADER_HANDLE.clone(), + mesh_pipeline: mesh_pipeline.clone(), + }); } /// Single instance data containing position, scale and color. @@ -110,44 +138,67 @@ fn queue_custom( pipeline_cache: Res, meshes: Res>, render_mesh_instances: Res, + maybe_batched_instance_buffers: Option< + Res>, + >, material_meshes: Query<(Entity, &MainEntity), With>, mut transparent_render_phases: ResMut>, - views: Query<(&ExtractedView, &Msaa)>, + views: Query<&ExtractedView>, + view_key_cache: Res, ) { let draw_custom = transparent_3d_draw_functions.read().id::(); - for (view, msaa) in &views { + for view in &views { let Some(transparent_phase) = transparent_render_phases.get_mut(&view.retained_view_entity) else { continue; }; - let msaa_key = MeshPipelineKey::from_msaa_samples(msaa.samples()); - let view_key = msaa_key | MeshPipelineKey::from_hdr(view.hdr); - let rangefinder = view.rangefinder3d(); + let Some(&view_key) = view_key_cache.get(&view.retained_view_entity) else { + continue; + }; for (entity, main_entity) in &material_meshes { let Some(mesh_instance) = render_mesh_instances.render_mesh_queue_data(*main_entity) else { continue; }; - let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id) else { + let Some(mesh) = meshes.get(mesh_instance.mesh_asset_id()) else { continue; }; - let key = - view_key | MeshPipelineKey::from_primitive_topology(mesh.primitive_topology()); + let key = view_key + | MeshPipelineKey::from_primitive_topology_and_strip_index( + mesh.primitive_topology(), + mesh.index_format(), + ); + let pipeline = pipelines .specialize(&pipeline_cache, &custom_pipeline, key, &mesh.layout) .unwrap(); transparent_phase.add(Transparent3d { + sorting_info: TransparentSortingInfo3d::Sorted { + mesh_center: pbr::get_mesh_instance_world_from_local( + *main_entity, + mesh_instance.current_uniform_index, + &render_mesh_instances, + maybe_batched_instance_buffers.as_deref(), + ) + .transform_point3( + meshes + .get(mesh_instance.mesh_asset_id()) + .unwrap() + .aabb_center, + ), + depth_bias: 0.0, + }, entity: (entity, *main_entity), pipeline, draw_function: draw_custom, - distance: rangefinder.distance(&mesh_instance.center), + distance: 0.0, batch_range: 0..1, extra_index: PhaseItemExtraIndex::None, - indexed: false, + indexed: true, }); } } @@ -234,17 +285,6 @@ struct CustomPipeline { mesh_pipeline: MeshPipeline, } -impl FromWorld for CustomPipeline { - fn from_world(world: &mut World) -> Self { - let mesh_pipeline = world.resource::().clone(); - - CustomPipeline { - shader: SHADER_HANDLE.clone(), - mesh_pipeline, - } - } -} - impl SpecializedMeshPipeline for CustomPipeline { type Key = MeshPipelineKey; @@ -255,33 +295,6 @@ impl SpecializedMeshPipeline for CustomPipeline { ) -> Result { let mut descriptor = self.mesh_pipeline.specialize(key, layout)?; - let color_format = TextureFormat::Rgba8UnormSrgb; - - descriptor.depth_stencil = Some(DepthStencilState { - format: TextureFormat::Depth32Float, - depth_compare: CompareFunction::Always, - stencil: StencilState::default(), - depth_write_enabled: false, - bias: DepthBiasState::default(), - }); - - descriptor.fragment.as_mut().unwrap().targets[0] = Some(ColorTargetState { - format: color_format, - blend: Some(BlendState { - color: BlendComponent { - src_factor: BlendFactor::SrcAlpha, - dst_factor: BlendFactor::OneMinusSrcAlpha, - operation: BlendOperation::Add, - }, - alpha: BlendComponent { - src_factor: BlendFactor::SrcAlpha, - dst_factor: BlendFactor::OneMinusSrcAlpha, - operation: BlendOperation::Add, - }, - }), - write_mask: ColorWrites::ALL, - }); - descriptor.vertex.shader = self.shader.clone(); descriptor.vertex.buffers.push(VertexBufferLayout { array_stride: size_of::() as u64, @@ -340,14 +353,14 @@ impl RenderCommand

for DrawMeshInstanced { else { return RenderCommandResult::Skip; }; - let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id) else { + let Some(gpu_mesh) = meshes.into_inner().get(mesh_instance.mesh_asset_id()) else { return RenderCommandResult::Skip; }; let Some(instance_buffer) = instance_buffer else { return RenderCommandResult::Skip; }; let Some(vertex_buffer_slice) = - mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id) + mesh_allocator.mesh_vertex_slice(&mesh_instance.mesh_asset_id()) else { return RenderCommandResult::Skip; }; @@ -361,7 +374,7 @@ impl RenderCommand

for DrawMeshInstanced { count, } => { let Some(index_buffer_slice) = - mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id) + mesh_allocator.mesh_index_slice(&mesh_instance.mesh_asset_id()) else { return RenderCommandResult::Skip; }; From c6fbf8909fbcf0d618c08a667b41a028a5142353 Mon Sep 17 00:00:00 2001 From: hacknus Date: Wed, 20 May 2026 11:53:51 +0200 Subject: [PATCH 2/2] fix opacity --- src/bevy_voxel_plot.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bevy_voxel_plot.rs b/src/bevy_voxel_plot.rs index c00a5b5..59b81ed 100644 --- a/src/bevy_voxel_plot.rs +++ b/src/bevy_voxel_plot.rs @@ -168,6 +168,7 @@ fn queue_custom( }; let key = view_key + | MeshPipelineKey::BLEND_ALPHA | MeshPipelineKey::from_primitive_topology_and_strip_index( mesh.primitive_topology(), mesh.index_format(),