mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Cave performance improvements
This commit is contained in:
parent
3c846d4d17
commit
767731ecb0
15
Cargo.lock
generated
15
Cargo.lock
generated
@ -3166,8 +3166,22 @@ version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6acddbefae08bfba73e27f55513f491f35c365d84bf3002bf85ba9b916c5e5f"
|
||||
dependencies = [
|
||||
"inline_tweak_derive",
|
||||
"lazy_static",
|
||||
"proc-macro2 1.0.78",
|
||||
"rustc-hash",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inline_tweak_derive"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46d62a0a3b6af04d4eee8e7251cd758ce74b0ed86253d3e4ac8a1b297a75f4a0"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.78",
|
||||
"quote 1.0.35",
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7442,6 +7456,7 @@ dependencies = [
|
||||
"hashbrown 0.13.2",
|
||||
"image",
|
||||
"indicatif",
|
||||
"inline_tweak",
|
||||
"itertools 0.10.5",
|
||||
"kiddo",
|
||||
"lazy_static",
|
||||
|
@ -40,7 +40,7 @@ packed_simd = { version = "0.3.9", optional = true }
|
||||
rayon = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
ron = { workspace = true }
|
||||
# inline_tweak = { workspace = true, features = ["derive"] }
|
||||
inline_tweak = { workspace = true, features = ["derive"] }
|
||||
kiddo = "0.2"
|
||||
strum = { workspace = true }
|
||||
|
||||
@ -69,6 +69,10 @@ svg_fmt = "0.4"
|
||||
harness = false
|
||||
name = "tree"
|
||||
|
||||
[[bench]]
|
||||
harness = false
|
||||
name = "cave"
|
||||
|
||||
[[example]]
|
||||
name = "chunk_compression_benchmarks"
|
||||
required-features = ["bin_compression"]
|
||||
|
67
world/benches/cave.rs
Normal file
67
world/benches/cave.rs
Normal file
@ -0,0 +1,67 @@
|
||||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use rayon::ThreadPoolBuilder;
|
||||
use vek::Vec2;
|
||||
use veloren_world::{
|
||||
layer,
|
||||
sim::{FileOpts, WorldOpts, DEFAULT_WORLD_MAP},
|
||||
Land, World,
|
||||
};
|
||||
|
||||
fn cave(c: &mut Criterion) {
|
||||
let pool = ThreadPoolBuilder::new().build().unwrap();
|
||||
let (world, index) = World::generate(
|
||||
123,
|
||||
WorldOpts {
|
||||
seed_elements: true,
|
||||
world_file: FileOpts::LoadAsset(DEFAULT_WORLD_MAP.into()),
|
||||
..WorldOpts::default()
|
||||
},
|
||||
&pool,
|
||||
&|_| {},
|
||||
);
|
||||
let land = Land::from_sim(world.sim());
|
||||
|
||||
c.bench_function("generate", |b| {
|
||||
b.iter(|| {
|
||||
let entrances = black_box(layer::cave::surface_entrances(&land))
|
||||
.step_by(5)
|
||||
.map(|e| e / 32);
|
||||
for entrance in entrances {
|
||||
_ = black_box(world.generate_chunk(
|
||||
index.as_index_ref(),
|
||||
entrance,
|
||||
None,
|
||||
|| false,
|
||||
None,
|
||||
));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function("generate_specific", |b| {
|
||||
b.iter(|| {
|
||||
let base_positions = vec![
|
||||
Vec2::new(600, 650),
|
||||
Vec2::new(630, 300),
|
||||
Vec2::new(809, 141),
|
||||
];
|
||||
for base_pos in base_positions {
|
||||
for i in 0..=4 {
|
||||
for j in 0..=4 {
|
||||
let pos = base_pos + Vec2::new(i as i32, j as i32) - 2;
|
||||
_ = black_box(world.generate_chunk(
|
||||
index.as_index_ref(),
|
||||
pos,
|
||||
None,
|
||||
|| false,
|
||||
None,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
criterion_group!(benches, cave);
|
||||
criterion_main!(benches);
|
@ -174,6 +174,7 @@ impl Tunnel {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline_tweak::tweak_fn]
|
||||
fn biome_at(&self, wpos: Vec3<i32>, info: &CanvasInfo) -> Biome {
|
||||
let Some(col) = info.col_or_gen(wpos.xy()) else {
|
||||
return Biome::default();
|
||||
@ -202,7 +203,7 @@ impl Tunnel {
|
||||
.mul(2.0)
|
||||
.sub(1.0)
|
||||
.add(
|
||||
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32 * 0.75))
|
||||
((col.alt - wpos.z as f32) / (AVG_LEVEL_DEPTH as f32 * LAYERS as f32 * 0.6))
|
||||
.clamped(0.0, 2.5),
|
||||
),
|
||||
below,
|
||||
@ -233,38 +234,38 @@ impl Tunnel {
|
||||
// Mushrooms grow underground and thrive in a humid environment with moderate
|
||||
// temperatures
|
||||
let mushroom = underground
|
||||
* close(humidity, 1.0, 0.7, 3)
|
||||
* close(temp, 1.5, 0.9, 3)
|
||||
* close(depth, 1.0, 0.6, 3);
|
||||
* close(humidity, 1.0, 0.7, 4)
|
||||
* close(temp, 1.5, 0.9, 4)
|
||||
* close(depth, 1.0, 0.6, 4);
|
||||
// Extremely hot and dry areas deep underground
|
||||
let fire = underground
|
||||
* close(humidity, 0.0, 0.6, 3)
|
||||
* close(temp, 2.0, 1.3, 3)
|
||||
* close(depth, 1.0, 0.55, 3);
|
||||
* close(humidity, 0.0, 0.6, 4)
|
||||
* close(temp, 2.0, 1.3, 4)
|
||||
* close(depth, 1.0, 0.55, 4);
|
||||
// Overgrown with plants that need a moderate climate to survive
|
||||
let leafy = underground
|
||||
* close(humidity, 0.8, 0.8, 3)
|
||||
* close(temp, 0.95, 0.85, 3)
|
||||
* close(depth, 0.0, 0.6, 3);
|
||||
* close(humidity, 0.8, 0.8, 4)
|
||||
* close(temp, 0.75, 1.25, 4)
|
||||
* close(depth, 0.0, 0.75, 4);
|
||||
// Cool temperature, dry and devoid of value
|
||||
let dusty = close(humidity, 0.0, 0.5, 3) * close(temp, -0.1, 0.6, 3);
|
||||
let dusty = close(humidity, 0.0, 0.5, 4) * close(temp, -0.1, 0.6, 4);
|
||||
// Deep underground and freezing cold
|
||||
let icy = underground
|
||||
* close(temp, -1.5, 1.3, 3)
|
||||
* close(depth, 1.0, 0.65, 3)
|
||||
* close(humidity, 1.0, 0.7, 3);
|
||||
* close(temp, -1.5, 1.3, 4)
|
||||
* close(depth, 1.0, 0.6, 4)
|
||||
* close(humidity, 1.0, 0.7, 4);
|
||||
// Rocky cold cave that appear near the surface
|
||||
let snowy = close(temp, -0.6, 0.5, 3) * close(depth, 0.0, 0.45, 3);
|
||||
let snowy = close(temp, -0.6, 0.5, 4) * close(depth, 0.0, 0.45, 4);
|
||||
// Crystals grow deep underground in areas rich with minerals. They are present
|
||||
// in areas with colder temperatures and low humidity
|
||||
let crystal = underground
|
||||
* close(humidity, 0.0, 0.5, 3)
|
||||
* close(temp, -0.6, 0.75, 3)
|
||||
* close(depth, 1.0, 0.55, 3)
|
||||
* close(mineral, 2.0, 1.25, 3);
|
||||
* close(humidity, 0.0, 0.5, 4)
|
||||
* close(temp, -0.6, 0.75, 4)
|
||||
* close(depth, 1.0, 0.55, 4)
|
||||
* close(mineral, 2.0, 1.25, 4);
|
||||
// Hot, dry and shallow
|
||||
let sandy =
|
||||
close(humidity, 0.0, 0.3, 3) * close(temp, 0.7, 0.9, 3) * close(depth, 0.0, 0.6, 3);
|
||||
close(humidity, 0.0, 0.3, 4) * close(temp, 0.7, 0.9, 4) * close(depth, 0.0, 0.6, 4);
|
||||
|
||||
let biomes = [
|
||||
barren, mushroom, fire, leafy, dusty, icy, snowy, crystal, sandy,
|
||||
@ -434,6 +435,7 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
||||
})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !tunnels.is_empty() {
|
||||
let giant_tree_dist = info
|
||||
.chunk
|
||||
@ -497,6 +499,7 @@ struct Biome {
|
||||
depth: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum CaveStructure {
|
||||
Mushroom(Mushroom),
|
||||
Crystal(CrystalCluster),
|
||||
@ -508,24 +511,28 @@ enum CaveStructure {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Mushroom {
|
||||
pos: Vec3<i32>,
|
||||
stalk: f32,
|
||||
head_color: Rgb<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Crystal {
|
||||
dir: Vec3<f32>,
|
||||
length: f32,
|
||||
radius: f32,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct CrystalCluster {
|
||||
pos: Vec3<i32>,
|
||||
crystals: Vec<Crystal>,
|
||||
color: Rgb<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Flower {
|
||||
pos: Vec3<i32>,
|
||||
stalk: f32,
|
||||
@ -535,6 +542,7 @@ struct Flower {
|
||||
// rotation: Mat3<f32>,
|
||||
}
|
||||
|
||||
#[inline_tweak::tweak_fn]
|
||||
fn write_column<R: Rng>(
|
||||
canvas: &mut Canvas,
|
||||
col: &ColumnSample,
|
||||
@ -543,7 +551,7 @@ fn write_column<R: Rng>(
|
||||
z_range: Range<i32>,
|
||||
tunnel: Tunnel,
|
||||
dimensions: (f32, f32, f32),
|
||||
giant_tree_factor: f32,
|
||||
giant_tree_dist: f32,
|
||||
structure_cache: &mut SmallCache<Vec3<i32>, Option<CaveStructure>>,
|
||||
rng: &mut R,
|
||||
) {
|
||||
@ -741,22 +749,21 @@ fn write_column<R: Rng>(
|
||||
0
|
||||
};
|
||||
|
||||
let mut get_structure = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
||||
for (wpos2d, seed) in StructureGen2d::new(34537, 24, 8).get(wpos.xy()) {
|
||||
let structure = if let Some(structure) =
|
||||
structure_cache.get(wpos2d.with_z(tunnel.a.depth), |_| {
|
||||
let mut rng = RandomPerm::new(seed);
|
||||
let structures = StructureGen2d::new(34537, 24, 8)
|
||||
.get(wpos2d)
|
||||
.as_slice()
|
||||
.iter()
|
||||
.filter_map(|(wpos2d, seed)| {
|
||||
let structure = structure_cache.get(wpos2d.with_z(tunnel.a.depth), |_| {
|
||||
let mut rng = RandomPerm::new(*seed);
|
||||
let (z_range, horizontal, vertical, _) =
|
||||
tunnel.z_range_at(wpos2d.map(|e| e as f64 + 0.5), info)?;
|
||||
let pos = wpos2d.with_z(z_range.start);
|
||||
|
||||
let biome = tunnel.biome_at(pos, &info);
|
||||
let ground_below = !tunnel_bounds_at(pos.xy(), &info, &info.land())
|
||||
.any(|(_, z_range, _, _, _, _)| z_range.contains(&(z_range.start - 1)));
|
||||
if !ground_below {
|
||||
return None;
|
||||
}
|
||||
|
||||
let tunnel_intersection = || {
|
||||
tunnel_bounds_at(pos.xy(), &info, &info.land())
|
||||
.any(|(_, z_range, _, _, _, _)| z_range.contains(&(z_range.start - 1)))
|
||||
};
|
||||
if biome.mushroom > 0.7
|
||||
&& vertical > 16.0
|
||||
&& rng.gen_bool(
|
||||
@ -764,6 +771,9 @@ fn write_column<R: Rng>(
|
||||
* close(biome.mushroom, 1.0, 0.7, 1) as f64,
|
||||
)
|
||||
{
|
||||
if tunnel_intersection() {
|
||||
return None;
|
||||
}
|
||||
let purp = rng.gen_range(0..50);
|
||||
Some(CaveStructure::Mushroom(Mushroom {
|
||||
pos,
|
||||
@ -780,6 +790,9 @@ fn write_column<R: Rng>(
|
||||
} else if biome.crystal > 0.5
|
||||
&& rng.gen_bool(0.4 * close(biome.crystal, 1.0, 0.7, 2) as f64)
|
||||
{
|
||||
if tunnel_intersection() {
|
||||
return None;
|
||||
}
|
||||
let on_ground = rng.gen_bool(0.6);
|
||||
let pos = wpos2d.with_z(if on_ground {
|
||||
z_range.start
|
||||
@ -788,8 +801,7 @@ fn write_column<R: Rng>(
|
||||
});
|
||||
|
||||
let mut crystals: Vec<Crystal> = Vec::new();
|
||||
let max_length =
|
||||
(48.0 * close(vertical, MAX_RADIUS, MAX_RADIUS, 1)).max(12.0);
|
||||
let max_length = (48.0 * close(vertical, MAX_RADIUS, MAX_RADIUS, 1)).max(12.0);
|
||||
let length = rng.gen_range(8.0..max_length);
|
||||
let radius =
|
||||
Lerp::lerp(2.0, 4.5, length / max_length + rng.gen_range(-0.1..0.1));
|
||||
@ -839,6 +851,9 @@ fn write_column<R: Rng>(
|
||||
* biome.leafy) as f64,
|
||||
)
|
||||
{
|
||||
if tunnel_intersection() {
|
||||
return None;
|
||||
}
|
||||
let petal_radius = rng.gen_range(8.0..16.0);
|
||||
Some(CaveStructure::Flower(Flower {
|
||||
pos,
|
||||
@ -850,13 +865,15 @@ fn write_column<R: Rng>(
|
||||
petal_height: 0.4 * petal_radius * (1.0 + rng.gen::<f32>().powf(2.0)),
|
||||
petal_radius,
|
||||
}))
|
||||
} else if (biome.leafy > 0.7 || giant_tree_factor > 0.0)
|
||||
} else if (biome.leafy > 0.7 || giant_tree_dist > 0.0)
|
||||
&& rng.gen_bool(
|
||||
(0.5 * close(biome.leafy, 1.0, 0.5, 1).max(1.0 + giant_tree_factor)
|
||||
as f64)
|
||||
(0.5 * close(biome.leafy, 1.0, 0.5, 1).max(1.0 + giant_tree_dist) as f64)
|
||||
.clamped(0.0, 1.0),
|
||||
)
|
||||
{
|
||||
if tunnel_intersection() {
|
||||
return None;
|
||||
}
|
||||
Some(CaveStructure::GiantRoot {
|
||||
pos,
|
||||
radius: rng.gen_range(
|
||||
@ -869,26 +886,36 @@ fn write_column<R: Rng>(
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
structure
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
});
|
||||
|
||||
structure
|
||||
.as_ref()
|
||||
.map(|structure| (*seed, structure.clone()))
|
||||
})
|
||||
.collect_vec();
|
||||
let get_structure = |wpos: Vec3<i32>, dynamic_rng: &mut R| {
|
||||
let warp = |wposf: Vec3<f64>, freq: f64, amp: Vec3<f32>, seed: u32| -> Option<Vec3<f32>> {
|
||||
let xy = wposf.xy();
|
||||
let xz = Vec2::new(wposf.x, wposf.z);
|
||||
let yz = Vec2::new(wposf.y, wposf.z);
|
||||
Some(
|
||||
Vec3::new(
|
||||
FastNoise2d::new(seed).get(yz * freq),
|
||||
FastNoise2d::new(seed).get(xz * freq),
|
||||
FastNoise2d::new(seed).get(xy * freq),
|
||||
) * amp,
|
||||
)
|
||||
};
|
||||
for (seed, structure) in structures.iter() {
|
||||
let seed = *seed;
|
||||
match structure {
|
||||
CaveStructure::Mushroom(mushroom) => {
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let warp_freq = 1.0 / 32.0;
|
||||
let warp_amp = Vec3::new(12.0, 12.0, 12.0);
|
||||
let xy = wposf.xy();
|
||||
let xz = Vec2::new(wposf.x, wposf.z);
|
||||
let yz = Vec2::new(wposf.y, wposf.z);
|
||||
let warp_offset = warp(wposf, warp_freq, warp_amp, seed)?;
|
||||
let wposf_warped = wposf.map(|e| e as f32)
|
||||
+ Vec3::new(
|
||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
||||
) * warp_amp
|
||||
+ warp_offset
|
||||
* (wposf.z as f32 - mushroom.pos.z as f32)
|
||||
.mul(0.1)
|
||||
.clamped(0.0, 1.0);
|
||||
@ -1011,15 +1038,9 @@ fn write_column<R: Rng>(
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let warp_freq = 1.0 / 16.0;
|
||||
let warp_amp = Vec3::new(8.0, 8.0, 8.0);
|
||||
let xy = wposf.xy();
|
||||
let xz = Vec2::new(wposf.x, wposf.z);
|
||||
let yz = Vec2::new(wposf.y, wposf.z);
|
||||
let warp_offset = warp(wposf, warp_freq, warp_amp, seed)?;
|
||||
let wposf_warped = wposf.map(|e| e as f32)
|
||||
+ Vec3::new(
|
||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
||||
) * warp_amp
|
||||
+ warp_offset
|
||||
* (wposf.z as f32 - flower.pos.z as f32)
|
||||
.mul(1.0 / flower.stalk)
|
||||
.sub(1.0)
|
||||
@ -1044,8 +1065,7 @@ fn write_column<R: Rng>(
|
||||
let dist_sq = rpos.xy().magnitude_squared();
|
||||
let petal_radius_sq = flower.petal_radius.powi(2);
|
||||
if dist_sq < petal_radius_sq {
|
||||
let petal_height_at =
|
||||
(dist_sq / petal_radius_sq).powf(1.0) * flower.petal_height;
|
||||
let petal_height_at = (dist_sq / petal_radius_sq) * flower.petal_height;
|
||||
if rpos.z > petal_height_at - 1.0
|
||||
&& rpos.z <= petal_height_at + petal_thickness
|
||||
{
|
||||
@ -1108,16 +1128,9 @@ fn write_column<R: Rng>(
|
||||
} => {
|
||||
let wposf = wpos.map(|e| e as f64);
|
||||
let warp_freq = 1.0 / 32.0;
|
||||
let warp_amp = Vec3::new(20.0, 20.0, 20.0);
|
||||
let xy = wposf.xy();
|
||||
let xz = Vec2::new(wposf.x, wposf.z);
|
||||
let yz = Vec2::new(wposf.y, wposf.z);
|
||||
let wposf_warped = wposf.map(|e| e as f32)
|
||||
+ Vec3::new(
|
||||
FastNoise2d::new(seed).get(yz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xz * warp_freq),
|
||||
FastNoise2d::new(seed).get(xy * warp_freq),
|
||||
) * warp_amp;
|
||||
let warp_amp = Vec3::new(12.0, 12.0, 12.0);
|
||||
let warp_offset = warp(wposf, warp_freq, warp_amp, seed)?;
|
||||
let wposf_warped = wposf.map(|e| e as f32) + warp_offset;
|
||||
let rpos = wposf_warped - pos.map(|e| e as f32);
|
||||
let dist_sq = rpos.xy().magnitude_squared();
|
||||
if dist_sq < radius.powi(2) {
|
||||
@ -1142,7 +1155,7 @@ fn write_column<R: Rng>(
|
||||
for z in bedrock..z_range.end {
|
||||
let wpos = wpos2d.with_z(z);
|
||||
let mut try_spawn_entity = false;
|
||||
canvas.map_resource(wpos, |_block| {
|
||||
canvas.set(wpos, {
|
||||
if z < z_range.start - 4 && !void_below {
|
||||
Block::new(BlockKind::Lava, Rgb::new(255, 65, 0))
|
||||
} else if basalt > 0.0
|
||||
|
@ -111,6 +111,58 @@ impl StructureGen2d {
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Note: Generates all possible closest samples for elements in the range
|
||||
/// of min to max, *exclusive.*
|
||||
pub fn iter_with_wpos(
|
||||
&self,
|
||||
min: Vec2<i32>,
|
||||
max: Vec2<i32>,
|
||||
) -> impl Iterator<Item = (Vec2<i32>, StructureField)> {
|
||||
let freq = self.freq;
|
||||
let spread = self.spread;
|
||||
let spread_mul = Self::spread_mul(spread);
|
||||
assert!(spread * 2 == spread_mul);
|
||||
assert!(spread_mul <= freq);
|
||||
let spread = spread as i32;
|
||||
let freq = freq as i32;
|
||||
let freq_offset = Self::freq_offset(freq);
|
||||
assert!(freq_offset * 2 == freq);
|
||||
|
||||
let min_index = Self::sample_to_index_internal(freq, min) - 1;
|
||||
let max_index = Self::sample_to_index_internal(freq, max) + 1;
|
||||
assert!(min_index.x < max_index.x);
|
||||
// NOTE: xlen > 0
|
||||
let xlen = (max_index.x - min_index.x) as u32;
|
||||
assert!(min_index.y < max_index.y);
|
||||
// NOTE: ylen > 0
|
||||
let ylen = (max_index.y - min_index.y) as u32;
|
||||
// NOTE: Cannot fail, since every product of u32s fits in a u64.
|
||||
let len = ylen as u64 * xlen as u64;
|
||||
// NOTE: since iteration is *exclusive* for the initial range, it's fine that we
|
||||
// don't go up to the maximum value.
|
||||
// NOTE: we convert to usize first, and then iterate, because we want to make
|
||||
// sure we get a properly indexed parallel iterator that can deal with
|
||||
// the whole range at once.
|
||||
let x_field = self.x_field;
|
||||
let y_field = self.y_field;
|
||||
let seed_field = self.seed_field;
|
||||
(0..len).map(move |xy| {
|
||||
let index = min_index + Vec2::new((xy % xlen as u64) as i32, (xy / xlen as u64) as i32);
|
||||
let index_wpos = min + Vec2::new((xy % xlen as u64) as i32, (xy / len as u64) as i32);
|
||||
let field = Self::index_to_sample_internal(
|
||||
freq,
|
||||
freq_offset,
|
||||
spread,
|
||||
spread_mul,
|
||||
x_field,
|
||||
y_field,
|
||||
seed_field,
|
||||
index,
|
||||
);
|
||||
(index_wpos, field)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Sampler<'static> for StructureGen2d {
|
||||
|
Loading…
Reference in New Issue
Block a user