From de6bb68fba254c691ba519c9b964cccb8af796d7 Mon Sep 17 00:00:00 2001 From: TheGrimsey Date: Tue, 3 Dec 2024 19:31:21 +0100 Subject: [PATCH] Cache data noise for each point when generating & add SAMPLES counter. Also update many_tiles to have some nicer mountains. --- Cargo.toml | 1 + examples/many_tiles.rs | 172 ++++++++++++++++++++++++++++++----------- src/noise.rs | 151 ++++++++++++++++++++++++++---------- 3 files changed, 239 insertions(+), 85 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8784f8a..beb88cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ license = "MIT OR Apache-2.0" readme = "README.md" [features] +count_samples = [] debug_draw = ["rendering", "bevy/bevy_gizmos", "dep:bevy_color"] rendering = ["dep:bevy_render", "dep:bevy_pbr"] serialize = ["dep:serde"] diff --git a/examples/many_tiles.rs b/examples/many_tiles.rs index ad82ad9..b1a2e96 100644 --- a/examples/many_tiles.rs +++ b/examples/many_tiles.rs @@ -60,38 +60,46 @@ fn main() { NoiseLayer { operation: LayerOperation::Noise { noise: LayerNoiseSettings { - amplitude: 16.0, - frequency: 0.005, - seed: 3, + amplitude: 128.0, + frequency: 0.002, + seed: 281139797, domain_warp: vec![DomainWarping { - amplitude: 25.0, - frequency: 0.01, - z_offset: 100.0 - }, - DomainWarping { - amplitude: 50.0, - frequency: 0.006, - z_offset: 50.0 - }, - DomainWarping { - amplitude: 60.0, - frequency: 0.004, - z_offset: 10.0 + amplitude: 30.0, + frequency: 0.001, + z_offset: 3.55 }], - scaling: NoiseScaling::Normalized + scaling: NoiseScaling::Ridged } }, + filters: vec![NoiseFilter { + condition: NoiseFilterCondition::Above(0.9), + falloff: 0.3, + falloff_easing_function: EasingFunction::SmoothStep, + compare_to: FilterComparingTo::Spline { index: 0 }, + }], + filter_combinator: FilterCombinator::Max + }, + NoiseLayer { + operation: LayerOperation::Noise { + noise: LayerNoiseSettings { + amplitude: 64.0, + frequency: 0.002, + seed: 3, + domain_warp: vec![], + scaling: NoiseScaling::Ridged + }, + }, filters: vec![], filter_combinator: FilterCombinator::Max }, NoiseLayer { operation: LayerOperation::Noise { noise: LayerNoiseSettings { - amplitude: 8.0, - frequency: 0.01, - seed: 1, + amplitude: 32.0, + frequency: 0.002, + seed: 891670187, domain_warp: vec![], - scaling: NoiseScaling::Normalized + scaling: NoiseScaling::Ridged } }, filters: vec![], @@ -100,11 +108,11 @@ fn main() { NoiseLayer { operation: LayerOperation::Noise { noise: LayerNoiseSettings { - amplitude: 4.0, - frequency: 0.02, + amplitude: 8.0, + frequency: 0.006, seed: 2, domain_warp: vec![], - scaling: NoiseScaling::Normalized + scaling: NoiseScaling::Ridged } }, filters: vec![], @@ -113,11 +121,42 @@ fn main() { NoiseLayer { operation: LayerOperation::Noise { noise: LayerNoiseSettings { - amplitude: 2.0, - frequency: 0.04, + amplitude: 16.0, + frequency: 0.004, seed: 3, domain_warp: vec![], - scaling: NoiseScaling::Normalized + scaling: NoiseScaling::Ridged + }, + }, + filters: vec![], + filter_combinator: FilterCombinator::Max + }, + NoiseLayer { + operation: LayerOperation::Noise { + noise: LayerNoiseSettings { + amplitude: 128.0, + frequency: 0.0005, + seed: 3, + domain_warp: vec![], + scaling: NoiseScaling::Ridged + }, + }, + filters: vec![NoiseFilter { + condition: NoiseFilterCondition::Above(0.8), + falloff: 0.25, + falloff_easing_function: EasingFunction::SmoothStep, + compare_to: FilterComparingTo::Spline { index: 0 }, + }], + filter_combinator: FilterCombinator::Max + }, + NoiseLayer { + operation: LayerOperation::Noise { + noise: LayerNoiseSettings { + amplitude: 64.0, + frequency: 0.002, + seed: 3, + domain_warp: vec![], + scaling: NoiseScaling::Ridged }, }, filters: vec![], @@ -125,14 +164,37 @@ fn main() { }, ], filters: vec![NoiseFilter { - condition: NoiseFilterCondition::Above(0.4), - falloff: 0.1, - falloff_easing_function: EasingFunction::CubicInOut, + condition: NoiseFilterCondition::Above(0.6), + falloff: 0.15, + falloff_easing_function: EasingFunction::SmoothStep, compare_to: FilterComparingTo::Spline { index: 0 }, }], filter_combinator: FilterCombinator::Min } ], + data: vec![ + LayerNoiseSettings { + amplitude: 1.0, + frequency: 0.0003, + seed: 3110758200, + domain_warp: vec![], + scaling: NoiseScaling::Unitized + }, + LayerNoiseSettings { + amplitude: 1.0, + frequency: 0.0001, + seed: 2400218420, + domain_warp: vec![], + scaling: NoiseScaling::Unitized + }, + LayerNoiseSettings { + amplitude: 1.0, + frequency: 0.0001, + seed: 1228950654, + domain_warp: vec![], + scaling: NoiseScaling::Unitized + }, + ], ..default() }), terrain_settings: TerrainSettings { @@ -172,7 +234,7 @@ fn insert_rules( terrain_noise_settings.splines.extend([ TerrainNoiseSplineLayer { amplitude_curve: continentallness.clone(), - frequency: 0.001, + frequency: 0.0005, seed: 5, domain_warp: vec![], filters: vec![], @@ -180,15 +242,29 @@ fn insert_rules( }, TerrainNoiseSplineLayer { amplitude_curve: peaks_and_valleys.clone(), - frequency: 0.005, - seed: 6, - domain_warp: vec![], - filters: vec![NoiseFilter { - condition: NoiseFilterCondition::Above(0.3), - falloff: 0.2, - falloff_easing_function: EasingFunction::SmoothStep, - compare_to: FilterComparingTo::Spline { index: 0 } - }], + frequency: 0.002, + seed: 14085, + domain_warp: vec![ + DomainWarping { + amplitude: 40.0, + frequency: 0.009, + z_offset: 93.0 + } + ], + filters: vec![ + NoiseFilter { + condition: NoiseFilterCondition::Above(0.3), + falloff: 0.2, + falloff_easing_function: EasingFunction::SmoothStep, + compare_to: FilterComparingTo::Spline { index: 0 } + }, + NoiseFilter { + condition: NoiseFilterCondition::Above(1.0), + falloff: 1.0, + falloff_easing_function: EasingFunction::SmoothStep, + compare_to: FilterComparingTo::Data { index: 0 } + } + ], filter_combinator: FilterCombinator::Min }, ]); @@ -327,7 +403,7 @@ fn spawn_terrain(mut commands: Commands, terrain_settings: Res) ..default() }); - let terrain_range = 5; + let terrain_range = 15; for x in -terrain_range..terrain_range { for z in -terrain_range..terrain_range { @@ -394,11 +470,15 @@ impl EditorWindow for NoiseDebugWindow { let translation = transform.translation(); + let mut data = Vec::with_capacity(noise_settings.data.len()); + noise_settings.sample_data(noise_cache, noise_index_cache, translation.xz(), &mut data); + let height = noise_settings.sample_position( noise_cache, noise_index_cache, translation.xz(), lookup_curves, + &data ); ui.heading(format!("Height: {height}")); @@ -423,13 +503,13 @@ impl EditorWindow for NoiseDebugWindow { translation.z, noise_settings, noise_cache, - &noise_index_cache.data_index_cache, + &data, &noise_index_cache.spline_index_cache, cached_noise, lookup_curves, ); - let strength = calc_filter_strength(translation.xz(), &spline.filters, spline.filter_combinator, noise_settings, noise_cache, &noise_index_cache.data_index_cache, &noise_index_cache.spline_index_cache); + let strength = calc_filter_strength(translation.xz(), &spline.filters, spline.filter_combinator, noise_settings, noise_cache, &data, &noise_index_cache.spline_index_cache); if let Some(lookup_curve) = lookup_curves.get(&spline.amplitude_curve) { ui.label(format!( @@ -447,18 +527,18 @@ impl EditorWindow for NoiseDebugWindow { let noise = group.sample( noise_settings, noise_cache, - &noise_index_cache.data_index_cache, + &data, &noise_index_cache.spline_index_cache, group_noises, translation.xz() ); - let strength = calc_filter_strength(translation.xz(), &group.filters, group.filter_combinator, noise_settings, noise_cache, &noise_index_cache.data_index_cache, &noise_index_cache.spline_index_cache); + let strength = calc_filter_strength(translation.xz(), &group.filters, group.filter_combinator, noise_settings, noise_cache, &data, &noise_index_cache.spline_index_cache); egui::CollapsingHeader::new(format!("GROUP {i}: {noise:.3} ({strength:.3})")).id_source(format!("group_{i}")).show(ui, |ui| { unsafe { for (i,layer) in group.layers.iter().enumerate() { - let strength = calc_filter_strength(translation.xz(), &layer.filters, layer.filter_combinator, noise_settings, noise_cache, &noise_index_cache.data_index_cache, &noise_index_cache.spline_index_cache); + let strength = calc_filter_strength(translation.xz(), &layer.filters, layer.filter_combinator, noise_settings, noise_cache, &data, &noise_index_cache.spline_index_cache); match &layer.operation { LayerOperation::Noise { noise } => { diff --git a/src/noise.rs b/src/noise.rs index ca7b796..309ae15 100644 --- a/src/noise.rs +++ b/src/noise.rs @@ -1,3 +1,6 @@ +use std::cell::Cell; + +use bevy_log::info; use ::noise::{NoiseFn, Simplex}; use bevy_asset::{Assets, Handle}; use bevy_math::{UVec4, Vec2, Vec4}; @@ -131,6 +134,9 @@ impl TerrainNoiseSplineLayer { pub fn sample_raw(&self, x: f32, z: f32, noise: &Simplex) -> f32 { let (x, z) = self.domain_warp.iter().fold((x, z), |(x, z), warp| warp.warp(x, z, noise)); + #[cfg(feature = "count_samples")] + SAMPLES.set(SAMPLES.get() + 1); + (noise.get([(x * self.frequency) as f64, (z * self.frequency) as f64]) / 2.0 + 0.5) as f32 } @@ -145,13 +151,13 @@ impl TerrainNoiseSplineLayer { z: f32, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[f32], spline_noise_cache: &[u32], noise: &Simplex, lookup_curves: &Assets, ) -> f32 { if let Some(curve) = lookup_curves.get(&self.amplitude_curve) { - let strength = calc_filter_strength(Vec2::new(x, z), &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let strength = calc_filter_strength(Vec2::new(x, z), &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); curve.lookup(self.sample_raw(x, z, noise)) * strength } else { @@ -166,6 +172,9 @@ impl TerrainNoiseSplineLayer { fn sample_simd_raw(&self, x: Vec4, z: Vec4, noise: &Simplex) -> Vec4 { let (x, z) = self.domain_warp.iter().fold((x, z), |(x, z), warp| warp.warp_simd(x, z, noise)); + #[cfg(feature = "count_samples")] + SAMPLES.set(SAMPLES.get() + 4); + // Step 1: Get the noise values for all 4 positions (x, z) let noise_values = Vec4::new( noise.get([(x.x * self.frequency) as f64, (z.x * self.frequency) as f64]) as f32, @@ -185,14 +194,14 @@ impl TerrainNoiseSplineLayer { z: Vec4, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[Vec4], spline_noise_cache: &[u32], noise: &Simplex, lookup_curves: &Assets, ) -> Vec4 { // Fetch the lookup curve and apply it to all 4 noise values if let Some(curve) = lookup_curves.get(&self.amplitude_curve) { - let strength = calc_filter_strength_simd(x, z, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let strength = calc_filter_strength_simd(x, z, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); let normalized_noise = self.sample_simd_raw(x, z, noise); @@ -303,6 +312,9 @@ impl LayerNoiseSettings { pub fn sample_scaled_raw(&self, x: f32, z: f32, noise: &Simplex) -> f32 { let (x, z) = self.domain_warp.iter().fold((x, z), |(x, z), warp| warp.warp(x, z, noise)); + #[cfg(feature = "count_samples")] + SAMPLES.set(SAMPLES.get() + 1); + let noise = noise.get([(x * self.frequency) as f64, (z * self.frequency) as f64]) as f32; match &self.scaling { @@ -330,6 +342,9 @@ impl LayerNoiseSettings { let x = x * self.frequency; let z = z * self.frequency; + #[cfg(feature = "count_samples")] + SAMPLES.set(SAMPLES.get() + 4); + let noise =Vec4::new( noise.get([x.x as f64, z.x as f64]) as f32, noise.get([x.y as f64, z.y as f64]) as f32, @@ -400,22 +415,16 @@ pub fn calc_filter_strength( combinator: FilterCombinator, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[f32], spline_noise_cache: &[u32] ) -> f32 { if let Some(initial_filter) = filters.first() { unsafe { let sample_filter = |filter: &NoiseFilter| match &filter.compare_to { - FilterComparingTo::Data { index } => noise_settings - .data + FilterComparingTo::Data { index } => data_noise_values .get(*index as usize) - .map_or(0.0, |layer| { - layer.sample_scaled_raw( - pos.x, - pos.y, - noise_cache.get_by_index(data_noise_cache[*index as usize] as usize), - ) - }), + .cloned() + .unwrap_or(0.0), FilterComparingTo::Spline { index } => noise_settings .splines .get(*index as usize) @@ -430,7 +439,7 @@ pub fn calc_filter_strength( .biome .get(*index as usize) .map_or(0.0, |biome| { - calc_filter_strength(pos, &biome.filters, biome.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache) + calc_filter_strength(pos, &biome.filters, biome.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache) }), }; let initial_filter_strength = initial_filter.get_filter(sample_filter(initial_filter)); @@ -461,22 +470,16 @@ fn calc_filter_strength_simd( combinator: FilterCombinator, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[Vec4], spline_noise_cache: &[u32] ) -> Vec4 { if let Some(initial_filter) = filters.first() { unsafe { let sample_filter = |filter: &NoiseFilter| match &filter.compare_to { - FilterComparingTo::Data { index } => noise_settings - .data + FilterComparingTo::Data { index } => data_noise_values .get(*index as usize) - .map_or(Vec4::ZERO, |layer| { - layer.sample_simd_scaled_raw( - x, - z, - noise_cache.get_by_index(data_noise_cache[*index as usize] as usize), - ) - }), + .cloned() + .unwrap_or(Vec4::ZERO), FilterComparingTo::Spline { index } => noise_settings .splines .get(*index as usize) @@ -491,7 +494,7 @@ fn calc_filter_strength_simd( .biome .get(*index as usize) .map_or(Vec4::ZERO, |biome| { - calc_filter_strength_simd(x, z, &biome.filters, biome.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache) + calc_filter_strength_simd(x, z, &biome.filters, biome.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache) }), }; let initial_filter_strength = initial_filter.get_filter_simd(sample_filter(initial_filter)); @@ -535,19 +538,19 @@ impl NoiseGroup { &self, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[f32], spline_noise_cache: &[u32], layer_noise_cache: &[u32], pos: Vec2, ) -> f32 { - let group_strength = calc_filter_strength(pos, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let group_strength = calc_filter_strength(pos, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); if group_strength <= f32::EPSILON { return 0.0; } unsafe { let group_height = self.layers.iter().enumerate().fold(0.0, |acc, (i, layer)| { - let layer_strength = calc_filter_strength(pos, &layer.filters, layer.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let layer_strength = calc_filter_strength(pos, &layer.filters, layer.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); if layer_strength > f32::EPSILON { let layer_value = match &layer.operation { @@ -577,20 +580,20 @@ impl NoiseGroup { &self, noise_settings: &TerrainNoiseSettings, noise_cache: &NoiseCache, - data_noise_cache: &[u32], + data_noise_values: &[Vec4], spline_noise_cache: &[u32], layer_noise_cache: &[u32], x: Vec4, z: Vec4 ) -> Vec4 { - let group_strength = calc_filter_strength_simd(x, z, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let group_strength = calc_filter_strength_simd(x, z, &self.filters, self.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); if group_strength.cmple(Vec4::splat(f32::EPSILON)).all() { return Vec4::ZERO; } unsafe { let group_height = self.layers.iter().enumerate().fold(Vec4::ZERO, |acc, (i, layer)| { - let layer_strength = calc_filter_strength_simd(x, z, &layer.filters, layer.filter_combinator, noise_settings, noise_cache, data_noise_cache, spline_noise_cache); + let layer_strength = calc_filter_strength_simd(x, z, &layer.filters, layer.filter_combinator, noise_settings, noise_cache, data_noise_values, spline_noise_cache); if layer_strength.cmpge(Vec4::splat(f32::EPSILON)).any() { let layer_value = match &layer.operation { @@ -766,6 +769,51 @@ pub struct TerrainNoiseSettings { pub noise_groups: Vec, } impl TerrainNoiseSettings { + pub fn sample_data( + &self, + noise_cache: &NoiseCache, + noise_index_cache: &NoiseIndexCache, + pos: Vec2, + data: &mut Vec + ) { + unsafe { + data.extend( + self.data.iter().zip(noise_index_cache.data_index_cache.iter()) + .map(|(data_layer, noise_index)| data_layer.sample_scaled_raw(pos.x, pos.y, noise_cache.get_by_index(*noise_index as usize))) + ); + } + } + + pub fn sample_data_simd( + &self, + noise_cache: &NoiseCache, + noise_index_cache: &NoiseIndexCache, + x: Vec4, + z: Vec4, + data: &mut Vec + ) { + unsafe { + data.extend( + self.data.iter().zip(noise_index_cache.data_index_cache.iter()) + .map(|(data_layer, noise_index)| data_layer.sample_simd_scaled_raw(x, z, noise_cache.get_by_index(*noise_index as usize))) + ); + } + } + + pub fn sample_biomes( + &self, + noise_cache: &NoiseCache, + noise_index_cache: &NoiseIndexCache, + pos: Vec2, + data_noise_values: &[f32], + biomes: &mut Vec + ) { + biomes.extend( + self.biome.iter() + .map(|biome| calc_filter_strength(pos, &biome.filters, biome.filter_combinator, self, noise_cache, data_noise_values, &noise_index_cache.data_index_cache)) + ); + } + /// Samples noise height at the position. /// /// Returns 0.0 if there are no noise layers. @@ -775,6 +823,7 @@ impl TerrainNoiseSettings { noise_index_cache: &NoiseIndexCache, pos: Vec2, lookup_curves: &Assets, + data_noise_values: &[f32] ) -> f32 { unsafe { let spline_height = self.splines.iter().enumerate().fold(0.0, |acc, (i, layer)| { @@ -783,7 +832,7 @@ impl TerrainNoiseSettings { pos.y, self, noise_cache, - &noise_index_cache.data_index_cache, + data_noise_values, &noise_index_cache.spline_index_cache, noise_cache.get_by_index(noise_index_cache.spline_index_cache[i] as usize), lookup_curves, @@ -791,7 +840,7 @@ impl TerrainNoiseSettings { }); let layer_height = self.noise_groups.iter().enumerate().fold(0.0, |acc, (i, group)| { - acc + group.sample(self, noise_cache, &noise_index_cache.data_index_cache, &noise_index_cache.spline_index_cache, &noise_index_cache.group_index_cache[noise_index_cache.group_offset_cache[i] as usize..], pos) + acc + group.sample(self, noise_cache, data_noise_values, &noise_index_cache.spline_index_cache, &noise_index_cache.group_index_cache[noise_index_cache.group_offset_cache[i] as usize..], pos) }); spline_height + layer_height @@ -804,7 +853,8 @@ impl TerrainNoiseSettings { noise_index_cache: &NoiseIndexCache, lookup_curves: &Assets, x: Vec4, - z: Vec4 + z: Vec4, + data_cached: &[Vec4] ) -> Vec4 { unsafe { let spline_height = self.splines.iter().enumerate().fold(Vec4::ZERO, |acc, (i, layer)| { @@ -813,7 +863,7 @@ impl TerrainNoiseSettings { z, self, noise_cache, - &noise_index_cache.data_index_cache, + data_cached, &noise_index_cache.spline_index_cache, noise_cache.get_by_index(noise_index_cache.spline_index_cache[i] as usize), lookup_curves, @@ -821,7 +871,7 @@ impl TerrainNoiseSettings { }); let layer_height = self.noise_groups.iter().enumerate().fold(Vec4::ZERO, |acc, (i, group)| { - acc + group.sample_simd(self, noise_cache, &noise_index_cache.data_index_cache, &noise_index_cache.spline_index_cache, &noise_index_cache.group_index_cache[noise_index_cache.group_offset_cache[i] as usize..], x, z) + acc + group.sample_simd(self, noise_cache, data_cached, &noise_index_cache.spline_index_cache, &noise_index_cache.group_index_cache[noise_index_cache.group_offset_cache[i] as usize..], x, z) }); spline_height + layer_height @@ -829,6 +879,11 @@ impl TerrainNoiseSettings { } } +#[cfg(feature = "count_samples")] +thread_local! { + pub static SAMPLES: Cell = const { Cell::new(0) }; +} + pub(super) fn apply_noise_simd( heights: &mut [f32], terrain_settings: &TerrainSettings, @@ -839,10 +894,16 @@ pub(super) fn apply_noise_simd( lookup_curves: &Assets, terrain_noise_layers: &TerrainNoiseSettings, ) { + let edge_points = terrain_settings.edge_points as usize; let length = heights.len(); let simd_len = length / 4 * 4; // Length rounded down to the nearest multiple of 4 + #[cfg(feature = "count_samples")] + SAMPLES.set(0); + + let mut data_simd = Vec::with_capacity(terrain_noise_layers.data.len()); + // Process in chunks of 4 for i in (0..simd_len).step_by(4) { // Unpack four (x, z) pairs in parallel @@ -859,7 +920,10 @@ pub(super) fn apply_noise_simd( let x_translated = x_positions + Vec4::splat(terrain_translation.x); let z_translated = z_positions + Vec4::splat(terrain_translation.y); - let final_heights = terrain_noise_layers.sample_position_simd(noise_cache, noise_index_cache, lookup_curves, x_translated, z_translated); + data_simd.clear(); + terrain_noise_layers.sample_data_simd(noise_cache, noise_index_cache, x_translated, z_translated, &mut data_simd); + + let final_heights = terrain_noise_layers.sample_position_simd(noise_cache, noise_index_cache, lookup_curves, x_translated, z_translated, &data_simd); // Store the results back into the heights array heights[i] = final_heights.x; @@ -868,11 +932,20 @@ pub(super) fn apply_noise_simd( heights[i + 3] = final_heights.w; } + + let mut data = Vec::with_capacity(terrain_noise_layers.data.len()); + // Process any remaining heights that aren't divisible by 4 for (i, height) in heights.iter_mut().enumerate().skip(simd_len) { let (x, z) = index_to_x_z(i, edge_points); let vertex_position = terrain_translation + Vec2::new(x as f32 * scale, z as f32 * scale); - *height = terrain_noise_layers.sample_position(noise_cache, noise_index_cache, vertex_position, lookup_curves); + data.clear(); + terrain_noise_layers.sample_data(noise_cache, noise_index_cache, vertex_position, &mut data); + + *height = terrain_noise_layers.sample_position(noise_cache, noise_index_cache, vertex_position, lookup_curves, &data); } + + #[cfg(feature = "count_samples")] + info!("Average samples: {}", SAMPLES.get() / length); }