diff --git a/world/Cargo.toml b/world/Cargo.toml index 365cd84162..8f3feb6f86 100644 --- a/world/Cargo.toml +++ b/world/Cargo.toml @@ -37,3 +37,7 @@ criterion = "0.3" tracing-subscriber = { version = "0.2.3", default-features = false, features = ["fmt", "chrono", "ansi", "smallvec"] } minifb = "0.19.1" simple = "0.3" + +[[bench]] +harness = false +name = "tree" diff --git a/world/benches/tree.rs b/world/benches/tree.rs new file mode 100644 index 0000000000..d785e59aca --- /dev/null +++ b/world/benches/tree.rs @@ -0,0 +1,34 @@ +use veloren_world::layer::tree::ProceduralTree; +use criterion::{black_box, criterion_group, criterion_main, Benchmark, Criterion, BatchSize}; + +fn tree(c: &mut Criterion) { + c.bench_function("generate", |b| { + let mut i = 0; + b.iter(|| { + i += 1; + black_box(ProceduralTree::generate(i)); + }); + }); + + c.bench_function("sample", |b| { + let mut i = 0; + b.iter_batched( + || { i += 1; ProceduralTree::generate(i) }, + |tree| { + let bounds = tree.get_bounds(); + for x in (bounds.min.x as i32..bounds.max.x as i32).step_by(3) { + for y in (bounds.min.y as i32..bounds.max.y as i32).step_by(3) { + for z in (bounds.min.z as i32..bounds.max.z as i32).step_by(3) { + let pos = (x as f32, y as f32, z as f32).into(); + black_box(tree.is_branch_or_leaves_at(pos)); + } + } + } + }, + BatchSize::SmallInput, + ); + }); +} + +criterion_group!(benches, tree); +criterion_main!(benches); diff --git a/world/src/layer/tree.rs b/world/src/layer/tree.rs index 3a2be18920..229948c3be 100644 --- a/world/src/layer/tree.rs +++ b/world/src/layer/tree.rs @@ -100,8 +100,7 @@ pub fn apply_trees_to(canvas: &mut Canvas) { ForestKind::Baobab => *BAOBABS, // ForestKind::Oak => *OAKS, ForestKind::Oak => { - let mut rng = RandomPerm::new(seed); - break 'model TreeModel::Procedural(ProceduralTree::generate(&mut rng)); + break 'model TreeModel::Procedural(ProceduralTree::generate(seed)); }, ForestKind::Pine => *PINES, ForestKind::Birch => *BIRCHES, @@ -194,23 +193,24 @@ pub fn apply_trees_to(canvas: &mut Canvas) { } // TODO: Rename this to `Tree` when the name conflict is gone -struct ProceduralTree { +pub struct ProceduralTree { branches: Vec, } impl ProceduralTree { - pub fn generate(rng: &mut impl Rng) -> Self { + pub fn generate(seed: u32) -> Self { + let mut rng = RandomPerm::new(seed); let mut branches = Vec::new(); const ITERATIONS: usize = 4; fn add_branches(branches: &mut Vec, start: Vec3, dir: Vec3, depth: usize, rng: &mut impl Rng) { let mut branch_dir = (dir + Vec3::::new(rng.gen_range(-1.0, 1.0),rng.gen_range(-1.0, 1.0),rng.gen_range(0.25, 1.0)).cross(dir).normalized() * 0.45 * (depth as f32 + 0.5)).normalized(); // I wish `vek` had a `Vec3::from_fn` - + if branch_dir.z < 0. { branch_dir.z = (branch_dir.z) / 16. + 0.2 } - + let branch_len = 12.0 / (depth as f32 * 0.25 + 1.0); // Zipf, I guess let end = start + branch_dir * branch_len; @@ -249,7 +249,7 @@ impl ProceduralTree { Vec3::new(dx, dy, height - rng.gen_range(0.0, height / 3.0)), Vec3::new(current_angle.cos(), current_angle.sin(), rng.gen_range(0.2 * i as f32, 0.7 * i as f32)).normalized(), 1, - rng + &mut rng, ); if rng.gen_range(0, 4) != 2 { break;