Implement carving strategy for lake connections.

Also fix mapgen slopes and make a much more pleasing world.
This commit is contained in:
Joshua Yanovski 2019-11-22 03:55:19 +01:00
parent e01bb8a8c9
commit 72287f2041
5 changed files with 166 additions and 65 deletions

View File

@ -51,7 +51,7 @@ impl ClientInit {
let mut last_err = None;
'tries: for _ in 0..60 + 1 {
'tries: for _ in 0..960 + 1 {
// 300 Seconds
if cancel2.load(Ordering::Relaxed) {
break;

View File

@ -64,8 +64,9 @@ fn main() {
.unwrap_or((CONFIG.sea_level, CONFIG.sea_level, CONFIG.sea_level, 0.0, 0.0, None, None));
let humidity = humidity.min(1.0).max(0.0);
let temperature = temperature.min(1.0).max(-1.0) * 0.5 + 0.5;
let pos = pos * TerrainChunkSize::RECT_SIZE.map(|e| e as i32);
let downhill_pos = (downhill
.map(|downhill_pos| downhill_pos.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32))
.map(|downhill_pos| downhill_pos/*.map2(TerrainChunkSize::RECT_SIZE, |e, sz: u32| e / sz as i32)*/)
.unwrap_or(pos)
- pos)/* * scale*/
+ pos;
@ -92,12 +93,12 @@ fn main() {
let forward_vec = Vec3::new(
(downhill_pos.x - pos.x) as f64,
(downhill_pos.y - pos.y) as f64,
(downhill_alt - alt) as f64,
(downhill_alt - alt) as f64 * (CONFIG.mountain_scale as f64 / gain as f64),
);
let up_vec = Vec3::new(
(cross_pos.x - pos.x) as f64,
(cross_pos.y - pos.y) as f64,
(cross_alt - alt) as f64,
(cross_alt - alt) as f64 * (CONFIG.mountain_scale as f64 / gain as f64),
);
let surface_normal = forward_vec.cross(up_vec).normalized();
// let surface_normal = Vec3::new((alt_tl - alt_tr) as f64, 1.0, (alt_tl - alt_bl) as f64).normalized();
@ -139,23 +140,17 @@ fn main() {
0,
255,
]),
Some(RiverKind::Lake { .. }) => u32::from_le_bytes([
(((64.0 + water_alt * 191.0) + (- water_depth * 64.0)) * 1.0) as u8,
(((32.0 + water_alt * 95.0) + (- water_depth * 32.0)) * 1.0) as u8,
0,
255,
]),
Some(RiverKind::River { .. }) => u32::from_le_bytes([
64 + (alt * 191.0) as u8,
32 + (alt * 95.0) as u8,
0,
255,
]),
None => {
None if water_alt >= water_depth => {
let (r, g, b) = (
(alt * if is_temperature { temperature as f64 } else if is_shaded { alt } else { 0.0 }).sqrt(),
(if is_shaded { alt } else { alt } * if is_temperature { temperature as f64 } else if is_shaded { alt } else { 0.0 }).sqrt(),
if is_shaded { 0.2 + (alt * 0.8) } else { alt },
(alt * if is_humidity { humidity as f64 } else if is_shaded { alt } else { 0.0 }).sqrt(),
(if is_shaded { alt } else { alt } * if is_humidity { humidity as f64 } else if is_shaded { alt } else { 0.0 }).sqrt(),
);
let light = if is_shaded {
light
@ -174,7 +169,13 @@ fn main() {
(/*alt*//*alt * *//*(1.0 - humidity)*/(alt * temperature).sqrt() * 255.0) as u8,
255,
]) */
}
},
None | Some(RiverKind::Lake { .. }) => u32::from_le_bytes([
(((64.0 + water_alt * 191.0) + (- water_depth * 64.0)) * 1.0) as u8,
(((32.0 + water_alt * 95.0) + (- water_depth * 32.0)) * 1.0) as u8,
0,
255,
]),
};
}
}
@ -183,12 +184,16 @@ fn main() {
if win.is_key_down(minifb::Key::P) {
println!(
"\
Gain: {:?}\n\
Scale: {:?}\n\
Land(adjacent): (X = temp, Y = humidity): {:?}\n\
Rivers: {:?}\n\
Lakes: {:?}\n\
Oceans: {:?}\n\
Total water: {:?}\n\
Total land(adjacent): {:?}",
gain,
scale,
quads,
rivers,
lakes,

View File

@ -436,14 +436,14 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
(temp < CONFIG.snow_temp ||
downhill_alt.sub(CONFIG.sea_level) >= CONFIG.mountain_scale * 0.25)*/
is_rocky {
// sim.get_interpolated_monotone(wpos, |chunk| chunk.alt)?
sim.get_interpolated_monotone(wpos, |chunk| chunk.alt)?
// sim.get_interpolated_bilinear(wpos, |chunk| chunk.alt)?
sim.get_interpolated(wpos, |chunk| chunk.alt)?
// sim.get_interpolated(wpos, |chunk| chunk.alt)?
} else {
// sim.get_interpolated_monotone(wpos, |chunk| chunk.alt)?
sim.get_interpolated(wpos, |chunk| chunk.alt)?
sim.get_interpolated_monotone(wpos, |chunk| chunk.alt)?
// sim.get_interpolated(wpos, |chunk| chunk.alt)?
};
let basement = sim.get_interpolated/*get_interpolated_monotone*/(wpos, |chunk| chunk.basement)?;
let basement = sim./*get_interpolated*/get_interpolated_monotone(wpos, |chunk| chunk.basement)?;
// Find the average distance to each neighboring body of water.
let mut river_count = 0.0f64;

View File

@ -231,7 +231,7 @@ pub fn get_rivers(
let indirection_idx = indirection[chunk_idx];
// Find the lake we are flowing into.
let lake_idx = if indirection_idx < 0 {
// If we're a lake bottom, our own indirection is negative.
/* // If we're a lake bottom, our own indirection is negative.
let mut lake = &mut rivers[chunk_idx];
let neighbor_pass_idx = downhill_idx;
// Mass flow from this lake is treated as a weighting factor (this is currently
@ -278,7 +278,8 @@ pub fn get_rivers(
// basically a flat vector, but that might be okay from lake to other side of pass.
lake_neighbor_pass.spline_derivative += /*Vec2::new(weighted_flow.x, weighted_flow.y)*/
weighted_flow.map(|e| e as f32);
continue;
continue; */
chunk_idx
} else {
indirection_idx as usize
};
@ -295,14 +296,21 @@ pub fn get_rivers(
// Find the pass this lake is flowing into (i.e. water at the lake bottom gets
// pushed towards the point identified by pass_idx).
let neighbor_pass_idx = downhill[lake_idx];
let pass_idx = if /*downhill[lake_idx] >= 0*/true {
// This is a proper lake with a proper pass
(-indirection[lake_idx]) as usize
} else {
// This lake is actually the ocean.
lake_idx
};
let neighbor_pass_idx = downhill[pass_idx/*lake_idx*/];
// Find our own water height.
let chunk_water_alt = water_alt[chunk_idx];
if neighbor_pass_idx >= 0 {
// We may be a river. But we're not sure yet, since we still could be
// underwater. Check the lake height and see if our own water height is within ε of
// it.
let pass_idx = (-indirection[lake_idx]) as usize;
// let pass_idx = (-indirection[lake_idx]) as usize;
let lake_water_alt = water_alt[lake_idx];
if chunk_water_alt == lake_water_alt {
// Not a river.
@ -315,7 +323,8 @@ pub fn get_rivers(
// rather than downhill.
// NOTE: Safe because neighbor_pass_idx >= 0.
(
uniform_idx_as_vec2(neighbor_pass_idx as usize),
uniform_idx_as_vec2(downhill_idx),
// uniform_idx_as_vec2(neighbor_pass_idx as usize),
river_spline_derivative,
)
} else {
@ -607,6 +616,8 @@ fn erode(
log::debug!("Done draining...");
let height_scale = 1.0; // 1.0 / CONFIG.mountain_scale as f64;
let mmaxh = CONFIG.mountain_scale as f64 * height_scale;
// Minimum sediment thickness before we treat erosion as sediment based.
let sediment_thickness = 1.0;
// Since maximum uplift rate is expected to be 5.010e-4 m * y^-1, and
// 1.0 height units is 1.0 / height_scale m, whatever the
// max uplift rate is (in units / y), we can find dt by multiplying by
@ -640,12 +651,12 @@ fn erode(
// 2e-5 * dt;
// 2.244/2048*5*32/(250000/4)*10^6
// ln(tan(30/360*2*pi))-ln(tan(6/360*2*pi))*1500 = 3378
erosion_base as f64 + 2.244 / mmaxh as f64 * /*10.0*//*5.0*//*9.0*//*7.5*/5.0/*3.75*/ * max_uplift as f64;
erosion_base as f64 + 2.244 / mmaxh as f64 * /*10.0*//*5.0*//*9.0*//*7.5*//*5.0*//*2.5*/1.5/*3.75*/ * max_uplift as f64;
// 1e-5 * dt;
// (2.244*(5.010e-4)/512)/(2.244*(5.010e-4)/2500) = 4.88...
// 2.444 * 5
// Stream power erosion constant (sediment), in m^(1-2m) / year (times dt).
let k_fs = k_fb * /*1.0*//*2.0*/1.0/*4.0*/;
let k_fs = k_fb * /*1.0*//*2.0*/2.0/*4.0*/;
let ((dh, indirection, newh, area), mut max_slopes) = rayon::join(
|| {
let mut dh = downhill(h, |posi| is_ocean(posi));
@ -667,6 +678,8 @@ fn erode(
// max angle of slope depends on rock strength, which is computed from noise function.
let neighbor_coef = TerrainChunkSize::RECT_SIZE.map(|e| e as f64);
let chunk_area = neighbor_coef.x * neighbor_coef.y;
// TODO: Make more principled.
let mid_slope = (30.0 / 360.0 * 2.0 * f64::consts::PI).tan();
// Iterate in ascending height order.
let mut maxh = 0.0;
let mut nland = 0usize;
@ -699,7 +712,7 @@ fn erode(
let old_h_i = h[posi] as f64;
let old_b_i = b[posi] as f64;
let uplift_i = uplift(posi) as f64;
let k = if (old_h_i - old_b_i as f64) > 1.0e-6 {
let k = if (old_h_i - old_b_i as f64) > sediment_thickness {
// Sediment
k_fs
} else {
@ -723,8 +736,12 @@ fn erode(
if new_h_i <= wh_j {
new_h_i = wh_j;
} else {
let dz = (new_h_i - /*h_j*//*h_k*/wh_j).max(0.0) / height_scale/* * CONFIG.mountain_scale as f64*/;
let mag_slope = dz/*.abs()*/ / neighbor_distance;
nland += 1;
sumh += new_h_i;
sums += mag_slope;
}
}
// Set max_slope to this node's water height (max of receiver's water height and
@ -812,19 +829,28 @@ fn erode(
// Apply thermal erosion.
maxh = 0.0;
sumh = 0.0;
sums = 0.0;
for &posi in &*newh {
let posi = posi as usize;
let posj = dh[posi];
let old_h_i = h[posi] as f64;
let old_b_i = b[posi] as f64;
let max_slope = max_slopes[posi] as f64;
// Remember k_d for this chunk in max_slopes.
max_slopes[posi] = if (old_h_i - old_b_i as f64) > sediment_thickness {
// Sediment
kdsed
} else {
// Bedrock
kd(posi) / (max_slope / mid_slope/*.sqrt()*//*.powf(0.03125)*/)/*.sqrt()*/
};
if posj < 0 {
if posj == -1 {
panic!("Disconnected lake!");
}
// max_slopes[posi] = kd(posi);
// Egress with no outgoing flows.
// Egress with no outgoing flows.
} else {
let posj = posj as usize;
let old_h_i = h[posi] as f64;
let old_b_i = b[posi] as f64;
// Find the water height for this chunk's receiver; we only apply thermal erosion
// for chunks above water.
let wh_j = wh[posj] as f64;
@ -833,13 +859,15 @@ fn erode(
if
/* !is_lake_bottom */ /* !fake_neighbor */
wh_j < old_h_i {
let mut new_h_i = old_h_i;
let h_j = h[posj] as f64;
let mut new_h_i = old_h_i;//old_b_i;
// NOTE: Currently assuming that talus angle is the same once the substance is
// submerged in water, but actually that's probably not true.
let h_j = h[posj] as f64/*wh_j*/;
// let h_j = b[posj] as f64;
/* let indirection_idx = indirection[posi];
let is_lake_bottom = indirection_idx < 0;
let _fake_neighbor = is_lake_bottom && dxy.x.abs() > 1.0 && dxy.y.abs() > 1.0; */
// Test the slope.
let max_slope = max_slopes[posi] as f64;
// Hacky version of thermal erosion: only consider lowest neighbor, don't redistribute
// uplift to other neighbors.
let (posk, h_k) = /* neighbors(posi)
@ -879,11 +907,10 @@ fn erode(
// new_h_i = slope * neighbor_distance * height_scale /* / CONFIG.mountain_scale as f64 */ + h_j;
// sums += max_slope;
} else {
// max_slopes[posi] = 0.0;
sums += mag_slope;
// Just use the computed rate.
}
h[posi] = new_h_i as f32;
h/*b*/[posi] = new_h_i as f32;
// Make sure to update the basement as well!
b[posi] = old_b_i.min(new_h_i) as f32;
sumh += new_h_i;
@ -914,8 +941,8 @@ fn erode(
dt,
(),
h, b,
/*|posi| max_slopes[posi]*/kd,
kdsed,
|posi| max_slopes[posi]/*kd*/,
/* kdsed */-1.0,
);
log::debug!(
"Done eroding (max height: {:?}) (avg height: {:?}) (avg slope: {:?})",
@ -1327,19 +1354,69 @@ pub fn get_lakes(h: &[f32], downhill: &mut [isize]) -> (usize, Box<[i32]>, Box<[
// in the "downhill" graph, this is guaranteed never to visit a node more than
// once.
let start = newh.len();
// First, find the neighbor pass (assuming this is not the ocean).
let neighbor_pass_idx = downhill[chunk_idx];
let first_idx = if neighbor_pass_idx < 0 {
// This is the ocean.
chunk_idx
} else {
// This is a "real" lake.
let neighbor_pass_idx = neighbor_pass_idx as usize;
// Let's find our side of the pass.
let pass_idx = -indirection[chunk_idx];
// NOTE: Since only lakes are on the boundary, this should be a valid array index.
assert!(pass_idx >= 0);
let pass_idx = pass_idx as usize;
// Now, we should recompute flow paths so downhill nodes are contiguous.
// Carving strategy: reverse the path from the lake side of the pass to the
// lake bottom, and also set the lake side of the pass's downhill to its
// neighbor pass.
//
// TODO: Implement filling strategy (not just carving strategy).
let mut to_idx = neighbor_pass_idx;
let mut from_idx = pass_idx;
// NOTE: Since our side of the lake pass must be in the same basin as chunk_idx,
// and chunk_idx is the basin bottom, we must reach it before we reach an ocean
// node or other node with an invalid index.
while from_idx != chunk_idx {
// Reverse this (from, to) edge by first replacing to_idx with from_idx,
// then replacing from_idx's downhill with the old to_idx, and finally
// replacing from_idx with from_idx's old downhill.
//
// println!("Reversing (lake={:?}): to={:?}, from={:?}, dh={:?}", chunk_idx, to_idx, from_idx, downhill[from_idx]);
from_idx = mem::replace(
&mut downhill[from_idx],
mem::replace(
&mut to_idx,
// NOTE: This cast should be valid since the node is either a path on the way
// to a lake bottom, or a lake bottom with an actual pass outwards.
from_idx
) as isize,
) as usize;
}
// Remember to set the actual lake's from_idx properly!
downhill[from_idx] = to_idx as isize;
// Use our side of the pass as the initial node in the stack order.
// TODO: Verify that this stack order will not "double reach" any lake chunks.
pass_idx
};
// newh.push(chunk_idx as u32);
// New lake root
newh.push(chunk_idx as u32);
newh.push(first_idx as u32);
let mut cur = start;
while cur < newh.len() {
let node = newh[cur as usize];
for child in uphill(downhill, node as usize) {
// lake_idx is the index of our lake root.
// Check to make sure child (flowing into us) isn't a lake.
if indirection[child] >= 0
// Check to make sure child (flowing into us) is in the same lake.
if indirection[child] == chunk_idx as i32 || child == chunk_idx
// // Check to make sure child (flowing into us) isn't a lake.
// if indirection[child] >= 0 || child == chunk_idx
/* Note: equal to chunk_idx should be same */
{
assert!(h[child] >= h[node as usize]);
// assert!(h[child] >= h[node as usize]);
newh.push(child as u32);
}
}
@ -1403,14 +1480,14 @@ pub fn do_erosion(
let height_scale = 1.0; // 1.0 / CONFIG.mountain_scale as f64;
let mmaxh = CONFIG.mountain_scale as f64 * height_scale;
let dt = max_uplift as f64 / height_scale /* * CONFIG.mountain_scale as f64*/ / 5.010e-4;
let k_fb = (erosion_base as f64 + 2.244 / mmaxh as f64 * /*10.0*//*5.0*//*9.0*//*7.5*/5.0/*3.75*/ * max_uplift as f64) / dt;
let k_fb = (erosion_base as f64 + 2.244 / mmaxh as f64 * /*10.0*//*5.0*//*9.0*//*7.5*//*5.0*//*2.5*//*1.5*/4.0/*1.0*//*3.75*/ * max_uplift as f64) / dt;
let kd_bedrock =
/*1e-2*//*0.25e-2*/1e-2 * height_scale * height_scale/* / (CONFIG.mountain_scale as f64 * CONFIG.mountain_scale as f64) */
/* * k_fb / 2e-5 */;
let kdsed =
/*1.5e-2*//*1e-4*//*1.25e-2*/1.5e-2 * height_scale * height_scale/* / (CONFIG.mountain_scale as f64 * CONFIG.mountain_scale as f64) */
/* * k_fb / 2e-5 */;
let kd = |posi: usize| if is_ocean(posi) { /*0.0*/kd_bedrock } else { kd_bedrock };
let kd = |posi: usize| kd_bedrock; // if is_ocean(posi) { /*0.0*/kd_bedrock } else { kd_bedrock };
// Hillslope diffusion coefficient for sediment.
let mut is_done = bitbox![0; WORLD_SIZE.x * WORLD_SIZE.y];
for i in 0..n {

View File

@ -101,6 +101,9 @@ pub(crate) struct GenCtx {
pub fast_turb_y_nz: FastNoise,
pub town_gen: StructureGen2d,
pub river_seed: RandomField,
pub rock_strength_nz: HybridMulti_,
}
pub struct WorldSim {
@ -116,6 +119,7 @@ impl WorldSim {
pub fn generate(seed: u32) -> Self {
let mut rng = ChaChaRng::from_seed(seed_expan::rng_state(seed));
let continent_scale = 5_000.0f64/*32768.0*/.div(32.0).mul(TerrainChunkSize::RECT_SIZE.x as f64);
let rock_lacunarity = 0.5/*HybridMulti::DEFAULT_LACUNARITY*/;
let gen_ctx = GenCtx {
turb_x_nz: SuperSimplex::new().set_seed(rng.gen()),
@ -185,14 +189,12 @@ impl WorldSim {
fast_turb_y_nz: FastNoise::new(rng.gen()),
town_gen: StructureGen2d::new(rng.gen(), 2048, 1024),
};
let river_seed = RandomField::new(rng.gen());
let rock_lacunarity = 0.5/*HybridMulti::DEFAULT_LACUNARITY*/;
let rock_strength_nz = /*Fbm*/HybridMulti_/*BasicMulti*//*Fbm*/::new()
river_seed: RandomField::new(rng.gen()),
rock_strength_nz: /*Fbm*/HybridMulti_/*BasicMulti*//*Fbm*/::new()
.set_octaves(/*6*//*5*//*4*//*5*//*4*/6)
// persistence = lacunarity^(-(1.0 - fractal increment))
.set_persistence(/*0.9*/ /*2.0*//*1.5*//*HybridMulti::DEFAULT_LACUNARITY*/rock_lacunarity.powf(-(1.0 - 0.9)))
// NOTE: In paper, fractal increment is roughly 0.25.
.set_persistence(/*0.9*/ /*2.0*//*1.5*//*HybridMulti::DEFAULT_LACUNARITY*/rock_lacunarity.powf(-(1.0 - 0.25/*0.9*/)))
// 256*32/2^4
// (0.5^(-(1.0-0.9)))^4/256/32*2^4*16*32
// (0.5^(-(1.0-0.9)))^4/256/32*2^4*256*4
@ -203,7 +205,11 @@ impl WorldSim {
// .set_persistence(/*0.9*/ /*2.0*/0.67)
// .set_frequency(/*0.9*/ Fbm::DEFAULT_FREQUENCY / (2.0 * 32.0))
// .set_lacunarity(0.5)
.set_seed(rng.gen());
.set_seed(rng.gen()),
};
let river_seed = &gen_ctx.river_seed;
let rock_strength_nz = &gen_ctx.rock_strength_nz;
// NOTE: octaves should definitely fit into i32, but we should check anyway to make
// sure.
/* assert!(rock_strength_nz.persistence > 0.0);
@ -216,11 +222,11 @@ impl WorldSim {
.set_scale(1.0 / rock_strength_scale); */
let height_scale = 1.0f64; // 1.0 / CONFIG.mountain_scale as f64;
let max_erosion_per_delta_t = /*32.0*//*128.0*/128.0 * height_scale;
let max_erosion_per_delta_t = /*32.0*//*128.0*/32.0 * height_scale;
let erosion_pow_low = /*0.25*//*1.5*//*2.0*//*0.5*//*4.0*//*0.25*//*1.0*//*2.0*//*1.5*//*1.5*//*0.35*//*0.43*//*0.5*//*0.45*//*0.37*/1.002;
let erosion_pow_high = /*1.5*//*1.0*//*0.55*//*0.51*//*2.0*/1.002;
let erosion_center = /*0.45*//*0.75*//*0.75*//*0.5*//*0.75*/0.5;
let n_steps = /*100*/25/*100*//*37*/;//150;//37/*100*/;//50;//50;//37;//50;//37; // /*37*//*29*//*40*//*150*/37; //150;//200;
let n_steps = /*100*//*50*/100/*100*//*37*/;//150;//37/*100*/;//50;//50;//37;//50;//37; // /*37*//*29*//*40*//*150*/37; //150;//200;
let n_small_steps = 8;//8;//8; // 8
// fractal dimension should be between 0 and 0.9999...
@ -509,7 +515,8 @@ impl WorldSim {
1.0 / (WORLD_SIZE.x as f64 * WORLD_SIZE.y as f64).max(f64::EPSILON as f64 * 0.5);
let max_epsilon = (1.0 - 1.0 / (WORLD_SIZE.x as f64 * WORLD_SIZE.y as f64))
.min(1.0 - f64::EPSILON as f64 * 0.5);
let inv_func = /*|x: f64| x*//*exp_inverse_cdf*/logit/*hypsec_inverse_cdf*/;
// ((ln(0.6)-ln(1-0.6)) - (ln(1/(2048*2048))-ln((1-1/(2048*2048)))))/((ln(1-1/(2048*2048))-ln(1-(1-1/(2048*2048)))) - (ln(1/(2048*2048))-ln((1-1/(2048*2048)))))
let inv_func = /*|x: f64| x*/exp_inverse_cdf/*logit*//*hypsec_inverse_cdf*/;
let alt_exp_min_uniform = /*exp_inverse_cdf*//*logit*/inv_func(min_epsilon);
let alt_exp_max_uniform = /*exp_inverse_cdf*//*logit*/inv_func(max_epsilon);
@ -525,7 +532,7 @@ impl WorldSim {
/* let erosion_factor = |x: f64| logistic_cdf(logistic_base * if x <= /*erosion_center*/alt_old_center_uniform/*alt_old_center*/ { erosion_pow_low.ln() } else { erosion_pow_high.ln() } * log_odds(x))/*0.5 + (x - 0.5).signum() * ((x - 0.5).mul(2.0).abs(
).powf(erosion_pow).mul(0.5))*/; */
let erosion_factor = |x: f64| (/*if x <= /*erosion_center*/alt_old_center_uniform/*alt_old_center*/ { erosion_pow_low.ln() } else { erosion_pow_high.ln() } * */(/*exp_inverse_cdf*//*logit*/inv_func(x) - alt_exp_min_uniform) / (alt_exp_max_uniform - alt_exp_min_uniform))/*0.5 + (x - 0.5).signum() * ((x - 0.5).mul(2.0).abs(
).powf(erosion_pow).mul(0.5))*//*.powf(0.5)*//*.powf(1.5)*/.powf(2.0);
).powf(erosion_pow).mul(0.5))*/.powf(0.5)/*.powf(1.5)*//*.powf(2.0)*/;
let uplift_fn =
|posi| {
if is_ocean_fn(posi) {
@ -615,8 +622,15 @@ impl WorldSim {
} else {
(0.0, 0.0)
};
// tan(6/360*2*pi)*32 ~ 3.4
// 3.4/32*512 ~ 54
// 18/32*512 ~ 288
// tan(pi/6)*32 ~ 18
// tan(54/360*2*pi)*32
// let height = 1.0f64;
// let height = 1.0 / 7.0f64;
let bfrac = erosion_factor(0.5);
let height = (height - bfrac).abs().div(1.0 - bfrac);
let height = height
/* .mul(15.0 / 16.0)
.add(1.0 / 16.0) */
@ -638,6 +652,7 @@ impl WorldSim {
// -0.75
// -CONFIG.sea_level / CONFIG.mountain_scale
// 0.0
// 0.0
old_height(posi) // 0.0
} else {
// uplift_fn(posi)
@ -673,6 +688,7 @@ impl WorldSim {
.mul(0.045)*/)
};
old_height_uniform(posi)/*.powf(2.0)*/
// 0.0
/* // 0.0
// -/*CONFIG.sea_level / CONFIG.mountain_scale*//* 0.75 */1.0
// ((old_height(posi) - alt_old_min) as f64 / (alt_old_max - alt_old_min) as f64) as f32
@ -723,10 +739,10 @@ impl WorldSim {
} else {
indirection_idx as usize
};
// Find the pass this lake is flowing into (i.e. water at the lake bottom gets
/* // Find the pass this lake is flowing into (i.e. water at the lake bottom gets
// pushed towards the point identified by pass_idx).
let neighbor_pass_idx = dh[lake_idx];
let chunk_water_alt = if neighbor_pass_idx < 0 {
let neighbor_pass_idx = dh[lake_idx]; */
let chunk_water_alt = if /*neighbor_pass_idx*/dh[lake_idx] < 0 {
// This is either a boundary node (dh[chunk_idx] == -2, i.e. water is at sea level)
// or part of a lake that flows directly into the ocean. In the former case, water
// is at sea level so we just return 0.0. In the latter case, the lake bottom must
@ -740,12 +756,15 @@ impl WorldSim {
// figure out the initial water height (which fill_sinks will then extend to make
// sure it fills the entire basin).
// Find the height of the pass into which our lake is flowing.
let pass_height_j = alt[neighbor_pass_idx as usize];
// Find the height of "our" side of the pass (the part of it that drains into this
// chunk's lake).
let pass_idx = -indirection[lake_idx];
let pass_height_i = alt[pass_idx as usize];
let pass_idx = -indirection[lake_idx] as usize;
let pass_height_i = alt[pass_idx];
// Find the pass this lake is flowing into (i.e. water at the lake bottom gets
// pushed towards the point identified by pass_idx).
let neighbor_pass_idx = dh[pass_idx/*lake_idx*/];
// Find the height of the pass into which our lake is flowing.
let pass_height_j = alt[neighbor_pass_idx as usize];
// Find the maximum of these two heights.
let pass_height = pass_height_i.max(pass_height_j);
// Use the pass height as the initial water altitude.
@ -769,10 +788,10 @@ impl WorldSim {
} else {
indirection_idx as usize
};
// Find the pass this lake is flowing into (i.e. water at the lake bottom gets
/* // Find the pass this lake is flowing into (i.e. water at the lake bottom gets
// pushed towards the point identified by pass_idx).
let neighbor_pass_idx = dh[lake_idx];
if neighbor_pass_idx < 0 {
let neighbor_pass_idx = dh[lake_idx]; */
if /*neighbor_pass_idx*/dh[lake_idx] < 0 {
// This is either a boundary node (dh[chunk_idx] == -2, i.e. water is at sea level)
// or part of a lake that flows directly into the ocean. In the former case, water
// is at sea level so we just return 0.0. In the latter case, the lake bottom must