Merge branch 'train-track-shadows' into 'master'

Train track shadows

See merge request veloren/veloren!3688
This commit is contained in:
Justin Shipsey 2022-11-12 13:00:24 +00:00
commit 420e824a3e
13 changed files with 234 additions and 36 deletions

View File

@ -1,5 +1,7 @@
#version 420 core
#define HAS_SHADOW_MAPS
#include <constants.glsl>
#include <globals.glsl>
#include <srgb.glsl>
@ -14,7 +16,7 @@ in vec3 f_pos;
layout (location = 2)
in vec3 f_norm;
layout (std140, set = 1, binding = 0)
layout (std140, set = 2, binding = 0)
uniform u_locals {
vec4 w_pos;
vec4 w_color;

View File

@ -9,7 +9,7 @@ in vec4 v_color;
layout (location = 2)
in vec3 v_norm;
layout (std140, set = 1, binding = 0)
layout (std140, set = 2, binding = 0)
uniform u_locals {
vec4 w_pos;
vec4 w_color;

View File

@ -0,0 +1,61 @@
#version 420 core
#include <globals.glsl>
layout (location = 0)
in vec3 v_pos;
layout (location = 1)
in vec4 v_color;
layout (location = 2)
in vec3 v_norm;
layout (std140, set = 1, binding = 0)
uniform u_locals {
vec4 w_pos;
vec4 w_color;
vec4 w_ori;
};
layout (std140, set = 0, binding = 9)
uniform u_light_shadows {
mat4 shadowMatrices;
mat4 texture_mat;
};
layout (location = 0)
out vec4 f_color;
layout (location = 1)
out vec3 f_pos;
layout (location = 2)
out vec3 f_norm;
void main() {
f_color = w_color * v_color;
// Build rotation matrix
// https://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Rotation_matrices
mat3 rotation_matrix;
float q0 = w_ori[3];
float q1 = w_ori[0];
float q2 = w_ori[1];
float q3 = w_ori[2];
float r00 = 1 - 2 * (pow(q2, 2) + pow(q3, 2));
float r01 = 2 * (q1 * q2 - q0 * q3);
float r02 = 2 * (q0 * q2 + q1 * q3);
rotation_matrix[0] = vec3(r00, r01, r02);
float r10 = 2 * (q1 * q2 + q0 * q3);
float r11 = 1 - 2 * (pow(q1, 2) + pow(q3, 2));
float r12 = 2 * (q2 * q3 - q0 * q1);
rotation_matrix[1] = vec3(r10, r11, r12);
float r20 = 2 * (q1 * q3 - q0 * q2);
float r21 = 2 * (q0 * q1 + q2 * q3);
float r22 = 1 - 2 * (pow(q1, 2) + pow(q2, 2));
rotation_matrix[2] = vec3(r20, r21, r22);
f_pos = (v_pos * rotation_matrix + w_pos.xyz) - focus_off.xyz;
f_norm = normalize(v_norm);
gl_Position = shadowMatrices * vec4(f_pos, 1);
}

View File

@ -20,7 +20,7 @@ pub use self::{
model::{DynamicModel, Model, SubModel},
pipelines::{
clouds::Locals as CloudsLocals,
debug::{DebugPipeline, Locals as DebugLocals, Vertex as DebugVertex},
debug::{DebugLayout, DebugPipeline, Locals as DebugLocals, Vertex as DebugVertex},
figure::{
BoneData as FigureBoneData, BoneMeshes, FigureLayout, FigureModel,
Locals as FigureLocals,
@ -49,9 +49,10 @@ pub use self::{
},
renderer::{
drawer::{
DebugDrawer, Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer, ParticleDrawer,
PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer, TerrainDrawer,
TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer, UiDrawer,
DebugDrawer, DebugShadowDrawer, Drawer, FigureDrawer, FigureShadowDrawer,
FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer,
SpriteDrawer, TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
UiDrawer,
},
ColLightInfo, Renderer,
},

View File

@ -12,7 +12,7 @@ pub struct Vertex {
}
impl Vertex {
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
pub fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
const ATTRIBUTES: [wgpu::VertexAttribute; 3] =
wgpu::vertex_attr_array![0 => Float32x3, 1 => Float32x4, 2 => Float32x3];
wgpu::VertexBufferLayout {
@ -80,7 +80,11 @@ impl DebugPipeline {
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Debug pipeline layout"),
push_constant_ranges: &[],
bind_group_layouts: &[&global_layouts.globals, &layout.locals],
bind_group_layouts: &[
&global_layouts.globals,
&global_layouts.shadow_textures,
&layout.locals,
],
});
let samples = aa_mode.samples();

View File

@ -1,6 +1,6 @@
use super::super::{
AaMode, Bound, ColLightInfo, Consts, FigureLayout, GlobalsLayouts, Renderer, TerrainLayout,
TerrainVertex, Texture,
AaMode, Bound, ColLightInfo, Consts, DebugLayout, DebugVertex, FigureLayout, GlobalsLayouts,
Renderer, TerrainLayout, TerrainVertex, Texture,
};
use bytemuck::{Pod, Zeroable};
use vek::*;
@ -331,3 +331,71 @@ impl PointShadowPipeline {
}
}
}
pub struct ShadowDebugPipeline {
pub pipeline: wgpu::RenderPipeline,
}
impl ShadowDebugPipeline {
pub fn new(
device: &wgpu::Device,
vs_module: &wgpu::ShaderModule,
global_layout: &GlobalsLayouts,
debug_layout: &DebugLayout,
aa_mode: AaMode,
) -> Self {
let render_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Directed shadow debug pipeline layout"),
push_constant_ranges: &[],
bind_group_layouts: &[&global_layout.globals, &debug_layout.locals],
});
let samples = aa_mode.samples();
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Directed shadow debug pipeline"),
layout: Some(&render_pipeline_layout),
vertex: wgpu::VertexState {
module: vs_module,
entry_point: "main",
buffers: &[DebugVertex::desc()],
},
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Front),
clamp_depth: true,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24Plus,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState {
front: wgpu::StencilFaceState::IGNORE,
back: wgpu::StencilFaceState::IGNORE,
read_mask: !0,
write_mask: !0,
},
bias: wgpu::DepthBiasState {
constant: 0,
slope_scale: 0.0,
clamp: 0.0,
},
}),
multisample: wgpu::MultisampleState {
count: samples,
mask: !0,
alpha_to_coverage_enabled: false,
},
fragment: None,
});
Self {
pipeline: render_pipeline,
}
}
}

