mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add particle pipeline
This commit is contained in:
parent
42a10a6059
commit
7e35617f59
@ -17,6 +17,7 @@ uniform u_globals {
|
||||
// 1 - ThirdPerson
|
||||
uint cam_mode;
|
||||
float sprite_render_distance;
|
||||
float particle_render_distance;
|
||||
};
|
||||
|
||||
// Specifies the pattern used in the player dithering
|
||||
|
38
assets/voxygen/shaders/particle-frag.glsl
Normal file
38
assets/voxygen/shaders/particle-frag.glsl
Normal file
@ -0,0 +1,38 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
|
||||
in vec3 f_pos;
|
||||
flat in vec3 f_norm;
|
||||
in vec3 f_col;
|
||||
in float f_ao;
|
||||
in float f_light;
|
||||
|
||||
out vec4 tgt_color;
|
||||
|
||||
#include <sky.glsl>
|
||||
#include <light.glsl>
|
||||
|
||||
const float FADE_DIST = 32.0;
|
||||
|
||||
void main() {
|
||||
vec3 light, diffuse_light, ambient_light;
|
||||
get_sun_diffuse(f_norm, time_of_day.x, light, diffuse_light, ambient_light, 1.0);
|
||||
float point_shadow = shadow_at(f_pos, f_norm);
|
||||
diffuse_light *= f_light * point_shadow;
|
||||
ambient_light *= f_light, point_shadow;
|
||||
vec3 point_light = light_at(f_pos, f_norm);
|
||||
light += point_light;
|
||||
diffuse_light += point_light;
|
||||
float ao = pow(f_ao, 0.5) * 0.85 + 0.15;
|
||||
ambient_light *= ao;
|
||||
diffuse_light *= ao;
|
||||
vec3 surf_color = illuminate(f_col, light, diffuse_light, ambient_light);
|
||||
|
||||
float fog_level = fog(f_pos.xyz, focus_pos.xyz, medium.x);
|
||||
vec4 clouds;
|
||||
vec3 fog_color = get_sky_color(normalize(f_pos - cam_pos.xyz), time_of_day.x, cam_pos.xyz, f_pos, 0.5, true, clouds);
|
||||
vec3 color = mix(mix(surf_color, fog_color, fog_level), clouds.rgb, clouds.a);
|
||||
|
||||
tgt_color = vec4(color, 1.0 - clamp((distance(focus_pos.xy, f_pos.xy) - (particle_render_distance - FADE_DIST)) / FADE_DIST, 0, 1));
|
||||
}
|
62
assets/voxygen/shaders/particle-vert.glsl
Normal file
62
assets/voxygen/shaders/particle-vert.glsl
Normal file
@ -0,0 +1,62 @@
|
||||
#version 330 core
|
||||
|
||||
#include <globals.glsl>
|
||||
#include <srgb.glsl>
|
||||
|
||||
in vec3 v_pos;
|
||||
in uint v_col;
|
||||
in uint v_norm_ao;
|
||||
in vec4 inst_mat0;
|
||||
in vec4 inst_mat1;
|
||||
in vec4 inst_mat2;
|
||||
in vec4 inst_mat3;
|
||||
in vec3 inst_col;
|
||||
in float inst_wind_sway;
|
||||
|
||||
out vec3 f_pos;
|
||||
flat out vec3 f_norm;
|
||||
out vec3 f_col;
|
||||
out float f_ao;
|
||||
out float f_light;
|
||||
|
||||
const float SCALE = 1.0 / 11.0;
|
||||
|
||||
void main() {
|
||||
mat4 inst_mat;
|
||||
inst_mat[0] = inst_mat0;
|
||||
inst_mat[1] = inst_mat1;
|
||||
inst_mat[2] = inst_mat2;
|
||||
inst_mat[3] = inst_mat3;
|
||||
|
||||
vec3 particle_pos = (inst_mat * vec4(0, 0, 0, 1)).xyz;
|
||||
|
||||
f_pos = (inst_mat * vec4(v_pos * SCALE, 1)).xyz;
|
||||
f_pos.z -= 25.0 * pow(distance(focus_pos.xy, f_pos.xy) / view_distance.x, 20.0);
|
||||
|
||||
// Wind waving
|
||||
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.x * 0.1) * sin(tick.x * 0.25),
|
||||
0.0
|
||||
) * pow(abs(v_pos.z) * SCALE, 1.3) * 0.2;
|
||||
|
||||
// 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 = (inst_mat * vec4(normals[(v_norm_ao >> 0) & 0x7u], 0)).xyz;
|
||||
|
||||
vec3 col = vec3((uvec3(v_col) >> uvec3(0, 8, 16)) & uvec3(0xFFu)) / 255.0;
|
||||
f_col = srgb_to_linear(col) * srgb_to_linear(inst_col);
|
||||
f_ao = float((v_norm_ao >> 3) & 0x3u) / 4.0;
|
||||
|
||||
// Select glowing
|
||||
if (select_pos.w > 0 && select_pos.xyz == floor(particle_pos)) {
|
||||
f_col *= 4.0;
|
||||
}
|
||||
|
||||
f_light = 1.0;
|
||||
|
||||
gl_Position =
|
||||
all_mat *
|
||||
vec4(f_pos, 1);
|
||||
gl_Position.z = -1000.0 / (gl_Position.z + 10000.0);
|
||||
}
|
@ -266,6 +266,7 @@ pub enum Event {
|
||||
ToggleSmoothPan(bool),
|
||||
AdjustViewDistance(u32),
|
||||
AdjustSpriteRenderDistance(u32),
|
||||
AdjustParticleRenderDistance(u32),
|
||||
AdjustFigureLoDRenderDistance(u32),
|
||||
AdjustMusicVolume(f32),
|
||||
AdjustSfxVolume(f32),
|
||||
|
@ -1845,6 +1845,7 @@ impl<'a> Widget for SettingsWindow<'a> {
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.sprite_dist_text, ui);
|
||||
|
||||
|
||||
Text::new(&format!(
|
||||
"{}",
|
||||
self.global_state.settings.graphics.sprite_render_distance
|
||||
@ -1898,6 +1899,8 @@ impl<'a> Widget for SettingsWindow<'a> {
|
||||
.color(TEXT_COLOR)
|
||||
.set(state.ids.figure_dist_value, ui);
|
||||
|
||||
// TODO: Particle View Distance slider.
|
||||
|
||||
// AaMode
|
||||
Text::new(&self.localized_strings.get("hud.settings.antialiasing_mode"))
|
||||
.down_from(state.ids.gamma_slider, 8.0)
|
||||
|
@ -3,6 +3,7 @@ pub mod fluid;
|
||||
pub mod postprocess;
|
||||
pub mod skybox;
|
||||
pub mod sprite;
|
||||
pub mod particle;
|
||||
pub mod terrain;
|
||||
pub mod ui;
|
||||
|
||||
@ -29,6 +30,7 @@ gfx_defines! {
|
||||
gamma: [f32; 4] = "gamma",
|
||||
cam_mode: u32 = "cam_mode",
|
||||
sprite_render_distance: f32 = "sprite_render_distance",
|
||||
particle_render_distance: f32 = "particle_render_distance",
|
||||
}
|
||||
|
||||
constant Light {
|
||||
@ -61,6 +63,7 @@ impl Globals {
|
||||
gamma: f32,
|
||||
cam_mode: CameraMode,
|
||||
sprite_render_distance: f32,
|
||||
particle_render_distance: f32,
|
||||
) -> Self {
|
||||
Self {
|
||||
view_mat: view_mat.into_col_arrays(),
|
||||
@ -81,6 +84,7 @@ impl Globals {
|
||||
gamma: [gamma; 4],
|
||||
cam_mode: cam_mode as u32,
|
||||
sprite_render_distance,
|
||||
particle_render_distance,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -103,6 +107,7 @@ impl Default for Globals {
|
||||
1.0,
|
||||
CameraMode::ThirdPerson,
|
||||
250.0,
|
||||
250.0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
90
voxygen/src/render/pipelines/particle.rs
Normal file
90
voxygen/src/render/pipelines/particle.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use super::{
|
||||
super::{Pipeline, TgtColorFmt, TgtDepthStencilFmt},
|
||||
Globals, Light, Shadow,
|
||||
};
|
||||
use gfx::{
|
||||
self, gfx_defines, gfx_impl_struct_meta, gfx_pipeline, gfx_pipeline_inner,
|
||||
gfx_vertex_struct_meta,
|
||||
state::{ColorMask, Comparison, Stencil, StencilOp},
|
||||
};
|
||||
use vek::*;
|
||||
|
||||
gfx_defines! {
|
||||
vertex Vertex {
|
||||
pos: [f32; 3] = "v_pos",
|
||||
// ____BBBBBBBBGGGGGGGGRRRRRRRR
|
||||
col: u32 = "v_col",
|
||||
// ...AANNN
|
||||
// A = AO
|
||||
// N = Normal
|
||||
norm_ao: u32 = "v_norm_ao",
|
||||
}
|
||||
|
||||
vertex Instance {
|
||||
inst_mat0: [f32; 4] = "inst_mat0",
|
||||
inst_mat1: [f32; 4] = "inst_mat1",
|
||||
inst_mat2: [f32; 4] = "inst_mat2",
|
||||
inst_mat3: [f32; 4] = "inst_mat3",
|
||||
inst_col: [f32; 3] = "inst_col",
|
||||
inst_wind_sway: f32 = "inst_wind_sway",
|
||||
}
|
||||
|
||||
pipeline pipe {
|
||||
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||
ibuf: gfx::InstanceBuffer<Instance> = (),
|
||||
|
||||
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||
lights: gfx::ConstantBuffer<Light> = "u_lights",
|
||||
shadows: gfx::ConstantBuffer<Shadow> = "u_shadows",
|
||||
|
||||
noise: gfx::TextureSampler<f32> = "t_noise",
|
||||
|
||||
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", ColorMask::all(), gfx::preset::blend::ALPHA),
|
||||
tgt_depth_stencil: gfx::DepthStencilTarget<TgtDepthStencilFmt> = (gfx::preset::depth::LESS_EQUAL_WRITE,Stencil::new(Comparison::Always,0xff,(StencilOp::Keep,StencilOp::Keep,StencilOp::Keep))),
|
||||
}
|
||||
}
|
||||
|
||||
impl Vertex {
|
||||
#[allow(clippy::collapsible_if)]
|
||||
pub fn new(pos: Vec3<f32>, norm: Vec3<f32>, col: Rgb<f32>, ao: f32) -> Self {
|
||||
let norm_bits = if norm.x != 0.0 {
|
||||
if norm.x < 0.0 { 0 } else { 1 }
|
||||
} else if norm.y != 0.0 {
|
||||
if norm.y < 0.0 { 2 } else { 3 }
|
||||
} else {
|
||||
if norm.z < 0.0 { 4 } else { 5 }
|
||||
};
|
||||
|
||||
Self {
|
||||
pos: pos.into_array(),
|
||||
col: col
|
||||
.map2(Rgb::new(0, 8, 16), |e, shift| ((e * 255.0) as u32) << shift)
|
||||
.reduce_bitor(),
|
||||
norm_ao: norm_bits | (((ao * 3.9999) as u32) << 3),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn new(mat: Mat4<f32>, col: Rgb<f32>, wind_sway: f32) -> Self {
|
||||
let mat_arr = mat.into_col_arrays();
|
||||
Self {
|
||||
inst_mat0: mat_arr[0],
|
||||
inst_mat1: mat_arr[1],
|
||||
inst_mat2: mat_arr[2],
|
||||
inst_mat3: mat_arr[3],
|
||||
inst_col: col.into_array(),
|
||||
inst_wind_sway: wind_sway,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Instance {
|
||||
fn default() -> Self { Self::new(Mat4::identity(), Rgb::broadcast(1.0), 0.0) }
|
||||
}
|
||||
|
||||
pub struct ParticlePipeline;
|
||||
|
||||
impl Pipeline for ParticlePipeline {
|
||||
type Vertex = Vertex;
|
||||
}
|
@ -4,7 +4,7 @@ use super::{
|
||||
instances::Instances,
|
||||
mesh::Mesh,
|
||||
model::{DynamicModel, Model},
|
||||
pipelines::{figure, fluid, postprocess, skybox, sprite, terrain, ui, Globals, Light, Shadow},
|
||||
pipelines::{figure, fluid, postprocess, skybox, sprite, particle, terrain, ui, Globals, Light, Shadow},
|
||||
texture::Texture,
|
||||
AaMode, CloudMode, FluidMode, Pipeline, RenderError,
|
||||
};
|
||||
@ -70,6 +70,7 @@ pub struct Renderer {
|
||||
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
|
||||
fluid_pipeline: GfxPipeline<fluid::pipe::Init<'static>>,
|
||||
sprite_pipeline: GfxPipeline<sprite::pipe::Init<'static>>,
|
||||
particle_pipeline: GfxPipeline<particle::pipe::Init<'static>>,
|
||||
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
|
||||
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||
player_shadow_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
|
||||
@ -103,6 +104,7 @@ impl Renderer {
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
player_shadow_pipeline,
|
||||
@ -146,6 +148,7 @@ impl Renderer {
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
player_shadow_pipeline,
|
||||
@ -341,6 +344,7 @@ impl Renderer {
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
player_shadow_pipeline,
|
||||
@ -350,6 +354,7 @@ impl Renderer {
|
||||
self.terrain_pipeline = terrain_pipeline;
|
||||
self.fluid_pipeline = fluid_pipeline;
|
||||
self.sprite_pipeline = sprite_pipeline;
|
||||
self.particle_pipeline = particle_pipeline;
|
||||
self.ui_pipeline = ui_pipeline;
|
||||
self.postprocess_pipeline = postprocess_pipeline;
|
||||
self.player_shadow_pipeline = player_shadow_pipeline;
|
||||
@ -711,6 +716,37 @@ impl Renderer {
|
||||
);
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided particle in the upcoming frame.
|
||||
pub fn render_particles(
|
||||
&mut self,
|
||||
model: &Model<particle::ParticlePipeline>,
|
||||
globals: &Consts<Globals>,
|
||||
instances: &Instances<particle::Instance>,
|
||||
lights: &Consts<Light>,
|
||||
shadows: &Consts<Shadow>,
|
||||
) {
|
||||
self.encoder.draw(
|
||||
&gfx::Slice {
|
||||
start: model.vertex_range().start,
|
||||
end: model.vertex_range().end,
|
||||
base_vertex: 0,
|
||||
instances: Some((instances.count() as u32, 0)),
|
||||
buffer: gfx::IndexBuffer::Auto,
|
||||
},
|
||||
&self.particle_pipeline.pso,
|
||||
&particle::pipe::Data {
|
||||
vbuf: model.vbuf.clone(),
|
||||
ibuf: instances.ibuf.clone(),
|
||||
globals: globals.buf.clone(),
|
||||
lights: lights.buf.clone(),
|
||||
shadows: shadows.buf.clone(),
|
||||
noise: (self.noise_tex.srv.clone(), self.noise_tex.sampler.clone()),
|
||||
tgt_color: self.tgt_color_view.clone(),
|
||||
tgt_depth_stencil: (self.tgt_depth_stencil_view.clone(), (1, 1)),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Queue the rendering of the provided UI element in the upcoming frame.
|
||||
pub fn render_ui_element(
|
||||
&mut self,
|
||||
@ -793,6 +829,7 @@ fn create_pipelines(
|
||||
GfxPipeline<terrain::pipe::Init<'static>>,
|
||||
GfxPipeline<fluid::pipe::Init<'static>>,
|
||||
GfxPipeline<sprite::pipe::Init<'static>>,
|
||||
GfxPipeline<particle::pipe::Init<'static>>,
|
||||
GfxPipeline<ui::pipe::Init<'static>>,
|
||||
GfxPipeline<postprocess::pipe::Init<'static>>,
|
||||
GfxPipeline<figure::pipe::Init<'static>>,
|
||||
@ -914,6 +951,18 @@ fn create_pipelines(
|
||||
gfx::state::CullFace::Back,
|
||||
)?;
|
||||
|
||||
// Construct a pipeline for rendering particles
|
||||
let particle_pipeline = create_pipeline(
|
||||
factory,
|
||||
particle::pipe::new(),
|
||||
&assets::load_watched::<String>("voxygen.shaders.particle-vert", shader_reload_indicator)
|
||||
.unwrap(),
|
||||
&assets::load_watched::<String>("voxygen.shaders.particle-frag", shader_reload_indicator)
|
||||
.unwrap(),
|
||||
&include_ctx,
|
||||
gfx::state::CullFace::Back,
|
||||
)?;
|
||||
|
||||
// Construct a pipeline for rendering UI elements
|
||||
let ui_pipeline = create_pipeline(
|
||||
factory,
|
||||
@ -975,6 +1024,7 @@ fn create_pipelines(
|
||||
terrain_pipeline,
|
||||
fluid_pipeline,
|
||||
sprite_pipeline,
|
||||
particle_pipeline,
|
||||
ui_pipeline,
|
||||
postprocess_pipeline,
|
||||
player_shadow_pipeline,
|
||||
|
@ -78,6 +78,7 @@ pub struct SceneData<'a> {
|
||||
pub gamma: f32,
|
||||
pub mouse_smoothing: bool,
|
||||
pub sprite_render_distance: f32,
|
||||
pub particle_render_distance: f32,
|
||||
pub figure_lod_render_distance: f32,
|
||||
pub is_aiming: bool,
|
||||
}
|
||||
@ -369,6 +370,7 @@ impl Scene {
|
||||
scene_data.gamma,
|
||||
self.camera.get_mode(),
|
||||
scene_data.sprite_render_distance as f32 - 20.0,
|
||||
scene_data.particle_render_distance as f32 - 20.0,
|
||||
)])
|
||||
.expect("Failed to update global constants");
|
||||
|
||||
|
@ -190,6 +190,7 @@ impl Scene {
|
||||
scene_data.gamma,
|
||||
self.camera.get_mode(),
|
||||
250.0,
|
||||
250.0,
|
||||
)]) {
|
||||
error!(?e, "Renderer failed to update");
|
||||
}
|
||||
|
@ -785,6 +785,11 @@ impl PlayState for SessionState {
|
||||
sprite_render_distance;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
HudEvent::AdjustParticleRenderDistance(particle_render_distance) => {
|
||||
global_state.settings.graphics.particle_render_distance =
|
||||
particle_render_distance;
|
||||
global_state.settings.save_to_file_warn();
|
||||
},
|
||||
HudEvent::AdjustFigureLoDRenderDistance(figure_lod_render_distance) => {
|
||||
global_state.settings.graphics.figure_lod_render_distance =
|
||||
figure_lod_render_distance;
|
||||
@ -997,7 +1002,9 @@ impl PlayState for SessionState {
|
||||
gamma: global_state.settings.graphics.gamma,
|
||||
mouse_smoothing: global_state.settings.gameplay.smooth_pan_enable,
|
||||
sprite_render_distance: global_state.settings.graphics.sprite_render_distance
|
||||
as f32,
|
||||
as f32,
|
||||
particle_render_distance: global_state.settings.graphics.particle_render_distance
|
||||
as f32,
|
||||
figure_lod_render_distance: global_state
|
||||
.settings
|
||||
.graphics
|
||||
|
@ -603,6 +603,7 @@ impl Default for Log {
|
||||
pub struct GraphicsSettings {
|
||||
pub view_distance: u32,
|
||||
pub sprite_render_distance: u32,
|
||||
pub particle_render_distance: u32,
|
||||
pub figure_lod_render_distance: u32,
|
||||
pub max_fps: u32,
|
||||
pub fov: u16,
|
||||
@ -619,6 +620,7 @@ impl Default for GraphicsSettings {
|
||||
Self {
|
||||
view_distance: 10,
|
||||
sprite_render_distance: 150,
|
||||
particle_render_distance: 150,
|
||||
figure_lod_render_distance: 250,
|
||||
max_fps: 60,
|
||||
fov: 50,
|
||||
|
Loading…
Reference in New Issue
Block a user