mirror of
https://github.com/eliasstepanik/voxel-simulation.git
synced 2026-01-10 21:38:29 +00:00
Integrate bevy_app_compute for GPU meshing
This commit is contained in:
parent
1802595f7e
commit
5a7269a446
@ -21,4 +21,6 @@ smallvec = "1.14.0"
|
||||
once_cell = "1.21.3"
|
||||
rayon = "1.10.0"
|
||||
bincode = "1.3"
|
||||
bevy_app_compute = "0.16"
|
||||
bytemuck = { version = "1.14", features = ["derive"] }
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use crate::plugins::environment::systems::voxels::debug::{draw_grid, visualize_octree_system};
|
||||
use crate::plugins::environment::systems::voxels::lod::update_chunk_lods;
|
||||
use crate::plugins::environment::systems::voxels::meshing_gpu::GpuMeshingPlugin;
|
||||
use crate::plugins::environment::systems::voxels::meshing_gpu::{
|
||||
GpuMeshingWorker, queue_gpu_meshing,
|
||||
};
|
||||
use bevy_app_compute::prelude::{AppComputePlugin, AppComputeWorkerPlugin};
|
||||
use crate::plugins::environment::systems::voxels::queue_systems;
|
||||
use crate::plugins::environment::systems::voxels::queue_systems::{
|
||||
enqueue_visible_chunks, process_chunk_queue,
|
||||
@ -25,7 +28,8 @@ impl Plugin for EnvironmentPlugin {
|
||||
crate::plugins::environment::systems::voxel_system::setup,
|
||||
),
|
||||
);
|
||||
app.add_plugins(GpuMeshingPlugin);
|
||||
app.add_plugins(AppComputePlugin);
|
||||
app.add_plugins(AppComputeWorkerPlugin::<GpuMeshingWorker>::default());
|
||||
|
||||
let view_distance_chunks = 100;
|
||||
app.insert_resource(ChunkCullingCfg {
|
||||
@ -52,6 +56,7 @@ impl Plugin for EnvironmentPlugin {
|
||||
process_chunk_queue.after(enqueue_visible_chunks),
|
||||
update_chunk_lods.after(process_chunk_queue),
|
||||
rebuild_dirty_chunks.after(process_chunk_queue), // 4. (re)mesh dirty chunks
|
||||
queue_gpu_meshing.after(rebuild_dirty_chunks),
|
||||
/* ---------- optional debug drawing ------- */
|
||||
visualize_octree_system
|
||||
.run_if(should_visualize_octree)
|
||||
|
||||
@ -1,107 +1,67 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::render::render_resource::*;
|
||||
use bevy::render::renderer::RenderDevice;
|
||||
use bevy::render::RenderApp;
|
||||
use bevy_app_compute::prelude::*;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
|
||||
use super::structure::{MeshBufferPool, SparseVoxelOctree};
|
||||
|
||||
/// Runs greedy meshing on the GPU.
|
||||
pub struct GpuMeshingPlugin;
|
||||
#[repr(C)]
|
||||
#[derive(ShaderType, Copy, Clone, Pod, Zeroable, Default)]
|
||||
pub struct Params {
|
||||
pub origin: Vec3,
|
||||
pub step: f32,
|
||||
pub axis: u32,
|
||||
pub dir: i32,
|
||||
pub slice: u32,
|
||||
pub _pad: u32,
|
||||
}
|
||||
|
||||
impl Plugin for GpuMeshingPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
let render_app = app.sub_app_mut(RenderApp);
|
||||
render_app
|
||||
.init_resource::<GpuMeshingPipeline>()
|
||||
.add_systems(Render, queue_gpu_meshing);
|
||||
#[repr(C)]
|
||||
#[derive(ShaderType, Copy, Clone, Pod, Zeroable, Default)]
|
||||
pub struct VertexGpu {
|
||||
pub pos: Vec3,
|
||||
pub normal: Vec3,
|
||||
pub uv: Vec2,
|
||||
}
|
||||
|
||||
#[derive(TypePath)]
|
||||
struct GreedyMeshingShader;
|
||||
|
||||
impl ComputeShader for GreedyMeshingShader {
|
||||
fn shader() -> ShaderRef {
|
||||
"shaders/greedy_meshing.wgsl".into()
|
||||
}
|
||||
}
|
||||
|
||||
/// GPU worker executing greedy meshing for chunks.
|
||||
#[derive(Resource)]
|
||||
pub struct GpuMeshingPipeline {
|
||||
pub pipeline: CachedComputePipelineId,
|
||||
pub layout: BindGroupLayout,
|
||||
}
|
||||
pub struct GpuMeshingWorker;
|
||||
|
||||
impl FromWorld for GpuMeshingPipeline {
|
||||
fn from_world(world: &mut World) -> Self {
|
||||
let asset_server = world.resource::<AssetServer>();
|
||||
let shader: Handle<Shader> = asset_server.load("shaders/greedy_meshing.wgsl");
|
||||
let render_device = world.resource::<RenderDevice>();
|
||||
let layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
||||
label: Some("meshing_layout"),
|
||||
entries: &[
|
||||
BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: ShaderStages::COMPUTE,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Storage { read_only: true },
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 1,
|
||||
visibility: ShaderStages::COMPUTE,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Uniform,
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 2,
|
||||
visibility: ShaderStages::COMPUTE,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Storage { read_only: false },
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 3,
|
||||
visibility: ShaderStages::COMPUTE,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Storage { read_only: false },
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
BindGroupLayoutEntry {
|
||||
binding: 4,
|
||||
visibility: ShaderStages::COMPUTE,
|
||||
ty: BindingType::Buffer {
|
||||
ty: BufferBindingType::Storage { read_only: false },
|
||||
has_dynamic_offset: false,
|
||||
min_binding_size: None,
|
||||
},
|
||||
count: None,
|
||||
},
|
||||
],
|
||||
});
|
||||
let pipeline_descriptor = ComputePipelineDescriptor {
|
||||
label: Some("meshing_pipeline".into()),
|
||||
layout: vec![layout.clone()],
|
||||
shader,
|
||||
shader_defs: vec![],
|
||||
entry_point: "main".into(),
|
||||
};
|
||||
let render_queue = world.resource::<RenderDevice>();
|
||||
let pipeline_cache = world.resource::<PipelineCache>();
|
||||
let pipeline = pipeline_cache.queue_compute_pipeline(render_queue, &pipeline_descriptor);
|
||||
Self { pipeline, layout }
|
||||
impl ComputeWorker for GpuMeshingWorker {
|
||||
fn build(world: &mut World) -> AppComputeWorker<Self> {
|
||||
AppComputeWorkerBuilder::new(world)
|
||||
.add_storage::<u32>("voxels", &[0u32; 1])
|
||||
.add_uniform("params", &Params::default())
|
||||
.add_storage::<VertexGpu>("vertices", &[VertexGpu::default(); 1])
|
||||
.add_storage::<u32>("indices", &[0u32; 1])
|
||||
.add_storage::<u32>("counts", &[0u32; 2])
|
||||
.add_pass::<GreedyMeshingShader>(
|
||||
[1, 1, 1],
|
||||
&["voxels", "params", "vertices", "indices", "counts"],
|
||||
)
|
||||
.one_shot()
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
/// System that dispatches the compute shader for dirty chunks.
|
||||
fn queue_gpu_meshing(
|
||||
/// Placeholder system that will dispatch the compute worker for dirty chunks.
|
||||
pub fn queue_gpu_meshing(
|
||||
mut worker: ResMut<AppComputeWorker<GpuMeshingWorker>>,
|
||||
_octrees: Query<&SparseVoxelOctree>,
|
||||
_pool: ResMut<MeshBufferPool>,
|
||||
_pipeline: Res<GpuMeshingPipeline>,
|
||||
) {
|
||||
// TODO: upload voxel buffers and dispatch compute passes per chunk.
|
||||
if !worker.ready() {
|
||||
return;
|
||||
}
|
||||
// TODO: populate the worker buffers with chunk data before dispatching.
|
||||
worker.execute();
|
||||
}
|
||||
|
||||
@ -7,6 +7,6 @@ mod chunk;
|
||||
pub mod culling;
|
||||
pub mod lod;
|
||||
mod meshing;
|
||||
mod meshing_gpu;
|
||||
pub mod meshing_gpu;
|
||||
pub mod queue_systems;
|
||||
pub mod render_chunks;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user