mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
WIP for humidity.
This commit is contained in:
parent
2828e40ef4
commit
680b81a5e6
@ -5,4 +5,5 @@ pub enum ForestKind {
|
|||||||
Oak,
|
Oak,
|
||||||
Pine,
|
Pine,
|
||||||
SnowPine,
|
SnowPine,
|
||||||
|
Mangrove,
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ pub fn structure_gen<'a>(
|
|||||||
ForestKind::Oak => &OAKS,
|
ForestKind::Oak => &OAKS,
|
||||||
ForestKind::Pine => &PINES,
|
ForestKind::Pine => &PINES,
|
||||||
ForestKind::SnowPine => &SNOW_PINES,
|
ForestKind::SnowPine => &SNOW_PINES,
|
||||||
|
ForestKind::Mangrove => &MANGROVE_TREES,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -421,6 +422,19 @@ lazy_static! {
|
|||||||
];
|
];
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pub static ref MANGROVE_TREES: Vec<Arc<Structure>> = vec![
|
||||||
|
// oak stumps
|
||||||
|
assets::load_map("world.tree.mangrove.1", |s: Structure| s
|
||||||
|
.with_center(Vec3::new(15, 18, 10)))
|
||||||
|
.unwrap(),
|
||||||
|
assets::load_map("world.tree.mangrove.2", |s: Structure| s
|
||||||
|
.with_center(Vec3::new(15, 18, 10)))
|
||||||
|
.unwrap(),
|
||||||
|
assets::load_map("world.tree.mangrove.3", |s: Structure| s
|
||||||
|
.with_center(Vec3::new(15, 188888888, 10)))
|
||||||
|
.unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
pub static ref QUIRKY: Vec<Arc<Structure>> = vec![
|
pub static ref QUIRKY: Vec<Arc<Structure>> = vec![
|
||||||
st_asset("world.structure.natural.tower-ruin", (11, 14, 5)),
|
st_asset("world.structure.natural.tower-ruin", (11, 14, 5)),
|
||||||
st_asset("world.structure.natural.witch-hut", (10, 13, 9)),
|
st_asset("world.structure.natural.witch-hut", (10, 13, 9)),
|
||||||
@ -431,4 +445,6 @@ lazy_static! {
|
|||||||
st_asset("world.structure.natural.ribcage-large", (13, 19, 8)),
|
st_asset("world.structure.natural.ribcage-large", (13, 19, 8)),
|
||||||
st_asset("world.structure.natural.skull-large", (15, 20, 4)),
|
st_asset("world.structure.natural.skull-large", (15, 20, 4)),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,9 @@ pub struct Config {
|
|||||||
pub snow_temp: f32,
|
pub snow_temp: f32,
|
||||||
pub tropical_temp: f32,
|
pub tropical_temp: f32,
|
||||||
pub desert_temp: f32,
|
pub desert_temp: f32,
|
||||||
|
pub desert_hum: f32,
|
||||||
|
pub forest_hum: f32,
|
||||||
|
pub jungle_hum: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CONFIG: Config = Config {
|
pub const CONFIG: Config = Config {
|
||||||
@ -12,4 +15,7 @@ pub const CONFIG: Config = Config {
|
|||||||
snow_temp: -0.4,
|
snow_temp: -0.4,
|
||||||
tropical_temp: 0.25,
|
tropical_temp: 0.25,
|
||||||
desert_temp: 0.45,
|
desert_temp: 0.45,
|
||||||
|
desert_hum: 0.1,
|
||||||
|
forest_hum: 0.4,
|
||||||
|
jungle_hum: 0.7,
|
||||||
};
|
};
|
||||||
|
@ -14,10 +14,13 @@ use common::{
|
|||||||
terrain::{BiomeKind, TerrainChunkSize},
|
terrain::{BiomeKind, TerrainChunkSize},
|
||||||
vol::VolSize,
|
vol::VolSize,
|
||||||
};
|
};
|
||||||
use noise::{BasicMulti, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex};
|
use noise::{BasicMulti, Billow, HybridMulti, MultiFractal, NoiseFn, RidgedMulti, Seedable, SuperSimplex};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
use rand_chacha::ChaChaRng;
|
use rand_chacha::ChaChaRng;
|
||||||
use std::ops::{Add, Div, Mul, Neg, Sub};
|
use std::{
|
||||||
|
f32,
|
||||||
|
ops::{Add, Div, Mul, Neg, Sub},
|
||||||
|
};
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
pub const WORLD_SIZE: Vec2<usize> = Vec2 { x: 1024, y: 1024 };
|
pub const WORLD_SIZE: Vec2<usize> = Vec2 { x: 1024, y: 1024 };
|
||||||
@ -29,7 +32,10 @@ pub(crate) struct GenCtx {
|
|||||||
pub alt_nz: HybridMulti,
|
pub alt_nz: HybridMulti,
|
||||||
pub hill_nz: SuperSimplex,
|
pub hill_nz: SuperSimplex,
|
||||||
pub temp_nz: SuperSimplex,
|
pub temp_nz: SuperSimplex,
|
||||||
|
// Fresh groundwater (currently has no effect, but should influence humidity)
|
||||||
pub dry_nz: BasicMulti,
|
pub dry_nz: BasicMulti,
|
||||||
|
// Humidity noise
|
||||||
|
pub humid_nz : Billow,
|
||||||
pub small_nz: BasicMulti,
|
pub small_nz: BasicMulti,
|
||||||
pub rock_nz: HybridMulti,
|
pub rock_nz: HybridMulti,
|
||||||
pub cliff_nz: HybridMulti,
|
pub cliff_nz: HybridMulti,
|
||||||
@ -72,6 +78,7 @@ impl WorldSim {
|
|||||||
.set_seed(gen_seed()),
|
.set_seed(gen_seed()),
|
||||||
temp_nz: SuperSimplex::new().set_seed(gen_seed()),
|
temp_nz: SuperSimplex::new().set_seed(gen_seed()),
|
||||||
dry_nz: BasicMulti::new().set_seed(gen_seed()),
|
dry_nz: BasicMulti::new().set_seed(gen_seed()),
|
||||||
|
humid_nz: Billow::new().set_seed(gen_seed()),
|
||||||
small_nz: BasicMulti::new().set_octaves(2).set_seed(gen_seed()),
|
small_nz: BasicMulti::new().set_octaves(2).set_seed(gen_seed()),
|
||||||
rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()),
|
rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()),
|
||||||
cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()),
|
cliff_nz: HybridMulti::new().set_persistence(0.3).set_seed(gen_seed()),
|
||||||
@ -304,6 +311,7 @@ pub struct SimChunk {
|
|||||||
pub alt: f32,
|
pub alt: f32,
|
||||||
pub temp: f32,
|
pub temp: f32,
|
||||||
pub dryness: f32,
|
pub dryness: f32,
|
||||||
|
pub humidity: f32,
|
||||||
pub rockiness: f32,
|
pub rockiness: f32,
|
||||||
pub is_cliffs: bool,
|
pub is_cliffs: bool,
|
||||||
pub near_cliffs: bool,
|
pub near_cliffs: bool,
|
||||||
@ -345,6 +353,9 @@ impl SimChunk {
|
|||||||
|
|
||||||
let temp = gen_ctx.temp_nz.get((wposf.div(12000.0)).into_array()) as f32;
|
let temp = gen_ctx.temp_nz.get((wposf.div(12000.0)).into_array()) as f32;
|
||||||
|
|
||||||
|
// FIXME: Currently unused, but should represent fresh groundwater level.
|
||||||
|
// Should be correlated a little with humidity, somewhat negatively with altitude,
|
||||||
|
// and very negatively with difference in temperature from zero.
|
||||||
let dryness = gen_ctx.dry_nz.get(
|
let dryness = gen_ctx.dry_nz.get(
|
||||||
(wposf
|
(wposf
|
||||||
.add(Vec2::new(
|
.add(Vec2::new(
|
||||||
@ -393,8 +404,7 @@ impl SimChunk {
|
|||||||
.max(0.0)
|
.max(0.0)
|
||||||
.min(1.0);
|
.min(1.0);
|
||||||
|
|
||||||
let alt = (CONFIG.sea_level
|
let alt_pre = alt_base
|
||||||
+ alt_base
|
|
||||||
+ (0.0
|
+ (0.0
|
||||||
+ alt_main
|
+ alt_main
|
||||||
+ (gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32)
|
+ (gen_ctx.small_nz.get((wposf.div(300.0)).into_array()) as f32)
|
||||||
@ -402,9 +412,49 @@ impl SimChunk {
|
|||||||
.mul(1.6))
|
.mul(1.6))
|
||||||
.add(1.0)
|
.add(1.0)
|
||||||
.mul(0.5)
|
.mul(0.5)
|
||||||
.mul(chaos)
|
.mul(chaos);
|
||||||
.mul(CONFIG.mountain_scale))
|
|
||||||
* map_edge_factor;
|
let alt = (CONFIG.sea_level + alt_pre.mul(CONFIG.mountain_scale)) * map_edge_factor;
|
||||||
|
|
||||||
|
// 0 to 1, hopefully.
|
||||||
|
let humid_base =
|
||||||
|
(gen_ctx.humid_nz.get(wposf.div(1024.0).into_array()) as f32)
|
||||||
|
.add(1.0)
|
||||||
|
.mul(0.5)
|
||||||
|
as f32;
|
||||||
|
|
||||||
|
// Ideally, humidity is correlated negatively with altitude and slightly positively with
|
||||||
|
// dryness. For now we just do "negatively with altitude." We currently opt not to have
|
||||||
|
// it affected by temperature. Negative humidity is lower, positive humidity is higher.
|
||||||
|
//
|
||||||
|
// Because we want to start at 0, rise, and then saturate at 1, we use a cumulative logistic
|
||||||
|
// distribution, calculated as:
|
||||||
|
// 1/2 + 1/2 * tanh((x - μ) / (2s))
|
||||||
|
//
|
||||||
|
// where x is the random variable (altitude relative to sea level without mountain
|
||||||
|
// scaling), μ is the altitude where humidity should be at its midpoint (currently set to 1),
|
||||||
|
// and s is the scale parameter proportional to the standard deviation σ of the humidity
|
||||||
|
// function of altitude (s = √3/π * σ). Currently we also set σ to -1, so we get ~ 68% of
|
||||||
|
// the variation due to altitude between sea level and 2 * mountain_scale (it is negative
|
||||||
|
// to make the distribution higher when the altitude is lower).
|
||||||
|
let humid_alt_sigma = -1.0;
|
||||||
|
let humid_alt_2s = 3.0f32.sqrt().mul(f32::consts::FRAC_2_PI).mul(humid_alt_sigma);
|
||||||
|
let humid_alt_mu = 1.0;
|
||||||
|
let humid_alt = alt_pre
|
||||||
|
.sub(humid_alt_mu)
|
||||||
|
.div(humid_alt_2s)
|
||||||
|
.atanh()
|
||||||
|
.mul(0.5)
|
||||||
|
.add(0.5);
|
||||||
|
// Now we just take a (currently) unweighted average of our randomly generated base humidity
|
||||||
|
// (from scaled to be from 0 to 1) and our randomly generated "base" humidity. We can
|
||||||
|
// adjust this weighting factor as desired.
|
||||||
|
let humid_weight = 1.0;
|
||||||
|
let humid_alt_weight = 1.0;
|
||||||
|
let humidity =
|
||||||
|
humid_base.mul(humid_weight)
|
||||||
|
.add(humid_alt.mul(humid_alt_weight))
|
||||||
|
.div(humid_weight + humid_alt_weight);
|
||||||
|
|
||||||
let cliff = gen_ctx.cliff_nz.get((wposf.div(2048.0)).into_array()) as f32 + chaos * 0.2;
|
let cliff = gen_ctx.cliff_nz.get((wposf.div(2048.0)).into_array()) as f32 + chaos * 0.2;
|
||||||
|
|
||||||
@ -414,6 +464,7 @@ impl SimChunk {
|
|||||||
alt,
|
alt,
|
||||||
temp,
|
temp,
|
||||||
dryness,
|
dryness,
|
||||||
|
humidity,
|
||||||
rockiness: (gen_ctx.rock_nz.get((wposf.div(1024.0)).into_array()) as f32)
|
rockiness: (gen_ctx.rock_nz.get((wposf.div(1024.0)).into_array()) as f32)
|
||||||
.sub(0.1)
|
.sub(0.1)
|
||||||
.mul(1.3)
|
.mul(1.3)
|
||||||
@ -429,7 +480,8 @@ impl SimChunk {
|
|||||||
.mul(0.5)
|
.mul(0.5)
|
||||||
.mul(1.2 - chaos * 0.95)
|
.mul(1.2 - chaos * 0.95)
|
||||||
.add(0.05)
|
.add(0.05)
|
||||||
.mul(if alt > CONFIG.sea_level + 5.0 {
|
// No trees in the ocean (currently), no trees in true deserts.
|
||||||
|
.mul(if alt > CONFIG.sea_level + 5.0 && humidity > CONFIG.desert_hum {
|
||||||
1.0
|
1.0
|
||||||
} else {
|
} else {
|
||||||
0.0
|
0.0
|
||||||
@ -437,13 +489,46 @@ impl SimChunk {
|
|||||||
.max(0.0),
|
.max(0.0),
|
||||||
forest_kind: if temp > 0.0 {
|
forest_kind: if temp > 0.0 {
|
||||||
if temp > CONFIG.desert_temp {
|
if temp > CONFIG.desert_temp {
|
||||||
ForestKind::Palm
|
if humidity > CONFIG.jungle_hum {
|
||||||
|
// 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 {
|
||||||
|
// Low but not desert humidity, so we should really have some other
|
||||||
|
// terrain...
|
||||||
|
ForestKind::Savannah
|
||||||
|
}
|
||||||
} else if temp > CONFIG.tropical_temp {
|
} else if temp > CONFIG.tropical_temp {
|
||||||
ForestKind::Savannah
|
if humidity > CONFIG.jungle_hum {
|
||||||
|
ForestKind::Mangrove
|
||||||
|
} else if humidity > CONFIG.forest_hum {
|
||||||
|
// NOTE: Probably the wrong kind of tree for this climtae.
|
||||||
|
ForestKind::Oak
|
||||||
|
} else {
|
||||||
|
ForestKind::Savannah
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ForestKind::Oak
|
if humidity > CONFIG.jungle_hum {
|
||||||
|
// Temperate climate with jungle humidity...
|
||||||
|
// https://en.wikipedia.org/wiki/Humid_subtropical_climates are often
|
||||||
|
// densely wooded and full of water. Semitropical rainforests, basically.
|
||||||
|
// For now we just treet them like otehr rainforests.
|
||||||
|
ForestKind::Mangrove
|
||||||
|
} else if humidity > CONFIG.forest_hum {
|
||||||
|
// Moderate climate, moderate humidity.
|
||||||
|
ForestKind::Oak
|
||||||
|
} else {
|
||||||
|
// With moderate temperature and low humidity, we should probably see
|
||||||
|
// something different from savannah, but oh well...
|
||||||
|
ForestKind::Savannah
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// For now we don't take humidity into account for cold climates (but we really
|
||||||
|
// should!).
|
||||||
if temp > CONFIG.snow_temp {
|
if temp > CONFIG.snow_temp {
|
||||||
ForestKind::Pine
|
ForestKind::Pine
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user