Add post-process pipeline

Former-commit-id: aed1fff25f7fd95fe040b0877011cbe57e77eba3
This commit is contained in:
robojumper 2019-05-06 10:22:47 +02:00
parent 370ec5cbd6
commit 821ab80c5b
8 changed files with 255 additions and 10 deletions

View File

@ -0,0 +1,30 @@
#version 330 core
uniform sampler2D src_color;
in vec2 f_pos;
layout (std140)
uniform u_locals {
vec4 nul;
};
layout (std140)
uniform u_globals {
mat4 view_mat;
mat4 proj_mat;
vec4 cam_pos;
vec4 focus_pos;
vec4 view_distance;
vec4 time_of_day;
vec4 tick;
};
out vec4 tgt_color;
void main() {
// Uncomment to invert colors
//tgt_color = vec4(vec3(1.0, 1.0, 1.0) - texture2D(src_color, (f_pos + 1.0) / 2.0).xyz, 1.0);
tgt_color = texture2D(src_color, (f_pos + 1.0) / 2.0);
}

View File

@ -0,0 +1,27 @@
#version 330 core
in vec2 v_pos;
layout (std140)
uniform u_locals {
vec4 nul;
};
layout (std140)
uniform u_globals {
mat4 view_mat;
mat4 proj_mat;
vec4 cam_pos;
vec4 focus_pos;
vec4 view_distance;
vec4 time_of_day;
vec4 tick;
};
out vec2 f_pos;
void main() {
f_pos = v_pos;
gl_Position = vec4(v_pos, 0.0, 1.0);
}

View File

