Added BlocksOfInterest and block particle emission

This commit is contained in:
Joshua Barretto 2020-08-18 16:51:43 +01:00
parent 14fd023854
commit d1bbfc9960
7 changed files with 158 additions and 25 deletions

View File

@ -18,7 +18,7 @@
in vec3 f_pos;
flat in vec3 f_norm;
in vec3 f_col;
in vec4 f_col;
out vec4 tgt_color;
@ -50,7 +50,7 @@ void main() {
DirectionalLight sun_info = get_sun_info(sun_dir, point_shadow * sun_shade_frac, f_pos);
DirectionalLight moon_info = get_moon_info(moon_dir, point_shadow * moon_shade_frac);
vec3 surf_color = f_col;
vec3 surf_color = f_col.rgb;
float alpha = 1.0;
const float n2 = 1.5;
const float R_s2s0 = pow((1.0 - n2) / (1.0 + n2), 2);
@ -82,5 +82,5 @@ void main() {
vec3 color = surf_color;
#endif
tgt_color = vec4(color, 0.3);
tgt_color = vec4(color, f_col.a);
}

View File

@ -26,7 +26,7 @@ in int inst_mode;
out vec3 f_pos;
flat out vec3 f_norm;
out vec3 f_col;
out vec4 f_col;
out float f_ao;
out float f_light;
@ -43,6 +43,7 @@ const int FIREWORK_GREEN = 5;
const int FIREWORK_PURPLE = 6;
const int FIREWORK_RED = 7;
const int FIREWORK_YELLOW = 8;
const int LEAF = 9;
// meters per second squared (acceleration)
const float earth_gravity = 9.807;
@ -50,7 +51,7 @@ const float earth_gravity = 9.807;
struct Attr {
vec3 offs;
float scale;
vec3 col;
vec4 col;
};
float lifetime = tick.x - inst_time;
@ -90,7 +91,7 @@ void main() {
vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.1)// + vec3(sin(lifetime), sin(lifetime + 1.5), sin(lifetime * 4) * 0.25)
),
linear_scale(0.5),
vec3(1)
vec4(1, 1, 1, 0.3)
);
} else if (inst_mode == FIRE) {
attr = Attr(
@ -99,7 +100,7 @@ void main() {
vec3(rand2 * 0.1, rand3 * 0.1, 2.0 + rand4 * 1.0)
),
1.0,
vec3(2, rand5 + 2, 0)
vec4(2, 0.8 + rand5 * 0.3, 0, 1)
);
} else if (inst_mode == GUN_POWDER_SPARK) {
attr = Attr(
@ -108,7 +109,7 @@ void main() {
vec3(rand4, rand5, rand6) * 2.0 + grav_vel(earth_gravity)
),
1.0,
vec3(3.5, 3 + rand7, 0)
vec4(3.5, 3 + rand7, 0, 1)
);
} else if (inst_mode == SHRAPNEL) {
attr = Attr(
@ -117,7 +118,7 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 1)
);
} else if (inst_mode == FIREWORK_BLUE) {
attr = Attr(
@ -126,7 +127,7 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 0.3)
);
} else if (inst_mode == FIREWORK_GREEN) {
attr = Attr(
@ -135,7 +136,7 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 0.3)
);
} else if (inst_mode == FIREWORK_PURPLE) {
attr = Attr(
@ -144,7 +145,7 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 0.3)
);
} else if (inst_mode == FIREWORK_RED) {
attr = Attr(
@ -153,7 +154,7 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 0.3)
);
} else if (inst_mode == FIREWORK_YELLOW) {
attr = Attr(
@ -162,7 +163,16 @@ void main() {
vec3(rand4, rand5, rand6) * 40.0 + grav_vel(earth_gravity)
),
3.0 + rand0,
vec3(0.6 + rand7 * 0.4)
vec4(vec3(0.6 + rand7 * 0.4), 0.3)
);
} else if (inst_mode == LEAF) {
attr = Attr(
linear_motion(
vec3(1.0, 1.0, 0.0),
vec3(0, 0, -2.0)
) + vec3(sin(lifetime), sin(lifetime + 0.7), sin(lifetime * 0.5)) * 2.0,
4,
vec4(vec3(0.2 + rand7 * 0.2, 0.2 + (0.5 + rand6 * 0.5) * 0.6, 0), 1)
);
} else {
attr = Attr(
@ -171,7 +181,7 @@ void main() {
vec3(rand2 * 0.1, rand3 * 0.1, 1.0 + rand4 * 0.5)
),
exp_scale(-0.2),
vec3(1)
vec4(1)
);
}
@ -179,14 +189,12 @@ 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));
f_norm =
f_norm =
// inst_pos *
normals[(v_norm_ao >> 0) & 0x7u];
//vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0;
f_col =
//srgb_to_linear(col) *
srgb_to_linear(attr.col);
f_col = vec4(srgb_to_linear(attr.col.rgb), attr.col.a);
gl_Position =
all_mat *

