Better humidity, better snow trees

This commit is contained in:
Joshua Barretto 2020-11-09 15:06:37 +00:00
parent 3f02aa5134
commit 71718d9c98
6 changed files with 108 additions and 29 deletions

View File

@ -34,6 +34,7 @@ make_case_elim!(
WeakRock = 0x11, // Explodable
// 0x12 <= x < 0x20 is reserved for future rocks
Grass = 0x20, // Note: *not* the same as grass sprites
Snow = 0x21,
// 0x21 <= x < 0x30 is reserved for future grasses
Earth = 0x30,
Sand = 0x31,

View File

@ -4,6 +4,6 @@ pub enum ForestKind {
Savannah,
Oak,
Pine,
SnowPine,
// SnowPine,
Mangrove,
}

View File

@ -733,7 +733,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
);
// Columns near water get a humidity boost
let humidity = Lerp::lerp(
Lerp::lerp(humidity, 1.0, 0.1),
Lerp::lerp(humidity, 1.0, 0.25),
humidity,
water_dist
.map(|water_dist| water_dist / 20.0)
@ -879,7 +879,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
humidity
.sub(CONFIG.desert_hum)
.div(CONFIG.forest_hum.sub(CONFIG.desert_hum))
.mul(1.0),
.mul(1.25),
);
// From forest to jungle humidity, we go from snow to dark grass to grass to
// tropics to sand depending on temperature.
@ -947,15 +947,17 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
.max(-humidity.sub(CONFIG.desert_hum))
.mul(16.0)
.add((marble_small - 0.5) * 0.5);
let (alt, ground, sub_surface_color) = if snow_cover <= 0.5 && alt > water_level {
let (alt, ground, sub_surface_color, snow_cover) = if snow_cover <= 0.5 && alt > water_level
{
// Allow snow cover.
(
alt + 1.0 - snow_cover.max(0.0),
Rgb::lerp(snow, ground, snow_cover),
Lerp::lerp(sub_surface_color, ground, alt.sub(basement).mul(0.15)),
true,
)
} else {
(alt, ground, sub_surface_color)
(alt, ground, sub_surface_color, false)
};
// Make river banks not have grass
@ -1024,6 +1026,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
water_dist,
path,
cave,
snow_cover,
chunk: sim_chunk,
})
@ -1052,6 +1055,7 @@ pub struct ColumnSample<'a> {
pub water_dist: Option<f32>,
pub path: Option<(f32, Vec2<f32>, Path, Vec2<f32>)>,
pub cave: Option<(f32, Vec2<f32>, Cave, Vec2<f32>)>,
pub snow_cover: bool,
pub chunk: &'a SimChunk,
}

View File

@ -59,7 +59,7 @@ pub const CONFIG: Config = Config {
desert_temp: 0.8,
desert_hum: 0.15,
forest_hum: 0.5,
jungle_hum: 0.85,
jungle_hum: 0.75,
rainfall_chunk_rate: 1.0 / (512.0 * 32.0 * 32.0),
river_roughness: 0.06125,
river_max_width: 2.0,

View File

@ -6,7 +6,7 @@ use crate::{
Canvas, CONFIG,
};
use common::{
terrain::{structure::Structure, Block},
terrain::{structure::Structure, Block, BlockKind},
vol::ReadVol,
};
use lazy_static::lazy_static;
@ -18,7 +18,7 @@ lazy_static! {
pub static ref OAK_STUMPS: Vec<Arc<Structure>> = Structure::load_group("oak_stumps");
pub static ref PINES: Vec<Arc<Structure>> = Structure::load_group("pines");
pub static ref PALMS: Vec<Arc<Structure>> = Structure::load_group("palms");
pub static ref SNOW_PINES: Vec<Arc<Structure>> = Structure::load_group("snow_pines");
// pub static ref SNOW_PINES: Vec<Arc<Structure>> = Structure::load_group("snow_pines");
pub static ref ACACIAS: Vec<Arc<Structure>> = Structure::load_group("acacias");
pub static ref FRUIT_TREES: Vec<Arc<Structure>> = Structure::load_group("fruit_trees");
pub static ref BIRCHES: Vec<Arc<Structure>> = Structure::load_group("birch");
@ -77,7 +77,7 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
ForestKind::Oak if QUIRKY_RAND.get(seed) % 14 == 7 => &BIRCHES,
ForestKind::Oak => &OAKS,
ForestKind::Pine => &PINES,
ForestKind::SnowPine => &SNOW_PINES,
// ForestKind::SnowPine => &SNOW_PINES,
ForestKind::Mangrove => &MANGROVE_TREES,
}
};
@ -96,7 +96,8 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
};
let bounds = tree.model.get_bounds();
for z in bounds.min.z..bounds.max.z {
let mut is_top = true;
for z in (bounds.min.z..bounds.max.z).rev() {
let wpos = Vec3::new(wpos2d.x, wpos2d.y, tree.pos.z + z);
let model_pos = Vec3::from(
(wpos - tree.pos)
@ -121,7 +122,19 @@ pub fn apply_trees_to(canvas: &mut Canvas) {
col,
Block::air,
)
.map(|block| canvas.set(wpos, block));
.map(|block| {
if is_top && col.snow_cover && block.kind() == BlockKind::Leaves {
canvas.set(
wpos + Vec3::unit_z(),
Block::new(BlockKind::Snow, Rgb::new(210, 210, 255)),
);
}
canvas.set(wpos, block);
is_top = false;
})
.unwrap_or_else(|| {
is_top = true;
});
}
}
});

