mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added rare structures, totally refactored structure spawning
This commit is contained in:
parent
29803524fd
commit
44b5473a82
BIN
assets/world/structure/natural/Witch_Hut.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/structure/natural/Witch_Hut.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/world/structure/natural/tower_ruin.vox
(Stored with Git LFS)
Normal file
BIN
assets/world/structure/natural/tower_ruin.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -31,7 +31,7 @@ float get_sun_brightness(vec3 sun_dir) {
|
|||||||
const float PERSISTENT_AMBIANCE = 0.008;
|
const float PERSISTENT_AMBIANCE = 0.008;
|
||||||
|
|
||||||
vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
vec3 get_sun_diffuse(vec3 norm, float time_of_day) {
|
||||||
const float SUN_AMBIANCE = 0.1;
|
const float SUN_AMBIANCE = 0.075;
|
||||||
|
|
||||||
vec3 sun_dir = get_sun_dir(time_of_day);
|
vec3 sun_dir = get_sun_dir(time_of_day);
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum ForestKind {
|
pub enum ForestKind {
|
||||||
Palm,
|
Palm,
|
||||||
|
Savannah,
|
||||||
Oak,
|
Oak,
|
||||||
Pine,
|
Pine,
|
||||||
SnowPine,
|
SnowPine,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
mod tree;
|
mod natural;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
column::{ColumnGen, ColumnSample},
|
column::{ColumnGen, ColumnSample},
|
||||||
@ -6,7 +6,7 @@ use crate::{
|
|||||||
World,
|
World,
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
terrain::{structure::StructureBlock, Block},
|
terrain::{structure::StructureBlock, Block, Structure},
|
||||||
vol::{ReadVol, Vox},
|
vol::{ReadVol, Vox},
|
||||||
};
|
};
|
||||||
use noise::NoiseFn;
|
use noise::NoiseFn;
|
||||||
@ -86,19 +86,34 @@ impl<'a> BlockGen<'a> {
|
|||||||
let sample = Self::sample_column(column_gen, column_cache, wpos)?;
|
let sample = Self::sample_column(column_gen, column_cache, wpos)?;
|
||||||
|
|
||||||
// Tree samples
|
// Tree samples
|
||||||
let mut tree_samples = [None, None, None, None, None, None, None, None, None];
|
let mut structure_samples = [None, None, None, None, None, None, None, None, None];
|
||||||
for i in 0..tree_samples.len() {
|
for i in 0..structure_samples.len() {
|
||||||
tree_samples[i] = Self::sample_column(
|
let st_sample = Self::sample_column(
|
||||||
column_gen,
|
column_gen,
|
||||||
column_cache,
|
column_cache,
|
||||||
Vec2::from(sample.close_trees[i].0),
|
Vec2::from(sample.close_trees[i].0),
|
||||||
);
|
);
|
||||||
|
structure_samples[i] = st_sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(ZCache {
|
let mut structures = [None, None, None, None, None, None, None, None, None];
|
||||||
sample,
|
for i in 0..structures.len() {
|
||||||
tree_samples,
|
let (st_pos, st_seed) = sample.close_trees[i];
|
||||||
})
|
let st_info = natural::structure_gen(
|
||||||
|
column_gen,
|
||||||
|
column_cache,
|
||||||
|
i,
|
||||||
|
st_pos,
|
||||||
|
st_seed,
|
||||||
|
&structure_samples,
|
||||||
|
);
|
||||||
|
|
||||||
|
if let (Some(st_info), Some(st_sample)) = (st_info, structure_samples[i].clone()) {
|
||||||
|
structures[i] = Some((st_info, st_sample));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(ZCache { sample, structures })
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
@ -128,9 +143,8 @@ impl<'a> BlockGen<'a> {
|
|||||||
..
|
..
|
||||||
} = &z_cache?.sample;
|
} = &z_cache?.sample;
|
||||||
|
|
||||||
let tree_samples = &z_cache?.tree_samples;
|
let structures = &z_cache?.structures;
|
||||||
|
|
||||||
let wpos2d = Vec2::from(wpos);
|
|
||||||
let wposf = wpos.map(|e| e as f64);
|
let wposf = wpos.map(|e| e as f64);
|
||||||
|
|
||||||
let (definitely_underground, height, water_height) =
|
let (definitely_underground, height, water_height) =
|
||||||
@ -193,7 +207,7 @@ impl<'a> BlockGen<'a> {
|
|||||||
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
// let warm_stone = Block::new(1, Rgb::new(165, 165, 130));
|
||||||
let water = Block::new(1, Rgb::new(100, 150, 255));
|
let water = Block::new(1, Rgb::new(100, 150, 255));
|
||||||
|
|
||||||
let grass_depth = 2.0;
|
let grass_depth = 1.5 + 2.0 * chaos;
|
||||||
let block = if (wposf.z as f32) < height - grass_depth {
|
let block = if (wposf.z as f32) < height - grass_depth {
|
||||||
let col = Lerp::lerp(
|
let col = Lerp::lerp(
|
||||||
sub_surface_color.map(|e| (e * 255.0) as u8),
|
sub_surface_color.map(|e| (e * 255.0) as u8),
|
||||||
@ -307,55 +321,32 @@ impl<'a> BlockGen<'a> {
|
|||||||
let block = if definitely_underground {
|
let block = if definitely_underground {
|
||||||
block.unwrap_or(Block::empty())
|
block.unwrap_or(Block::empty())
|
||||||
} else {
|
} else {
|
||||||
match block {
|
block
|
||||||
Some(block) => block,
|
.or_else(|| {
|
||||||
None => (&close_trees).iter().enumerate().fold(
|
structures.iter().find_map(|st| {
|
||||||
air,
|
let (st, st_sample) = st.as_ref()?;
|
||||||
|block, (tree_idx, (tree_pos, tree_seed))| {
|
|
||||||
if !block.is_empty() {
|
|
||||||
block
|
|
||||||
} else {
|
|
||||||
match &tree_samples[tree_idx] {
|
|
||||||
Some(tree_sample)
|
|
||||||
if wpos2d.distance_squared(*tree_pos) < 28 * 28
|
|
||||||
&& tree_sample.tree_density
|
|
||||||
> 0.5 + (*tree_seed as f32 / 1000.0).fract() * 0.2
|
|
||||||
&& tree_sample.alt > tree_sample.water_level
|
|
||||||
&& tree_sample.spawn_rate > 0.5 =>
|
|
||||||
{
|
|
||||||
let cliff_height = Self::get_cliff_height(
|
|
||||||
column_gen,
|
|
||||||
column_cache,
|
|
||||||
tree_pos.map(|e| e as f32),
|
|
||||||
&tree_sample.close_cliffs,
|
|
||||||
cliff_hill,
|
|
||||||
);
|
|
||||||
let height = tree_sample.alt.max(cliff_height);
|
|
||||||
let tree_pos3d =
|
|
||||||
Vec3::new(tree_pos.x, tree_pos.y, height as i32);
|
|
||||||
let rpos = wpos - tree_pos3d;
|
|
||||||
|
|
||||||
let trees = tree::kinds(tree_sample.forest_kind); // Choose tree kind
|
let rpos = wpos - st.pos;
|
||||||
|
let block_pos = Vec3::unit_z() * rpos.z
|
||||||
|
+ Vec3::from(st.units.0) * rpos.x
|
||||||
|
+ Vec3::from(st.units.1) * rpos.y;
|
||||||
|
|
||||||
block.or(trees[*tree_seed as usize % trees.len()]
|
st.volume
|
||||||
.get((rpos * 128) / 128) // Scaling
|
.get((block_pos * 128) / 128) // Scaling
|
||||||
.map(|b| {
|
.map(|b| {
|
||||||
block_from_structure(
|
block_from_structure(
|
||||||
*b,
|
*b,
|
||||||
rpos,
|
block_pos,
|
||||||
*tree_pos,
|
st.pos.into(),
|
||||||
*tree_seed,
|
st.seed,
|
||||||
&tree_sample,
|
st_sample,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.unwrap_or(Block::empty()))
|
.ok()
|
||||||
}
|
.filter(|block| !block.is_empty())
|
||||||
_ => block,
|
})
|
||||||
}
|
})
|
||||||
}
|
.unwrap_or(Block::empty())
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(block)
|
Some(block)
|
||||||
@ -364,7 +355,14 @@ impl<'a> BlockGen<'a> {
|
|||||||
|
|
||||||
pub struct ZCache<'a> {
|
pub struct ZCache<'a> {
|
||||||
sample: ColumnSample<'a>,
|
sample: ColumnSample<'a>,
|
||||||
tree_samples: [Option<ColumnSample<'a>>; 9],
|
structures: [Option<(StructureInfo, ColumnSample<'a>)>; 9],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct StructureInfo {
|
||||||
|
pos: Vec3<i32>,
|
||||||
|
seed: u32,
|
||||||
|
units: (Vec2<i32>, Vec2<i32>),
|
||||||
|
volume: &'static Structure,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> SamplerMut for BlockGen<'a> {
|
impl<'a> SamplerMut for BlockGen<'a> {
|
||||||
|
@ -1,16 +1,65 @@
|
|||||||
use crate::all::ForestKind;
|
use super::{BlockGen, StructureInfo, ZCache};
|
||||||
|
use crate::{
|
||||||
|
all::ForestKind,
|
||||||
|
column::{ColumnGen, ColumnSample},
|
||||||
|
util::{HashCache, RandomPerm, Sampler},
|
||||||
|
};
|
||||||
use common::{assets, terrain::Structure};
|
use common::{assets, terrain::Structure};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
|
|
||||||
pub fn kinds(forest_kind: ForestKind) -> &'static [Arc<Structure>] {
|
static VOLUME_RAND: RandomPerm = RandomPerm::new(0);
|
||||||
match forest_kind {
|
static UNIT_RAND: RandomPerm = RandomPerm::new(1);
|
||||||
|
static QUIRKY_RAND: RandomPerm = RandomPerm::new(2);
|
||||||
|
|
||||||
|
pub fn structure_gen<'a>(
|
||||||
|
column_gen: &ColumnGen<'a>,
|
||||||
|
column_cache: &mut HashCache<Vec2<i32>, Option<ColumnSample<'a>>>,
|
||||||
|
idx: usize,
|
||||||
|
st_pos: Vec2<i32>,
|
||||||
|
st_seed: u32,
|
||||||
|
structure_samples: &[Option<ColumnSample>; 9],
|
||||||
|
) -> Option<StructureInfo> {
|
||||||
|
let st_sample = &structure_samples[idx].as_ref()?;
|
||||||
|
|
||||||
|
// Assuming it's a tree... figure out when it SHOULDN'T spawn
|
||||||
|
if st_sample.tree_density < 0.5 + (st_seed as f32 / 1000.0).fract() * 0.2
|
||||||
|
|| st_sample.alt < st_sample.water_level
|
||||||
|
|| st_sample.spawn_rate < 0.5
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cliff_height = BlockGen::get_cliff_height(
|
||||||
|
column_gen,
|
||||||
|
column_cache,
|
||||||
|
st_pos.map(|e| e as f32),
|
||||||
|
&st_sample.close_cliffs,
|
||||||
|
st_sample.cliff_hill,
|
||||||
|
);
|
||||||
|
|
||||||
|
let wheight = st_sample.alt.max(cliff_height);
|
||||||
|
let st_pos3d = Vec3::new(st_pos.x, st_pos.y, wheight as i32);
|
||||||
|
|
||||||
|
let volumes: &'static [_] = match st_sample.forest_kind {
|
||||||
ForestKind::Palm => &PALMS,
|
ForestKind::Palm => &PALMS,
|
||||||
|
ForestKind::Savannah => &PALMS,
|
||||||
|
ForestKind::Oak if QUIRKY_RAND.get(st_seed) % 64 == 0 => &QUIRKY,
|
||||||
|
ForestKind::Oak if QUIRKY_RAND.get(st_seed) % 16 == 0 => &OAK_STUMPS,
|
||||||
ForestKind::Oak => &OAKS,
|
ForestKind::Oak => &OAKS,
|
||||||
ForestKind::Pine => &PINES,
|
ForestKind::Pine => &PINES,
|
||||||
ForestKind::SnowPine => &SNOW_PINES,
|
ForestKind::SnowPine => &SNOW_PINES,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
const UNIT_CHOICES: [(Vec2<i32>, Vec2<i32>); 1] = [(Vec2 { x: 1, y: 0 }, Vec2 { x: 0, y: 1 })];
|
||||||
|
|
||||||
|
Some(StructureInfo {
|
||||||
|
pos: st_pos3d,
|
||||||
|
seed: st_seed,
|
||||||
|
units: UNIT_CHOICES[UNIT_RAND.get(st_seed) as usize % UNIT_CHOICES.len()],
|
||||||
|
volume: &volumes[VOLUME_RAND.get(st_seed) as usize % volumes.len()],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -43,6 +92,9 @@ lazy_static! {
|
|||||||
assets::load_map("world/tree/oak_green/9.vox", |s: Structure| s
|
assets::load_map("world/tree/oak_green/9.vox", |s: Structure| s
|
||||||
.with_center(Vec3::new(26, 26, 14)))
|
.with_center(Vec3::new(26, 26, 14)))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static ref OAK_STUMPS: Vec<Arc<Structure>> = vec![
|
||||||
// oak stumps
|
// oak stumps
|
||||||
assets::load_map("world/tree/oak_stump/1.vox", |s: Structure| s
|
assets::load_map("world/tree/oak_stump/1.vox", |s: Structure| s
|
||||||
.with_center(Vec3::new(15, 18, 10)))
|
.with_center(Vec3::new(15, 18, 10)))
|
||||||
@ -350,4 +402,10 @@ lazy_static! {
|
|||||||
.unwrap(),
|
.unwrap(),
|
||||||
];
|
];
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
pub static ref QUIRKY: Vec<Arc<Structure>> = vec![
|
||||||
|
assets::load_map("world/structure/natural/tower_ruin.vox", |s: Structure| s
|
||||||
|
.with_center(Vec3::new(11, 14, 7)))
|
||||||
|
.unwrap(),
|
||||||
|
];
|
||||||
}
|
}
|
@ -61,7 +61,7 @@ impl<'a> Sampler for ColumnGen<'a> {
|
|||||||
let riverless_alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?
|
let riverless_alt = sim.get_interpolated(wpos, |chunk| chunk.alt)?
|
||||||
+ (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32)
|
+ (sim.gen_ctx.small_nz.get((wposf.div(256.0)).into_array()) as f32)
|
||||||
.abs()
|
.abs()
|
||||||
.mul(chaos.max(0.2))
|
.mul(chaos.max(0.15))
|
||||||
.mul(64.0);
|
.mul(64.0);
|
||||||
|
|
||||||
let cliffs = sim_chunk.cliffs;
|
let cliffs = sim_chunk.cliffs;
|
||||||
@ -127,7 +127,7 @@ impl<'a> Sampler for ColumnGen<'a> {
|
|||||||
.mul(256.0),
|
.mul(256.0),
|
||||||
),
|
),
|
||||||
Rgb::lerp(tropical, sand, temp.sub(CONFIG.desert_temp).mul(32.0)),
|
Rgb::lerp(tropical, sand, temp.sub(CONFIG.desert_temp).mul(32.0)),
|
||||||
temp.sub(CONFIG.tropical_temp).mul(128.0),
|
temp.sub(CONFIG.tropical_temp).mul(64.0),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Work out if we're on a path or near a town
|
// Work out if we're on a path or near a town
|
||||||
|
@ -368,18 +368,18 @@ impl SimChunk {
|
|||||||
.into_array(),
|
.into_array(),
|
||||||
) as f32;
|
) as f32;
|
||||||
|
|
||||||
let chaos = (gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32)
|
let chaos = (gen_ctx.chaos_nz.get((wposf.div(6_000.0)).into_array()) as f32)
|
||||||
.add(1.0)
|
.add(1.0)
|
||||||
.mul(0.5)
|
.mul(0.5)
|
||||||
.mul(
|
.mul(
|
||||||
(gen_ctx.chaos_nz.get((wposf.div(6_000.0)).into_array()) as f32)
|
(gen_ctx.chaos_nz.get((wposf.div(4_000.0)).into_array()) as f32)
|
||||||
.powf(2.0)
|
.powf(2.0)
|
||||||
.add(0.5)
|
.add(0.5)
|
||||||
.min(1.0),
|
.min(1.0),
|
||||||
)
|
)
|
||||||
.mul(temp.mul(4.0).sub(1.0).neg().add(0.25).max(0.05).min(1.0))
|
.add(0.1 * hill)
|
||||||
.powf(1.5)
|
.mul(temp.mul(4.0).sub(1.0).neg().add(1.25).max(0.15).min(1.0))
|
||||||
.add(0.1 * hill);
|
.powf(1.5);
|
||||||
|
|
||||||
let chaos = chaos + chaos.mul(16.0).sin().mul(0.02);
|
let chaos = chaos + chaos.mul(16.0).sin().mul(0.02);
|
||||||
|
|
||||||
@ -397,14 +397,13 @@ impl SimChunk {
|
|||||||
+ 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)
|
||||||
* alt_main.max(0.1)
|
.mul(alt_main.max(0.1))
|
||||||
* chaos
|
.mul(1.6))
|
||||||
* 1.6)
|
.add(1.0)
|
||||||
.add(1.0)
|
.mul(0.5)
|
||||||
.mul(0.5)
|
.mul(chaos)
|
||||||
.mul(chaos)
|
.mul(CONFIG.mountain_scale);
|
||||||
.mul(CONFIG.mountain_scale);
|
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
@ -436,6 +435,8 @@ impl SimChunk {
|
|||||||
forest_kind: if temp > 0.0 {
|
forest_kind: if temp > 0.0 {
|
||||||
if temp > CONFIG.desert_temp {
|
if temp > CONFIG.desert_temp {
|
||||||
ForestKind::Palm
|
ForestKind::Palm
|
||||||
|
} else if temp > CONFIG.desert_temp {
|
||||||
|
ForestKind::Savannah
|
||||||
} else {
|
} else {
|
||||||
ForestKind::Oak
|
ForestKind::Oak
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ pub mod structure;
|
|||||||
// Reexports
|
// Reexports
|
||||||
pub use self::{
|
pub use self::{
|
||||||
hash_cache::HashCache,
|
hash_cache::HashCache,
|
||||||
random::RandomField,
|
random::{RandomField, RandomPerm},
|
||||||
sampler::{Sampler, SamplerMut},
|
sampler::{Sampler, SamplerMut},
|
||||||
structure::StructureGen2d,
|
structure::StructureGen2d,
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ pub struct RandomField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RandomField {
|
impl RandomField {
|
||||||
pub fn new(seed: u32) -> Self {
|
pub const fn new(seed: u32) -> Self {
|
||||||
Self { seed }
|
Self { seed }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,3 +35,28 @@ impl Sampler for RandomField {
|
|||||||
a
|
a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RandomPerm {
|
||||||
|
seed: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RandomPerm {
|
||||||
|
pub const fn new(seed: u32) -> Self {
|
||||||
|
Self { seed }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sampler for RandomPerm {
|
||||||
|
type Index = u32;
|
||||||
|
type Sample = u32;
|
||||||
|
|
||||||
|
fn get(&self, perm: Self::Index) -> Self::Sample {
|
||||||
|
let mut a = perm;
|
||||||
|
a = (a ^ 61) ^ (a >> 16);
|
||||||
|
a = a + (a << 3);
|
||||||
|
a = a ^ (a >> 4);
|
||||||
|
a = a * 0x27d4eb2d;
|
||||||
|
a = a ^ (a >> 15);
|
||||||
|
a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user