mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add lava to caves, which sets you on fire if you swim in it. Currently requires uncommenting #define LAVA
in the shaders, and only looks good with cheap fluid mode.
This commit is contained in:
parent
e7f54d6306
commit
2226a4c6a9
@ -37,6 +37,8 @@ layout(location = 1) flat in uint f_pos_norm;
|
||||
// ShadowLocals shadowMats[/*MAX_LAYER_FACES*/192];
|
||||
// };
|
||||
|
||||
//#define LAVA
|
||||
|
||||
layout(std140, set = 2, binding = 0)
|
||||
uniform u_locals {
|
||||
vec3 model_offs;
|
||||
@ -78,7 +80,11 @@ void main() {
|
||||
// vec3 view_dir = normalize(-vec3(vert_pos4)/* / vert_pos4.w*/);
|
||||
vec3 view_dir = -cam_to_frag;
|
||||
// vec3 surf_color = /*srgb_to_linear*/(vec3(0.4, 0.7, 2.0));
|
||||
#ifdef LAVA
|
||||
vec3 water_color = (1.0 - MU_LAVA);
|
||||
#else
|
||||
/*const */vec3 water_color = (1.0 - MU_WATER) * MU_SCATTER;//srgb_to_linear(vec3(0.2, 0.5, 1.0));
|
||||
#endif
|
||||
// /*const */vec3 water_color = srgb_to_linear(vec3(0.0, 0.25, 0.5));
|
||||
|
||||
/* vec3 sun_dir = get_sun_dir(time_of_day.x);
|
||||
@ -118,7 +124,11 @@ void main() {
|
||||
// Water is transparent so both normals are valid.
|
||||
vec3 cam_norm = faceforward(f_norm, f_norm, cam_to_frag);
|
||||
|
||||
#ifdef LAVA
|
||||
vec3 mu = MU_LAVA;
|
||||
#else
|
||||
vec3 mu = MU_WATER;
|
||||
#endif
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation = vec3(1.0);//compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
|
||||
|
||||
@ -177,7 +187,14 @@ void main() {
|
||||
// float reflected_light_point = /*length*/(diffuse_light_point.r) + f_light * point_shadow;
|
||||
// reflected_light += k_d * (diffuse_light_point + f_light * point_shadow * shade_frac) + specular_light_point;
|
||||
|
||||
float passthrough = clamp(dot(cam_norm, -cam_to_frag) * 1.0 - 0.2, 0, 1);
|
||||
#ifdef LAVA
|
||||
float opacity = 0.9;
|
||||
emitted_light = vec3(0.1, 0, 0);
|
||||
#else
|
||||
float opacity = 0.2;
|
||||
#endif
|
||||
|
||||
float passthrough = clamp(dot(cam_norm, -cam_to_frag) * 1.0 - opacity, 0, 1);
|
||||
float min_refl = min(emitted_light.r, min(emitted_light.g, emitted_light.b));
|
||||
|
||||
vec3 surf_color = illuminate(max_light, view_dir, water_color * /* fog_color * */emitted_light, /*surf_color * */water_color * reflected_light);
|
||||
|
@ -88,6 +88,8 @@ float wave_height(vec3 pos) {
|
||||
return pow(abs(height), 0.5) * sign(height) * 15.0;
|
||||
}
|
||||
|
||||
//#define LAVA
|
||||
|
||||
void main() {
|
||||
// First 3 normals are negative, next 3 are positive
|
||||
vec3 normals[6] = vec3[](vec3(-1,0,0), vec3(1,0,0), vec3(0,-1,0), vec3(0,1,0), vec3(0,0,-1), vec3(0,0,1));
|
||||
@ -148,7 +150,12 @@ void main() {
|
||||
vec3 norm = vec3(0, 0, 1) * nmap.z + b_norm * nmap.x + c_norm * nmap.y;
|
||||
// vec3 norm = f_norm;
|
||||
|
||||
#ifdef LAVA
|
||||
vec3 water_color = (1.0 - MU_LAVA);
|
||||
#else
|
||||
vec3 water_color = (1.0 - MU_WATER) * MU_SCATTER;
|
||||
#endif
|
||||
|
||||
#if (SHADOW_MODE == SHADOW_MODE_CHEAP || SHADOW_MODE == SHADOW_MODE_MAP || FLUID_MODE == FLUID_MODE_SHINY)
|
||||
float f_alt = alt_at(f_pos.xy);
|
||||
#elif (SHADOW_MODE == SHADOW_MODE_NONE || FLUID_MODE == FLUID_MODE_CHEAP)
|
||||
@ -230,7 +237,12 @@ void main() {
|
||||
// vec3 water_color_direct = exp(-MU_WATER);//exp(-MU_WATER);//vec3(1.0);
|
||||
// vec3 water_color_direct = exp(-water_attenuation * (water_depth_to_light + water_depth_to_camera));
|
||||
// vec3 water_color_ambient = exp(-water_attenuation * (water_depth_to_vertical + water_depth_to_camera));
|
||||
|
||||
#ifdef LAVA
|
||||
vec3 mu = MU_LAVA;
|
||||
#else
|
||||
vec3 mu = MU_WATER;
|
||||
#endif
|
||||
// NOTE: Default intersection point is camera position, meaning if we fail to intersect we assume the whole camera is in water.
|
||||
vec3 cam_attenuation = compute_attenuation_point(f_pos, -view_dir, mu, fluid_alt, cam_pos.xyz);
|
||||
// float water_depth_to_vertical = max(/*f_alt - f_pos.z*/f_light, 0.0);
|
||||
@ -290,7 +302,13 @@ void main() {
|
||||
// reflected_light += point_light;
|
||||
// vec3 surf_color = srgb_to_linear(vec3(0.2, 0.5, 1.0)) * light * diffuse_light * ambient_light;
|
||||
const float REFLECTANCE = 0.5;
|
||||
#ifdef LAVA
|
||||
//vec3 surf_color = illuminate(max_light, view_dir, water_color * emitted_light, reflect_color * REFLECTANCE + water_color * reflected_light);
|
||||
vec3 surf_color = vec3(1, 0.25, 0);
|
||||
#else
|
||||
vec3 surf_color = illuminate(max_light, view_dir, water_color * emitted_light/* * log(1.0 - MU_WATER)*/, /*cam_attenuation * *//*water_color * */reflect_color * REFLECTANCE + water_color * reflected_light/* * log(1.0 - MU_WATER)*/);
|
||||
#endif
|
||||
//vec3 surf_color = illuminate(max_light, view_dir, water_color * emitted_light/* * log(1.0 - MU_WATER)*/, /*cam_attenuation * *//*water_color * */reflect_color * REFLECTANCE + water_color * reflected_light/* * log(1.0 - MU_WATER)*/);
|
||||
|
||||
// passthrough = pow(passthrough, 1.0 / (1.0 + water_depth_to_camera));
|
||||
/* surf_color = cam_attenuation.g < 0.5 ?
|
||||
|
@ -2,7 +2,9 @@
|
||||
#define SRGB_GLSL
|
||||
// Linear RGB, attenuation coefficients for water at roughly R, G, B wavelengths.
|
||||
// See https://en.wikipedia.org/wiki/Electromagnetic_absorption_by_water
|
||||
|
||||
const vec3 MU_WATER = vec3(0.6, 0.04, 0.01);
|
||||
const vec3 MU_LAVA = vec3(0.1, 0.75, 1.0);
|
||||
|
||||
// // NOTE: Automatic in v4.0
|
||||
// float
|
||||
|
@ -557,7 +557,7 @@ impl<const AVERAGE_PALETTE: bool> VoxelImageDecoding for TriPngEncoding<AVERAGE_
|
||||
} else {
|
||||
use BlockKind::*;
|
||||
match kind {
|
||||
Air | Water => Rgb { r: 0, g: 0, b: 0 },
|
||||
Air | Water | Lava => Rgb { r: 0, g: 0, b: 0 },
|
||||
Rock => Rgb {
|
||||
r: 93,
|
||||
g: 110,
|
||||
|
@ -9,11 +9,38 @@ use serde::{Deserialize, Serialize};
|
||||
use std::f32::consts::PI;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum LiquidKind {
|
||||
Water,
|
||||
Lava,
|
||||
}
|
||||
|
||||
impl LiquidKind {
|
||||
/// If an entity is in multiple overlapping liquid blocks, which one takes
|
||||
/// precedence? (should be a rare edge case, since checkerboard patterns of
|
||||
/// water and lava shouldn't show up in worldgen)
|
||||
pub fn merge(self, other: LiquidKind) -> LiquidKind {
|
||||
use LiquidKind::{Lava, Water};
|
||||
match (self, other) {
|
||||
(Water, Water) => Water,
|
||||
(Water, Lava) => Lava,
|
||||
(Lava, _) => Lava,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Fluid medium in which the entity exists
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum Fluid {
|
||||
Air { vel: Vel, elevation: f32 },
|
||||
Water { vel: Vel, depth: f32 },
|
||||
Air {
|
||||
vel: Vel,
|
||||
elevation: f32,
|
||||
},
|
||||
Liquid {
|
||||
kind: LiquidKind,
|
||||
vel: Vel,
|
||||
depth: f32,
|
||||
},
|
||||
}
|
||||
|
||||
impl Fluid {
|
||||
@ -21,7 +48,14 @@ impl Fluid {
|
||||
pub fn density(&self) -> Density {
|
||||
match self {
|
||||
Self::Air { .. } => Density(AIR_DENSITY),
|
||||
Self::Water { .. } => Density(WATER_DENSITY),
|
||||
Self::Liquid {
|
||||
kind: LiquidKind::Water,
|
||||
..
|
||||
} => Density(WATER_DENSITY),
|
||||
Self::Liquid {
|
||||
kind: LiquidKind::Lava,
|
||||
..
|
||||
} => Density(WATER_DENSITY),
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,14 +87,14 @@ impl Fluid {
|
||||
pub fn flow_vel(&self) -> Vel {
|
||||
match self {
|
||||
Self::Air { vel, .. } => *vel,
|
||||
Self::Water { vel, .. } => *vel,
|
||||
Self::Liquid { vel, .. } => *vel,
|
||||
}
|
||||
}
|
||||
|
||||
// Very simple but useful in reducing mental overhead
|
||||
pub fn relative_flow(&self, vel: &Vel) -> Vel { Vel(self.flow_vel().0 - vel.0) }
|
||||
|
||||
pub fn is_liquid(&self) -> bool { matches!(self, Fluid::Water { .. }) }
|
||||
pub fn is_liquid(&self) -> bool { matches!(self, Fluid::Liquid { .. }) }
|
||||
|
||||
pub fn elevation(&self) -> Option<f32> {
|
||||
match self {
|
||||
@ -71,7 +105,7 @@ impl Fluid {
|
||||
|
||||
pub fn depth(&self) -> Option<f32> {
|
||||
match self {
|
||||
Fluid::Water { depth, .. } => Some(*depth),
|
||||
Fluid::Liquid { depth, .. } => Some(*depth),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
use super::SpriteKind;
|
||||
use crate::{comp::tool::ToolKind, make_case_elim};
|
||||
use crate::{
|
||||
comp::{fluid_dynamics::LiquidKind, tool::ToolKind},
|
||||
make_case_elim,
|
||||
};
|
||||
use enum_iterator::IntoEnumIterator;
|
||||
use hashbrown::HashMap;
|
||||
use lazy_static::lazy_static;
|
||||
@ -27,6 +30,7 @@ make_case_elim!(
|
||||
pub enum BlockKind {
|
||||
Air = 0x00, // Air counts as a fluid
|
||||
Water = 0x01,
|
||||
Lava = 0x02,
|
||||
// 0x02 <= x < 0x10 are reserved for other fluids. These are 2^n aligned to allow bitwise
|
||||
// checking of common conditions. For example, `is_fluid` is just `block_kind &
|
||||
// 0x0F == 0` (this is a very common operation used in meshing that could do with
|
||||
@ -63,6 +67,15 @@ impl BlockKind {
|
||||
#[inline]
|
||||
pub const fn is_liquid(&self) -> bool { self.is_fluid() && !self.is_air() }
|
||||
|
||||
#[inline]
|
||||
pub const fn liquid_kind(&self) -> Option<LiquidKind> {
|
||||
Some(match self {
|
||||
BlockKind::Water => LiquidKind::Water,
|
||||
BlockKind::Lava => LiquidKind::Lava,
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Determine whether the block is filled (i.e: fully solid). Right now,
|
||||
/// this is the opposite of being a fluid.
|
||||
#[inline]
|
||||
|
@ -1,8 +1,8 @@
|
||||
use common::{
|
||||
comp::{
|
||||
fluid_dynamics::Fluid, Buff, BuffCategory, BuffChange, BuffEffect, BuffId, BuffKind,
|
||||
BuffSource, Buffs, Energy, Health, HealthChange, HealthSource, Inventory, ModifierKind,
|
||||
PhysicsState, Stats,
|
||||
fluid_dynamics::{LiquidKind, Fluid}, Buff, BuffCategory, BuffChange, BuffData, BuffEffect, BuffId,
|
||||
BuffKind, BuffSource, Buffs, Energy, Health, HealthChange, HealthSource, Inventory,
|
||||
ModifierKind, PhysicsState, Stats,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
resources::DeltaTime,
|
||||
@ -45,34 +45,39 @@ impl<'a> System<'a> for Sys {
|
||||
// Set to false to avoid spamming server
|
||||
buffs.set_event_emission(false);
|
||||
stats.set_event_emission(false);
|
||||
for (entity, mut buff_comp, energy, mut stat, health) in (
|
||||
for (entity, mut buff_comp, energy, mut stat, health, physics_state) in (
|
||||
&read_data.entities,
|
||||
&mut buffs,
|
||||
&read_data.energies,
|
||||
&mut stats,
|
||||
&read_data.healths,
|
||||
read_data.physics_states.maybe(),
|
||||
)
|
||||
.join()
|
||||
{
|
||||
let in_fluid = physics_state.and_then(|p| p.in_fluid);
|
||||
|
||||
if matches!(in_fluid, Some(Fluid::Liquid { kind: LiquidKind::Lava, .. })) {
|
||||
if !buff_comp.contains(BuffKind::Burning) {
|
||||
buff_comp.insert(Buff::new(
|
||||
BuffKind::Burning,
|
||||
BuffData::new(200.0, None),
|
||||
vec![BuffCategory::Natural],
|
||||
BuffSource::World,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let (buff_comp_kinds, buff_comp_buffs): (
|
||||
&HashMap<BuffKind, Vec<BuffId>>,
|
||||
&mut HashMap<BuffId, Buff>,
|
||||
) = buff_comp.parts();
|
||||
let mut expired_buffs = Vec::<BuffId>::new();
|
||||
|
||||
// For each buff kind present on entity, if the buff kind queues, only ticks
|
||||
// duration of strongest buff of that kind, else it ticks durations of all buffs
|
||||
// of that kind. Any buffs whose durations expire are marked expired.
|
||||
for (kind, ids) in buff_comp_kinds.iter() {
|
||||
// Only get the physics state component if the entity has the burning buff, as
|
||||
// we don't need it for any other conditions yet
|
||||
let in_fluid = if matches!(kind, BuffKind::Burning) {
|
||||
read_data
|
||||
.physics_states
|
||||
.get(entity)
|
||||
.and_then(|p| p.in_fluid)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if kind.queues() {
|
||||
if let Some((Some(buff), id)) =
|
||||
ids.get(0).map(|id| (buff_comp_buffs.get_mut(id), id))
|
||||
@ -257,7 +262,7 @@ fn tick_buff(
|
||||
}
|
||||
if let Some(remaining_time) = &mut buff.time {
|
||||
// Extinguish Burning buff when in water
|
||||
if matches!(buff.kind, BuffKind::Burning) && matches!(in_fluid, Some(Fluid::Water { .. })) {
|
||||
if matches!(buff.kind, BuffKind::Burning) && matches!(in_fluid, Some(Fluid::Liquid { kind: LiquidKind::Water, .. })) {
|
||||
*remaining_time = Duration::default();
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use common::{
|
||||
comp::{
|
||||
body::ship::figuredata::{VoxelCollider, VOXEL_COLLIDER_MANIFEST},
|
||||
fluid_dynamics::{Fluid, Wings},
|
||||
fluid_dynamics::{Fluid, LiquidKind, Wings},
|
||||
BeamSegment, Body, CharacterState, Collider, Density, Mass, Mounting, Ori, PhysicsState,
|
||||
Pos, PosVelDefer, PreviousPhysCache, Projectile, Scale, Shockwave, Stats, Sticky, Vel,
|
||||
},
|
||||
@ -905,13 +905,15 @@ impl<'a> PhysicsData<'a> {
|
||||
.terrain
|
||||
.get(pos.0.map(|e| e.floor() as i32))
|
||||
.ok()
|
||||
.and_then(|vox| vox.is_liquid().then_some(1.0))
|
||||
.map(|depth| Fluid::Water {
|
||||
depth,
|
||||
vel: Vel::zero(),
|
||||
.and_then(|vox| {
|
||||
vox.liquid_kind().map(|kind| Fluid::Liquid {
|
||||
kind,
|
||||
depth: 1.0,
|
||||
vel: Vel::zero(),
|
||||
})
|
||||
})
|
||||
.or_else(|| match physics_state.in_fluid {
|
||||
Some(Fluid::Water { .. }) | None => Some(Fluid::Air {
|
||||
Some(Fluid::Liquid { .. }) | None => Some(Fluid::Air {
|
||||
elevation: pos.0.z,
|
||||
vel: Vel::default(),
|
||||
}),
|
||||
@ -1541,24 +1543,26 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
|
||||
});
|
||||
|
||||
// Find liquid immersion and wall collision all in one round of iteration
|
||||
let mut max_liquid_z = None::<f32>;
|
||||
let mut liquid = None::<(LiquidKind, f32)>;
|
||||
let mut wall_dir_collisions = [false; 4];
|
||||
near_iter.for_each(|(i, j, k)| {
|
||||
let block_pos = player_voxel_pos + Vec3::new(i, j, k);
|
||||
|
||||
if let Some(block) = terrain.get(block_pos).ok().copied() {
|
||||
// Check for liquid blocks
|
||||
if block.is_liquid() {
|
||||
if let Some(block_liquid) = block.liquid_kind() {
|
||||
let liquid_aabb = Aabb {
|
||||
min: block_pos.map(|e| e as f32),
|
||||
// The liquid part of a liquid block always extends 1 block high.
|
||||
max: block_pos.map(|e| e as f32) + Vec3::one(),
|
||||
};
|
||||
if player_aabb.collides_with_aabb(liquid_aabb) {
|
||||
max_liquid_z = Some(match max_liquid_z {
|
||||
Some(z) => z.max(liquid_aabb.max.z),
|
||||
None => liquid_aabb.max.z,
|
||||
});
|
||||
liquid = match liquid {
|
||||
Some((kind, max_liquid_z)) => {
|
||||
Some((kind.merge(block_liquid), max_liquid_z.max(liquid_aabb.max.z)))
|
||||
},
|
||||
None => Some((block_liquid, liquid_aabb.max.z)),
|
||||
};
|
||||
}
|
||||
}
|
||||
// Check for walls
|
||||
@ -1594,23 +1598,24 @@ fn box_voxel_collision<'a, T: BaseVol<Vox = Block> + ReadVol>(
|
||||
physics_state.ground_vel = ground_vel;
|
||||
}
|
||||
|
||||
physics_state.in_fluid = max_liquid_z
|
||||
.map(|max_z| max_z - pos.0.z) // NOTE: assumes min_z == 0.0
|
||||
.map(|depth| {
|
||||
physics_state
|
||||
physics_state.in_fluid = liquid
|
||||
.map(|(kind, max_z)| (kind, max_z - pos.0.z)) // NOTE: assumes min_z == 0.0
|
||||
.map(|(kind, depth)| {
|
||||
(kind, physics_state
|
||||
.in_liquid()
|
||||
// This is suboptimal because it doesn't check for true depth,
|
||||
// so it can cause problems for situations like swimming down
|
||||
// a river and spawning or teleporting in(/to) water
|
||||
.map(|old_depth| (old_depth + old_pos.z - pos.0.z).max(depth))
|
||||
.unwrap_or(depth)
|
||||
.unwrap_or(depth))
|
||||
})
|
||||
.map(|depth| Fluid::Water {
|
||||
.map(|(kind, depth)| Fluid::Liquid {
|
||||
kind,
|
||||
depth,
|
||||
vel: Vel::zero(),
|
||||
})
|
||||
.or_else(|| match physics_state.in_fluid {
|
||||
Some(Fluid::Water { .. }) | None => Some(Fluid::Air {
|
||||
Some(Fluid::Liquid { .. }) | None => Some(Fluid::Air {
|
||||
elevation: pos.0.z,
|
||||
vel: Vel::default(),
|
||||
}),
|
||||
|
@ -210,10 +210,15 @@ pub fn apply_caves_to(canvas: &mut Canvas, rng: &mut impl Rng) {
|
||||
//make pits
|
||||
for z in cave_base - pit_depth..cave_base {
|
||||
if pit_condition && (cave_roof - cave_base) > 10 {
|
||||
let kind = if z < (cave_base - pit_depth) + (3 * pit_depth / 4) {
|
||||
BlockKind::Lava
|
||||
} else {
|
||||
BlockKind::Air
|
||||
};
|
||||
canvas.set(
|
||||
Vec3::new(wpos2d.x, wpos2d.y, z),
|
||||
Block::new(
|
||||
BlockKind::Air,
|
||||
kind,
|
||||
noisy_color(info.index().colors.layer.scaffold.into(), 8),
|
||||
),
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user