View File

@ -88,6 +88,7 @@ impl Vertex {
}
}
#[derive(Copy, Clone)]
pub enum ParticleMode {
CampfireSmoke = 0,
CampfireFire = 1,
@ -98,6 +99,7 @@ pub enum ParticleMode {
FireworkPurple = 6,
FireworkRed = 7,
FireworkYellow = 8,
Leaf = 9,
}
impl ParticleMode {

View File

@ -942,7 +942,8 @@ impl Scene {
self.figure_mgr.clean(scene_data.tick);
// Maintain the particles.
self.particle_mgr.maintain(renderer, &scene_data);
self.particle_mgr
.maintain(renderer, &scene_data, &self.terrain);
// Maintain audio
self.sfx_mgr.maintain(

View File

@ -1,4 +1,4 @@
use super::SceneData;
use super::{terrain::BlocksOfInterest, SceneData, Terrain};
use crate::{
mesh::{greedy::GreedyMesh, Meshable},
render::{
@ -11,10 +11,14 @@ use common::{
comp::{item::Reagent, object, Body, CharacterState, Pos},
figure::Segment,
outcome::Outcome,
spiral::Spiral2d,
state::DeltaTime,
terrain::TerrainChunk,
vol::RectRasterableVol,
};
use dot_vox::DotVoxData;
use hashbrown::HashMap;
use rand::Rng;
use rand::prelude::*;
use specs::{Join, WorldExt};
use std::time::Duration;
use vek::*;
@ -83,7 +87,12 @@ impl ParticleMgr {
}
}
pub fn maintain(&mut self, renderer: &mut Renderer, scene_data: &SceneData) {
pub fn maintain(
&mut self,
renderer: &mut Renderer,
scene_data: &SceneData,
terrain: &Terrain<TerrainChunk>,
) {
if scene_data.particles_enabled {
// update timings
self.scheduler.maintain(scene_data.state.get_time());
@ -95,6 +104,7 @@ impl ParticleMgr {
// add new Particle
self.maintain_body_particles(scene_data);
self.maintain_boost_particles(scene_data);
self.maintain_block_particles(scene_data, terrain);
} else {
// remove all particle lifespans
self.particles.clear();
@ -245,6 +255,58 @@ impl ParticleMgr {
}
}
#[allow(clippy::same_item_push)] // TODO: Pending review in #587
fn maintain_block_particles(
&mut self,
scene_data: &SceneData,
terrain: &Terrain<TerrainChunk>,
) {
let dt = scene_data.state.ecs().fetch::<DeltaTime>().0;
let time = scene_data.state.get_time();
let player_pos = scene_data
.state
.read_component_cloned::<Pos>(scene_data.player_entity)
.unwrap_or_default();
let player_chunk = player_pos.0.xy().map2(TerrainChunk::RECT_SIZE, |e, sz| {
(e.floor() as i32).div_euclid(sz as i32)
});
type BoiFn<'a> = fn(&'a BlocksOfInterest) -> &'a [Vec3<i32>];
let particles: &[(BoiFn, _, _, _)] = &[
(|boi| &boi.leaves, 0.005, 30.0, ParticleMode::Leaf),
(|boi| &boi.embers, 20.0, 0.25, ParticleMode::CampfireFire),
(|boi| &boi.embers, 6.0, 30.0, ParticleMode::CampfireSmoke),
];
const RANGE: usize = 4;
for offset in Spiral2d::new().take((RANGE * 2 + 1).pow(2)) {
let chunk_pos = player_chunk + offset;
terrain.get(chunk_pos).map(|chunk_data| {
for (get_blocks, rate, dur, mode) in particles.iter() {
let blocks = get_blocks(&chunk_data.blocks_of_interest);
let avg_particles = dt * blocks.len() as f32 * *rate;
let particle_count = avg_particles.trunc() as usize
+ (thread_rng().gen::<f32>() < avg_particles.fract()) as usize;
for _ in 0..particle_count {
let block_pos =
Vec3::from(chunk_pos * TerrainChunk::RECT_SIZE.map(|e| e as i32))
+ blocks.choose(&mut thread_rng()).copied().unwrap(); // Can't fail
self.particles.push(Particle::new(
Duration::from_secs_f32(*dur),
time,
*mode,
block_pos.map(|e: i32| e as f32 + 0.5),
));
}
}
});
}
}
fn upload_particles(&mut self, renderer: &mut Renderer) {
let all_cpu_instances = self
.particles

View File

@ -1,3 +1,7 @@
mod watcher;
pub use self::watcher::BlocksOfInterest;
use crate::{
mesh::{greedy::GreedyMesh, Meshable},
render::{
@ -35,7 +39,7 @@ enum Visibility {
Visible = 2,
}
struct TerrainChunkData {
pub struct TerrainChunkData {
// GPU data
load_time: f32,
opaque_model: Model<TerrainPipeline>,
@ -43,6 +47,7 @@ struct TerrainChunkData {
col_lights: guillotiere::AllocId,
sprite_instances: HashMap<(BlockKind, usize), Instances<SpriteInstance>>,
locals: Consts<TerrainLocals>,
pub blocks_of_interest: BlocksOfInterest,
visible: Visibility,
can_shadow_point: bool,
@ -51,6 +56,7 @@ struct TerrainChunkData {
frustum_last_plane_index: u8,
}
#[derive(Copy, Clone)]
struct ChunkMeshState {
pos: Vec2<i32>,
started_tick: u64,
@ -67,6 +73,7 @@ struct MeshWorkerResponse {
col_lights_info: ColLightInfo,
sprite_instances: HashMap<(BlockKind, usize), Vec<SpriteInstance>>,
started_tick: u64,
blocks_of_interest: BlocksOfInterest,
}
struct SpriteConfig {
@ -392,6 +399,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
started_tick: u64,
volume: <VolGrid2d<V> as SampleVol<Aabr<i32>>>::Sample,
max_texture_size: u16,
chunk: Arc<TerrainChunk>,
range: Aabb<i32>,
sprite_data: &HashMap<(BlockKind, usize), Vec<SpriteData>>,
) -> MeshWorkerResponse {
@ -446,6 +454,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
instances
},
blocks_of_interest: BlocksOfInterest::from_chunk(&chunk),
started_tick,
}
}
@ -2575,7 +2584,7 @@ impl<V: RectRasterableVol> Terrain<V> {
// Limit ourselves to u16::MAX even if larger textures are supported.
let max_texture_size = renderer.max_texture_size();
for todo in self
for (todo, chunk) in self
.mesh_todo
.values_mut()
.filter(|todo| {
@ -2584,6 +2593,14 @@ impl<V: RectRasterableVol> Terrain<V> {
.unwrap_or(true)
})
.min_by_key(|todo| todo.active_worker.unwrap_or(todo.started_tick))
// Find a reference to the actual `TerrainChunk` we're meshing
.and_then(|todo| {
let pos = todo.pos;
Some((todo, scene_data.state
.terrain()
.get_key_arc(pos)
.cloned()?))
})
{
// TODO: find a alternative!
if scene_data.thread_pool.queued_jobs() > 0 {
@ -2644,6 +2661,7 @@ impl<V: RectRasterableVol> Terrain<V> {
started_tick,
volume,
max_texture_size,
chunk,
aabb,
&sprite_data,
));
@ -2737,6 +2755,7 @@ impl<V: RectRasterableVol> Terrain<V> {
visible: Visibility::OutOfRange,
can_shadow_point: false,
can_shadow_sun: false,
blocks_of_interest: response.blocks_of_interest,
z_bounds: response.z_bounds,
frustum_last_plane_index: 0,
});
@ -2921,6 +2940,10 @@ impl<V: RectRasterableVol> Terrain<V> {
)
}
pub fn get(&self, chunk_key: Vec2<i32>) -> Option<&TerrainChunkData> {
self.chunks.get(&chunk_key)
}
pub fn chunk_count(&self) -> usize { self.chunks.len() }
pub fn visible_chunk_count(&self) -> usize {

View File

@ -0,0 +1,37 @@
use common::{
terrain::{BlockKind, TerrainChunk},
vol::{IntoVolIterator, RectRasterableVol},
};
use rand::prelude::*;
use vek::*;
pub struct BlocksOfInterest {
pub leaves: Vec<Vec3<i32>>,
pub embers: Vec<Vec3<i32>>,
}
impl BlocksOfInterest {
pub fn from_chunk(chunk: &TerrainChunk) -> Self {
let mut leaves = Vec::new();
let mut embers = Vec::new();
chunk
.vol_iter(
Vec3::new(0, 0, chunk.get_min_z()),
Vec3::new(
TerrainChunk::RECT_SIZE.x as i32,
TerrainChunk::RECT_SIZE.y as i32,
chunk.get_max_z(),
),
)
.for_each(|(pos, block)| {
if block.kind() == BlockKind::Leaves && thread_rng().gen_range(0, 16) == 0 {
leaves.push(pos);
} else if block.kind() == BlockKind::Ember {
embers.push(pos);
}
});
Self { leaves, embers }
}
}