mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improved river/lake rendering
This commit is contained in:
parent
bfbca3e517
commit
87c7d6e982
@ -551,7 +551,7 @@ impl<'a> MapConfig<'a> {
|
|||||||
downhill_wpos,
|
downhill_wpos,
|
||||||
);
|
);
|
||||||
let (_t, _pt, dist) = if let Some((t, pt, dist)) =
|
let (_t, _pt, dist) = if let Some((t, pt, dist)) =
|
||||||
quadratic_nearest_point(&coeffs, wposf)
|
quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, downhill_wpos))
|
||||||
{
|
{
|
||||||
(t, pt, dist)
|
(t, pt, dist)
|
||||||
} else {
|
} else {
|
||||||
|
@ -293,7 +293,25 @@ pub fn river_spline_coeffs(
|
|||||||
pub fn quadratic_nearest_point(
|
pub fn quadratic_nearest_point(
|
||||||
spline: &Vec3<Vec2<f64>>,
|
spline: &Vec3<Vec2<f64>>,
|
||||||
point: Vec2<f64>,
|
point: Vec2<f64>,
|
||||||
|
line: Vec2<Vec2<f64>>,
|
||||||
) -> Option<(f64, Vec2<f64>, f64)> {
|
) -> Option<(f64, Vec2<f64>, f64)> {
|
||||||
|
let line = LineSegment2 {
|
||||||
|
start: line.x,
|
||||||
|
end: line.y,
|
||||||
|
};
|
||||||
|
let len_sq = line.start.distance_squared(line.end);
|
||||||
|
let t = ((point - line.start).dot(line.end - line.start) / len_sq).clamped(0.0, 1.0);
|
||||||
|
let pos = line.start + (line.end - line.start) * t;
|
||||||
|
return Some((t, pos, pos.distance_squared(point)));
|
||||||
|
|
||||||
|
// let curve = QuadraticBezier2 {
|
||||||
|
// start: spline.x,
|
||||||
|
// ctrl: spline.y,
|
||||||
|
// end: spline.z,
|
||||||
|
// };
|
||||||
|
// let (t, pos) = curve.binary_search_point_by_steps(point, 16, 0.001);
|
||||||
|
// return Some((t, pos, curve.evaluate(t).distance_squared(point)));
|
||||||
|
|
||||||
let a = spline.z.x;
|
let a = spline.z.x;
|
||||||
let b = spline.y.x;
|
let b = spline.y.x;
|
||||||
let c = spline.x.x;
|
let c = spline.x.x;
|
||||||
|
@ -147,23 +147,27 @@ impl<'a> BlockGen<'a> {
|
|||||||
} else {
|
} else {
|
||||||
Some(Block::new(BlockKind::Earth, col))
|
Some(Block::new(BlockKind::Earth, col))
|
||||||
}
|
}
|
||||||
} else if (wposf.z as f32) < height {
|
} else if wposf.z as i32 <= height as i32 {
|
||||||
let grass_factor = (wposf.z as f32 - (height - grass_depth))
|
let grass_factor = (wposf.z as f32 - (height - grass_depth))
|
||||||
.div(grass_depth)
|
.div(grass_depth)
|
||||||
.sqrt();
|
.sqrt();
|
||||||
let col = Lerp::lerp(sub_surface_color, surface_color, grass_factor);
|
|
||||||
// Surface
|
// Surface
|
||||||
Some(Block::new(
|
Some(if water_level.floor() > height {
|
||||||
if snow_cover {
|
Block::new(
|
||||||
|
BlockKind::Sand,
|
||||||
|
sub_surface_color.map(|e| (e * 255.0) as u8),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let col = Lerp::lerp(sub_surface_color, surface_color, grass_factor);
|
||||||
|
if grass_factor < 0.7 {
|
||||||
|
Block::new(BlockKind::Earth, col.map(|e| (e * 255.0) as u8))
|
||||||
|
} else if snow_cover {
|
||||||
//if temp < CONFIG.snow_temp + 0.031 {
|
//if temp < CONFIG.snow_temp + 0.031 {
|
||||||
BlockKind::Snow
|
Block::new(BlockKind::Snow, col.map(|e| (e * 255.0) as u8))
|
||||||
} else if grass_factor > 0.7 {
|
|
||||||
BlockKind::Grass
|
|
||||||
} else {
|
} else {
|
||||||
BlockKind::Earth
|
Block::new(BlockKind::Grass, col.map(|e| (e * 255.0) as u8))
|
||||||
},
|
}
|
||||||
col.map(|e| (e * 255.0) as u8),
|
})
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
Some((neighbor_pos, neighbor_chunk, &neighbor_chunk.river))
|
Some((neighbor_pos, neighbor_chunk, &neighbor_chunk.river))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let gradient = sim.get_gradient_approx(chunk_pos);
|
||||||
|
|
||||||
let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * (2.0f64.sqrt())) + 12.0;
|
let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * (2.0f64.sqrt())) + 12.0;
|
||||||
let neighbor_river_data = neighbor_river_data.map(|(posj, chunkj, river)| {
|
let neighbor_river_data = neighbor_river_data.map(|(posj, chunkj, river)| {
|
||||||
let kind = match river.river_kind {
|
let kind = match river.river_kind {
|
||||||
@ -120,9 +122,9 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
};
|
};
|
||||||
let downhill_wpos = downhill_pos.map(|e| e as f64);
|
let downhill_wpos = downhill_pos.map(|e| e as f64);
|
||||||
let downhill_pos =
|
let downhill_pos =
|
||||||
downhill_pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
downhill_pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e.div_euclid(sz as i32));
|
||||||
let neighbor_pos = posj.map(|e| e as f64) * neighbor_coef;
|
let neighbor_wpos = posj.map(|e| e as f64) * neighbor_coef;// + neighbor_coef * 0.5;
|
||||||
let direction = neighbor_pos - downhill_wpos;
|
let direction = neighbor_wpos - downhill_wpos;
|
||||||
let river_width_min = if let RiverKind::River { cross_section } = kind {
|
let river_width_min = if let RiverKind::River { cross_section } = kind {
|
||||||
cross_section.x as f64
|
cross_section.x as f64
|
||||||
} else {
|
} else {
|
||||||
@ -130,16 +132,25 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
};
|
};
|
||||||
let downhill_chunk = sim.get(downhill_pos).expect("How can this not work?");
|
let downhill_chunk = sim.get(downhill_pos).expect("How can this not work?");
|
||||||
let coeffs =
|
let coeffs =
|
||||||
river_spline_coeffs(neighbor_pos, chunkj.river.spline_derivative, downhill_wpos);
|
river_spline_coeffs(neighbor_wpos, chunkj.river.spline_derivative, downhill_wpos);
|
||||||
let (direction, coeffs, downhill_chunk, river_t, river_pos, river_dist) = match kind {
|
let (direction, coeffs, downhill_chunk, river_t, river_pos, river_dist) = match kind {
|
||||||
RiverKind::River { .. } => {
|
RiverKind::River { .. } => {
|
||||||
if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf) {
|
if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, downhill_wpos)) /*{
|
||||||
|
let curve = CubicBezier2 {
|
||||||
|
start: neighbor_wpos,
|
||||||
|
ctrl0: neighbor_wpos * 0.75 + downhill_wpos * 0.25 + chunkj.river.spline_derivative.map(|e| e as f64).normalized() * 0.0,
|
||||||
|
ctrl1: downhill_wpos * 0.75 + neighbor_wpos * 0.25 - downhill_chunk.river.spline_derivative.map(|e| e as f64).normalized() * 0.0,
|
||||||
|
end: downhill_wpos,
|
||||||
|
};
|
||||||
|
let (t, pos) = curve.binary_search_point_by_steps(wposf, 16, 0.001);
|
||||||
|
Some((t, pos, curve.evaluate(t).distance_squared(wposf)))
|
||||||
|
}*/ {
|
||||||
(direction, coeffs, downhill_chunk, t, pt, dist.sqrt())
|
(direction, coeffs, downhill_chunk, t, pt, dist.sqrt())
|
||||||
} else {
|
} else {
|
||||||
let ndist = wposf.distance_squared(neighbor_pos);
|
let ndist = wposf.distance_squared(neighbor_wpos);
|
||||||
let ddist = wposf.distance_squared(downhill_wpos);
|
let ddist = wposf.distance_squared(downhill_wpos);
|
||||||
let (closest_pos, closest_dist, closest_t) = if ndist <= ddist {
|
let (closest_pos, closest_dist, closest_t) = if ndist <= ddist {
|
||||||
(neighbor_pos, ndist, 0.0)
|
(neighbor_wpos, ndist, 0.0)
|
||||||
} else {
|
} else {
|
||||||
(downhill_wpos, ddist, 1.0)
|
(downhill_wpos, ddist, 1.0)
|
||||||
};
|
};
|
||||||
@ -156,7 +167,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
RiverKind::Lake { neighbor_pass_pos } => {
|
RiverKind::Lake { neighbor_pass_pos } => {
|
||||||
let pass_dist = neighbor_pass_pos
|
let pass_dist = neighbor_pass_pos
|
||||||
.map2(
|
.map2(
|
||||||
neighbor_pos
|
neighbor_wpos
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |f, g| (f as i32, g as i32)),
|
.map2(TerrainChunkSize::RECT_SIZE, |f, g| (f as i32, g as i32)),
|
||||||
|e, (f, g)| ((e - f) / g).abs(),
|
|e, (f, g)| ((e - f) / g).abs(),
|
||||||
)
|
)
|
||||||
@ -169,7 +180,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
};
|
};
|
||||||
let pass_dist = neighbor_pass_pos
|
let pass_dist = neighbor_pass_pos
|
||||||
.map2(
|
.map2(
|
||||||
neighbor_pos
|
neighbor_wpos
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |f, g| (f as i32, g as i32)),
|
.map2(TerrainChunkSize::RECT_SIZE, |f, g| (f as i32, g as i32)),
|
||||||
|e, (f, g)| ((e - f) / g).abs(),
|
|e, (f, g)| ((e - f) / g).abs(),
|
||||||
)
|
)
|
||||||
@ -181,9 +192,9 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
let neighbor_pass_pos = neighbor_pass_pos
|
let neighbor_pass_pos = neighbor_pass_pos
|
||||||
.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32);
|
||||||
let coeffs =
|
let coeffs =
|
||||||
river_spline_coeffs(neighbor_pos, spline_derivative, neighbor_pass_wpos);
|
river_spline_coeffs(neighbor_wpos, spline_derivative, neighbor_pass_wpos);
|
||||||
let direction = neighbor_pos - neighbor_pass_wpos;
|
let direction = neighbor_wpos - neighbor_pass_wpos;
|
||||||
if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf) {
|
if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, neighbor_pass_wpos)) {
|
||||||
(
|
(
|
||||||
direction,
|
direction,
|
||||||
coeffs,
|
coeffs,
|
||||||
@ -193,10 +204,10 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
dist.sqrt(),
|
dist.sqrt(),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let ndist = wposf.distance_squared(neighbor_pos);
|
let ndist = wposf.distance_squared(neighbor_wpos);
|
||||||
/* let ddist = wposf.distance_squared(neighbor_pass_wpos); */
|
/* let ddist = wposf.distance_squared(neighbor_pass_wpos); */
|
||||||
let (closest_pos, closest_dist, closest_t) = /*if ndist <= ddist */ {
|
let (closest_pos, closest_dist, closest_t) = /*if ndist <= ddist */ {
|
||||||
(neighbor_pos, ndist, 0.0)
|
(neighbor_wpos, ndist, 0.0)
|
||||||
} /* else {
|
} /* else {
|
||||||
(neighbor_pass_wpos, ddist, 1.0)
|
(neighbor_pass_wpos, ddist, 1.0)
|
||||||
} */;
|
} */;
|
||||||
@ -211,8 +222,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
RiverKind::Ocean => {
|
RiverKind::Ocean => {
|
||||||
let ndist = wposf.distance_squared(neighbor_pos);
|
let ndist = wposf.distance_squared(neighbor_wpos);
|
||||||
let (closest_pos, closest_dist, closest_t) = (neighbor_pos, ndist, 0.0);
|
let (closest_pos, closest_dist, closest_t) = (neighbor_wpos, ndist, 0.0);
|
||||||
(
|
(
|
||||||
direction,
|
direction,
|
||||||
coeffs,
|
coeffs,
|
||||||
@ -243,12 +254,13 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
river_t.max(0.0).min(1.0).sqrt(),
|
river_t.max(0.0).min(1.0).sqrt(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let river_width = river_width * (1.0 + river_width_noise * 0.3);
|
let river_width = river_width;// * (1.0 + river_width_noise * 0.3);
|
||||||
// To find the distance, we just evaluate the quadratic equation at river_t and
|
// To find the distance, we just evaluate the quadratic equation at river_t and
|
||||||
// see if it's within width (but we should be able to use it for a
|
// see if it's within width (but we should be able to use it for a
|
||||||
// lot more, and this probably isn't the very best approach anyway
|
// lot more, and this probably isn't the very best approach anyway
|
||||||
// since it will bleed out). let river_pos = coeffs.x * river_t *
|
// since it will bleed out). let river_pos = coeffs.x * river_t *
|
||||||
// river_t + coeffs.y * river_t + coeffs.z;
|
// river_t + coeffs.y * river_t + coeffs.z;
|
||||||
|
// let river_width = 32.0f64;
|
||||||
let res = Vec2::new(0.0, (river_dist - (river_width * 0.5).max(1.0)).max(0.0));
|
let res = Vec2::new(0.0, (river_dist - (river_width * 0.5).max(1.0)).max(0.0));
|
||||||
(
|
(
|
||||||
posj,
|
posj,
|
||||||
@ -263,26 +275,187 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
// Cliffs
|
let downhill = sim_chunk.downhill;
|
||||||
let cliff_factor = (alt
|
let downhill_pos = downhill.and_then(|downhill_pos| sim.get(downhill_pos));
|
||||||
+ self.sim.gen_ctx.hill_nz.get(wposf.div(64.0).into_array()) as f32 * 8.0
|
debug_assert!(sim_chunk.water_alt >= CONFIG.sea_level);
|
||||||
+ self.sim.gen_ctx.hill_nz.get(wposf.div(350.0).into_array()) as f32 * 128.0)
|
|
||||||
.rem_euclid(200.0)
|
let downhill_water_alt = downhill_pos
|
||||||
/ 64.0
|
.map(|downhill_chunk| {
|
||||||
- 1.0;
|
downhill_chunk
|
||||||
let cliff_scale =
|
.water_alt
|
||||||
((self.sim.gen_ctx.hill_nz.get(wposf.div(128.0).into_array()) as f32 * 1.5 + 0.75)
|
.min(sim_chunk.water_alt)
|
||||||
+ self.sim.gen_ctx.hill_nz.get(wposf.div(48.0).into_array()) as f32 * 0.1)
|
.max(sim_chunk.alt.min(sim_chunk.water_alt))
|
||||||
.clamped(0.0, 1.0)
|
})
|
||||||
.powf(2.0);
|
.unwrap_or(CONFIG.sea_level);
|
||||||
let cliff_height = sim.get_interpolated(wpos, |chunk| chunk.cliff_height)? * cliff_scale;
|
|
||||||
let cliff = if cliff_factor < 0.0 {
|
#[derive(Default)]
|
||||||
cliff_factor.abs().powf(1.5)
|
struct WeightedSum<T> { sum: T, weight: T, min: Option<T>, max: Option<T> }
|
||||||
} else {
|
impl WeightedSum<f32> {
|
||||||
0.0
|
fn with(self, value: f32, weight: f32) -> Self {
|
||||||
} * (1.0 - near_water * 3.0).max(0.0).powi(2);
|
Self {
|
||||||
let cliff_offset = cliff * cliff_height;
|
sum: self.sum + value * weight,
|
||||||
let alt = alt + (cliff - 0.5) * cliff_height;
|
weight: self.weight + weight,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// With an upper bound
|
||||||
|
fn with_min(self, min: f32) -> Self {
|
||||||
|
Self { min: Some(self.min.unwrap_or(min).min(min)), ..self }
|
||||||
|
}
|
||||||
|
/// With a lower bound
|
||||||
|
fn with_max(self, max: f32) -> Self {
|
||||||
|
Self { max: Some(self.max.unwrap_or(max).max(max)), ..self }
|
||||||
|
}
|
||||||
|
fn eval_or(&self, default: f32) -> f32 {
|
||||||
|
let res = if self.weight > 0.0 {
|
||||||
|
self.sum / self.weight
|
||||||
|
} else {
|
||||||
|
default
|
||||||
|
};
|
||||||
|
let res = match self.min {
|
||||||
|
Some(min) => res.min(min),
|
||||||
|
None => res,
|
||||||
|
};
|
||||||
|
let res = match self.max {
|
||||||
|
Some(max) => res.max(max),
|
||||||
|
None => res,
|
||||||
|
};
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let water_level = neighbor_river_data.clone().fold(
|
||||||
|
WeightedSum::default(),
|
||||||
|
|water_level, (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
|
||||||
|
(
|
||||||
|
Some(kind/*RiverKind::River { cross_section }*/),
|
||||||
|
Some((_, dist, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
||||||
|
) => {
|
||||||
|
// Distance from river center
|
||||||
|
let river_dist = river_pos.distance(wposf);
|
||||||
|
// Distance from edge of river
|
||||||
|
let river_edge_dist = (river_dist - river_width * 0.5).max(0.0) as f32;
|
||||||
|
// 0.0 = not near river, 1.0 = in middle of river
|
||||||
|
let near_river = ((river_dist / river_width) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
|
||||||
|
|
||||||
|
match kind {
|
||||||
|
RiverKind::River { .. } if river_edge_dist <= 0.0 => {
|
||||||
|
// Alt of river water *is* the alt of land
|
||||||
|
let river_water_alt = Lerp::lerp(river_chunk.alt, downhill_chunk.alt, river_t as f32);
|
||||||
|
water_level.with(river_water_alt, near_river)
|
||||||
|
},
|
||||||
|
// Slightly wider threshold is chosen in case the lake bounds are a bit wrong
|
||||||
|
RiverKind::Lake { .. } if river_edge_dist <= 16.0 => {
|
||||||
|
let lake_water_alt = Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_chunk.alt.max(downhill_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
);
|
||||||
|
water_level.with_max(lake_water_alt)
|
||||||
|
},
|
||||||
|
_ => water_level,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
(_, _) => water_level,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let water_level = water_level.eval_or(CONFIG.sea_level);
|
||||||
|
|
||||||
|
let riverless_alt = alt;
|
||||||
|
let alt = neighbor_river_data.clone().fold(
|
||||||
|
WeightedSum::default().with(riverless_alt, 1.0),
|
||||||
|
|alt, (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
|
||||||
|
(
|
||||||
|
Some(kind/*RiverKind::River { cross_section }*/),
|
||||||
|
Some((_, dist, river_width, (river_t, (river_pos, _), downhill_chunk))),
|
||||||
|
) => {
|
||||||
|
// Distance from river center
|
||||||
|
let river_dist = river_pos.distance(wposf);
|
||||||
|
// Distance from edge of river
|
||||||
|
let river_edge_dist = (river_dist - river_width * 0.5).max(0.0) as f32;
|
||||||
|
// 0.0 = not near river, 1.0 = in middle of river
|
||||||
|
let near_river = ((river_dist / river_width) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
|
||||||
|
|
||||||
|
// Maximum depth of the river basin (including banks)
|
||||||
|
let river_basin = (river_width as f32 + 1.0).ln() * 1.5;
|
||||||
|
// River basin depth at the current column
|
||||||
|
let basin_depth = near_river * river_basin;
|
||||||
|
|
||||||
|
let water_alt = match kind {
|
||||||
|
RiverKind::River { .. } => {
|
||||||
|
// Alt of river water *is* the alt of land
|
||||||
|
Some(Lerp::lerp(river_chunk.alt, downhill_chunk.alt, river_t as f32))
|
||||||
|
},
|
||||||
|
RiverKind::Lake { .. } => Some(Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_chunk.alt.max(downhill_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
)),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(water_alt) = water_alt {
|
||||||
|
if river_edge_dist <= 0.0 {
|
||||||
|
const MIN_DEPTH: f32 = 0.5;
|
||||||
|
let near_centre = ((river_dist / (river_width * 0.5)) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);;
|
||||||
|
let riverbed_depth = near_centre * river_width as f32 * 0.35 + MIN_DEPTH;
|
||||||
|
alt.with_min(water_alt - riverbed_depth)
|
||||||
|
} else {
|
||||||
|
const GORGE: f32 = 0.5;
|
||||||
|
const BANK_SCALE: f32 = 24.0;
|
||||||
|
const BANK_STRENGTH: f32 = 100.0;
|
||||||
|
// Weighting of this riverbank on nearby terrain (higher when closer to the river). This
|
||||||
|
// 'pulls' the riverbank toward the river's altitude to make sure that we get a smooth
|
||||||
|
// transition from normal terrain to the water.
|
||||||
|
let weight = Lerp::lerp(
|
||||||
|
BANK_STRENGTH / (1.0 + (river_edge_dist as f32 - 1.0).max(0.0) * BANK_STRENGTH / BANK_SCALE),
|
||||||
|
0.0,
|
||||||
|
(river_edge_dist / BANK_SCALE).clamped(0.0, 1.0),
|
||||||
|
);
|
||||||
|
let alt = alt.with(water_alt + GORGE, weight);
|
||||||
|
// Add "walls" around weirdly back-curving segments to prevent water walls
|
||||||
|
// let alt = if river_edge_dist <= 1.0 && river_t > 0.0 && river_t < 1.0 {
|
||||||
|
// alt.with_max(water_alt + GORGE)
|
||||||
|
// } else {
|
||||||
|
// alt
|
||||||
|
// };
|
||||||
|
alt
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alt
|
||||||
|
}
|
||||||
|
|
||||||
|
// match kind {
|
||||||
|
// RiverKind::River { .. } => {
|
||||||
|
// // Alt of river water *is* the alt of land
|
||||||
|
// let river_water_alt = Lerp::lerp(river_chunk.alt, downhill_chunk.alt, river_t as f32);
|
||||||
|
|
||||||
|
// if river_edge_dist <= 0.0 {
|
||||||
|
// const GORGE: f32 = 1.0;
|
||||||
|
// let near_centre = ((river_dist / (river_width * 0.5)) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);;
|
||||||
|
// let riverbed_depth = near_centre * river_width as f32 * 0.35 + GORGE;
|
||||||
|
// alt.with_min(river_water_alt - riverbed_depth)
|
||||||
|
// } else {
|
||||||
|
// const BANK_SCALE: f32 = 8.0;
|
||||||
|
// const BANK_STRENGTH: f32 = 100.0;
|
||||||
|
// alt.with(river_water_alt, BANK_STRENGTH / (1.0 + river_edge_dist as f32 * BANK_STRENGTH / BANK_SCALE))
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// RiverKind::Lake { .. } => {
|
||||||
|
// let lake_water_alt = Lerp::lerp(
|
||||||
|
// river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
// downhill_chunk.alt.max(downhill_chunk.water_alt),
|
||||||
|
// river_t as f32,
|
||||||
|
// );
|
||||||
|
// alt
|
||||||
|
// },
|
||||||
|
// _ => alt,
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
(_, _) => alt,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let alt = alt.eval_or(riverless_alt);
|
||||||
|
|
||||||
// Find the average distance to each neighboring body of water.
|
// Find the average distance to each neighboring body of water.
|
||||||
let mut river_count = 0.0f64;
|
let mut river_count = 0.0f64;
|
||||||
@ -291,6 +464,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
let mut river_overlap_distance_product = 0.0f64;
|
let mut river_overlap_distance_product = 0.0f64;
|
||||||
let mut max_river = None;
|
let mut max_river = None;
|
||||||
let mut max_key = None;
|
let mut max_key = None;
|
||||||
|
let mut max_dip = 0.0f32;
|
||||||
// IDEA:
|
// IDEA:
|
||||||
// For every "nearby" chunk, check whether it is a river. If so, find the
|
// For every "nearby" chunk, check whether it is a river. If so, find the
|
||||||
// closest point on the river segment to wposf (if two point are
|
// closest point on the river segment to wposf (if two point are
|
||||||
@ -318,6 +492,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// 0, the weighted altitude of this point should go from
|
// 0, the weighted altitude of this point should go from
|
||||||
// alt to river_alt.
|
// alt to river_alt.
|
||||||
neighbor_river_data.for_each(|(river_chunk_idx, river_chunk, river, dist)| {
|
neighbor_river_data.for_each(|(river_chunk_idx, river_chunk, river, dist)| {
|
||||||
|
return; // TODO: Not this
|
||||||
|
|
||||||
match river.river_kind {
|
match river.river_kind {
|
||||||
Some(kind) => {
|
Some(kind) => {
|
||||||
if kind.is_river() && dist.is_none() {
|
if kind.is_river() && dist.is_none() {
|
||||||
@ -325,19 +501,20 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// closest point between t = 0.0 and t = 1.0).
|
// closest point between t = 0.0 and t = 1.0).
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
let river_dist = dist.map(|(_, dist, _, (river_t, _, downhill_river))| {
|
let river_dist = dist.map(|(_, dist, river_width, (river_t, (river_pos, _), downhill_river))| {
|
||||||
let downhill_height = if kind.is_river() {
|
let downhill_height = if kind.is_river() {
|
||||||
Lerp::lerp(
|
// Lerp::lerp(
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
// river_chunk.alt.max(river_chunk.water_alt),
|
||||||
downhill_river.alt.max(downhill_river.water_alt),
|
// downhill_river.alt.max(downhill_river.water_alt),
|
||||||
river_t as f32,
|
// river_t as f32,
|
||||||
) as f64
|
// ) as f64
|
||||||
|
river_width - (river_pos - wposf).magnitude()
|
||||||
} else {
|
} else {
|
||||||
let neighbor_pos =
|
let neighbor_pos =
|
||||||
river_chunk_idx.map(|e| e as f64) * neighbor_coef;
|
river_chunk_idx.map(|e| e as f64) * neighbor_coef;
|
||||||
-(wposf - neighbor_pos).magnitude()
|
river_width - (wposf - neighbor_pos).magnitude()
|
||||||
};
|
};
|
||||||
(Reverse((dist.x, dist.y)), downhill_height)
|
(Reverse((dist.x, dist.y /*- if kind.is_river() { 0.01 } else { 0.0 }*/)), downhill_height)
|
||||||
});
|
});
|
||||||
let river_dist = river_dist.or_else(|| {
|
let river_dist = river_dist.or_else(|| {
|
||||||
if !kind.is_river() {
|
if !kind.is_river() {
|
||||||
@ -363,7 +540,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
// between the edge of the river that we intersect, and the remaining distance
|
// between the edge of the river that we intersect, and the remaining distance
|
||||||
// until the nearest point in "this" chunk (i.e. the one whose top-left corner
|
// until the nearest point in "this" chunk (i.e. the one whose top-left corner
|
||||||
// is chunk_pos) that is at least 2 chunks away from the river source.
|
// is chunk_pos) that is at least 2 chunks away from the river source.
|
||||||
if let Some((_, dist, _, (river_t, _, downhill_river_chunk))) = dist {
|
if let Some((_, dist, river_width, (river_t, (river_pos, _), downhill_river_chunk))) = dist {
|
||||||
let max_distance = if !river.is_river() {
|
let max_distance = if !river.is_river() {
|
||||||
/*(*/
|
/*(*/
|
||||||
TerrainChunkSize::RECT_SIZE.x as f64 /* * (1.0 - (2.0f64.sqrt() / 2.0))) + 4.0*/ - lake_width * 0.5
|
TerrainChunkSize::RECT_SIZE.x as f64 /* * (1.0 - (2.0f64.sqrt() / 2.0))) + 4.0*/ - lake_width * 0.5
|
||||||
@ -371,7 +548,18 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
TerrainChunkSize::RECT_SIZE.x as f64
|
TerrainChunkSize::RECT_SIZE.x as f64
|
||||||
};
|
};
|
||||||
let scale_factor = max_distance;
|
let scale_factor = max_distance;
|
||||||
let river_dist = dist.y;
|
let river_dist = if kind.is_river() {
|
||||||
|
// dist.y
|
||||||
|
((river_pos - wposf).magnitude() - river_width * 0.5).max(0.0)
|
||||||
|
} else {
|
||||||
|
let water_chunk = river_chunk_idx.map(|e| e as f64);
|
||||||
|
let water_aabr = Aabr {
|
||||||
|
min: water_chunk * neighbor_coef,
|
||||||
|
max: (water_chunk + 1.0) * neighbor_coef,
|
||||||
|
};
|
||||||
|
/*water_aabr.distance_to_point(wposf)*/
|
||||||
|
(river_pos - wposf).magnitude() / (TerrainChunkSize::RECT_SIZE.x as f64 * 0.1)
|
||||||
|
};
|
||||||
|
|
||||||
if !(dist.x == 0.0 && river_dist < scale_factor) {
|
if !(dist.x == 0.0 && river_dist < scale_factor) {
|
||||||
return;
|
return;
|
||||||
@ -397,6 +585,13 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
overlap_count += 1.0 - river_scale;
|
overlap_count += 1.0 - river_scale;
|
||||||
river_count += 1.0;
|
river_count += 1.0;
|
||||||
river_distance_product *= river_scale;
|
river_distance_product *= river_scale;
|
||||||
|
max_dip = max_dip.max(-river_alt_diff + if let RiverKind::River { cross_section } = kind {
|
||||||
|
let river_depth = river_width as f32 * 0.5;
|
||||||
|
|
||||||
|
(cross_section.y * river_depth).max(0.0) + 1.5
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {}
|
None => {}
|
||||||
@ -418,12 +613,12 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let alt_for_river = alt
|
let alt_for_river = alt;
|
||||||
+ if overlap_count == 0.0 {
|
// + if overlap_count == 0.0 {
|
||||||
0.0
|
// 0.0
|
||||||
} else {
|
// } else {
|
||||||
river_overlap_distance_product / overlap_count
|
// river_overlap_distance_product / overlap_count
|
||||||
} as f32;
|
// } as f32;
|
||||||
|
|
||||||
let riverless_alt_delta = (sim.gen_ctx.small_nz.get(
|
let riverless_alt_delta = (sim.gen_ctx.small_nz.get(
|
||||||
(wposf_turb.div(200.0 * (32.0 / TerrainChunkSize::RECT_SIZE.x as f64))).into_array(),
|
(wposf_turb.div(200.0 * (32.0 / TerrainChunkSize::RECT_SIZE.x as f64))).into_array(),
|
||||||
@ -441,21 +636,29 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
.abs()
|
.abs()
|
||||||
.mul(3.0);
|
.mul(3.0);
|
||||||
|
|
||||||
let downhill = sim_chunk.downhill;
|
// Cliffs
|
||||||
let downhill_pos = downhill.and_then(|downhill_pos| sim.get(downhill_pos));
|
let cliff_factor = (alt
|
||||||
debug_assert!(sim_chunk.water_alt >= CONFIG.sea_level);
|
+ self.sim.gen_ctx.hill_nz.get(wposf.div(64.0).into_array()) as f32 * 8.0
|
||||||
|
+ self.sim.gen_ctx.hill_nz.get(wposf.div(350.0).into_array()) as f32 * 128.0)
|
||||||
let downhill_water_alt = downhill_pos
|
.rem_euclid(200.0)
|
||||||
.map(|downhill_chunk| {
|
/ 64.0
|
||||||
downhill_chunk
|
- 1.0;
|
||||||
.water_alt
|
let cliff_scale =
|
||||||
.min(sim_chunk.water_alt)
|
((self.sim.gen_ctx.hill_nz.get(wposf.div(128.0).into_array()) as f32 * 1.5 + 0.75)
|
||||||
.max(sim_chunk.alt.min(sim_chunk.water_alt))
|
+ self.sim.gen_ctx.hill_nz.get(wposf.div(48.0).into_array()) as f32 * 0.1)
|
||||||
})
|
.clamped(0.0, 1.0)
|
||||||
.unwrap_or(CONFIG.sea_level);
|
.powf(2.0);
|
||||||
|
let cliff_height = sim.get_interpolated(wpos, |chunk| chunk.cliff_height)? * cliff_scale;
|
||||||
|
let cliff = if cliff_factor < 0.0 {
|
||||||
|
cliff_factor.abs().powf(1.5)
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
} * (1.0 - near_water * 3.0).max(0.0).powi(2);
|
||||||
|
let cliff_offset = cliff * cliff_height;
|
||||||
|
let riverless_alt_delta = riverless_alt_delta + (cliff - 0.5) * cliff_height;
|
||||||
|
|
||||||
let river_gouge = 0.5;
|
let river_gouge = 0.5;
|
||||||
let (_in_water, water_dist, alt_, water_level, _riverless_alt, warp_factor) = if let Some(
|
let (_in_water, water_dist, alt_, old_water_level, _riverless_alt, warp_factor) = if let Some(
|
||||||
(max_border_river_pos, river_chunk, max_border_river, max_border_river_dist),
|
(max_border_river_pos, river_chunk, max_border_river, max_border_river_dist),
|
||||||
) =
|
) =
|
||||||
max_river
|
max_river
|
||||||
@ -464,264 +667,248 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
//
|
//
|
||||||
// If we are <= water_alt, we are in the lake; otherwise, we are flowing into
|
// If we are <= water_alt, we are in the lake; otherwise, we are flowing into
|
||||||
// it.
|
// it.
|
||||||
let (in_water, water_dist, new_alt, new_water_alt, riverless_alt, warp_factor) =
|
match max_border_river.river_kind {
|
||||||
max_border_river
|
Some(RiverKind::River { cross_section }) => 'block: {
|
||||||
.river_kind
|
if max_border_river_dist.map(|(_, dist, _, _)| dist)
|
||||||
.and_then(|river_kind| {
|
!= Some(Vec2::zero())
|
||||||
match river_kind {
|
{
|
||||||
RiverKind::River { cross_section } => {
|
let (_, _, river_width, (_, (river_pos, _), _)) =
|
||||||
if max_border_river_dist.map(|(_, dist, _, _)| dist)
|
max_border_river_dist.unwrap();
|
||||||
!= Some(Vec2::zero())
|
let river_dist = wposf.distance(river_pos);
|
||||||
{
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let (
|
|
||||||
_,
|
|
||||||
_,
|
|
||||||
river_width,
|
|
||||||
(river_t, (river_pos, _), downhill_river_chunk),
|
|
||||||
) = max_border_river_dist.unwrap();
|
|
||||||
let river_alt = Lerp::lerp(
|
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
|
||||||
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
|
||||||
river_t as f32,
|
|
||||||
);
|
|
||||||
let new_alt = river_alt - river_gouge;
|
|
||||||
let river_dist = wposf.distance(river_pos);
|
|
||||||
let river_height_factor = river_dist / (river_width * 0.5);
|
|
||||||
|
|
||||||
let valley_alt = Lerp::lerp(
|
// FIXME: Make water altitude accurate.
|
||||||
new_alt - cross_section.y.max(1.0),
|
break 'block (
|
||||||
new_alt - 1.0,
|
river_scale_factor <= 1.0,
|
||||||
(river_height_factor * river_height_factor) as f32,
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
);
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
|
downhill_water_alt,
|
||||||
|
alt, //alt_for_river,
|
||||||
|
river_scale_factor as f32,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let (
|
||||||
|
_,
|
||||||
|
_,
|
||||||
|
river_width,
|
||||||
|
(river_t, (river_pos, _), downhill_river_chunk),
|
||||||
|
) = max_border_river_dist.unwrap();
|
||||||
|
let river_alt = Lerp::lerp(
|
||||||
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
|
downhill_river_chunk.alt.max(downhill_river_chunk.water_alt),
|
||||||
|
river_t as f32,
|
||||||
|
);
|
||||||
|
let new_alt = river_alt - river_gouge;
|
||||||
|
let river_dist = wposf.distance(river_pos);
|
||||||
|
let river_height_factor = river_dist / (river_width * 0.5);
|
||||||
|
|
||||||
Some((
|
// This is not a good way to determine river depth, but we do it
|
||||||
true,
|
// anyway. TODO: Make the erosion
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
// sim output better river depths through `cross_section`.
|
||||||
valley_alt,
|
let river_depth = river_width as f32 * 0.5;
|
||||||
new_alt,
|
|
||||||
alt, //river_alt + cross_section.y.max(1.0),
|
|
||||||
0.0,
|
|
||||||
))
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
max_border_river
|
|
||||||
.river_kind
|
|
||||||
.map(|river_kind| {
|
|
||||||
match river_kind {
|
|
||||||
RiverKind::Ocean => {
|
|
||||||
let (
|
|
||||||
_,
|
|
||||||
dist,
|
|
||||||
river_width,
|
|
||||||
(river_t, (river_pos, _), downhill_river_chunk),
|
|
||||||
) = if let Some(dist) = max_border_river_dist {
|
|
||||||
dist
|
|
||||||
} else {
|
|
||||||
error!(
|
|
||||||
?max_border_river,
|
|
||||||
?chunk_pos,
|
|
||||||
?max_border_river_pos,
|
|
||||||
"downhill error details"
|
|
||||||
);
|
|
||||||
panic!(
|
|
||||||
"Oceans should definitely have a downhill! \
|
|
||||||
...Right?"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
let lake_water_alt = Lerp::lerp(
|
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
|
||||||
downhill_river_chunk
|
|
||||||
.alt
|
|
||||||
.max(downhill_river_chunk.water_alt),
|
|
||||||
river_t as f32,
|
|
||||||
);
|
|
||||||
|
|
||||||
if dist == Vec2::zero() {
|
let valley_alt = Lerp::lerp(
|
||||||
let river_dist = wposf.distance(river_pos);
|
new_alt - (cross_section.y * river_depth).max(1.0),
|
||||||
let _river_height_factor =
|
new_alt - 1.0,
|
||||||
river_dist / (river_width * 0.5);
|
(river_height_factor * river_height_factor) as f32,
|
||||||
return (
|
);
|
||||||
true,
|
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
|
||||||
alt_for_river
|
|
||||||
.min(lake_water_alt - 1.0 - river_gouge),
|
|
||||||
lake_water_alt - river_gouge,
|
|
||||||
alt_for_river.max(lake_water_alt),
|
|
||||||
0.0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
(
|
(
|
||||||
river_scale_factor <= 1.0,
|
true,
|
||||||
Some(
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
(wposf.distance(river_pos) - river_width * 0.5)
|
alt_for_river - max_dip,//valley_alt.min(alt),
|
||||||
as f32,
|
new_alt.max(valley_alt.min(alt) + 1.0),
|
||||||
),
|
alt, //river_alt + cross_section.y.max(1.0),
|
||||||
alt_for_river,
|
river_scale_factor as f32,//0.0,
|
||||||
downhill_water_alt,
|
)
|
||||||
alt_for_river,
|
},
|
||||||
river_scale_factor as f32,
|
Some(RiverKind::Ocean) => 'block: {
|
||||||
)
|
let (
|
||||||
},
|
_,
|
||||||
RiverKind::Lake { .. } => {
|
dist,
|
||||||
let lake_dist = (max_border_river_pos.map(|e| e as f64)
|
river_width,
|
||||||
* neighbor_coef)
|
(river_t, (river_pos, _), downhill_river_chunk),
|
||||||
.distance(wposf);
|
) = if let Some(dist) = max_border_river_dist {
|
||||||
let downhill_river_chunk = max_border_river_pos;
|
dist
|
||||||
let lake_id_dist = downhill_river_chunk - chunk_pos;
|
} else {
|
||||||
let in_bounds = lake_id_dist.x >= -1
|
error!(
|
||||||
&& lake_id_dist.y >= -1
|
?max_border_river,
|
||||||
&& lake_id_dist.x <= 1
|
?chunk_pos,
|
||||||
&& lake_id_dist.y <= 1;
|
?max_border_river_pos,
|
||||||
let in_bounds = in_bounds
|
"downhill error details"
|
||||||
&& (lake_id_dist.x >= 0 && lake_id_dist.y >= 0);
|
);
|
||||||
let (_, dist, _, (river_t, _, downhill_river_chunk)) =
|
panic!(
|
||||||
if let Some(dist) = max_border_river_dist {
|
"Oceans should definitely have a downhill! \
|
||||||
dist
|
...Right?"
|
||||||
} else if lake_dist
|
);
|
||||||
<= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
};
|
||||||
|| in_bounds
|
let lake_water_alt = Lerp::lerp(
|
||||||
{
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
let gouge_factor = 0.0;
|
downhill_river_chunk
|
||||||
return (
|
.alt
|
||||||
in_bounds
|
.max(downhill_river_chunk.water_alt),
|
||||||
|| downhill_water_alt
|
river_t as f32,
|
||||||
.max(river_chunk.water_alt)
|
) + 1.0;
|
||||||
> alt_for_river,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river,
|
|
||||||
(downhill_water_alt.max(river_chunk.water_alt)
|
|
||||||
- river_gouge),
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32
|
|
||||||
* (1.0 - gouge_factor),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
false,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river,
|
|
||||||
downhill_water_alt,
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
let lake_dist = dist.y;
|
if dist == Vec2::zero() {
|
||||||
let lake_water_alt = Lerp::lerp(
|
let river_dist = wposf.distance(river_pos);
|
||||||
river_chunk.alt.max(river_chunk.water_alt),
|
let _river_height_factor =
|
||||||
downhill_river_chunk
|
river_dist / (river_width * 0.5);
|
||||||
.alt
|
break 'block (
|
||||||
.max(downhill_river_chunk.water_alt),
|
true,
|
||||||
river_t as f32,
|
Some((river_dist - river_width * 0.5) as f32),
|
||||||
);
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
if dist == Vec2::zero() {
|
// .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
return (
|
lake_water_alt,
|
||||||
true,
|
alt, //alt_for_river.max(lake_water_alt),
|
||||||
Some(lake_dist as f32),
|
0.0,
|
||||||
alt_for_river
|
);
|
||||||
.min(lake_water_alt - 1.0 - river_gouge),
|
}
|
||||||
lake_water_alt - river_gouge,
|
|
||||||
alt_for_river.max(lake_water_alt),
|
|
||||||
0.0,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
|
||||||
|| in_bounds
|
|
||||||
{
|
|
||||||
let gouge_factor = if in_bounds && lake_dist <= 1.0 {
|
|
||||||
1.0
|
|
||||||
} else {
|
|
||||||
0.0
|
|
||||||
};
|
|
||||||
let in_bounds_ = lake_dist
|
|
||||||
<= TerrainChunkSize::RECT_SIZE.x as f64 * 0.5;
|
|
||||||
if gouge_factor == 1.0 {
|
|
||||||
return (
|
|
||||||
true,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt.min(lake_water_alt - 1.0 - river_gouge),
|
|
||||||
downhill_water_alt.max(lake_water_alt)
|
|
||||||
- river_gouge,
|
|
||||||
alt.max(lake_water_alt),
|
|
||||||
0.0,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
true,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river,
|
|
||||||
if in_bounds_ {
|
|
||||||
downhill_water_alt.max(lake_water_alt)
|
|
||||||
} else {
|
|
||||||
downhill_water_alt
|
|
||||||
} - river_gouge,
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32
|
|
||||||
* (1.0 - gouge_factor),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(
|
|
||||||
river_scale_factor <= 1.0,
|
|
||||||
Some(lake_dist as f32),
|
|
||||||
alt_for_river,
|
|
||||||
downhill_water_alt,
|
|
||||||
alt_for_river,
|
|
||||||
river_scale_factor as f32,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
RiverKind::River { .. } => {
|
|
||||||
let (_, _, river_width, (_, (river_pos, _), _)) =
|
|
||||||
max_border_river_dist.unwrap();
|
|
||||||
let river_dist = wposf.distance(river_pos);
|
|
||||||
|
|
||||||
// FIXME: Make water altitude accurate.
|
(
|
||||||
(
|
river_scale_factor <= 1.0,
|
||||||
river_scale_factor <= 1.0,
|
Some(
|
||||||
Some((river_dist - river_width * 0.5) as f32),
|
(wposf.distance(river_pos) - river_width * 0.5)
|
||||||
alt_for_river,
|
as f32,
|
||||||
downhill_water_alt,
|
),
|
||||||
alt, //alt_for_river,
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
river_scale_factor as f32,
|
downhill_water_alt + 1.0,
|
||||||
)
|
alt, //alt_for_river,
|
||||||
},
|
river_scale_factor as f32,
|
||||||
}
|
)
|
||||||
})
|
},
|
||||||
.unwrap_or((
|
Some(RiverKind::Lake { .. }) => 'block: {
|
||||||
false,
|
let lake_chunk = max_border_river_pos.map(|e| e as f64);
|
||||||
None,
|
let lake_aabr = Aabr {
|
||||||
|
min: lake_chunk * neighbor_coef,
|
||||||
|
max: (lake_chunk + 1.0) * neighbor_coef,
|
||||||
|
};
|
||||||
|
let lake_dist = lake_aabr.distance_to_point(wposf);
|
||||||
|
let downhill_river_chunk = max_border_river_pos;
|
||||||
|
let lake_id_dist = downhill_river_chunk - chunk_pos;
|
||||||
|
let in_bounds = lake_id_dist.x >= -1
|
||||||
|
&& lake_id_dist.y >= -1
|
||||||
|
&& lake_id_dist.x <= 1
|
||||||
|
&& lake_id_dist.y <= 1;
|
||||||
|
let in_bounds = in_bounds
|
||||||
|
&& (lake_id_dist.x >= 0 && lake_id_dist.y >= 0);
|
||||||
|
let (_, dist, _, (river_t, _, downhill_river_chunk)) =
|
||||||
|
if let Some(dist) = max_border_river_dist {
|
||||||
|
dist
|
||||||
|
} else if lake_dist
|
||||||
|
<= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
||||||
|
|| in_bounds
|
||||||
|
{
|
||||||
|
let gouge_factor = 0.0;
|
||||||
|
break 'block (
|
||||||
|
in_bounds
|
||||||
|
|| downhill_water_alt
|
||||||
|
.max(river_chunk.water_alt)
|
||||||
|
> alt_for_river,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
|
(downhill_water_alt.max(river_chunk.water_alt)
|
||||||
|
- river_gouge),
|
||||||
alt_for_river,
|
alt_for_river,
|
||||||
|
river_scale_factor as f32
|
||||||
|
* (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
break 'block (
|
||||||
|
false,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
downhill_water_alt,
|
downhill_water_alt,
|
||||||
alt, //alt_for_river,
|
alt_for_river,
|
||||||
river_scale_factor as f32,
|
river_scale_factor as f32,
|
||||||
))
|
);
|
||||||
});
|
};
|
||||||
(
|
|
||||||
in_water,
|
let lake_dist = dist.y;
|
||||||
water_dist,
|
let lake_water_alt = Lerp::lerp(
|
||||||
new_alt,
|
river_chunk.alt.max(river_chunk.water_alt),
|
||||||
new_water_alt,
|
downhill_river_chunk
|
||||||
riverless_alt,
|
.alt
|
||||||
warp_factor,
|
.max(downhill_river_chunk.water_alt),
|
||||||
)
|
river_t as f32,
|
||||||
|
);
|
||||||
|
// if dist == Vec2::zero() {
|
||||||
|
// return (
|
||||||
|
// true,
|
||||||
|
// Some(lake_dist as f32),
|
||||||
|
// alt_for_river,
|
||||||
|
// // .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
|
// lake_water_alt - river_gouge,
|
||||||
|
// alt_for_river.max(lake_water_alt),
|
||||||
|
// 0.0,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
if lake_dist <= TerrainChunkSize::RECT_SIZE.x as f64 * 1.0
|
||||||
|
|| in_bounds
|
||||||
|
{
|
||||||
|
let gouge_factor = if in_bounds && lake_dist <= 1.0 {
|
||||||
|
1.0
|
||||||
|
} else {
|
||||||
|
0.0
|
||||||
|
};
|
||||||
|
let in_bounds_ = lake_dist
|
||||||
|
<= TerrainChunkSize::RECT_SIZE.x as f64 * 0.5;
|
||||||
|
if gouge_factor == 1.0 {
|
||||||
|
break 'block (
|
||||||
|
true,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
|
// .min(lake_water_alt - 1.0 - river_gouge),
|
||||||
|
downhill_water_alt.max(lake_water_alt)
|
||||||
|
- river_gouge,
|
||||||
|
alt.max(lake_water_alt),
|
||||||
|
0.0,// river_scale_factor as f32* (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
break 'block (
|
||||||
|
true,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
|
if in_bounds_ {
|
||||||
|
downhill_water_alt.max(lake_water_alt)
|
||||||
|
} else {
|
||||||
|
downhill_water_alt//.max(lake_water_alt)
|
||||||
|
}.max(river_chunk.water_alt) - river_gouge,
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32
|
||||||
|
* (1.0 - gouge_factor),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(
|
||||||
|
river_scale_factor <= 1.0,
|
||||||
|
Some(lake_dist as f32),
|
||||||
|
alt_for_river - max_dip,//alt_for_river.max(lake_water_alt).max(river_chunk.water_alt),
|
||||||
|
downhill_water_alt,
|
||||||
|
alt_for_river,
|
||||||
|
river_scale_factor as f32,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
None => (
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
|
downhill_water_alt,
|
||||||
|
alt, //alt_for_river,
|
||||||
|
1.0,
|
||||||
|
),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
alt_for_river,
|
alt_for_river - max_dip,//alt_for_river,
|
||||||
downhill_water_alt,
|
downhill_water_alt,
|
||||||
alt, //alt_for_river,
|
alt, //alt_for_river,
|
||||||
1.0,
|
1.0,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
// NOTE: To disable warp, uncomment this line.
|
// NOTE: To disable warp, uncomment this line.
|
||||||
// let warp_factor = 0.0;
|
let warp_factor = 0.0;
|
||||||
|
|
||||||
let riverless_alt_delta = Lerp::lerp(0.0, riverless_alt_delta, warp_factor);
|
let riverless_alt_delta = Lerp::lerp(0.0, riverless_alt_delta, warp_factor);
|
||||||
let riverless_alt = alt + riverless_alt_delta; //riverless_alt + riverless_alt_delta;
|
let riverless_alt = alt + riverless_alt_delta; //riverless_alt + riverless_alt_delta;
|
||||||
@ -982,18 +1169,17 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
.add(((marble - 0.5) / 0.5) * 0.5)
|
.add(((marble - 0.5) / 0.5) * 0.5)
|
||||||
.add(((marble_mid - 0.5) / 0.5) * 0.25)
|
.add(((marble_mid - 0.5) / 0.5) * 0.25)
|
||||||
.add(((marble_small - 0.5) / 0.5) * 0.175);
|
.add(((marble_small - 0.5) / 0.5) * 0.175);
|
||||||
let (alt, ground, sub_surface_color, snow_cover) = if snow_cover <= 0.0 && alt > water_level
|
let (alt, ground, sub_surface_color) = if snow_cover <= 0.0 {
|
||||||
{
|
|
||||||
// Allow snow cover.
|
// Allow snow cover.
|
||||||
(
|
(
|
||||||
alt + 1.0 - snow_cover.max(0.0),
|
alt + if alt > water_level { 1.0 - snow_cover.max(0.0) } else { 0.0 },
|
||||||
Rgb::lerp(snow, ground, snow_cover),
|
Rgb::lerp(snow, ground, snow_cover),
|
||||||
Lerp::lerp(sub_surface_color, ground, alt.sub(basement).mul(0.15)),
|
Lerp::lerp(sub_surface_color, ground, alt.sub(basement).mul(0.15)),
|
||||||
true,
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(alt, ground, sub_surface_color, false)
|
(alt, ground, sub_surface_color)
|
||||||
};
|
};
|
||||||
|
let snow_cover = snow_cover <= 0.0;
|
||||||
|
|
||||||
// Make river banks not have grass
|
// Make river banks not have grass
|
||||||
let ground = water_dist
|
let ground = water_dist
|
||||||
@ -1020,8 +1206,6 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
|
|||||||
5.0
|
5.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let gradient = sim.get_gradient_approx(chunk_pos);
|
|
||||||
|
|
||||||
let path = sim.get_nearest_path(wpos);
|
let path = sim.get_nearest_path(wpos);
|
||||||
let cave = sim.get_nearest_cave(wpos);
|
let cave = sim.get_nearest_cave(wpos);
|
||||||
|
|
||||||
|
@ -603,7 +603,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
let underwater = col.water_level > col.alt;
|
let underwater = col.alt < col.water_level;
|
||||||
|
|
||||||
let kind = scatter
|
let kind = scatter
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -35,6 +35,7 @@ pub fn apply_shrubs_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
|||||||
|
|
||||||
if RandomPerm::new(seed).chance(37, col.tree_density * 0.3)
|
if RandomPerm::new(seed).chance(37, col.tree_density * 0.3)
|
||||||
&& col.water_dist.map_or(true, |d| d > 8.0)
|
&& col.water_dist.map_or(true, |d| d > 8.0)
|
||||||
|
&& col.alt > col.water_level
|
||||||
&& col.spawn_rate > 0.9
|
&& col.spawn_rate > 0.9
|
||||||
&& col.path.map_or(true, |(d, _, _, _)| d > 6.0)
|
&& col.path.map_or(true, |(d, _, _, _)| d > 6.0)
|
||||||
{
|
{
|
||||||
|
@ -467,7 +467,7 @@ impl TreeConfig {
|
|||||||
trunk_len: 13.0 * scale,
|
trunk_len: 13.0 * scale,
|
||||||
trunk_radius: 1.65 * scale,
|
trunk_radius: 1.65 * scale,
|
||||||
branch_child_len: 0.75,
|
branch_child_len: 0.75,
|
||||||
branch_child_radius: 0.75,
|
branch_child_radius: 0.6,
|
||||||
branch_child_radius_lerp: true,
|
branch_child_radius_lerp: true,
|
||||||
leaf_radius: 1.5 * log_scale..2.0 * log_scale,
|
leaf_radius: 1.5 * log_scale..2.0 * log_scale,
|
||||||
leaf_radius_scaled: 0.0,
|
leaf_radius_scaled: 0.0,
|
||||||
|
@ -1563,8 +1563,10 @@ impl WorldSim {
|
|||||||
let dist = rpos.map(|e| e as f32).magnitude();
|
let dist = rpos.map(|e| e as f32).magnitude();
|
||||||
if let Some(c) = self.get_mut(cliff + rpos) {
|
if let Some(c) = self.get_mut(cliff + rpos) {
|
||||||
let warp = 1.0 / (1.0 + dist);
|
let warp = 1.0 / (1.0 + dist);
|
||||||
c.tree_density *= 1.0 - warp;
|
if !c.river.near_water() {
|
||||||
c.cliff_height = Lerp::lerp(44.0, 0.0, -1.0 + dist / 3.5);
|
c.tree_density *= 1.0 - warp;
|
||||||
|
c.cliff_height = Lerp::lerp(44.0, 0.0, -1.0 + dist / 3.5);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2219,7 +2221,9 @@ impl SimChunk {
|
|||||||
} else {
|
} else {
|
||||||
Some(
|
Some(
|
||||||
uniform_idx_as_vec2(map_size_lg, downhill_pre as usize)
|
uniform_idx_as_vec2(map_size_lg, downhill_pre as usize)
|
||||||
* TerrainChunkSize::RECT_SIZE.map(|e| e as i32),
|
* TerrainChunkSize::RECT_SIZE.map(|e| e as i32)
|
||||||
|
// + TerrainChunkSize::RECT_SIZE.map(|e| e as i32 / 2)
|
||||||
|
,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2295,10 +2299,10 @@ impl SimChunk {
|
|||||||
.min(1.0);
|
.min(1.0);
|
||||||
|
|
||||||
// Add geologically short timescale undulation to the world for various reasons
|
// Add geologically short timescale undulation to the world for various reasons
|
||||||
let alt = alt
|
let alt =
|
||||||
// Don't add undulation to rivers, mainly because this could accidentally result in rivers flowing uphill
|
// Don't add undulation to rivers, mainly because this could accidentally result in rivers flowing uphill
|
||||||
+ if river.near_water() {
|
if river.near_water() {
|
||||||
0.0
|
alt
|
||||||
} else {
|
} else {
|
||||||
// Sand dunes (formed over a short period of time, so we don't care about erosion sim)
|
// Sand dunes (formed over a short period of time, so we don't care about erosion sim)
|
||||||
let warp = Vec2::new(
|
let warp = Vec2::new(
|
||||||
@ -2323,7 +2327,12 @@ impl SimChunk {
|
|||||||
const SOIL_SCALE: f32 = 16.0;
|
const SOIL_SCALE: f32 = 16.0;
|
||||||
let soil = soil_nz * SOIL_SCALE * tree_density.sqrt() * humidity.sqrt();
|
let soil = soil_nz * SOIL_SCALE * tree_density.sqrt() * humidity.sqrt();
|
||||||
|
|
||||||
dune + soil
|
// Prevent dunes pushing the altitude underwater
|
||||||
|
if alt + dune + soil < water_alt {
|
||||||
|
alt
|
||||||
|
} else {
|
||||||
|
alt + dune + soil
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
Loading…
Reference in New Issue
Block a user