diff --git a/Cargo.toml b/Cargo.toml index 4d7fb08..c949e5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ default = [] rapier = ["bevy_rapier3d"] xpbd = ["bevy_xpbd_3d"] debug_draw = ["bevy/bevy_gizmos"] -trace = [] [[example]] name = "rapier3d" @@ -68,3 +67,8 @@ bevy = { version = "0.11", default-features = false, features = [ "zstd", ] } futures-lite = "1.13" +criterion = { version = "0.5" } + +[[bench]] +name = "simple_geometry" +harness = false \ No newline at end of file diff --git a/benches/simple_geometry.rs b/benches/simple_geometry.rs new file mode 100644 index 0000000..91d1441 --- /dev/null +++ b/benches/simple_geometry.rs @@ -0,0 +1,97 @@ +use bevy::prelude::{UVec2, Transform, Vec3}; +use criterion::{Criterion, criterion_group, criterion_main, black_box}; +use oxidized_navigation::{build_tile_sync, NavMeshSettings, conversion::{GeometryToConvert, GeometryCollection, ColliderType}}; +use parry3d::shape::Cuboid; + + +fn generate_single_primitive_geometry() { + let tile_coord = UVec2::new(0, 0); + let heightfields = vec![]; + + + let geometry_collections = vec![ + GeometryCollection { + transform: Transform::from_xyz(0.0, 0.0, 0.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(10.0, 0.2, 10.0).into()))), + area: None + } + ]; + let nav_mesh_settings = NavMeshSettings { + cell_width: 0.25, + cell_height: 0.1, + tile_width: 100, + world_half_extents: 12.5, + world_bottom_bound: -100.0, + max_traversable_slope_radians: (40.0_f32 - 0.1).to_radians(), + walkable_height: 20, + walkable_radius: 1, + step_height: 3, + min_region_area: 100, + merge_region_area: 500, + max_contour_simplification_error: 1.1, + max_edge_length: 80, + max_tile_generation_tasks: Some(1), + }; + + black_box(build_tile_sync(geometry_collections, tile_coord, heightfields, &nav_mesh_settings)); +} + +fn generate_many_primitive_geometry() { + let tile_coord = UVec2::new(0, 0); + let heightfields = vec![]; + + + let geometry_collections = vec![ + GeometryCollection { + transform: Transform::from_xyz(0.0, 0.0, 0.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(10.0, 0.2, 10.0).into()))), + area: None + }, + GeometryCollection { + transform: Transform::from_xyz(5.0, 1.0, 0.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(1.0, 1.0, 1.0).into()))), + area: None + }, + GeometryCollection { + transform: Transform::from_xyz(-5.0, 1.0, 2.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(4.0, 1.0, 1.0).into()))), + area: None + }, + GeometryCollection { + transform: Transform::from_xyz(-2.5, 2.0, 2.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(1.0, 2.0, 1.0).into()))), + area: None + }, + GeometryCollection { + transform: Transform::from_xyz(-2.5, 2.0, -2.0), + geometry_to_convert: GeometryToConvert::Collider(ColliderType::Cuboid(Cuboid::new(Vec3::new(1.0, 2.0, 1.0).into()))), + area: None + } + ]; + let nav_mesh_settings = NavMeshSettings { + cell_width: 0.25, + cell_height: 0.1, + tile_width: 100, + world_half_extents: 12.5, + world_bottom_bound: -100.0, + max_traversable_slope_radians: (40.0_f32 - 0.1).to_radians(), + walkable_height: 20, + walkable_radius: 1, + step_height: 3, + min_region_area: 100, + merge_region_area: 500, + max_contour_simplification_error: 1.1, + max_edge_length: 80, + max_tile_generation_tasks: Some(1), + }; + + black_box(build_tile_sync(geometry_collections, tile_coord, heightfields, &nav_mesh_settings)); +} + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("Generate Single Primitive Geometry", |b| b.iter(generate_single_primitive_geometry)); + c.bench_function("Generate Many Primitive Geometry", |b| b.iter(generate_many_primitive_geometry)); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); \ No newline at end of file diff --git a/src/conversion.rs b/src/conversion.rs index a9d3009..cc0ebcb 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -7,13 +7,13 @@ use parry3d::{ use crate::{heightfields::TriangleCollection, Area}; -pub(super) struct GeometryCollection { - pub(super) transform: Transform, - pub(super) geometry_to_convert: GeometryToConvert, - pub(super) area: Option, +pub struct GeometryCollection { + pub transform: Transform, + pub geometry_to_convert: GeometryToConvert, + pub area: Option, } -pub(super) enum ColliderType { +pub enum ColliderType { Cuboid(Cuboid), Ball(Ball), Capsule(Capsule), @@ -22,7 +22,7 @@ pub(super) enum ColliderType { Triangle(Triangle), } -pub(super) enum GeometryToConvert { +pub enum GeometryToConvert { Collider(ColliderType), ParryTriMesh(Vec>, Vec<[u32; 3]>), } diff --git a/src/heightfields.rs b/src/heightfields.rs index 50773a7..c9c5d43 100644 --- a/src/heightfields.rs +++ b/src/heightfields.rs @@ -58,10 +58,10 @@ pub(super) struct TriangleCollection { pub(super) area: Option, } -pub(super) struct HeightFieldCollection { - pub(super) transform: Transform, - pub(super) heightfield: Arc, - pub(super) area: Option, +pub struct HeightFieldCollection { + pub transform: Transform, + pub heightfield: Arc, + pub area: Option, } pub(super) fn build_heightfield_tile( diff --git a/src/lib.rs b/src/lib.rs index 6f49c06..8bb3dbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,11 +49,11 @@ use parry3d::na::Vector3; use parry3d::shape::{HeightField, TypedShape}; use regions::build_regions; use smallvec::SmallVec; -use tiles::{create_nav_mesh_tile_from_poly_mesh, NavMeshTiles}; +use tiles::{create_nav_mesh_tile_from_poly_mesh, NavMeshTiles, NavMeshTile}; pub mod colliders; mod contour; -mod conversion; +pub mod conversion; #[cfg(feature = "debug_draw")] pub mod debug_draw; mod heightfields; @@ -614,8 +614,23 @@ async fn build_tile( nav_mesh: Arc>, ) { #[cfg(feature = "trace")] - let _span = info_span!("Build Tile").entered(); + let _span = info_span!("Async build Tile").entered(); + let nav_mesh_tile = build_tile_sync(geometry_collections, tile_coord, heightfields, &nav_mesh_settings); + + let Ok(mut nav_mesh) = nav_mesh.write() else { + error!("Nav-Mesh lock has been poisoned. Generation can no longer be continued."); + return; + }; + + if nav_mesh.tile_generations.get(&tile_coord).unwrap_or(&0) < &generation { + nav_mesh.tile_generations.insert(tile_coord, generation); + + nav_mesh.add_tile(tile_coord, nav_mesh_tile, &nav_mesh_settings); + } +} + +pub fn build_tile_sync(geometry_collections: Vec, tile_coord: UVec2, heightfields: Vec, nav_mesh_settings: &NavMeshSettings) -> NavMeshTile { let triangle_collection = { #[cfg(feature = "trace")] let _span = info_span!("Convert Geometry Collections").entered(); @@ -629,61 +644,51 @@ async fn build_tile( tile_coord, triangle_collection, heightfields, - &nav_mesh_settings, + nav_mesh_settings, ) }; let mut open_tile = { #[cfg(feature = "trace")] let _span = info_span!("Build Open Heightfield Tile").entered(); - build_open_heightfield_tile(voxelized_tile, &nav_mesh_settings) + build_open_heightfield_tile(voxelized_tile, nav_mesh_settings) }; // Remove areas that are too close to a wall. { #[cfg(feature = "trace")] let _span = info_span!("Erode walkable area").entered(); - erode_walkable_area(&mut open_tile, &nav_mesh_settings); + erode_walkable_area(&mut open_tile, nav_mesh_settings); } { #[cfg(feature = "trace")] let _span = info_span!("Calculate distance field").entered(); - calculate_distance_field(&mut open_tile, &nav_mesh_settings); + calculate_distance_field(&mut open_tile, nav_mesh_settings); } { #[cfg(feature = "trace")] let _span = info_span!("Build regions").entered(); - build_regions(&mut open_tile, &nav_mesh_settings); + build_regions(&mut open_tile, nav_mesh_settings); } let contour_set = { #[cfg(feature = "trace")] let _span = info_span!("Build contours").entered(); - build_contours(open_tile, &nav_mesh_settings) + build_contours(open_tile, nav_mesh_settings) }; let poly_mesh = { #[cfg(feature = "trace")] let _span = info_span!("Build poly mesh").entered(); - build_poly_mesh(contour_set, &nav_mesh_settings) + build_poly_mesh(contour_set, nav_mesh_settings) }; - let nav_mesh_tile = { + + { #[cfg(feature = "trace")] let _span = info_span!("Create nav-mesh tile from poly mesh").entered(); - create_nav_mesh_tile_from_poly_mesh(poly_mesh, tile_coord, &nav_mesh_settings) - }; - - let Ok(mut nav_mesh) = nav_mesh.write() else { - error!("Nav-Mesh lock has been poisoned. Generation can no longer be continued."); - return; - }; - - if nav_mesh.tile_generations.get(&tile_coord).unwrap_or(&0) < &generation { - nav_mesh.tile_generations.insert(tile_coord, generation); - - nav_mesh.add_tile(tile_coord, nav_mesh_tile, &nav_mesh_settings); + create_nav_mesh_tile_from_poly_mesh(poly_mesh, tile_coord, nav_mesh_settings) } }