Added terrain scatter densities

This commit is contained in:
Joshua Barretto 2020-08-09 17:34:48 +01:00
parent 9329b4ce55
commit 6633298722
5 changed files with 96 additions and 20 deletions

View File

@ -20,6 +20,7 @@ use dot_vox::DotVoxData;
use hashbrown::HashMap;
use std::{f32, fmt::Debug, i32, marker::PhantomData, time::Duration};
use treeculler::{BVol, Frustum, AABB};
use tracing::warn;
use vek::*;
struct TerrainChunkData {
@ -142,7 +143,7 @@ fn sprite_config_for(kind: BlockKind) -> Option<SpriteConfig> {
wind_sway: 0.1,
}),
BlockKind::LargeGrass => Some(SpriteConfig {
variations: 3,
variations: 1,
wind_sway: 0.5,
}),
@ -3141,23 +3142,28 @@ impl<V: RectRasterableVol> Terrain<V> {
let dist_sqrd = Vec2::from(focus_pos).distance_squared(chunk_center);
if dist_sqrd < sprite_render_distance.powf(2.0) {
for (kind, instances) in &chunk.sprite_instances {
renderer.render_sprites(
if dist_sqrd < sprite_high_detail_distance.powf(2.0) {
&self.sprite_models[&kind][0]
} else if dist_sqrd < sprite_hid_detail_distance.powf(2.0) {
&self.sprite_models[&kind][1]
} else if dist_sqrd < sprite_mid_detail_distance.powf(2.0) {
&self.sprite_models[&kind][2]
} else if dist_sqrd < sprite_low_detail_distance.powf(2.0) {
&self.sprite_models[&kind][3]
} else {
&self.sprite_models[&kind][4]
},
globals,
&instances,
lights,
shadows,
);
if let Some(models) = self.sprite_models.get(&kind) {
renderer.render_sprites(
if dist_sqrd < sprite_high_detail_distance.powf(2.0) {
&self.sprite_models[&kind][0]
} else if dist_sqrd < sprite_hid_detail_distance.powf(2.0) {
&self.sprite_models[&kind][1]
} else if dist_sqrd < sprite_mid_detail_distance.powf(2.0) {
&self.sprite_models[&kind][2]
} else if dist_sqrd < sprite_low_detail_distance.powf(2.0) {
&self.sprite_models[&kind][3]
} else {
&self.sprite_models[&kind][4]
},
globals,
&instances,
lights,
shadows,
);
} else {
warn!("Sprite model for {:?} does not exists", kind);
}
}
}
}

View File

@ -283,6 +283,7 @@ impl<'a> BlockGen<'a> {
&& marble_small > 0.55
&& (marble * 3173.7).fract() < 0.6
&& humidity > CONFIG.desert_hum
&& false
{
let treasures = [BlockKind::Chest, BlockKind::Velorite];
@ -322,6 +323,7 @@ impl<'a> BlockGen<'a> {
} else if (wposf.z as f32) < height + 0.9
&& temp > CONFIG.desert_temp
&& (marble * 4423.5).fract() < 0.0005
&& false
{
let large_cacti = [
BlockKind::LargeCactus,

View File

@ -22,12 +22,14 @@ impl Index {
pub struct Noise {
pub cave_nz: SuperSimplex,
pub scatter_nz: SuperSimplex,
}
impl Noise {
fn new(seed: u32) -> Self {
Self {
cave_nz: SuperSimplex::new().set_seed(seed),
cave_nz: SuperSimplex::new().set_seed(seed + 0),
scatter_nz: SuperSimplex::new().set_seed(seed + 1),
}
}
}

View File

@ -1,6 +1,7 @@
use crate::{
column::ColumnSample,
util::{RandomField, Sampler},
sim::SimChunk,
Index,
};
use common::{
@ -19,6 +20,70 @@ use std::{
use vek::*;
use rand::prelude::*;
fn close(x: f32, tgt: f32, falloff: f32) -> f32 { (1.0 - (x - tgt).abs() / falloff).max(0.0).powf(0.5) }
pub fn apply_scatter_to<'a>(
wpos2d: Vec2<i32>,
mut get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
vol: &mut (impl BaseVol<Vox = Block> + RectSizedVol + ReadVol + WriteVol),
index: &Index,
chunk: &SimChunk,
) {
use BlockKind::*;
let scatter: &[(_, fn(&SimChunk) -> (f32, Option<(f32, f32)>))] = &[
// (density, Option<(wavelen, threshold)>)
(BlueFlower, |c| (close(c.temp, -0.3, 0.7).min(close(c.humidity, 0.6, 0.35)) * 0.05, Some((48.0, 0.6)))),
(PinkFlower, |c| (close(c.temp, 0.15, 0.5).min(close(c.humidity, 0.6, 0.35)) * 0.05, Some((48.0, 0.6)))),
(DeadBush, |c| (close(c.temp, 0.8, 0.3).min(close(c.humidity, 0.0, 0.4)) * 0.015, None)),
(Twigs, |c| ((c.tree_density - 0.5).max(0.0) * 0.0025, None)),
(Stones, |c| ((c.rockiness - 0.5).max(0.0) * 0.005, None)),
];
for y in 0..vol.size_xy().y as i32 {
for x in 0..vol.size_xy().x as i32 {
let offs = Vec2::new(x, y);
let wpos2d = wpos2d + offs;
// Sample terrain
let col_sample = if let Some(col_sample) = get_column(offs) {
col_sample
} else {
continue;
};
let bk = scatter
.iter()
.enumerate()
.find_map(|(i, (bk, f))| {
let (density, patch) = f(chunk);
if density <= 0.0 || patch.map(|(wavelen, threshold)| index
.noise
.scatter_nz
.get(wpos2d.map(|e| e as f64 / wavelen as f64 + i as f64 * 43.0).into_array()) < threshold as f64)
.unwrap_or(false)
|| !RandomField::new(i as u32).chance(Vec3::new(wpos2d.x, wpos2d.y, 0), density)
{
None
} else {
Some(*bk)
}
});
if let Some(bk) = bk {
let mut z = col_sample.alt as i32 - 4;
for _ in 0..8 {
if vol.get(Vec3::new(offs.x, offs.y, z)).map(|b| !b.is_solid()).unwrap_or(true) {
let _ = vol.set(Vec3::new(offs.x, offs.y, z), Block::new(bk, Rgb::broadcast(0)));
break;
}
z += 1;
}
}
}
}
}
pub fn apply_paths_to<'a>(
wpos2d: Vec2<i32>,
mut get_column: impl FnMut(Vec2<i32>) -> Option<&'a ColumnSample<'a>>,
@ -227,7 +292,7 @@ pub fn apply_caves_supplement<'a>(
let cave_roof = (cave.alt + cave_height) as i32;
// Scatter things in caves
if RandomField::new(index.seed).chance(wpos2d.into(), 0.0001)
if RandomField::new(index.seed).chance(wpos2d.into(), 0.00005)
&& cave_base < surface_z as i32 - 40
{
let entity = EntityInfo::at(Vec3::new(wpos2d.x as f32, wpos2d.y as f32, cave_base as f32))

View File

@ -176,6 +176,7 @@ impl World {
let mut rng = rand::thread_rng();
// Apply layers (paths, caves, etc.)
layer::apply_scatter_to(chunk_wpos2d, sample_get, &mut chunk, &self.index, sim_chunk);
layer::apply_paths_to(chunk_wpos2d, sample_get, &mut chunk, &self.index);
layer::apply_caves_to(chunk_wpos2d, sample_get, &mut chunk, &self.index);