Merge branch 'zesterer/worldgen' into 'master'

Worldgen Improvements

See merge request veloren/veloren!3378
This commit is contained in:
Joshua Barretto 2022-05-15 19:44:12 +00:00
commit eec2d67bb7
7 changed files with 103 additions and 104 deletions

View File

@ -201,7 +201,7 @@ float lights_at(vec3 wpos, vec3 wnorm, vec3 /*cam_to_frag*/view_dir, vec3 mu, ve
#ifdef FIGURE_SHADER #ifdef FIGURE_SHADER
// Non-physical hack. Subtle, but allows lanterns to glow nicely // Non-physical hack. Subtle, but allows lanterns to glow nicely
// TODO: Make lanterns use glowing cells instead // TODO: Make lanterns use glowing cells instead
ambiance += 1.0 / distance_2; ambiance += 0.1 / distance_2;
#endif #endif
directed_light += (is_direct ? mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light : vec3(0.0)) + ambiance * color; directed_light += (is_direct ? mix(LIGHT_AMBIANCE, 1.0, computed_shadow) * direct_light : vec3(0.0)) + ambiance * color;
// directed_light += (is_direct ? 1.0 : LIGHT_AMBIANCE) * max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light;// : vec3(0.0); // directed_light += (is_direct ? 1.0 : LIGHT_AMBIANCE) * max(computed_shadow, /*LIGHT_AMBIANCE*/0.0) * direct_light;// : vec3(0.0);

View File

@ -51,7 +51,7 @@ void main() {
f_norm = v_norm; f_norm = v_norm;
f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (hash(inst_pos.xyxy) * 0.35 + 0.65), 1.0); f_col = vec4(vec3(inst_col) * (1.0 / 255.0) * v_col * (hash(inst_pos.xyxy) * 0.35 + 0.65), 1.0);
if ((inst_flags & FLAG_SNOW_COVERED) > 0u) { if ((inst_flags & FLAG_SNOW_COVERED) > 0u && f_norm.z > 0.0) {
snow_cover = 1.0; snow_cover = 1.0;
} else { } else {
snow_cover = 0.0; snow_cover = 0.0;

View File

@ -58,9 +58,6 @@ impl<'a> BlockGen<'a> {
} }
pub fn get_with_z_cache(&mut self, wpos: Vec3<i32>, z_cache: Option<&ZCache>) -> Option<Block> { pub fn get_with_z_cache(&mut self, wpos: Vec3<i32>, z_cache: Option<&ZCache>) -> Option<Block> {
let BlockGen { column_gen } = self;
let world = column_gen.sim;
let z_cache = z_cache?; let z_cache = z_cache?;
let sample = &z_cache.sample; let sample = &z_cache.sample;
let &ColumnSample { let &ColumnSample {
@ -68,64 +65,23 @@ impl<'a> BlockGen<'a> {
basement, basement,
chaos, chaos,
water_level, water_level,
warp_factor,
surface_color, surface_color,
sub_surface_color, sub_surface_color,
//tree_density,
//forest_kind,
//close_structures,
marble: _,
marble_mid: _,
marble_small: _,
rock_density: _,
// temp,
// humidity,
stone_col, stone_col,
snow_cover, snow_cover,
cliff_offset, cliff_offset,
cliff_height, cliff_height,
// water_vel,
ice_depth, ice_depth,
.. ..
} = sample; } = sample;
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let (_definitely_underground, height, basement_height, water_height) =
if (wposf.z as f32) < alt - 64.0 * chaos {
// Shortcut warping
(true, alt, basement, water_level)
} else {
// Apply warping
let warp = world
.gen_ctx
.warp_nz
.get(wposf.div(24.0))
.mul((chaos - 0.1).max(0.0).min(1.0).powi(2))
.mul(16.0);
let warp = Lerp::lerp(0.0, warp, warp_factor);
let height = alt + warp;
(
false,
height,
basement + height - alt,
(if water_level <= alt {
water_level + warp
} else {
water_level
}),
)
};
// Sample blocks // Sample blocks
let water = Block::new(BlockKind::Water, Rgb::zero()); let water = Block::new(BlockKind::Water, Rgb::zero());
let grass_depth = (1.5 + 2.0 * chaos).min(alt - basement);
let grass_depth = (1.5 + 2.0 * chaos).min(height - basement_height); if (wposf.z as f32) < alt - grass_depth {
if (wposf.z as f32) < height - grass_depth { let stone_factor = (alt - grass_depth - wposf.z as f32) * 0.15;
let stone_factor = (height - grass_depth - wposf.z as f32) * 0.15;
let col = Lerp::lerp( let col = Lerp::lerp(
sub_surface_color, sub_surface_color,
stone_col.map(|e| e as f32 / 255.0), stone_col.map(|e| e as f32 / 255.0),
@ -134,12 +90,12 @@ impl<'a> BlockGen<'a> {
.map(|e| (e * 255.0) as u8); .map(|e| (e * 255.0) as u8);
if stone_factor >= 0.5 { if stone_factor >= 0.5 {
if wposf.z as f32 > height - cliff_offset.max(0.0) { if wposf.z as f32 > alt - cliff_offset.max(0.0) {
if cliff_offset.max(0.0) if cliff_offset.max(0.0)
> cliff_height > cliff_height
- (FastNoise::new(37).get(wposf / Vec3::new(6.0, 6.0, 10.0)) * 0.5 - (FastNoise::new(37).get(wposf / Vec3::new(6.0, 6.0, 10.0)) * 0.5
+ 0.5) + 0.5)
* (height - grass_depth - wposf.z as f32) * (alt - grass_depth - wposf.z as f32)
.mul(0.25) .mul(0.25)
.clamped(0.0, 8.0) .clamped(0.0, 8.0)
{ {
@ -159,12 +115,12 @@ impl<'a> BlockGen<'a> {
} else { } else {
Some(Block::new(BlockKind::Earth, col)) Some(Block::new(BlockKind::Earth, col))
} }
} else if wposf.z as i32 <= height as i32 { } else if wposf.z as i32 <= alt as i32 {
let grass_factor = (wposf.z as f32 - (height - grass_depth)) let grass_factor = (wposf.z as f32 - (alt - grass_depth))
.div(grass_depth) .div(grass_depth)
.sqrt(); .sqrt();
// Surface // Surface
Some(if water_level > height.ceil() { Some(if water_level > alt.ceil() {
Block::new( Block::new(
BlockKind::Sand, BlockKind::Sand,
sub_surface_color.map(|e| (e * 255.0) as u8), sub_surface_color.map(|e| (e * 255.0) as u8),
@ -184,11 +140,11 @@ impl<'a> BlockGen<'a> {
None None
} }
.or_else(|| { .or_else(|| {
let over_water = height < water_height; let over_water = alt < water_level;
// Water // Water
if over_water && (wposf.z as f32 - water_height).abs() < ice_depth { if over_water && (wposf.z as f32 - water_level).abs() < ice_depth {
Some(Block::new(BlockKind::Ice, CONFIG.ice_color)) Some(Block::new(BlockKind::Ice, CONFIG.ice_color))
} else if (wposf.z as f32) < water_height { } else if (wposf.z as f32) < water_level {
// Ocean // Ocean
Some(water) Some(water)
} else { } else {

View File

@ -116,7 +116,39 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
.map(|site| index.sites[*site].spawn_rules(wpos)) .map(|site| index.sites[*site].spawn_rules(wpos))
.fold(SpawnRules::default(), |a, b| a.combine(b)); .fold(SpawnRules::default(), |a, b| a.combine(b));
let gradient = sim.get_gradient_approx(chunk_pos); const SAMP_RES: i32 = 8;
let altx0 = sim.get_interpolated(wpos - Vec2::new(1, 0) * SAMP_RES, |chunk| chunk.alt);
let altx1 = sim.get_interpolated(wpos + Vec2::new(1, 0) * SAMP_RES, |chunk| chunk.alt);
let alty0 = sim.get_interpolated(wpos - Vec2::new(0, 1) * SAMP_RES, |chunk| chunk.alt);
let alty1 = sim.get_interpolated(wpos + Vec2::new(0, 1) * SAMP_RES, |chunk| chunk.alt);
let gradient =
altx0
.zip(altx1)
.zip_with(alty0.zip(alty1), |(altx0, altx1), (alty0, alty1)| {
Vec2::new(altx1 - altx0, alty1 - alty0)
.map(f32::abs)
.magnitude()
/ SAMP_RES as f32
});
let wposf3d = Vec3::new(wposf.x, wposf.y, alt as f64);
let marble_small = (sim.gen_ctx.hill_nz.get((wposf3d.div(3.0)).into_array()) as f32)
.powi(3)
.add(1.0)
.mul(0.5);
let marble_mid = (sim.gen_ctx.hill_nz.get((wposf3d.div(12.0)).into_array()) as f32)
.mul(0.75)
.add(1.0)
.mul(0.5);
//.add(marble_small.sub(0.5).mul(0.25));
let marble = (sim.gen_ctx.hill_nz.get((wposf3d.div(48.0)).into_array()) as f32)
.mul(0.75)
.add(1.0)
.mul(0.5);
let marble_mixed = marble
.add(marble_mid.sub(0.5).mul(0.5))
.add(marble_small.sub(0.5).mul(0.25));
let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * 2.0f64.sqrt()) + 6.0; let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * 2.0f64.sqrt()) + 6.0;
let neighbor_river_data = neighbor_river_data let neighbor_river_data = neighbor_river_data
@ -829,20 +861,34 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
} * (1.0 - near_water * 3.0).max(0.0).powi(2); } * (1.0 - near_water * 3.0).max(0.0).powi(2);
let cliff_offset = cliff * cliff_height; let cliff_offset = cliff * cliff_height;
let riverless_alt_delta = riverless_alt_delta + (cliff - 0.5) * cliff_height; let riverless_alt_delta = riverless_alt_delta + (cliff - 0.5) * cliff_height;
let basement_sub_alt =
sim.get_interpolated_monotone(wpos, |chunk| chunk.basement.sub(chunk.alt))?;
let warp_factor = water_dist.map_or(1.0, |d| d.max(0.0) / 64.0); let warp_factor = water_dist.map_or(1.0, |d| ((d - 0.0) / 64.0).clamped(0.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 warp_factor = warp_factor * spawn_rules.max_warp; let warp_factor = warp_factor * spawn_rules.max_warp;
let surface_rigidity = 1.0 - temp.max(0.0) * (1.0 - tree_density);
let surface_rigidity =
surface_rigidity.max(((basement_sub_alt + 3.0) / 1.5).clamped(0.0, 2.0));
let warp = ((marble_mid * 0.2 + marble * 0.8) * 2.0 - 1.0)
* 15.0
* gradient.unwrap_or(0.0).min(1.0)
* surface_rigidity
* warp_factor;
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 alt = alt + riverless_alt_delta; let alt = alt + riverless_alt_delta + warp;
let basement = let basement = alt + basement_sub_alt;
alt + sim.get_interpolated_monotone(wpos, |chunk| chunk.basement.sub(chunk.alt))?;
// Adjust this to make rock placement better // Adjust this to make rock placement better
let rock_density = rockiness; let rock_density = rockiness
+ water_dist
.filter(|wd| *wd > 2.0)
.map(|wd| (1.0 - wd / 32.0).clamped(0.0, 1.0).powf(0.5) * 10.0)
.unwrap_or(0.0);
// Columns near water have a more stable temperature and so get pushed towards // Columns near water have a more stable temperature and so get pushed towards
// the average (0) // the average (0)
@ -864,25 +910,6 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
.clamped(0.0, 1.0), .clamped(0.0, 1.0),
); );
let wposf3d = Vec3::new(wposf.x, wposf.y, alt as f64);
let marble_small = (sim.gen_ctx.hill_nz.get((wposf3d.div(3.0)).into_array()) as f32)
.powi(3)
.add(1.0)
.mul(0.5);
let marble_mid = (sim.gen_ctx.hill_nz.get((wposf3d.div(12.0)).into_array()) as f32)
.mul(0.75)
.add(1.0)
.mul(0.5);
//.add(marble_small.sub(0.5).mul(0.25));
let marble = (sim.gen_ctx.hill_nz.get((wposf3d.div(48.0)).into_array()) as f32)
.mul(0.75)
.add(1.0)
.mul(0.5);
let marble_mixed = marble
.add(marble_mid.sub(0.5).mul(0.5))
.add(marble_small.sub(0.5).mul(0.25));
// Colours // Colours
let Colors { let Colors {
cold_grass, cold_grass,
@ -1088,10 +1115,15 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
}) })
.max(-humidity.sub(CONFIG.desert_hum)) .max(-humidity.sub(CONFIG.desert_hum))
.mul(4.0) .mul(4.0)
.add(((marble - 0.5) / 0.5) * 0.5) .max(-0.25)
.add(((marble_mid - 0.5) / 0.5) * 0.25) // 'Simulate' avalanches moving snow from areas with high gradients to areas with high flux
.add(((marble_small - 0.5) / 0.5) * 0.175); .add((gradient.unwrap_or(0.0) - 0.5).max(0.0) * 0.1)
let (alt, ground, sub_surface_color) = if snow_factor <= 0.0 && alt > water_level { // .add(-flux * 0.003 * gradient.unwrap_or(0.0))
.add(((marble - 0.5) / 0.5) * 0.25)
.add(((marble_mid - 0.5) / 0.5) * 0.125)
.add(((marble_small - 0.5) / 0.5) * 0.0625);
let snow_cover = snow_factor <= 0.0;
let (alt, ground, sub_surface_color) = if snow_cover && alt > water_level {
// Allow snow cover. // Allow snow cover.
( (
alt + 1.0 - snow_factor.max(0.0), alt + 1.0 - snow_factor.max(0.0),
@ -1101,7 +1133,6 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
} else { } else {
(alt, ground, sub_surface_color) (alt, ground, sub_surface_color)
}; };
let snow_cover = snow_factor <= 0.0;
// Make river banks not have grass // Make river banks not have grass
let ground = water_dist let ground = water_dist

View File

@ -51,17 +51,17 @@ pub fn apply_rocks_to(canvas: &mut Canvas, _dynamic_rng: &mut impl Rng) {
rng.gen_range(1.0..4.0), rng.gen_range(1.0..4.0),
&mut rng, &mut rng,
))), ))),
(5..=i32::MAX, _, 10..=i32::MAX) => { (5..=i32::MAX, _, 0..=i32::MAX) => {
if col.temp > CONFIG.desert_temp - 0.1 if col.temp > CONFIG.desert_temp - 0.1
&& col.humidity < CONFIG.desert_hum + 0.1 && col.humidity < CONFIG.desert_hum + 0.1
{ {
Some(RockKind::Sandstone(VoronoiCell::generate( Some(RockKind::Sandstone(VoronoiCell::generate(
rng.gen_range(2.0..20.0 - 15.0 * col.tree_density), rng.gen_range(2.0..20.0 - 10.0 * col.tree_density),
&mut rng, &mut rng,
))) )))
} else { } else {
Some(RockKind::Rock(VoronoiCell::generate( Some(RockKind::Rock(VoronoiCell::generate(
rng.gen_range(2.0..20.0 - 15.0 * col.tree_density), rng.gen_range(2.0..20.0 - 10.0 * col.tree_density),
&mut rng, &mut rng,
))) )))
} }

View File

@ -498,9 +498,7 @@ impl World {
if rpos.is_any_negative() { if rpos.is_any_negative() {
return None; return None;
} else { } else {
rpos.map(|e| e as i16).with_z( rpos.map(|e| e as i16).with_z(col.alt as i16)
self.sim().get_alt_approx(tree.pos).unwrap_or(0.0) as i16,
)
} }
}, },
flags: lod::Flags::empty() flags: lod::Flags::empty()
@ -554,15 +552,27 @@ impl World {
.reduce_and() .reduce_and()
}) })
.filter(|(_, site)| matches!(&site.kind, SiteKind::GiantTree(_))) .filter(|(_, site)| matches!(&site.kind, SiteKind::GiantTree(_)))
.map(|(_, site)| lod::Object { .filter_map(|(_, site)| {
kind: lod::ObjectKind::GiantTree, let wpos2d = site.get_origin();
pos: { let col = ColumnGen::new(self.sim()).get((
let wpos2d = site.get_origin(); wpos2d,
(wpos2d - min_wpos) index,
.map(|e| e as i16) self.sim().calendar.as_ref(),
.with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16) ))?;
}, Some(lod::Object {
flags: lod::Flags::empty(), kind: lod::ObjectKind::GiantTree,
pos: {
(wpos2d - min_wpos)
.map(|e| e as i16)
.with_z(self.sim().get_alt_approx(wpos2d).unwrap_or(0.0) as i16)
},
flags: lod::Flags::empty()
| if col.snow_cover {
lod::Flags::SNOW_COVERED
} else {
lod::Flags::empty()
},
})
}), }),
); );

View File

@ -115,7 +115,6 @@ pub(crate) struct GenCtx {
// Small amounts of noise for simulating rough terrain. // Small amounts of noise for simulating rough terrain.
pub small_nz: BasicMulti, pub small_nz: BasicMulti,
pub rock_nz: HybridMulti, pub rock_nz: HybridMulti,
pub warp_nz: FastNoise,
pub tree_nz: BasicMulti, pub tree_nz: BasicMulti,
// TODO: unused, remove??? @zesterer // TODO: unused, remove??? @zesterer
@ -559,7 +558,6 @@ impl WorldSim {
small_nz: BasicMulti::new().set_octaves(2).set_seed(rng.gen()), small_nz: BasicMulti::new().set_octaves(2).set_seed(rng.gen()),
rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(rng.gen()), rock_nz: HybridMulti::new().set_persistence(0.3).set_seed(rng.gen()),
warp_nz: FastNoise::new(rng.gen()),
tree_nz: BasicMulti::new() tree_nz: BasicMulti::new()
.set_octaves(12) .set_octaves(12)
.set_persistence(0.75) .set_persistence(0.75)
@ -2348,6 +2346,10 @@ impl SimChunk {
const MIN_TREE_HUM: f32 = 0.15; const MIN_TREE_HUM: f32 = 0.15;
// Tree density increases exponentially with humidity... // 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)) let tree_density = (tree_density * (humidity - MIN_TREE_HUM).max(0.0).mul(1.0 + MIN_TREE_HUM) / temp.max(0.75))
// Places that are *too* wet (like marshes) also get fewer trees because the ground isn't stable enough for
// them.
//.mul((1.0 - flux * 0.05/*(humidity - 0.9).max(0.0) / 0.1*/).max(0.0))
.mul(0.25 + flux * 0.05)
// ...but is ultimately limited by available sunlight (and our tree generation system) // ...but is ultimately limited by available sunlight (and our tree generation system)
.min(1.0); .min(1.0);