@ -13,6 +13,9 @@ pub use self::{
model::Model,
pipelines::{
figure::{BoneData as FigureBoneData, FigurePipeline, Locals as FigureLocals},
postprocess::{
create_mesh as create_pp_mesh, Locals as PostProcessLocals, PostProcessPipeline,
},
skybox::{create_mesh as create_skybox_mesh, Locals as SkyboxLocals, SkyboxPipeline},
terrain::{Locals as TerrainLocals, TerrainPipeline},
ui::{

View File

@ -1,4 +1,5 @@
pub mod figure;
pub mod postprocess;
pub mod skybox;
pub mod terrain;
pub mod ui;

View File

@ -0,0 +1,71 @@
// Library
use gfx::{
self,
gfx_constant_struct_meta,
// Macros
gfx_defines,
gfx_impl_struct_meta,
gfx_pipeline,
gfx_pipeline_inner,
gfx_vertex_struct_meta,
};
// Local
use super::{
super::{Mesh, Pipeline, TgtColorFmt, TgtDepthFmt, Tri},
Globals,
};
gfx_defines! {
vertex Vertex {
pos: [f32; 2] = "v_pos",
}
constant Locals {
nul: [f32; 4] = "nul",
}
pipeline pipe {
vbuf: gfx::VertexBuffer<Vertex> = (),
locals: gfx::ConstantBuffer<Locals> = "u_locals",
globals: gfx::ConstantBuffer<Globals> = "u_globals",
src_sampler: gfx::TextureSampler<<TgtColorFmt as gfx::format::Formatted>::View> = "src_color",
tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
}
}
impl Locals {
pub fn default() -> Self {
Self { nul: [0.0; 4] }
}
}
pub struct PostProcessPipeline;
impl Pipeline for PostProcessPipeline {
type Vertex = Vertex;
}
pub fn create_mesh() -> Mesh<PostProcessPipeline> {
let mut mesh = Mesh::new();
#[rustfmt::skip]
mesh.push_tri(Tri::new(
Vertex { pos: [ 1.0, -1.0] },
Vertex { pos: [-1.0, 1.0] },
Vertex { pos: [-1.0, -1.0] },
));
#[rustfmt::skip]
mesh.push_tri(Tri::new(
Vertex { pos: [1.0, -1.0] },
Vertex { pos: [1.0, 1.0] },
Vertex { pos: [-1.0, 1.0] },
));
mesh
}

View File

@ -3,13 +3,14 @@ use super::{
gfx_backend,
mesh::Mesh,
model::Model,
pipelines::{figure, skybox, terrain, ui, Globals},
pipelines::{figure, postprocess, skybox, terrain, ui, Globals},
texture::Texture,
Pipeline, RenderError,
};
use gfx::{
self,
traits::{Device, FactoryExt},
handle::Sampler,
traits::{Device, Factory, FactoryExt},
};
use image;
use vek::*;
@ -24,6 +25,12 @@ pub type TgtColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, Tg
/// A handle to a window depth target.
pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, TgtDepthFmt>;
/// A handle to a render color target as a resource.
pub type TgtColorRes = gfx::handle::ShaderResourceView<
gfx_backend::Resources,
<TgtColorFmt as gfx::format::Formatted>::View,
>;
/// A type that encapsulates rendering state. `Renderer` is central to Voxygen's rendering
/// subsystem and contains any state necessary to interact with the GPU, along with pipeline state
/// objects (PSOs) needed to renderer different kinds of models to the screen.
@ -32,13 +39,21 @@ pub struct Renderer {
encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
factory: gfx_backend::Factory,
win_color_view: TgtColorView,
win_depth_view: TgtDepthView,
tgt_color_view: TgtColorView,
tgt_depth_view: TgtDepthView,
tgt_color_res: TgtColorRes,
sampler: Sampler<gfx_backend::Resources>,
skybox_pipeline: GfxPipeline<skybox::pipe::Init<'static>>,
figure_pipeline: GfxPipeline<figure::pipe::Init<'static>>,
terrain_pipeline: GfxPipeline<terrain::pipe::Init<'static>>,
ui_pipeline: GfxPipeline<ui::pipe::Init<'static>>,
postprocess_pipeline: GfxPipeline<postprocess::pipe::Init<'static>>,
}
impl Renderer {
@ -47,8 +62,8 @@ impl Renderer {
pub fn new(
device: gfx_backend::Device,
mut factory: gfx_backend::Factory,
tgt_color_view: TgtColorView,
tgt_depth_view: TgtDepthView,
win_color_view: TgtColorView,
win_depth_view: TgtDepthView,
) -> Result<Self, RenderError> {
// Construct a pipeline for rendering skyboxes
let skybox_pipeline = create_pipeline(
@ -82,29 +97,86 @@ impl Renderer {
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/shaders/ui.frag")),
)?;
// Construct a pipeline for rendering our post-processing
let postprocess_pipeline = create_pipeline(
&mut factory,
postprocess::pipe::new(),
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/shaders/postprocess.vert"
)),
include_bytes!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/shaders/postprocess.frag"
)),
)?;
let dims = win_color_view.get_dimensions();
let d_dims = win_depth_view.get_dimensions();
let (_, tgt_color_res, tgt_color_view) = factory
.create_render_target::<TgtColorFmt>(dims.0, dims.1)
.map_err(RenderError::CombinedError)?;
let (_, _, tgt_depth_view) = factory
.create_depth_stencil(d_dims.0, d_dims.1)
.map_err(RenderError::CombinedError)?;
let sampler = factory.create_sampler_linear();
Ok(Self {
device,
encoder: factory.create_command_buffer().into(),
factory,
win_color_view,
win_depth_view,
tgt_color_view,
tgt_depth_view,
tgt_color_res,
sampler,
skybox_pipeline,
figure_pipeline,
terrain_pipeline,
ui_pipeline,
postprocess_pipeline,
})
}
/// Get references to the internal render target views that get displayed directly by the window.
pub fn target_views(&self) -> (&TgtColorView, &TgtDepthView) {
(&self.tgt_color_view, &self.tgt_depth_view)
(&self.win_color_view, &self.win_depth_view)
}
/// Get mutable references to the internal render target views that get displayed directly by the window.
pub fn target_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthView) {
(&mut self.tgt_color_view, &mut self.tgt_depth_view)
(&mut self.win_color_view, &mut self.win_depth_view)
}
pub fn on_resize(&mut self) -> Result<(), RenderError> {
let dims = self.win_color_view.get_dimensions();
let d_dims = self.win_depth_view.get_dimensions();
if dims.0 > 0 && dims.1 > 0 {
let (_, tgt_color_res, tgt_color_view) = self
.factory
.create_render_target::<TgtColorFmt>(dims.0, dims.1)
.map_err(RenderError::CombinedError)?;
self.tgt_color_res = tgt_color_res;
self.tgt_color_view = tgt_color_view;
}
if d_dims.0 > 0 && d_dims.1 > 0 {
let (_, _, tgt_depth_view) = self
.factory
.create_depth_stencil(d_dims.0, d_dims.1)
.map_err(RenderError::CombinedError)?;
self.tgt_depth_view = tgt_depth_view;
}
Ok(())
}
/// Get the resolution of the render target.
@ -120,6 +192,8 @@ impl Renderer {
pub fn clear(&mut self, col: Rgba<f32>) {
self.encoder.clear(&self.tgt_color_view, col.into_array());
self.encoder.clear_depth(&self.tgt_depth_view, 1.0);
self.encoder.clear(&self.win_color_view, col.into_array());
self.encoder.clear_depth(&self.win_depth_view, 1.0);
}
/// Perform all queued draw calls for this frame and clean up discarded items.
@ -261,11 +335,31 @@ impl Renderer {
h: max.y - min.y,
},
tex: (tex.srv.clone(), tex.sampler.clone()),
tgt_color: self.tgt_color_view.clone(),
tgt_depth: self.tgt_depth_view.clone(),
tgt_color: self.win_color_view.clone(),
tgt_depth: self.win_depth_view.clone(),
},
);
}
pub fn render_post_process(
&mut self,
model: &Model<postprocess::PostProcessPipeline>,
globals: &Consts<Globals>,
locals: &Consts<postprocess::Locals>,
) {
self.encoder.draw(
&model.slice,
&self.postprocess_pipeline.pso,
&postprocess::pipe::Data {
vbuf: model.vbuf.clone(),
locals: locals.buf.clone(),
globals: globals.buf.clone(),
src_sampler: (self.tgt_color_res.clone(), self.sampler.clone()),
tgt_color: self.win_color_view.clone(),
tgt_depth: self.win_depth_view.clone(),
},
)
}
}
struct GfxPipeline<P: gfx::pso::PipelineInit> {

View File

@ -10,8 +10,8 @@ use crate::{
},
mesh::Meshable,
render::{
create_skybox_mesh, Consts, FigureLocals, Globals, Model, Renderer, SkyboxLocals,
SkyboxPipeline,
create_pp_mesh, create_skybox_mesh, Consts, FigureLocals, Globals, Model,
PostProcessLocals, PostProcessPipeline, Renderer, SkyboxLocals, SkyboxPipeline,
},
window::Event,
};
@ -28,11 +28,17 @@ struct Skybox {
locals: Consts<SkyboxLocals>,
}
struct PostProcess {
model: Model<PostProcessPipeline>,
locals: Consts<PostProcessLocals>,
}
pub struct Scene {
globals: Consts<Globals>,
camera: Camera,
skybox: Skybox,
postprocess: PostProcess,
terrain: Terrain,
figure_cache: FigureCache,
@ -51,6 +57,12 @@ impl Scene {
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
locals: renderer.create_consts(&[SkyboxLocals::default()]).unwrap(),
},
postprocess: PostProcess {
model: renderer.create_model(&create_pp_mesh()).unwrap(),
locals: renderer
.create_consts(&[PostProcessLocals::default()])
.unwrap(),
},
terrain: Terrain::new(),
figure_cache: FigureCache::new(),
}
@ -145,5 +157,11 @@ impl Scene {
// Render terrain and figures
self.terrain.render(renderer, &self.globals);
self.figure_cache.render(renderer, client, &self.globals);
renderer.render_post_process(
&self.postprocess.model,
&self.globals,
&self.postprocess.locals,
);
}
}

View File

@ -102,6 +102,7 @@ impl Window {
glutin::WindowEvent::Resized(glutin::dpi::LogicalSize { width, height }) => {
let (mut color_view, mut depth_view) = renderer.target_views_mut();
gfx_window_glutin::update_views(&window, &mut color_view, &mut depth_view);
renderer.on_resize().unwrap();
events.push(Event::Resize(Vec2::new(width as u32, height as u32)));
}
glutin::WindowEvent::ReceivedCharacter(c) => events.push(Event::Char(c)),