mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Added staircase to giant trees
This commit is contained in:
parent
ba4e979825
commit
9d7a647153
@ -87,5 +87,5 @@ pub struct TreeAttr {
|
|||||||
pub seed: u32,
|
pub seed: u32,
|
||||||
pub scale: f32,
|
pub scale: f32,
|
||||||
pub forest_kind: ForestKind,
|
pub forest_kind: ForestKind,
|
||||||
pub lanterns: bool,
|
pub inhabited: bool,
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
|||||||
canvas.foreach_col(|canvas, wpos2d, col| {
|
canvas.foreach_col(|canvas, wpos2d, col| {
|
||||||
let trees = info.land().get_near_trees(wpos2d);
|
let trees = info.land().get_near_trees(wpos2d);
|
||||||
|
|
||||||
for TreeAttr { pos, seed, scale, forest_kind, lanterns } in trees {
|
for TreeAttr { pos, seed, scale, forest_kind, inhabited } in trees {
|
||||||
let tree = if let Some(tree) = tree_cache.entry(pos).or_insert_with(|| {
|
let tree = if let Some(tree) = tree_cache.entry(pos).or_insert_with(|| {
|
||||||
let col = ColumnGen::new(info.land()).get((pos, info.index()))?;
|
let col = ColumnGen::new(info.land()).get((pos, info.index()))?;
|
||||||
|
|
||||||
@ -127,7 +127,7 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
|||||||
ForestKind::Giant => {
|
ForestKind::Giant => {
|
||||||
break 'model TreeModel::Procedural(
|
break 'model TreeModel::Procedural(
|
||||||
ProceduralTree::generate(
|
ProceduralTree::generate(
|
||||||
TreeConfig::giant(&mut RandomPerm::new(seed), scale),
|
TreeConfig::giant(&mut RandomPerm::new(seed), scale, inhabited),
|
||||||
&mut RandomPerm::new(seed),
|
&mut RandomPerm::new(seed),
|
||||||
),
|
),
|
||||||
StructureBlock::TemperateLeaves,
|
StructureBlock::TemperateLeaves,
|
||||||
@ -184,9 +184,10 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
|||||||
TreeModel::Structure(s) => s.get(model_pos).ok().copied(),
|
TreeModel::Structure(s) => s.get(model_pos).ok().copied(),
|
||||||
TreeModel::Procedural(t, leaf_block) => Some(
|
TreeModel::Procedural(t, leaf_block) => Some(
|
||||||
match t.is_branch_or_leaves_at(model_pos.map(|e| e as f32 + 0.5)) {
|
match t.is_branch_or_leaves_at(model_pos.map(|e| e as f32 + 0.5)) {
|
||||||
(true, _) => StructureBlock::Log,
|
(_, _, true) => StructureBlock::Hollow,
|
||||||
(_, true) => *leaf_block,
|
(true, _, _) => StructureBlock::Log,
|
||||||
(_, _) => StructureBlock::None,
|
(_, true, _) => *leaf_block,
|
||||||
|
(_, _, _) => StructureBlock::None,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
} {
|
} {
|
||||||
@ -201,8 +202,8 @@ pub fn apply_trees_to(canvas: &mut Canvas, dynamic_rng: &mut impl Rng) {
|
|||||||
Block::air,
|
Block::air,
|
||||||
)
|
)
|
||||||
.map(|block| {
|
.map(|block| {
|
||||||
// Add mushrooms to the tree
|
// Add lights to the tree
|
||||||
if lanterns && last_block.is_air() && block.kind() == BlockKind::Wood && dynamic_rng.gen_range(0..48) == 0 {
|
if inhabited && last_block.is_air() && block.kind() == BlockKind::Wood && dynamic_rng.gen_range(0..256) == 0 {
|
||||||
canvas.set(wpos + Vec3::unit_z(), Block::air(SpriteKind::Lantern));
|
canvas.set(wpos + Vec3::unit_z(), Block::air(SpriteKind::Lantern));
|
||||||
// Add a snow covering to the block above under certain circumstances
|
// Add a snow covering to the block above under certain circumstances
|
||||||
} else if col.snow_cover
|
} else if col.snow_cover
|
||||||
@ -266,6 +267,8 @@ pub struct TreeConfig {
|
|||||||
pub leaf_vertical_scale: f32,
|
pub leaf_vertical_scale: f32,
|
||||||
/// How evenly spaced (vs random) sub-branches are along their parent.
|
/// How evenly spaced (vs random) sub-branches are along their parent.
|
||||||
pub proportionality: f32,
|
pub proportionality: f32,
|
||||||
|
/// Whether the tree is inhabited (adds various features and effects)
|
||||||
|
pub inhabited: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeConfig {
|
impl TreeConfig {
|
||||||
@ -286,6 +289,7 @@ impl TreeConfig {
|
|||||||
branch_len_bias: 0.0,
|
branch_len_bias: 0.0,
|
||||||
leaf_vertical_scale: 1.0,
|
leaf_vertical_scale: 1.0,
|
||||||
proportionality: 0.0,
|
proportionality: 0.0,
|
||||||
|
inhabited: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,10 +310,11 @@ impl TreeConfig {
|
|||||||
branch_len_bias: 0.75,
|
branch_len_bias: 0.75,
|
||||||
leaf_vertical_scale: 0.3,
|
leaf_vertical_scale: 0.3,
|
||||||
proportionality: 1.0,
|
proportionality: 1.0,
|
||||||
|
inhabited: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn giant(rng: &mut impl Rng, scale: f32) -> Self {
|
pub fn giant(rng: &mut impl Rng, scale: f32, inhabited: bool) -> Self {
|
||||||
let log_scale = 1.0 + scale.log2().max(0.0);
|
let log_scale = 1.0 + scale.log2().max(0.0);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -325,6 +330,7 @@ impl TreeConfig {
|
|||||||
branch_len_bias: 0.0,
|
branch_len_bias: 0.0,
|
||||||
leaf_vertical_scale: 0.6,
|
leaf_vertical_scale: 0.6,
|
||||||
proportionality: 0.0,
|
proportionality: 0.0,
|
||||||
|
inhabited,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,7 +391,7 @@ impl ProceduralTree {
|
|||||||
0.0
|
0.0
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_stairs = branch_radius > 3.0 && start.xy().distance(end.xy()) < (start.z - end.z).abs();
|
let has_stairs = config.inhabited && branch_radius > 3.0 && start.xy().distance(end.xy()) < (start.z - end.z).abs();
|
||||||
let bark_radius = if has_stairs { 8.0 } else { 0.0 };
|
let bark_radius = if has_stairs { 8.0 } else { 0.0 };
|
||||||
|
|
||||||
// The AABB that covers this branch, along with wood and leaves that eminate
|
// The AABB that covers this branch, along with wood and leaves that eminate
|
||||||
@ -478,13 +484,13 @@ impl ProceduralTree {
|
|||||||
pub fn get_bounds(&self) -> Aabb<f32> { self.branches[self.trunk_idx].aabb }
|
pub fn get_bounds(&self) -> Aabb<f32> { self.branches[self.trunk_idx].aabb }
|
||||||
|
|
||||||
// Recursively search for branches or leaves by walking the tree's branch graph.
|
// Recursively search for branches or leaves by walking the tree's branch graph.
|
||||||
fn is_branch_or_leaves_at_inner(&self, pos: Vec3<f32>, branch_idx: usize) -> (bool, bool) {
|
fn is_branch_or_leaves_at_inner(&self, pos: Vec3<f32>, branch_idx: usize) -> (bool, bool, bool) {
|
||||||
let branch = &self.branches[branch_idx];
|
let branch = &self.branches[branch_idx];
|
||||||
// Always probe the sibling branch, since our AABB doesn't include its bounds
|
// Always probe the sibling branch, since our AABB doesn't include its bounds
|
||||||
// (it's not one of our children)
|
// (it's not one of our children)
|
||||||
let branch_or_leaves = branch
|
let branch_or_leaves = branch
|
||||||
.sibling_idx
|
.sibling_idx
|
||||||
.map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx)))
|
.map(|idx| Vec3::from(self.is_branch_or_leaves_at_inner(pos, idx)))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Only continue probing this sub-graph of the tree if the sample position falls
|
// Only continue probing this sub-graph of the tree if the sample position falls
|
||||||
@ -492,10 +498,10 @@ impl ProceduralTree {
|
|||||||
if branch.aabb.contains_point(pos) {
|
if branch.aabb.contains_point(pos) {
|
||||||
(branch_or_leaves
|
(branch_or_leaves
|
||||||
// Probe this branch
|
// Probe this branch
|
||||||
| Vec2::from(branch.is_branch_or_leaves_at(pos))
|
| Vec3::from(branch.is_branch_or_leaves_at(pos))
|
||||||
// Probe the children of this branch
|
// Probe the children of this branch
|
||||||
| branch.child_idx
|
| branch.child_idx
|
||||||
.map(|idx| Vec2::from(self.is_branch_or_leaves_at_inner(pos, idx)))
|
.map(|idx| Vec3::from(self.is_branch_or_leaves_at_inner(pos, idx)))
|
||||||
.unwrap_or_default())
|
.unwrap_or_default())
|
||||||
.into_tuple()
|
.into_tuple()
|
||||||
} else {
|
} else {
|
||||||
@ -506,7 +512,7 @@ impl ProceduralTree {
|
|||||||
/// Determine whether there are either branches or leaves at the given
|
/// Determine whether there are either branches or leaves at the given
|
||||||
/// position in the tree.
|
/// position in the tree.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) {
|
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool, bool) {
|
||||||
self.is_branch_or_leaves_at_inner(pos, self.trunk_idx)
|
self.is_branch_or_leaves_at_inner(pos, self.trunk_idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,7 +538,7 @@ struct Branch {
|
|||||||
impl Branch {
|
impl Branch {
|
||||||
/// Determine whether there are either branches or leaves at the given
|
/// Determine whether there are either branches or leaves at the given
|
||||||
/// position in the branch.
|
/// position in the branch.
|
||||||
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool) {
|
pub fn is_branch_or_leaves_at(&self, pos: Vec3<f32>) -> (bool, bool, bool) {
|
||||||
// fn finvsqrt(x: f32) -> f32 {
|
// fn finvsqrt(x: f32) -> f32 {
|
||||||
// let y = f32::from_bits(0x5f375a86 - (x.to_bits() >> 1));
|
// let y = f32::from_bits(0x5f375a86 - (x.to_bits() >> 1));
|
||||||
// y * (1.5 - ( x * 0.5 * y * y ))
|
// y * (1.5 - ( x * 0.5 * y * y ))
|
||||||
@ -542,19 +548,24 @@ impl Branch {
|
|||||||
let p_d2 = p.distance_squared(pos);
|
let p_d2 = p.distance_squared(pos);
|
||||||
|
|
||||||
if p_d2 < self.wood_radius.powi(2) {
|
if p_d2 < self.wood_radius.powi(2) {
|
||||||
(true, false)
|
(true, false, false) // Wood
|
||||||
} else if self.has_stairs && {
|
} else if {
|
||||||
let horizontal_projected = Lerp::lerp_unclamped(self.line.start, self.line.end, (pos.z - self.line.start.z) / (self.line.end.z - self.line.start.z));
|
let diff = (p - pos) / Vec3::new(1.0, 1.0, self.leaf_vertical_scale);
|
||||||
let rpos = pos.xy() - horizontal_projected.xy();
|
diff.magnitude_squared() < self.leaf_radius.powi(2)
|
||||||
|
} {
|
||||||
|
(false, true, false) // Leaves
|
||||||
|
} else {
|
||||||
|
let stair_width = 5.0;
|
||||||
|
let stair_thickness = 1.5;
|
||||||
|
let stair_space = 6.0;
|
||||||
|
if self.has_stairs && p_d2 < (self.wood_radius + stair_width).powi(2) {
|
||||||
|
let rpos = pos.xy() - p.xy();
|
||||||
let stretch = 32.0;
|
let stretch = 32.0;
|
||||||
let stair_section = ((rpos.x as f32).atan2(rpos.y as f32) / (f32::consts::PI * 2.0) * stretch + pos.z).rem_euclid(stretch);
|
let stair_section = ((rpos.x as f32).atan2(rpos.y as f32) / (f32::consts::PI * 2.0) * stretch + pos.z).rem_euclid(stretch);
|
||||||
stair_section < 2.0 && p_d2 < (self.wood_radius + 8.0).powi(2)
|
(stair_section < stair_thickness, false, stair_section >= stair_thickness && stair_section < stair_thickness + stair_space) // Stairs
|
||||||
} {
|
|
||||||
(true, false)
|
|
||||||
} else {
|
} else {
|
||||||
let diff = (p - pos) / Vec3::new(1.0, 1.0, self.leaf_vertical_scale);
|
(false, false, false)
|
||||||
|
}
|
||||||
(false, diff.magnitude_squared() < self.leaf_radius.powi(2))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2022,7 +2022,7 @@ impl WorldSim {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>())
|
.collect::<Vec<_>>())
|
||||||
.choose_seeded(seed),
|
.choose_seeded(seed),
|
||||||
lanterns: false,
|
inhabited: false,
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2034,7 +2034,7 @@ impl WorldSim {
|
|||||||
seed,
|
seed,
|
||||||
scale: 4.0,
|
scale: 4.0,
|
||||||
forest_kind: ForestKind::Giant,
|
forest_kind: ForestKind::Giant,
|
||||||
lanterns: true,
|
inhabited: (seed / 13) % 2 == 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
normal_trees.chain(giant_trees)
|
normal_trees.chain(giant_trees)
|
||||||
|
Loading…
Reference in New Issue
Block a user