diff --git a/client/assets/shaders/greedy_meshing.wgsl b/client/assets/shaders/greedy_meshing.wgsl index e13407f..aff1f9f 100644 --- a/client/assets/shaders/greedy_meshing.wgsl +++ b/client/assets/shaders/greedy_meshing.wgsl @@ -21,7 +21,7 @@ struct Vertex { @group(0) @binding(1) var params: Params; @group(0) @binding(2) var vertices: array; @group(0) @binding(3) var indices: array; -@group(0) @binding(4) var counts: atomic; +@group(0) @binding(4) var counts: array, 2>; const N: u32 = 16u; @@ -86,16 +86,21 @@ fn main(@builtin(global_invocation_id) id: vec3) { } var height: u32 = 1u; - outer: loop { + loop { if v0 + height >= N { break; } + var can_expand: bool = true; for (var du: u32 = 0u; du < width; du = du + 1u) { let idx = (u0 + du) * N + v0 + height; if !mask[idx] || visited[idx] { - break outer; + can_expand = false; + break; } } + if !can_expand { + break; + } height = height + 1u; } @@ -108,11 +113,11 @@ fn main(@builtin(global_invocation_id) id: vec3) { // Compute base world-space position. var base = params.origin; if axis == 0u { - base = base + vec3(f32(slice) + (dir > 0 ? 1.0 : 0.0), f32(u0), f32(v0)) * params.step; + base = base + vec3(f32(slice) + select(0.0, 1.0, dir > 0), f32(u0), f32(v0)) * params.step; } else if axis == 1u { - base = base + vec3(f32(v0), f32(slice) + (dir > 0 ? 1.0 : 0.0), f32(u0)) * params.step; + base = base + vec3(f32(v0), f32(slice) + select(0.0, 1.0, dir > 0), f32(u0)) * params.step; } else { - base = base + vec3(f32(u0), f32(v0), f32(slice) + (dir > 0 ? 1.0 : 0.0)) * params.step; + base = base + vec3(f32(u0), f32(v0), f32(slice) + select(0.0, 1.0, dir > 0)) * params.step; } let size = vec2(f32(width) * params.step, f32(height) * params.step); @@ -141,10 +146,10 @@ fn main(@builtin(global_invocation_id) id: vec3) { let p3 = base + v_unit * size.y; let vi = atomicAdd(&counts[0], 4u); - vertices[vi] = Vertex(pos: p0, normal: normal, uv: vec2(0.0, 1.0)); - vertices[vi + 1u] = Vertex(pos: p1, normal: normal, uv: vec2(1.0, 1.0)); - vertices[vi + 2u] = Vertex(pos: p2, normal: normal, uv: vec2(1.0, 0.0)); - vertices[vi + 3u] = Vertex(pos: p3, normal: normal, uv: vec2(0.0, 0.0)); + vertices[vi] = Vertex(p0, normal, vec2(0.0, 1.0)); + vertices[vi + 1u] = Vertex(p1, normal, vec2(1.0, 1.0)); + vertices[vi + 2u] = Vertex(p2, normal, vec2(1.0, 0.0)); + vertices[vi + 3u] = Vertex(p3, normal, vec2(0.0, 0.0)); let ii = atomicAdd(&counts[1], 6u); if dir > 0 { diff --git a/client/src/plugins/environment/systems/voxels/meshing_gpu.rs b/client/src/plugins/environment/systems/voxels/meshing_gpu.rs index 13c60c5..d4c59f6 100644 --- a/client/src/plugins/environment/systems/voxels/meshing_gpu.rs +++ b/client/src/plugins/environment/systems/voxels/meshing_gpu.rs @@ -1,7 +1,7 @@ use bevy::prelude::*; use bevy_app_compute::prelude::*; -use super::structure::{MeshBufferPool, SparseVoxelOctree}; +use super::structure::{CHUNK_SIZE, MeshBufferPool, SparseVoxelOctree}; #[repr(C)] #[derive(ShaderType, Copy, Clone, Default)] @@ -22,6 +22,11 @@ pub struct VertexGpu { pub uv: Vec2, } +const MAX_VOXELS: usize = (CHUNK_SIZE as usize) * (CHUNK_SIZE as usize) * (CHUNK_SIZE as usize); +const MAX_QUADS: usize = MAX_VOXELS * 6; +const MAX_VERTICES: usize = MAX_QUADS * 4; +const MAX_INDICES: usize = MAX_QUADS * 6; + #[derive(TypePath)] struct GreedyMeshingShader; @@ -37,11 +42,16 @@ pub struct GpuMeshingWorker; impl ComputeWorker for GpuMeshingWorker { fn build(world: &mut World) -> AppComputeWorker { + // Allocate large temporary arrays on the heap to avoid stack overflows + let voxels = Box::new([0u32; MAX_VOXELS]); + let vertices = Box::new([VertexGpu::default(); MAX_VERTICES]); + let indices = Box::new([0u32; MAX_INDICES]); + AppComputeWorkerBuilder::new(world) - .add_storage("voxels", &[0u32; 1]) + .add_storage("voxels", voxels.as_ref()) .add_uniform("params", &Params::default()) - .add_storage("vertices", &[VertexGpu::default(); 1]) - .add_storage("indices", &[0u32; 1]) + .add_storage("vertices", vertices.as_ref()) + .add_storage("indices", indices.as_ref()) .add_storage("counts", &[0u32; 2]) .add_pass::( [1, 1, 1],