View File

@ -1017,6 +1017,7 @@ impl Renderer {
shadow.point,
shadow.directed,
shadow.figure,
shadow.debug,
shadow_views,
);
@ -1076,16 +1077,19 @@ impl Renderer {
Some(point_pipeline),
Some(terrain_directed_pipeline),
Some(figure_directed_pipeline),
Some(debug_directed_pipeline),
ShadowMap::Enabled(shadow_map),
) = (
shadow_pipelines.point,
shadow_pipelines.directed,
shadow_pipelines.figure,
shadow_pipelines.debug,
&mut shadow.map,
) {
shadow_map.point_pipeline = point_pipeline;
shadow_map.terrain_directed_pipeline = terrain_directed_pipeline;
shadow_map.figure_directed_pipeline = figure_directed_pipeline;
shadow_map.debug_directed_pipeline = debug_directed_pipeline;
}
if let (

View File

@ -6,7 +6,6 @@ use super::{
pipelines::{
blit, bloom, clouds, debug, figure, fluid, lod_object, lod_terrain, particle, shadow,
skybox, sprite, terrain, trail, ui, ColLights, GlobalsBindGroup,
ShadowTexturesBindGroup,
},
},
rain_occlusion_map::{RainOcclusionMap, RainOcclusionMapRenderer},
@ -250,7 +249,6 @@ impl<'frame> Drawer<'frame> {
borrow: &self.borrow,
pipelines,
globals: self.globals,
shadows: &shadow.bind,
})
}
@ -681,6 +679,17 @@ impl<'pass> ShadowPassDrawer<'pass> {
TerrainShadowDrawer { render_pass }
}
pub fn draw_debug_shadows(&mut self) -> DebugShadowDrawer<'_, 'pass> {
let mut render_pass = self
.render_pass
.scope("directed_debug_shadows", self.borrow.device);
render_pass.set_pipeline(&self.shadow_renderer.debug_directed_pipeline.pipeline);
set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
DebugShadowDrawer { render_pass }
}
}
#[must_use]
@ -750,6 +759,23 @@ impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> {
}
}
#[must_use]
pub struct DebugShadowDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
}
impl<'pass_ref, 'pass: 'pass_ref> DebugShadowDrawer<'pass_ref, 'pass> {
pub fn draw<'data: 'pass>(
&mut self,
model: &'data Model<debug::Vertex>,
locals: &'data debug::BoundLocals,
) {
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
}
}
// First pass
#[must_use]
pub struct FirstPassDrawer<'pass> {
@ -757,7 +783,6 @@ pub struct FirstPassDrawer<'pass> {
borrow: &'pass RendererBorrow<'pass>,
pipelines: &'pass super::Pipelines,
globals: &'pass GlobalsBindGroup,
shadows: &'pass ShadowTexturesBindGroup,
}
impl<'pass> FirstPassDrawer<'pass> {
@ -776,10 +801,7 @@ impl<'pass> FirstPassDrawer<'pass> {
render_pass.set_pipeline(&self.pipelines.debug.pipeline);
set_quad_index_buffer::<debug::Vertex>(&mut render_pass, self.borrow);
DebugDrawer {
render_pass,
shadows: self.shadows,
}
DebugDrawer { render_pass }
}
pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
@ -862,7 +884,6 @@ impl<'pass> FirstPassDrawer<'pass> {
#[must_use]
pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
shadows: &'pass ShadowTexturesBindGroup,
}
impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'pass_ref, 'pass> {
@ -871,21 +892,12 @@ impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'pass_ref, 'pass> {
model: &'data Model<debug::Vertex>,
locals: &'data debug::BoundLocals,
) {
self.render_pass.set_bind_group(1, &locals.bind_group, &[]);
self.render_pass.set_bind_group(2, &locals.bind_group, &[]);
self.render_pass.set_vertex_buffer(0, model.buf().slice(..));
self.render_pass.draw(0..model.len() as u32, 0..1);
}
}
impl<'pass_ref, 'pass: 'pass_ref> Drop for DebugDrawer<'pass_ref, 'pass> {
fn drop(&mut self) {
// Maintain that the shadow bind group is set in
// slot 1 by default during the main pass
self.render_pass
.set_bind_group(1, &self.shadows.bind_group, &[]);
}
}
#[must_use]
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,

