mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add ParticleMgr
This commit is contained in:
parent
7e35617f59
commit
39b676cd8f
@ -11,6 +11,8 @@ in vec4 inst_mat1;
|
|||||||
in vec4 inst_mat2;
|
in vec4 inst_mat2;
|
||||||
in vec4 inst_mat3;
|
in vec4 inst_mat3;
|
||||||
in vec3 inst_col;
|
in vec3 inst_col;
|
||||||
|
in vec3 inst_vel;
|
||||||
|
in vec4 inst_tick;
|
||||||
in float inst_wind_sway;
|
in float inst_wind_sway;
|
||||||
|
|
||||||
out vec3 f_pos;
|
out vec3 f_pos;
|
||||||
@ -34,11 +36,14 @@ void main() {
|
|||||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||||
|
|
||||||
// Wind waving
|
// Wind waving
|
||||||
f_pos += inst_wind_sway * vec3(
|
//f_pos += inst_wind_sway * vec3(
|
||||||
sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
// sin(tick.x * 1.5 + f_pos.y * 0.1) * sin(tick.x * 0.35),
|
||||||
sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
// sin(tick.x * 1.5 + f_pos.x * 0.1) * sin(tick.x * 0.25),
|
||||||
0.0
|
// 0.0
|
||||||
) * pow(abs(v_pos.z) * SCALE, 1.3) * 0.2;
|
//) * pow(abs(v_pos.z) * SCALE, 1.3) * 0.2;
|
||||||
|
|
||||||
|
float elapsed = (tick.x - inst_tick.x) / 100000.0;
|
||||||
|
f_pos += (inst_vel * elapsed);
|
||||||
|
|
||||||
// First 3 normals are negative, next 3 are positive
|
// 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));
|
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));
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
// version in voxygen\src\meta.rs in order to reset save files to being empty
|
// version in voxygen\src\meta.rs in order to reset save files to being empty
|
||||||
|
|
||||||
use crate::comp::{
|
use crate::comp::{
|
||||||
body::object, projectile, Body, CharacterAbility, Gravity, HealthChange, HealthSource,
|
body::object, projectile, visual::ParticleEmitterMode, Body, CharacterAbility, Gravity,
|
||||||
LightEmitter, Projectile, ParticleEmitter,
|
HealthChange, HealthSource, LightEmitter, ParticleEmitter, Projectile,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -277,7 +277,7 @@ impl Tool {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
projectile_particles: Some(ParticleEmitter {
|
projectile_particles: Some(ParticleEmitter {
|
||||||
mode: 0,
|
mode: ParticleEmitterMode::Sprinkler,
|
||||||
}),
|
}),
|
||||||
projectile_gravity: None,
|
projectile_gravity: None,
|
||||||
},
|
},
|
||||||
@ -304,7 +304,7 @@ impl Tool {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
}),
|
||||||
projectile_particles: Some(ParticleEmitter {
|
projectile_particles: Some(ParticleEmitter {
|
||||||
mode: 0,
|
mode: ParticleEmitterMode::Sprinkler,
|
||||||
}),
|
}),
|
||||||
projectile_gravity: None,
|
projectile_gravity: None,
|
||||||
},
|
},
|
||||||
|
@ -18,7 +18,7 @@ mod player;
|
|||||||
pub mod projectile;
|
pub mod projectile;
|
||||||
pub mod skills;
|
pub mod skills;
|
||||||
mod stats;
|
mod stats;
|
||||||
mod visual;
|
pub mod visual;
|
||||||
|
|
||||||
// Reexports
|
// Reexports
|
||||||
pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout};
|
pub use ability::{CharacterAbility, CharacterAbilityType, ItemConfig, Loadout};
|
||||||
|
@ -46,37 +46,24 @@ impl Default for LightAnimation {
|
|||||||
impl Component for LightAnimation {
|
impl Component for LightAnimation {
|
||||||
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
|
||||||
}
|
}
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
|
pub enum ParticleEmitterMode {
|
||||||
|
Sprinkler,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct ParticleEmitter {
|
pub struct ParticleEmitter {
|
||||||
|
pub mode: ParticleEmitterMode,
|
||||||
/// Mode 1: sprinkler (inital_velocity, lifespan)
|
|
||||||
/// Mode 2: smoke (initial_position, boyancy_const, wind, lifespan)
|
|
||||||
pub mode: u8, // enum?
|
|
||||||
|
|
||||||
// pub vertices: Vec<i8>,
|
|
||||||
// pub texture: RasterFooBar,
|
|
||||||
|
|
||||||
// // mode 1 -- sprinkler.
|
|
||||||
// pub initial_position: [i8; 3],
|
|
||||||
// pub initial_velocity: [i8; 3],
|
|
||||||
// pub lifespan: u32, // in ticks?
|
|
||||||
|
|
||||||
// // mode 2 -- smoke
|
|
||||||
// pub initial_position: [i8; 3],
|
|
||||||
// pub boyancy_const: [i8; 3],
|
|
||||||
// pub wind_sway: [i8; 3],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ParticleEmitter {
|
impl Default for ParticleEmitter {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: 0,
|
mode: ParticleEmitterMode::Sprinkler,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for ParticleEmitter {
|
impl Component for ParticleEmitter {
|
||||||
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
type Storage = FlaggedStorage<Self, IDVStorage<Self>>;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ use world::util::Sampler;
|
|||||||
|
|
||||||
use scan_fmt::{scan_fmt, scan_fmt_some};
|
use scan_fmt::{scan_fmt, scan_fmt_some};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
use comp::visual::ParticleEmitterMode;
|
||||||
|
|
||||||
pub trait ChatCommandExt {
|
pub trait ChatCommandExt {
|
||||||
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String);
|
fn execute(&self, server: &mut Server, entity: EcsEntity, args: String);
|
||||||
@ -910,7 +911,9 @@ fn handle_light(
|
|||||||
.create_entity_synced()
|
.create_entity_synced()
|
||||||
.with(pos)
|
.with(pos)
|
||||||
.with(comp::ForceUpdate)
|
.with(comp::ForceUpdate)
|
||||||
.with(comp::ParticleEmitter { mode: 0 })
|
.with(comp::ParticleEmitter {
|
||||||
|
mode: ParticleEmitterMode::Sprinkler,
|
||||||
|
})
|
||||||
.with(light_emitter);
|
.with(light_emitter);
|
||||||
if let Some(light_offset) = light_offset_opt {
|
if let Some(light_offset) = light_offset_opt {
|
||||||
builder.with(light_offset).build();
|
builder.with(light_offset).build();
|
||||||
|
@ -6,6 +6,7 @@ use common::{
|
|||||||
},
|
},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
};
|
};
|
||||||
|
use comp::visual::ParticleEmitterMode;
|
||||||
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
use specs::{Builder, Entity as EcsEntity, WorldExt};
|
||||||
use vek::{Rgb, Vec3};
|
use vek::{Rgb, Vec3};
|
||||||
|
|
||||||
@ -117,7 +118,9 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3<f32>) {
|
|||||||
flicker: 1.0,
|
flicker: 1.0,
|
||||||
animated: true,
|
animated: true,
|
||||||
})
|
})
|
||||||
.with(ParticleEmitter { mode: 0 })
|
.with(ParticleEmitter {
|
||||||
|
mode: ParticleEmitterMode::Sprinkler,
|
||||||
|
})
|
||||||
.with(WaypointArea::default())
|
.with(WaypointArea::default())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
mesh::{vol, Meshable},
|
mesh::{vol, Meshable},
|
||||||
render::{self, FigurePipeline, Mesh, SpritePipeline},
|
render::{self, FigurePipeline, Mesh, ParticlePipeline, SpritePipeline},
|
||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
figure::Cell,
|
figure::Cell,
|
||||||
@ -11,6 +11,7 @@ use vek::*;
|
|||||||
|
|
||||||
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
type FigureVertex = <FigurePipeline as render::Pipeline>::Vertex;
|
||||||
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
|
type SpriteVertex = <SpritePipeline as render::Pipeline>::Vertex;
|
||||||
|
type ParticleVertex = <ParticlePipeline as render::Pipeline>::Vertex;
|
||||||
|
|
||||||
impl<'a, V: 'a> Meshable<'a, FigurePipeline, FigurePipeline> for V
|
impl<'a, V: 'a> Meshable<'a, FigurePipeline, FigurePipeline> for V
|
||||||
where
|
where
|
||||||
@ -147,6 +148,73 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, V: 'a> Meshable<'a, ParticlePipeline, ParticlePipeline> for V
|
||||||
|
where
|
||||||
|
V: BaseVol<Vox = Cell> + ReadVol + SizedVol,
|
||||||
|
/* TODO: Use VolIterator instead of manually iterating
|
||||||
|
* &'a V: IntoVolIterator<'a> + IntoFullVolIterator<'a>,
|
||||||
|
* &'a V: BaseVol<Vox=Cell>, */
|
||||||
|
{
|
||||||
|
type Pipeline = ParticlePipeline;
|
||||||
|
type Supplement = (Vec3<f32>, Vec3<f32>);
|
||||||
|
type TranslucentPipeline = ParticlePipeline;
|
||||||
|
|
||||||
|
#[allow(clippy::needless_range_loop)] // TODO: Pending review in #587
|
||||||
|
#[allow(clippy::or_fun_call)] // TODO: Pending review in #587
|
||||||
|
fn generate_mesh(
|
||||||
|
&'a self,
|
||||||
|
(offs, scale): Self::Supplement,
|
||||||
|
) -> (Mesh<Self::Pipeline>, Mesh<Self::TranslucentPipeline>) {
|
||||||
|
let mut mesh = Mesh::new();
|
||||||
|
|
||||||
|
let vol_iter = (self.lower_bound().x..self.upper_bound().x)
|
||||||
|
.map(|i| {
|
||||||
|
(self.lower_bound().y..self.upper_bound().y).map(move |j| {
|
||||||
|
(self.lower_bound().z..self.upper_bound().z).map(move |k| Vec3::new(i, j, k))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.flatten()
|
||||||
|
.map(|pos| (pos, self.get(pos).map(|x| *x).unwrap_or(Vox::empty())));
|
||||||
|
|
||||||
|
for (pos, vox) in vol_iter {
|
||||||
|
if let Some(col) = vox.get_color() {
|
||||||
|
vol::push_vox_verts(
|
||||||
|
&mut mesh,
|
||||||
|
faces_to_make(self, pos, true, |vox| vox.is_empty()),
|
||||||
|
offs + pos.map(|e| e as f32),
|
||||||
|
&[[[Rgba::from_opaque(col); 3]; 3]; 3],
|
||||||
|
|origin, norm, col, light, ao| {
|
||||||
|
ParticleVertex::new(
|
||||||
|
origin * scale,
|
||||||
|
norm,
|
||||||
|
linear_to_srgb(srgb_to_linear(col) * light),
|
||||||
|
ao,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
&{
|
||||||
|
let mut ls = [[[None; 3]; 3]; 3];
|
||||||
|
for x in 0..3 {
|
||||||
|
for y in 0..3 {
|
||||||
|
for z in 0..3 {
|
||||||
|
ls[z][y][x] = self
|
||||||
|
.get(pos + Vec3::new(x as i32, y as i32, z as i32) - 1)
|
||||||
|
.map(|v| v.is_empty())
|
||||||
|
.unwrap_or(true)
|
||||||
|
.then_some(1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ls
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(mesh, Mesh::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Use the 6 voxels/blocks surrounding the one at the specified position
|
/// Use the 6 voxels/blocks surrounding the one at the specified position
|
||||||
/// to detemine which faces should be drawn
|
/// to detemine which faces should be drawn
|
||||||
fn faces_to_make<V: ReadVol>(
|
fn faces_to_make<V: ReadVol>(
|
||||||
|
@ -22,6 +22,7 @@ pub use self::{
|
|||||||
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
|
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
|
||||||
},
|
},
|
||||||
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
|
||||||
|
particle::{Instance as ParticleInstance, ParticlePipeline},
|
||||||
sprite::{Instance as SpriteInstance, SpritePipeline},
|
sprite::{Instance as SpriteInstance, SpritePipeline},
|
||||||
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
terrain::{Locals as TerrainLocals, TerrainPipeline},
|
||||||
ui::{
|
ui::{
|
||||||
|
@ -2,6 +2,7 @@ use super::{
|
|||||||
super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt},
|
super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt},
|
||||||
Globals, Light, Shadow,
|
Globals, Light, Shadow,
|
||||||
};
|
};
|
||||||
|
use common::comp::visual::ParticleEmitterMode;
|
||||||
use gfx::{
|
use gfx::{
|
||||||
self, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner,
|
self, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner,
|
||||||
gfx_vertex_struct_meta,
|
gfx_vertex_struct_meta,
|
||||||
@ -26,7 +27,10 @@ gfx_defines! {
|
|||||||
inst_mat2: [f32; 4] = "inst_mat2",
|
inst_mat2: [f32; 4] = "inst_mat2",
|
||||||
inst_mat3: [f32; 4] = "inst_mat3",
|
inst_mat3: [f32; 4] = "inst_mat3",
|
||||||
inst_col: [f32; 3] = "inst_col",
|
inst_col: [f32; 3] = "inst_col",
|
||||||
|
inst_vel: [f32; 3] = "inst_vel",
|
||||||
|
inst_tick: [f32; 4] = "inst_tick",
|
||||||
inst_wind_sway: f32 = "inst_wind_sway",
|
inst_wind_sway: f32 = "inst_wind_sway",
|
||||||
|
mode: u8 = "mode",
|
||||||
}
|
}
|
||||||
|
|
||||||
pipeline pipe {
|
pipeline pipe {
|
||||||
@ -66,7 +70,14 @@ impl Vertex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
pub fn new(mat: Mat4<f32>, col: Rgb<f32>, wind_sway: f32) -> Self {
|
pub fn new(
|
||||||
|
mat: Mat4<f32>,
|
||||||
|
col: Rgb<f32>,
|
||||||
|
vel: Vec3<f32>,
|
||||||
|
tick: u64,
|
||||||
|
wind_sway: f32,
|
||||||
|
mode: ParticleEmitterMode,
|
||||||
|
) -> Self {
|
||||||
let mat_arr = mat.into_col_arrays();
|
let mat_arr = mat.into_col_arrays();
|
||||||
Self {
|
Self {
|
||||||
inst_mat0: mat_arr[0],
|
inst_mat0: mat_arr[0],
|
||||||
@ -74,13 +85,27 @@ impl Instance {
|
|||||||
inst_mat2: mat_arr[2],
|
inst_mat2: mat_arr[2],
|
||||||
inst_mat3: mat_arr[3],
|
inst_mat3: mat_arr[3],
|
||||||
inst_col: col.into_array(),
|
inst_col: col.into_array(),
|
||||||
|
inst_vel: vel.into_array(),
|
||||||
|
inst_tick: [tick as f32; 4],
|
||||||
|
|
||||||
inst_wind_sway: wind_sway,
|
inst_wind_sway: wind_sway,
|
||||||
|
|
||||||
|
mode: mode as u8,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Instance {
|
impl Default for Instance {
|
||||||
fn default() -> Self { Self::new(Mat4::identity(), Rgb::broadcast(1.0), 0.0) }
|
fn default() -> Self {
|
||||||
|
Self::new(
|
||||||
|
Mat4::identity(),
|
||||||
|
Rgb::broadcast(1.0),
|
||||||
|
Vec3::zero(),
|
||||||
|
0,
|
||||||
|
0.0,
|
||||||
|
ParticleEmitterMode::Sprinkler,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ParticlePipeline;
|
pub struct ParticlePipeline;
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
|
pub mod particle;
|
||||||
pub mod simple;
|
pub mod simple;
|
||||||
pub mod terrain;
|
pub mod terrain;
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
camera::{Camera, CameraMode},
|
camera::{Camera, CameraMode},
|
||||||
figure::FigureMgr,
|
figure::FigureMgr,
|
||||||
|
particle::ParticleMgr,
|
||||||
terrain::Terrain,
|
terrain::Terrain,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -62,6 +64,7 @@ pub struct Scene {
|
|||||||
loaded_distance: f32,
|
loaded_distance: f32,
|
||||||
select_pos: Option<Vec3<i32>>,
|
select_pos: Option<Vec3<i32>>,
|
||||||
|
|
||||||
|
particle_mgr: ParticleMgr,
|
||||||
figure_mgr: FigureMgr,
|
figure_mgr: FigureMgr,
|
||||||
sfx_mgr: SfxMgr,
|
sfx_mgr: SfxMgr,
|
||||||
music_mgr: MusicMgr,
|
music_mgr: MusicMgr,
|
||||||
@ -113,6 +116,7 @@ impl Scene {
|
|||||||
loaded_distance: 0.0,
|
loaded_distance: 0.0,
|
||||||
select_pos: None,
|
select_pos: None,
|
||||||
|
|
||||||
|
particle_mgr: ParticleMgr::new(renderer),
|
||||||
figure_mgr: FigureMgr::new(),
|
figure_mgr: FigureMgr::new(),
|
||||||
sfx_mgr: SfxMgr::new(),
|
sfx_mgr: SfxMgr::new(),
|
||||||
music_mgr: MusicMgr::new(),
|
music_mgr: MusicMgr::new(),
|
||||||
@ -128,6 +132,9 @@ impl Scene {
|
|||||||
/// Get a reference to the scene's terrain.
|
/// Get a reference to the scene's terrain.
|
||||||
pub fn terrain(&self) -> &Terrain<TerrainChunk> { &self.terrain }
|
pub fn terrain(&self) -> &Terrain<TerrainChunk> { &self.terrain }
|
||||||
|
|
||||||
|
/// Get a reference to the scene's particle manager.
|
||||||
|
pub fn particle_mgr(&self) -> &ParticleMgr { &self.particle_mgr }
|
||||||
|
|
||||||
/// Get a reference to the scene's figure manager.
|
/// Get a reference to the scene's figure manager.
|
||||||
pub fn figure_mgr(&self) -> &FigureMgr { &self.figure_mgr }
|
pub fn figure_mgr(&self) -> &FigureMgr { &self.figure_mgr }
|
||||||
|
|
||||||
@ -390,6 +397,16 @@ impl Scene {
|
|||||||
// Remove unused figures.
|
// Remove unused figures.
|
||||||
self.figure_mgr.clean(scene_data.tick);
|
self.figure_mgr.clean(scene_data.tick);
|
||||||
|
|
||||||
|
// Maintain the particles.
|
||||||
|
self.particle_mgr.maintain(
|
||||||
|
renderer,
|
||||||
|
&scene_data,
|
||||||
|
self.camera.get_focus_pos(),
|
||||||
|
self.loaded_distance,
|
||||||
|
view_mat,
|
||||||
|
proj_mat,
|
||||||
|
);
|
||||||
|
|
||||||
// Maintain audio
|
// Maintain audio
|
||||||
self.sfx_mgr
|
self.sfx_mgr
|
||||||
.maintain(audio, scene_data.state, scene_data.player_entity);
|
.maintain(audio, scene_data.state, scene_data.player_entity);
|
||||||
@ -425,6 +442,14 @@ impl Scene {
|
|||||||
scene_data.figure_lod_render_distance,
|
scene_data.figure_lod_render_distance,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.particle_mgr.render(
|
||||||
|
renderer,
|
||||||
|
&self.globals,
|
||||||
|
&self.lights,
|
||||||
|
&self.shadows,
|
||||||
|
self.camera.get_focus_pos(),
|
||||||
|
);
|
||||||
|
|
||||||
// Render the skybox.
|
// Render the skybox.
|
||||||
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
renderer.render_skybox(&self.skybox.model, &self.globals, &self.skybox.locals);
|
||||||
|
|
||||||
|
170
voxygen/src/scene/particle.rs
Normal file
170
voxygen/src/scene/particle.rs
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
use super::SceneData;
|
||||||
|
use crate::{
|
||||||
|
mesh::Meshable,
|
||||||
|
render::{
|
||||||
|
mesh::Quad, Consts, Globals, Instances, Light, Mesh, Model, ParticleInstance,
|
||||||
|
ParticlePipeline, Renderer, Shadow,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use common::{
|
||||||
|
assets,
|
||||||
|
comp::{visual::ParticleEmitterMode, Ori, ParticleEmitter, Pos, Vel},
|
||||||
|
figure::Segment,
|
||||||
|
vol::BaseVol,
|
||||||
|
};
|
||||||
|
use dot_vox::DotVoxData;
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use rand::Rng;
|
||||||
|
use specs::{Entity as EcsEntity, Join, WorldExt};
|
||||||
|
use tracing::{debug, error, warn};
|
||||||
|
use vek::{Mat4, Rgb, Vec3};
|
||||||
|
struct Particles {
|
||||||
|
// this is probably nieve,
|
||||||
|
// could cache and re-use between particles,
|
||||||
|
// should be a cache key?
|
||||||
|
// model: Model<ParticlePipeline>,
|
||||||
|
instances: Instances<ParticleInstance>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ParticleMgr {
|
||||||
|
entity_particles: HashMap<EcsEntity, Vec<Particles>>,
|
||||||
|
model_cache: Model<ParticlePipeline>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParticleMgr {
|
||||||
|
pub fn new(renderer: &mut Renderer) -> Self {
|
||||||
|
let offset = Vec3::zero();
|
||||||
|
let lod_scale = Vec3::one();
|
||||||
|
|
||||||
|
// TODO: from cache
|
||||||
|
let vox = assets::load_expect::<DotVoxData>("voxygen.voxel.not_found");
|
||||||
|
|
||||||
|
// TODO: from cache
|
||||||
|
let mesh = &Meshable::<ParticlePipeline, ParticlePipeline>::generate_mesh(
|
||||||
|
&Segment::from(vox.as_ref()),
|
||||||
|
(offset * lod_scale, Vec3::one() / lod_scale),
|
||||||
|
)
|
||||||
|
.0;
|
||||||
|
|
||||||
|
// TODO: from cache
|
||||||
|
let model = renderer
|
||||||
|
.create_model(mesh)
|
||||||
|
.expect("Failed to create particle model");
|
||||||
|
|
||||||
|
Self {
|
||||||
|
entity_particles: HashMap::new(),
|
||||||
|
model_cache: model,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn maintain(
|
||||||
|
&mut self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
scene_data: &SceneData,
|
||||||
|
focus_pos: Vec3<f32>,
|
||||||
|
loaded_distance: f32,
|
||||||
|
view_mat: Mat4<f32>,
|
||||||
|
proj_mat: Mat4<f32>,
|
||||||
|
) {
|
||||||
|
let state = scene_data.state;
|
||||||
|
let ecs = state.ecs();
|
||||||
|
|
||||||
|
let tick = scene_data.tick;
|
||||||
|
|
||||||
|
// remove dead particles
|
||||||
|
|
||||||
|
// remove dead entities, with dead particles
|
||||||
|
self.entity_particles.retain(|k, v| ecs.is_alive(*k));
|
||||||
|
|
||||||
|
// add living entities particles
|
||||||
|
for (_i, (entity, particle_emitter, pos, ori, vel)) in (
|
||||||
|
&ecs.entities(),
|
||||||
|
&ecs.read_storage::<ParticleEmitter>(),
|
||||||
|
&ecs.read_storage::<Pos>(),
|
||||||
|
ecs.read_storage::<Ori>().maybe(),
|
||||||
|
ecs.read_storage::<Vel>().maybe(),
|
||||||
|
)
|
||||||
|
.join()
|
||||||
|
.enumerate()
|
||||||
|
{
|
||||||
|
let entry = self
|
||||||
|
.entity_particles
|
||||||
|
.entry(entity)
|
||||||
|
.or_insert_with(|| into_particles(renderer, tick, particle_emitter, pos, ori, vel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(
|
||||||
|
&self,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
globals: &Consts<Globals>,
|
||||||
|
lights: &Consts<Light>,
|
||||||
|
shadows: &Consts<Shadow>,
|
||||||
|
focus_pos: Vec3<f32>,
|
||||||
|
) {
|
||||||
|
for particles in self.entity_particles.values() {
|
||||||
|
for particle in particles {
|
||||||
|
renderer.render_particles(
|
||||||
|
&self.model_cache,
|
||||||
|
globals,
|
||||||
|
&particle.instances,
|
||||||
|
lights,
|
||||||
|
shadows,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn into_particles(
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
tick: u64,
|
||||||
|
particle_emitter: &ParticleEmitter,
|
||||||
|
pos: &Pos,
|
||||||
|
ori: Option<&Ori>,
|
||||||
|
vel: Option<&Vel>,
|
||||||
|
) -> Vec<Particles> {
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
|
||||||
|
let desired_instance_count = 100;
|
||||||
|
|
||||||
|
// let ori_default = Ori::default();
|
||||||
|
let vel_default = Vel::default();
|
||||||
|
|
||||||
|
// let ori2 = ori.unwrap_or_else(|| &ori_default);
|
||||||
|
let vel2 = vel.unwrap_or_else(|| &vel_default).0;
|
||||||
|
let mut instances_vec = Vec::new();
|
||||||
|
|
||||||
|
for x in 0..desired_instance_count {
|
||||||
|
// how does ParticleEmitterMode fit in here?
|
||||||
|
// can we have a ParticleInstance type per ParticleEmitterMode?
|
||||||
|
// can we mix and match instance types in the same instances_vec?
|
||||||
|
instances_vec.push(ParticleInstance::new(
|
||||||
|
Mat4::identity()
|
||||||
|
// initial rotation
|
||||||
|
.rotated_x(rng.gen_range(0.0, 3.14 * 2.0))
|
||||||
|
.rotated_y(rng.gen_range(0.0, 3.14 * 2.0))
|
||||||
|
.rotated_z(rng.gen_range(0.0, 3.14 * 2.0))
|
||||||
|
// inition position
|
||||||
|
.translated_3d(
|
||||||
|
pos.0
|
||||||
|
+ Vec3::new(
|
||||||
|
rng.gen_range(-5.0, 5.0),
|
||||||
|
rng.gen_range(-5.0, 5.0),
|
||||||
|
rng.gen_range(0.0, 10.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Rgb::broadcast(1.0), // instance color
|
||||||
|
vel2 + Vec3::broadcast(rng.gen_range(-5.0, 5.0)),
|
||||||
|
tick,
|
||||||
|
rng.gen_range(0.0, 20.0), // wind sway
|
||||||
|
ParticleEmitterMode::Sprinkler, // particle_emitter.mode */
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
let instances = renderer
|
||||||
|
.create_instances(&instances_vec)
|
||||||
|
.expect("Failed to upload particle instances to the GPU!");
|
||||||
|
|
||||||
|
vec![Particles { instances }]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user