View File

@ -2056,11 +2056,6 @@ impl SimChunk {
// Even less granular--if this matters we can make the sign affect the quantity slightly.
let abs_lat_uniform = latitude_uniform.abs(); */
// Take the weighted average of our randomly generated base humidity, and the
// calculated water flux over this point in order to compute humidity.
const HUMID_WEIGHTS: [f32; 2] = [2.0, 1.0];
let humidity = cdf_irwin_hall(&HUMID_WEIGHTS, [humid_uniform, flux_uniform]);
// We also correlate temperature negatively with altitude and absolute latitude,
// using different weighting than we use for humidity.
const TEMP_WEIGHTS: [f32; 2] = [/* 1.5, */ 1.0, 2.0];
@ -2075,6 +2070,18 @@ impl SimChunk {
.sub(0.5)
.mul(2.0);
// Take the weighted average of our randomly generated base humidity, and the
// calculated water flux over this point in order to compute humidity.
const HUMID_WEIGHTS: [f32; 3] = [1.0, 1.0, 0.75];
let humidity = cdf_irwin_hall(&HUMID_WEIGHTS, [humid_uniform, flux_uniform, 1.0]);
// Moisture evaporates more in hot places
let humidity = humidity
* (1.0
- (temp - CONFIG.tropical_temp)
.max(0.0)
.div(1.0 - CONFIG.tropical_temp))
.max(0.0);
let mut alt = CONFIG.sea_level.add(alt_pre);
let basement = CONFIG.sea_level.add(basement_pre);
let water_alt = CONFIG.sea_level.add(water_alt_pre);
@ -2138,7 +2145,6 @@ impl SimChunk {
.mul(1.5)
.add(1.0)
.mul(0.5)
.mul(1.2 - chaos as f64 * 0.95)
.add(0.05)
.max(0.0)
.min(1.0);
@ -2149,14 +2155,17 @@ impl SimChunk {
1.0
} else {
// Weighted logit sum.
logistic_cdf(logit(humidity as f64) + 0.5 * logit(tree_density))
logistic_cdf(logit(tree_density))
}
// rescale to (-0.95, 0.95)
.sub(0.5)
.mul(0.95)
.add(0.5)
* (1.0 - temp as f64)
} as f32;
const MIN_TREE_HUM: f32 = 0.05;
// Tree density increases exponentially with humidity...
let tree_density = (tree_density * (humidity - MIN_TREE_HUM).max(0.0).mul(1.0 + MIN_TREE_HUM) / temp.max(0.75))
// ...but is ultimately limited by available sunlight (and our tree generation system)
.min(1.0);
// Sand dunes (formed over a short period of time)
let alt = alt
@ -2191,23 +2200,74 @@ impl SimChunk {
0.0
},
tree_density,
forest_kind: if temp > CONFIG.temperate_temp {
if temp > CONFIG.desert_temp {
if humidity > CONFIG.jungle_hum {
forest_kind: {
// Whittaker diagram
let candidates = [
// A smaller prevalence means that the range of values this tree appears in
// will shrink compared to neighbouring trees in the
// topology of the Whittaker diagram.
// Humidity, temperature, near_water, each with prevalence
(
ForestKind::Palm,
(CONFIG.desert_hum, 1.5),
(CONFIG.tropical_temp, 0.5),
(1.0, 2.0),
),
(
ForestKind::Savannah,
(CONFIG.desert_hum, 1.5),
(CONFIG.tropical_temp, 1.0),
(0.0, 1.0),
),
(
ForestKind::Oak,
(CONFIG.forest_hum, 1.5),
(CONFIG.temperate_temp, 1.5),
(0.0, 1.0),
),
(
ForestKind::Mangrove,
(CONFIG.jungle_hum, 0.5),
(CONFIG.tropical_temp, 0.5),
(0.0, 1.0),
),
(
ForestKind::Pine,
(CONFIG.desert_hum, 2.0),
(CONFIG.snow_temp, 2.5),
(0.0, 1.0),
),
];
candidates
.iter()
.min_by_key(|(_, (h, h_prev), (t, t_prev), (w, w_prev))| {
(Vec3::new(
(*h - humidity) / *h_prev,
(*t - temp) / *t_prev,
(*w - if river.near_water() { 1.0 } else { 0.0 }) / *w_prev,
)
.map(|e| e * e)
.sum()
* 10000.0) as i32
})
.map(|c| c.0)
.unwrap() // Can't fail
},
/*
if temp > CONFIG.temperate_temp {
if temp > CONFIG.tropical_temp {
if humidity > CONFIG.desert_hum && river.near_water() {
// Forests in desert temperatures with extremely high humidity
// should probably be different from palm trees, but we use them
// for now.
ForestKind::Palm
} else if humidity > CONFIG.forest_hum {
ForestKind::Palm
} else if humidity > CONFIG.desert_hum {
} else {
// Low but not desert humidity, so we should really have some other
// terrain...
ForestKind::Savannah
} else {
ForestKind::Savannah
}
} else if temp > CONFIG.tropical_temp {
} else if temp > CONFIG.forest_hum {
if humidity > CONFIG.jungle_hum {
if tree_density > 0.0 {
// println!("Mangrove: {:?}", wposf);
@ -2250,6 +2310,7 @@ impl SimChunk {
ForestKind::Pine
}
},
*/
spawn_rate: 1.0,
river,
warp_factor: 1.0,