View File

@ -60,6 +60,7 @@ pub struct ShadowPipelines {
pub point: Option<shadow::PointShadowPipeline>,
pub directed: Option<shadow::ShadowPipeline>,
pub figure: Option<shadow::ShadowFigurePipeline>,
pub debug: Option<shadow::ShadowDebugPipeline>,
}
pub struct RainOcclusionPipelines {
@ -140,6 +141,7 @@ struct ShaderModules {
point_light_shadows_vert: wgpu::ShaderModule,
light_shadows_directed_vert: wgpu::ShaderModule,
light_shadows_figure_vert: wgpu::ShaderModule,
light_shadows_debug_vert: wgpu::ShaderModule,
rain_occlusion_directed_vert: wgpu::ShaderModule,
rain_occlusion_figure_vert: wgpu::ShaderModule,
}
@ -360,6 +362,10 @@ impl ShaderModules {
"light-shadows-figure-vert",
ShaderKind::Vertex,
)?,
light_shadows_debug_vert: create_shader(
"light-shadows-debug-vert",
ShaderKind::Vertex,
)?,
rain_occlusion_directed_vert: create_shader(
"rain-occlusion-directed-vert",
ShaderKind::Vertex,
@ -458,7 +464,7 @@ fn create_ingame_and_shadow_pipelines(
needs: PipelineNeeds,
pool: &rayon::ThreadPool,
// TODO: Reduce the boilerplate in this file
tasks: [Task; 18],
tasks: [Task; 19],
) -> IngameAndShadowPipelines {
prof_span!(_guard, "create_ingame_and_shadow_pipelines");
@ -490,6 +496,7 @@ fn create_ingame_and_shadow_pipelines(
point_shadow_task,
terrain_directed_shadow_task,
figure_directed_shadow_task,
debug_directed_shadow_task,
terrain_directed_rain_occlusion_task,
figure_directed_rain_occlusion_task,
] = tasks;
@ -777,6 +784,21 @@ fn create_ingame_and_shadow_pipelines(
"figure directed shadow pipeline creation",
)
};
// Pipeline for rendering directional light debug shadow maps.
let create_debug_directed_shadow = || {
debug_directed_shadow_task.run(
|| {
shadow::ShadowDebugPipeline::new(
device,
&shaders.light_shadows_debug_vert,
&layouts.global,
&layouts.debug,
pipeline_modes.aa,
)
},
"figure directed shadow pipeline creation",
)
};
// Pipeline for rendering directional light terrain rain occlusion maps.
let create_terrain_directed_rain_occlusion = || {
terrain_directed_rain_occlusion_task.run(
@ -818,10 +840,9 @@ fn create_ingame_and_shadow_pipelines(
};
let j5 = || pool.join(create_postprocess, create_point_shadow);
let j6 = || {
pool.join(
create_terrain_directed_shadow,
create_figure_directed_shadow,
)
pool.join(create_terrain_directed_shadow, || {
pool.join(create_figure_directed_shadow, create_debug_directed_shadow)
})
};
let j7 = || {
pool.join(create_lod_object, || {
@ -839,7 +860,10 @@ fn create_ingame_and_shadow_pipelines(
((sprite, particle), (lod_terrain, (clouds, trail))),
),
(
((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)),
(
(postprocess, point_shadow),
(terrain_directed_shadow, (figure_directed_shadow, debug_directed_shadow)),
),
(lod_object, (terrain_directed_rain_occlusion, figure_directed_rain_occlusion)),
),
) = pool.join(
@ -869,6 +893,7 @@ fn create_ingame_and_shadow_pipelines(
point: Some(point_shadow),
directed: Some(terrain_directed_shadow),
figure: Some(figure_directed_shadow),
debug: Some(debug_directed_shadow),
},
rain_occlusion: RainOcclusionPipelines {
terrain: Some(terrain_directed_rain_occlusion),

View File

@ -49,6 +49,7 @@ impl assets::Compound for Shaders {
"figure-vert",
"light-shadows-figure-vert",
"light-shadows-directed-vert",
"light-shadows-debug-vert",
"rain-occlusion-figure-vert",
"rain-occlusion-directed-vert",
"point-light-shadows-vert",

View File

@ -14,6 +14,7 @@ pub struct ShadowMapRenderer {
pub point_pipeline: shadow::PointShadowPipeline,
pub terrain_directed_pipeline: shadow::ShadowPipeline,
pub figure_directed_pipeline: shadow::ShadowFigurePipeline,
pub debug_directed_pipeline: shadow::ShadowDebugPipeline,
pub layout: shadow::ShadowLayout,
}
@ -32,14 +33,16 @@ impl ShadowMap {
point: Option<shadow::PointShadowPipeline>,
directed: Option<shadow::ShadowPipeline>,
figure: Option<shadow::ShadowFigurePipeline>,
debug: Option<shadow::ShadowDebugPipeline>,
shadow_views: Option<(Texture, Texture)>,
) -> Self {
if let (
Some(point_pipeline),
Some(terrain_directed_pipeline),
Some(figure_directed_pipeline),
Some(debug_directed_pipeline),
Some(shadow_views),
) = (point, directed, figure, shadow_views)
) = (point, directed, figure, debug, shadow_views)
{
let (point_depth, directed_depth) = shadow_views;
@ -52,6 +55,7 @@ impl ShadowMap {
point_pipeline,
terrain_directed_pipeline,
figure_directed_pipeline,
debug_directed_pipeline,
layout,
})

View File

@ -1,5 +1,6 @@
use crate::render::{
Bound, Consts, DebugDrawer, DebugLocals, DebugVertex, Mesh, Model, Quad, Renderer, Tri,
Bound, Consts, DebugDrawer, DebugLocals, DebugShadowDrawer, DebugVertex, Mesh, Model, Quad,
Renderer, Tri,
};
use common::util::srgba_to_linear;
use hashbrown::{HashMap, HashSet};
@ -264,6 +265,7 @@ pub struct Debug {
pending_locals: HashMap<DebugShapeId, ([f32; 4], [f32; 4], [f32; 4])>,
pending_deletes: HashSet<DebugShapeId>,
models: HashMap<DebugShapeId, (Model<DebugVertex>, Bound<Consts<DebugLocals>>)>,
casts_shadow: HashSet<DebugShapeId>,
}
impl Debug {
@ -274,12 +276,16 @@ impl Debug {
pending_locals: HashMap::new(),
pending_deletes: HashSet::new(),
models: HashMap::new(),
casts_shadow: HashSet::new(),
}
}
pub fn add_shape(&mut self, shape: DebugShape) -> DebugShapeId {
let id = DebugShapeId(self.next_shape_id.0);
self.next_shape_id.0 += 1;
if matches!(shape, DebugShape::TrainTrack { .. }) {
self.casts_shadow.insert(id);
}
self.pending_shapes.insert(id, shape);
id
}
@ -332,6 +338,14 @@ impl Debug {
drawer.draw(model, locals);
}
}
pub fn render_shadows<'a>(&'a self, drawer: &mut DebugShadowDrawer<'_, 'a>) {
for id in self.casts_shadow.iter() {
if let Some((model, locals)) = self.models.get(id) {
drawer.draw(model, locals);
}
}
}
}
impl Default for Debug {

View File

@ -1244,6 +1244,8 @@ impl Scene {
tick,
camera_data,
);
self.debug
.render_shadows(&mut shadow_pass.draw_debug_shadows());
}
}