mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Made caves generate 425x faster
This commit is contained in:
parent
ec6b343dc8
commit
86f628037f
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
(
|
(
|
||||||
caverns: false, // TODO: Disabled by default until cave overhaul
|
caverns: false, // TODO: Disabled by default until cave overhaul
|
||||||
caves: false,
|
caves: true,
|
||||||
rocks: true,
|
rocks: true,
|
||||||
shrubs: true,
|
shrubs: true,
|
||||||
trees: true,
|
trees: true,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::scatter::close;
|
use super::scatter::close;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
util::{sampler::Sampler, FastNoise, RandomField, RandomPerm, StructureGen2d, LOCALITY},
|
util::{sampler::Sampler, FastNoise, RandomField, RandomPerm, StructureGen2d, LOCALITY, SQUARE_4},
|
||||||
Canvas, CanvasInfo, ColumnSample, Land,
|
Canvas, CanvasInfo, ColumnSample, Land,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
@ -80,6 +80,7 @@ pub fn surface_entrances<'a>(land: &'a Land) -> impl Iterator<Item = Vec2<i32>>
|
|||||||
.filter_map(|cell| Some(tunnel_below_from_cell(cell, 0, land)?.a.wpos))
|
.filter_map(|cell| Some(tunnel_below_from_cell(cell, 0, land)?.a.wpos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
pub struct Tunnel {
|
pub struct Tunnel {
|
||||||
a: Node,
|
a: Node,
|
||||||
b: Node,
|
b: Node,
|
||||||
@ -87,6 +88,8 @@ pub struct Tunnel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Tunnel {
|
impl Tunnel {
|
||||||
|
const RADIUS_RANGE: Range<f64> = 8.0..64.0;
|
||||||
|
|
||||||
fn ctrl_offset(&self) -> Vec2<f32> {
|
fn ctrl_offset(&self) -> Vec2<f32> {
|
||||||
let start = self.a.wpos.map(|e| e as f64 + 0.5);
|
let start = self.a.wpos.map(|e| e as f64 + 0.5);
|
||||||
let end = self.b.wpos.map(|e| e as f64 + 0.5);
|
let end = self.b.wpos.map(|e| e as f64 + 0.5);
|
||||||
@ -95,7 +98,7 @@ impl Tunnel {
|
|||||||
.map(|e| e as f32)
|
.map(|e| e as f32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn z_range_at(&self, wposf: Vec2<f64>, info: CanvasInfo) -> Option<(Range<i32>, f64)> {
|
fn possibly_near(&self, wposf: Vec2<f64>, threshold: f64) -> Option<(f64, Vec2<f64>, f64)> {
|
||||||
let start = self.a.wpos.map(|e| e as f64 + 0.5);
|
let start = self.a.wpos.map(|e| e as f64 + 0.5);
|
||||||
let end = self.b.wpos.map(|e| e as f64 + 0.5);
|
let end = self.b.wpos.map(|e| e as f64 + 0.5);
|
||||||
|
|
||||||
@ -104,43 +107,54 @@ impl Tunnel {
|
|||||||
wposf,
|
wposf,
|
||||||
Vec2::new(start, end),
|
Vec2::new(start, end),
|
||||||
) {
|
) {
|
||||||
let dist = closest.distance(wposf);
|
let dist2 = closest.distance_squared(wposf);
|
||||||
let radius = 8.0..64.0;
|
|
||||||
if dist < radius.end + 1.0 {
|
if dist2 < (Self::RADIUS_RANGE.end + threshold).powi(2) {
|
||||||
let radius = Lerp::lerp(
|
Some((t, closest, dist2.sqrt()))
|
||||||
radius.start,
|
} else {
|
||||||
radius.end,
|
None
|
||||||
(info.index().noise.cave_fbm_nz.get(
|
}
|
||||||
(wposf.with_z(info.land().get_alt_approx(self.a.wpos) as f64) / 200.0)
|
} else {
|
||||||
.into_array(),
|
None
|
||||||
) * 2.0
|
}
|
||||||
* 0.5
|
}
|
||||||
+ 0.5)
|
|
||||||
.clamped(0.0, 1.0)
|
fn z_range_at(&self, wposf: Vec2<f64>, info: CanvasInfo) -> Option<(Range<i32>, f64)> {
|
||||||
.powf(3.0),
|
let start = self.a.wpos.map(|e| e as f64 + 0.5);
|
||||||
);
|
let end = self.b.wpos.map(|e| e as f64 + 0.5);
|
||||||
let height_here = (1.0 - dist / radius).max(0.0).powf(0.3) * radius;
|
|
||||||
if height_here > 0.0 {
|
if let Some((t, closest, dist)) = self.possibly_near(wposf, 1.0) {
|
||||||
let z_offs = info
|
let radius = Lerp::lerp(
|
||||||
.index()
|
Self::RADIUS_RANGE.start,
|
||||||
.noise
|
Self::RADIUS_RANGE.end,
|
||||||
.cave_fbm_nz
|
(info.index().noise.cave_fbm_nz.get(
|
||||||
.get((wposf / 512.0).into_array())
|
(wposf.with_z(info.land().get_alt_approx(self.a.wpos) as f64) / 200.0)
|
||||||
* 96.0
|
.into_array(),
|
||||||
* ((1.0 - (t - 0.5).abs() * 2.0) * 8.0).min(1.0);
|
) * 2.0
|
||||||
let alt_here = info.land().get_alt_approx(closest.map(|e| e as i32));
|
* 0.5
|
||||||
let base = Lerp::lerp(
|
+ 0.5)
|
||||||
alt_here as f64 - self.a.depth as f64,
|
.clamped(0.0, 1.0)
|
||||||
alt_here as f64 - self.b.depth as f64,
|
.powf(3.0),
|
||||||
t,
|
);
|
||||||
) + z_offs;
|
let height_here = (1.0 - dist / radius).max(0.0).powf(0.3) * radius;
|
||||||
Some((
|
if height_here > 0.0 {
|
||||||
(base - height_here * 0.3) as i32..(base + height_here * 1.35) as i32,
|
let z_offs = info
|
||||||
radius,
|
.index()
|
||||||
))
|
.noise
|
||||||
} else {
|
.cave_fbm_nz
|
||||||
None
|
.get((wposf / 512.0).into_array())
|
||||||
}
|
* 96.0
|
||||||
|
* ((1.0 - (t - 0.5).abs() * 2.0) * 8.0).min(1.0);
|
||||||
|
let alt_here = info.land().get_alt_approx(closest.map(|e| e as i32));
|
||||||
|
let base = Lerp::lerp(
|
||||||
|
alt_here as f64 - self.a.depth as f64,
|
||||||
|
alt_here as f64 - self.b.depth as f64,
|
||||||
|
t,
|
||||||
|
) + z_offs;
|
||||||
|
Some((
|
||||||
|
(base - height_here * 0.3) as i32..(base + height_here * 1.35) as i32,
|
||||||
|
radius,
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -291,68 +305,102 @@ fn tunnels_down_from<'a>(
|
|||||||
.filter_map(move |rpos| tunnel_below_from_cell(col_cell + rpos, level, land))
|
.filter_map(move |rpos| tunnel_below_from_cell(col_cell + rpos, level, land))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn all_tunnels_at<'a>(
|
||||||
|
wpos2d: Vec2<i32>,
|
||||||
|
info: &'a CanvasInfo,
|
||||||
|
land: &'a Land,
|
||||||
|
) -> impl Iterator<Item = (u32, Tunnel)> + 'a {
|
||||||
|
(1..LAYERS + 1).flat_map(move |level| tunnels_at(wpos2d, level, land)
|
||||||
|
.chain(tunnels_down_from(wpos2d, level - 1, land))
|
||||||
|
.map(move |tunnel| (level, tunnel)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tunnel_bounds_at_from<'a>(
|
||||||
|
wpos2d: Vec2<i32>,
|
||||||
|
info: &'a CanvasInfo,
|
||||||
|
land: &'a Land,
|
||||||
|
tunnels: impl Iterator<Item = (u32, Tunnel)> + 'a,
|
||||||
|
) -> impl Iterator<Item = (u32, Range<i32>, f64, Tunnel)> + 'a {
|
||||||
|
let wposf = wpos2d.map(|e| e as f64 + 0.5);
|
||||||
|
info.col_or_gen(wpos2d).map(move |col| {
|
||||||
|
let col_alt = col.alt;
|
||||||
|
let col_water_dist = col.water_dist;
|
||||||
|
tunnels
|
||||||
|
.filter_map(move |(level, tunnel)| {
|
||||||
|
let (z_range, radius) = tunnel.z_range_at(wposf, *info)?;
|
||||||
|
// Avoid cave entrances intersecting water
|
||||||
|
let z_range = Lerp::lerp(
|
||||||
|
z_range.end,
|
||||||
|
z_range.start,
|
||||||
|
1.0 - (1.0
|
||||||
|
- ((col_water_dist.unwrap_or(1000.0) - 4.0).max(0.0) / 32.0)
|
||||||
|
.clamped(0.0, 1.0))
|
||||||
|
* (1.0
|
||||||
|
- ((col_alt - z_range.end as f32 - 4.0) / 8.0).clamped(0.0, 1.0)),
|
||||||
|
)..z_range.end;
|
||||||
|
if z_range.end - z_range.start > 0 {
|
||||||
|
Some((level, z_range, radius, tunnel))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tunnel_bounds_at<'a>(
|
pub fn tunnel_bounds_at<'a>(
|
||||||
wpos2d: Vec2<i32>,
|
wpos2d: Vec2<i32>,
|
||||||
info: &'a CanvasInfo,
|
info: &'a CanvasInfo,
|
||||||
land: &'a Land,
|
land: &'a Land,
|
||||||
) -> impl Iterator<Item = (u32, Range<i32>, f64, Tunnel)> + 'a {
|
) -> impl Iterator<Item = (u32, Range<i32>, f64, Tunnel)> + 'a {
|
||||||
let wposf = wpos2d.map(|e| e as f64 + 0.5);
|
tunnel_bounds_at_from(
|
||||||
info.col_or_gen(wpos2d).into_iter().flat_map(move |col| {
|
wpos2d,
|
||||||
let col_alt = col.alt;
|
info,
|
||||||
let col_water_dist = col.water_dist;
|
land,
|
||||||
(1..LAYERS + 1).flat_map(move |level| {
|
all_tunnels_at(wpos2d, info, land),
|
||||||
tunnels_at(wpos2d, level, land)
|
)
|
||||||
.chain(tunnels_down_from(wpos2d, level - 1, land))
|
|
||||||
.filter_map(move |tunnel| {
|
|
||||||
let (z_range, radius) = tunnel.z_range_at(wposf, *info)?;
|
|
||||||
// Avoid cave entrances intersecting water
|
|
||||||
let z_range = Lerp::lerp(
|
|
||||||
z_range.end,
|
|
||||||
z_range.start,
|
|
||||||
1.0 - (1.0
|
|
||||||
- ((col_water_dist.unwrap_or(1000.0) - 4.0).max(0.0) / 32.0)
|
|
||||||
.clamped(0.0, 1.0))
|
|
||||||
* (1.0
|
|
||||||
- ((col_alt - z_range.end as f32 - 4.0) / 8.0).clamped(0.0, 1.0)),
|
|
||||||
)..z_range.end;
|
|
||||||
if z_range.end - z_range.start > 0 {
|
|
||||||
Some((level, z_range, radius, tunnel))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
||||||
let info = canvas.info();
|
let info = canvas.info();
|
||||||
|
let land = info.land();
|
||||||
let mut mushroom_cache = HashMap::new();
|
let mut mushroom_cache = HashMap::new();
|
||||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
|
||||||
let land = info.land();
|
|
||||||
|
|
||||||
let tunnel_bounds = tunnel_bounds_at(wpos2d, &info, &land).collect::<Vec<_>>();
|
let diagonal = (TerrainChunkSize::RECT_SIZE.map(|e| e * e).sum() as f32).sqrt() as f64;
|
||||||
|
let tunnels = all_tunnels_at(info.wpos() + TerrainChunkSize::RECT_SIZE.map(|e| e as i32) / 2, &info, &land)
|
||||||
|
.filter(|(_, tunnel)| SQUARE_4
|
||||||
|
.into_iter()
|
||||||
|
.map(|rpos| info.wpos() + rpos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32))
|
||||||
|
.all(|wpos| tunnel.possibly_near(wpos.map(|e| e as f64), diagonal + 1.0).is_some()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// First, clear out tunnels
|
if !tunnels.is_empty() {
|
||||||
for (_, z_range, _, _) in &tunnel_bounds {
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
for z in z_range.start..z_range.end.min(col.alt as i32 + 1) {
|
let tunnel_bounds = tunnel_bounds_at_from(wpos2d, &info, &land, tunnels.iter().copied())
|
||||||
canvas.set(wpos2d.with_z(z), Block::air(SpriteKind::Empty));
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// First, clear out tunnels
|
||||||
|
for (_, z_range, _, _) in &tunnel_bounds {
|
||||||
|
for z in z_range.start..z_range.end.min(col.alt as i32 + 1) {
|
||||||
|
canvas.set(wpos2d.with_z(z), Block::air(SpriteKind::Empty));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (level, z_range, _radius, tunnel) in tunnel_bounds {
|
for (level, z_range, _radius, tunnel) in tunnel_bounds {
|
||||||
write_column(
|
write_column(
|
||||||
canvas,
|
canvas,
|
||||||
col,
|
col,
|
||||||
level,
|
level,
|
||||||
wpos2d,
|
wpos2d,
|
||||||
z_range.clone(),
|
z_range.clone(),
|
||||||
tunnel,
|
tunnel,
|
||||||
&mut mushroom_cache,
|
&mut mushroom_cache,
|
||||||
rng,
|
rng,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
Loading…
Reference in New Issue
Block a user