mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Implement a Debug pipeline for hitboxes and pathfinding lines.
- Implements mesh generation for cylinders and lines. - Implements an Id-allocator so that clients can mutate positions efficiently. - Is split into pipeline and scene modules. - Contains simple shaders that just pass through a position and color.
This commit is contained in:
parent
254c2fb868
commit
364890653f
19
assets/voxygen/shaders/debug-frag.glsl
Normal file
19
assets/voxygen/shaders/debug-frag.glsl
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#version 420 core
|
||||||
|
|
||||||
|
#include <globals.glsl>
|
||||||
|
|
||||||
|
layout (location = 0)
|
||||||
|
in vec4 f_color;
|
||||||
|
|
||||||
|
layout (std140, set = 1, binding = 0)
|
||||||
|
uniform u_locals {
|
||||||
|
vec4 w_pos;
|
||||||
|
vec4 w_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (location = 0)
|
||||||
|
out vec4 tgt_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
tgt_color = f_color;
|
||||||
|
}
|
20
assets/voxygen/shaders/debug-vert.glsl
Normal file
20
assets/voxygen/shaders/debug-vert.glsl
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#version 420 core
|
||||||
|
|
||||||
|
#include <globals.glsl>
|
||||||
|
|
||||||
|
layout (location = 0)
|
||||||
|
in vec3 v_pos;
|
||||||
|
|
||||||
|
layout (std140, set = 1, binding = 0)
|
||||||
|
uniform u_locals {
|
||||||
|
vec4 w_pos;
|
||||||
|
vec4 w_color;
|
||||||
|
};
|
||||||
|
|
||||||
|
layout (location = 0)
|
||||||
|
out vec4 f_color;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
f_color = w_color;
|
||||||
|
gl_Position = all_mat * vec4((v_pos + w_pos.xyz) - focus_off.xyz, 1);
|
||||||
|
}
|
@ -21,6 +21,7 @@ pub use self::{
|
|||||||
model::{DynamicModel, Model, SubModel},
|
model::{DynamicModel, Model, SubModel},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
clouds::Locals as CloudsLocals,
|
clouds::Locals as CloudsLocals,
|
||||||
|
debug::{DebugPipeline, Locals as DebugLocals, Vertex as DebugVertex},
|
||||||
figure::{
|
figure::{
|
||||||
BoneData as FigureBoneData, BoneMeshes, FigureLayout, FigureModel,
|
BoneData as FigureBoneData, BoneMeshes, FigureLayout, FigureModel,
|
||||||
Locals as FigureLocals,
|
Locals as FigureLocals,
|
||||||
|
201
voxygen/src/render/pipelines/debug.rs
Normal file
201
voxygen/src/render/pipelines/debug.rs
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
use super::{
|
||||||
|
super::{AaMode, Bound, Consts, GlobalsLayouts, Vertex as VertexTrait},
|
||||||
|
};
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use std::mem;
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
|
pub struct Vertex {
|
||||||
|
pub pos: [f32; 3],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Vertex {
|
||||||
|
fn desc<'a>() -> wgpu::VertexBufferLayout<'a> {
|
||||||
|
wgpu::VertexBufferLayout {
|
||||||
|
array_stride: Self::STRIDE,
|
||||||
|
step_mode: wgpu::InputStepMode::Vertex,
|
||||||
|
attributes: &[wgpu::VertexAttribute {
|
||||||
|
offset: 0,
|
||||||
|
shader_location: 0,
|
||||||
|
format: wgpu::VertexFormat::Float32x3,
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VertexTrait for Vertex {
|
||||||
|
//const QUADS_INDEX: Option<wgpu::IndexFormat> =
|
||||||
|
// Some(wgpu::IndexFormat::Uint32);
|
||||||
|
const QUADS_INDEX: Option<wgpu::IndexFormat> = None;
|
||||||
|
const STRIDE: wgpu::BufferAddress = mem::size_of::<Self>() as wgpu::BufferAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Copy, Clone, Debug, Zeroable, Pod)]
|
||||||
|
pub struct Locals {
|
||||||
|
/// pos is [f32; 4] instead of [f32; 3] so that Locals's size is a multiple
|
||||||
|
/// of 8 bytes (which is required by gfx), the last component is ignored
|
||||||
|
/// by the shader
|
||||||
|
pub pos: [f32; 4],
|
||||||
|
pub color: [f32; 4],
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BoundLocals = Bound<Consts<Locals>>;
|
||||||
|
|
||||||
|
/*gfx_defines! {
|
||||||
|
vertex Vertex {
|
||||||
|
pos: [f32; 3] = "v_pos",
|
||||||
|
}
|
||||||
|
|
||||||
|
constant Locals {
|
||||||
|
// pos is [f32; 4] instead of [f32; 3] so that Locals's size is a multiple of 8 bytes
|
||||||
|
// (which is required by gfx), the last component is ignored by the shader
|
||||||
|
pos: [f32; 4] = "w_pos",
|
||||||
|
color: [f32; 4] = "w_color",
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline pipe {
|
||||||
|
vbuf: gfx::VertexBuffer<Vertex> = (),
|
||||||
|
|
||||||
|
locals: gfx::ConstantBuffer<Locals> = "u_locals",
|
||||||
|
globals: gfx::ConstantBuffer<Globals> = "u_globals",
|
||||||
|
|
||||||
|
tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
|
||||||
|
//tgt_depth: gfx::DepthTarget<TgtDepthStencilFmt> = gfx::preset::depth::LESS_EQUAL_TEST,
|
||||||
|
tgt_depth: gfx::DepthTarget<TgtDepthStencilFmt> = gfx::preset::depth::PASS_TEST,
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
impl From<Vec3<f32>> for Vertex {
|
||||||
|
fn from(pos: Vec3<f32>) -> Vertex {
|
||||||
|
Vertex {
|
||||||
|
pos: [pos.x, pos.y, pos.z],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebugPipeline {
|
||||||
|
pub pipeline: wgpu::RenderPipeline,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugPipeline {
|
||||||
|
pub fn new(
|
||||||
|
device: &wgpu::Device,
|
||||||
|
vs_module: &wgpu::ShaderModule,
|
||||||
|
fs_module: &wgpu::ShaderModule,
|
||||||
|
global_layouts: &GlobalsLayouts,
|
||||||
|
layout: &DebugLayout,
|
||||||
|
aa_mode: AaMode,
|
||||||
|
) -> Self {
|
||||||
|
common_base::span!(_guard, "DebugPipeline::new");
|
||||||
|
let render_pipeline_layout =
|
||||||
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
label: Some("Debug pipeline layout"),
|
||||||
|
push_constant_ranges: &[],
|
||||||
|
bind_group_layouts: &[&global_layouts.globals, &layout.locals],
|
||||||
|
});
|
||||||
|
|
||||||
|
let samples = match aa_mode {
|
||||||
|
AaMode::None | AaMode::Fxaa => 1,
|
||||||
|
// TODO: Ensure sampling in the shader is exactly between the 4 texels
|
||||||
|
AaMode::MsaaX4 => 4,
|
||||||
|
AaMode::MsaaX8 => 8,
|
||||||
|
AaMode::MsaaX16 => 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: Some("Debug pipeline"),
|
||||||
|
layout: Some(&render_pipeline_layout),
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
module: vs_module,
|
||||||
|
entry_point: "main",
|
||||||
|
buffers: &[Vertex::desc()],
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState {
|
||||||
|
topology: wgpu::PrimitiveTopology::TriangleList,
|
||||||
|
strip_index_format: None,
|
||||||
|
front_face: wgpu::FrontFace::Ccw,
|
||||||
|
cull_mode: Some(wgpu::Face::Back),
|
||||||
|
clamp_depth: false,
|
||||||
|
polygon_mode: wgpu::PolygonMode::Fill,
|
||||||
|
conservative: false,
|
||||||
|
},
|
||||||
|
depth_stencil: Some(wgpu::DepthStencilState {
|
||||||
|
format: wgpu::TextureFormat::Depth32Float,
|
||||||
|
depth_write_enabled: true,
|
||||||
|
depth_compare: wgpu::CompareFunction::GreaterEqual,
|
||||||
|
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: Some(wgpu::FragmentState {
|
||||||
|
module: fs_module,
|
||||||
|
entry_point: "main",
|
||||||
|
targets: &[wgpu::ColorTargetState {
|
||||||
|
format: wgpu::TextureFormat::Rgba16Float,
|
||||||
|
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
|
||||||
|
write_mask: wgpu::ColorWrite::ALL,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
pipeline: render_pipeline,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DebugLayout {
|
||||||
|
pub locals: wgpu::BindGroupLayout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugLayout {
|
||||||
|
pub fn new(device: &wgpu::Device) -> Self {
|
||||||
|
Self {
|
||||||
|
locals: device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
|
label: None,
|
||||||
|
entries: &[wgpu::BindGroupLayoutEntry {
|
||||||
|
binding: 0,
|
||||||
|
visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT,
|
||||||
|
ty: wgpu::BindingType::Buffer {
|
||||||
|
ty: wgpu::BufferBindingType::Uniform,
|
||||||
|
has_dynamic_offset: false,
|
||||||
|
min_binding_size: None,
|
||||||
|
},
|
||||||
|
count: None,
|
||||||
|
}],
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_locals(&self, device: &wgpu::Device, locals: Consts<Locals>) -> BoundLocals {
|
||||||
|
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: &self.locals,
|
||||||
|
entries: &[wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: locals.buf().as_entire_binding(),
|
||||||
|
}],
|
||||||
|
});
|
||||||
|
|
||||||
|
BoundLocals {
|
||||||
|
bind_group,
|
||||||
|
with: locals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
pub mod blit;
|
pub mod blit;
|
||||||
pub mod clouds;
|
pub mod clouds;
|
||||||
|
pub mod debug;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod fluid;
|
pub mod fluid;
|
||||||
pub mod lod_terrain;
|
pub mod lod_terrain;
|
||||||
|
@ -21,7 +21,7 @@ use super::{
|
|||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
model::{DynamicModel, Model},
|
model::{DynamicModel, Model},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, clouds, figure, postprocess, shadow, sprite, terrain, ui, GlobalsBindGroup,
|
blit, clouds, debug, figure, postprocess, shadow, sprite, terrain, ui, GlobalsBindGroup,
|
||||||
GlobalsLayouts, ShadowTexturesBindGroup,
|
GlobalsLayouts, ShadowTexturesBindGroup,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
@ -48,6 +48,7 @@ struct Layouts {
|
|||||||
global: GlobalsLayouts,
|
global: GlobalsLayouts,
|
||||||
|
|
||||||
clouds: clouds::CloudsLayout,
|
clouds: clouds::CloudsLayout,
|
||||||
|
debug: debug::DebugLayout,
|
||||||
figure: figure::FigureLayout,
|
figure: figure::FigureLayout,
|
||||||
postprocess: postprocess::PostProcessLayout,
|
postprocess: postprocess::PostProcessLayout,
|
||||||
shadow: shadow::ShadowLayout,
|
shadow: shadow::ShadowLayout,
|
||||||
@ -266,6 +267,7 @@ impl Renderer {
|
|||||||
let global = GlobalsLayouts::new(&device);
|
let global = GlobalsLayouts::new(&device);
|
||||||
|
|
||||||
let clouds = clouds::CloudsLayout::new(&device);
|
let clouds = clouds::CloudsLayout::new(&device);
|
||||||
|
let debug = debug::DebugLayout::new(&device);
|
||||||
let figure = figure::FigureLayout::new(&device);
|
let figure = figure::FigureLayout::new(&device);
|
||||||
let postprocess = postprocess::PostProcessLayout::new(&device);
|
let postprocess = postprocess::PostProcessLayout::new(&device);
|
||||||
let shadow = shadow::ShadowLayout::new(&device);
|
let shadow = shadow::ShadowLayout::new(&device);
|
||||||
@ -278,6 +280,7 @@ impl Renderer {
|
|||||||
global,
|
global,
|
||||||
|
|
||||||
clouds,
|
clouds,
|
||||||
|
debug,
|
||||||
figure,
|
figure,
|
||||||
postprocess,
|
postprocess,
|
||||||
shadow,
|
shadow,
|
||||||
|
@ -2,7 +2,7 @@ use super::{
|
|||||||
super::{
|
super::{
|
||||||
buffer::Buffer,
|
buffer::Buffer,
|
||||||
pipelines::{
|
pipelines::{
|
||||||
figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel,
|
debug, figure, lod_terrain, shadow, sprite, terrain, ui, ColLights, GlobalModel,
|
||||||
GlobalsBindGroup,
|
GlobalsBindGroup,
|
||||||
},
|
},
|
||||||
texture::Texture,
|
texture::Texture,
|
||||||
@ -36,6 +36,11 @@ impl Renderer {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_debug_bound_locals(&mut self, vals: &[debug::Locals]) -> debug::BoundLocals {
|
||||||
|
let locals = self.create_consts(vals);
|
||||||
|
self.layouts.debug.bind_locals(&self.device, locals)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_ui_bound_locals(&mut self, vals: &[ui::Locals]) -> ui::BoundLocals {
|
pub fn create_ui_bound_locals(&mut self, vals: &[ui::Locals]) -> ui::BoundLocals {
|
||||||
let locals = self.create_consts(vals);
|
let locals = self.create_consts(vals);
|
||||||
self.layouts.ui.bind_locals(&self.device, locals)
|
self.layouts.ui.bind_locals(&self.device, locals)
|
||||||
|
@ -4,8 +4,8 @@ use super::{
|
|||||||
instances::Instances,
|
instances::Instances,
|
||||||
model::{DynamicModel, Model, SubModel},
|
model::{DynamicModel, Model, SubModel},
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, clouds, figure, fluid, lod_terrain, particle, shadow, skybox, sprite, terrain,
|
blit, clouds, debug, figure, fluid, lod_terrain, particle, shadow, skybox, sprite,
|
||||||
ui, ColLights, GlobalsBindGroup,
|
terrain, ui, ColLights, GlobalsBindGroup,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Renderer, ShadowMap, ShadowMapRenderer,
|
Renderer, ShadowMap, ShadowMapRenderer,
|
||||||
@ -534,6 +534,18 @@ impl<'pass> FirstPassDrawer<'pass> {
|
|||||||
render_pass.draw(0..model.len() as u32, 0..1);
|
render_pass.draw(0..model.len() as u32, 0..1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn draw_debug(&mut self) -> DebugDrawer<'_, 'pass> {
|
||||||
|
let mut render_pass = self.render_pass.scope("debug", self.borrow.device);
|
||||||
|
|
||||||
|
render_pass.set_pipeline(&self.pipelines.debug.pipeline);
|
||||||
|
set_quad_index_buffer::<debug::Vertex>(&mut render_pass, &self.borrow);
|
||||||
|
|
||||||
|
DebugDrawer {
|
||||||
|
render_pass,
|
||||||
|
globals: self.globals,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
|
pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model<lod_terrain::Vertex>) {
|
||||||
let mut render_pass = self.render_pass.scope("lod_terrain", self.borrow.device);
|
let mut render_pass = self.render_pass.scope("lod_terrain", self.borrow.device);
|
||||||
|
|
||||||
@ -601,6 +613,25 @@ impl<'pass> FirstPassDrawer<'pass> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct DebugDrawer<'pass_ref, 'pass: 'pass_ref> {
|
||||||
|
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
||||||
|
globals: &'pass GlobalsBindGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'pass_ref, 'pass: 'pass_ref> DebugDrawer<'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(0, &self.globals.bind_group, &[]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
|
pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> {
|
||||||
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
render_pass: Scope<'pass_ref, wgpu::RenderPass<'pass>>,
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use super::{
|
use super::{
|
||||||
super::{
|
super::{
|
||||||
pipelines::{
|
pipelines::{
|
||||||
blit, clouds, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox,
|
blit, clouds, debug, figure, fluid, lod_terrain, particle, postprocess, shadow, skybox,
|
||||||
sprite, terrain, ui,
|
sprite, terrain, ui,
|
||||||
},
|
},
|
||||||
AaMode, CloudMode, FluidMode, LightingMode, RenderError, RenderMode, ShadowMode,
|
AaMode, CloudMode, FluidMode, LightingMode, RenderError, RenderMode, ShadowMode,
|
||||||
@ -14,6 +14,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
/// All the pipelines
|
/// All the pipelines
|
||||||
pub struct Pipelines {
|
pub struct Pipelines {
|
||||||
|
pub debug: debug::DebugPipeline,
|
||||||
pub figure: figure::FigurePipeline,
|
pub figure: figure::FigurePipeline,
|
||||||
pub fluid: fluid::FluidPipeline,
|
pub fluid: fluid::FluidPipeline,
|
||||||
pub lod_terrain: lod_terrain::LodTerrainPipeline,
|
pub lod_terrain: lod_terrain::LodTerrainPipeline,
|
||||||
@ -32,6 +33,7 @@ pub struct Pipelines {
|
|||||||
/// Pipelines that are needed to render 3D stuff in-game
|
/// Pipelines that are needed to render 3D stuff in-game
|
||||||
/// Use to decouple interface pipeline creation when initializing the renderer
|
/// Use to decouple interface pipeline creation when initializing the renderer
|
||||||
pub struct IngamePipelines {
|
pub struct IngamePipelines {
|
||||||
|
debug: debug::DebugPipeline,
|
||||||
figure: figure::FigurePipeline,
|
figure: figure::FigurePipeline,
|
||||||
fluid: fluid::FluidPipeline,
|
fluid: fluid::FluidPipeline,
|
||||||
lod_terrain: lod_terrain::LodTerrainPipeline,
|
lod_terrain: lod_terrain::LodTerrainPipeline,
|
||||||
@ -66,6 +68,7 @@ pub struct InterfacePipelines {
|
|||||||
impl Pipelines {
|
impl Pipelines {
|
||||||
pub fn consolidate(interface: InterfacePipelines, ingame: IngamePipelines) -> Self {
|
pub fn consolidate(interface: InterfacePipelines, ingame: IngamePipelines) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
debug: ingame.debug,
|
||||||
figure: ingame.figure,
|
figure: ingame.figure,
|
||||||
fluid: ingame.fluid,
|
fluid: ingame.fluid,
|
||||||
lod_terrain: ingame.lod_terrain,
|
lod_terrain: ingame.lod_terrain,
|
||||||
@ -86,6 +89,8 @@ impl Pipelines {
|
|||||||
struct ShaderModules {
|
struct ShaderModules {
|
||||||
skybox_vert: wgpu::ShaderModule,
|
skybox_vert: wgpu::ShaderModule,
|
||||||
skybox_frag: wgpu::ShaderModule,
|
skybox_frag: wgpu::ShaderModule,
|
||||||
|
debug_vert: wgpu::ShaderModule,
|
||||||
|
debug_frag: wgpu::ShaderModule,
|
||||||
figure_vert: wgpu::ShaderModule,
|
figure_vert: wgpu::ShaderModule,
|
||||||
figure_frag: wgpu::ShaderModule,
|
figure_frag: wgpu::ShaderModule,
|
||||||
terrain_vert: wgpu::ShaderModule,
|
terrain_vert: wgpu::ShaderModule,
|
||||||
@ -232,6 +237,8 @@ impl ShaderModules {
|
|||||||
Ok(Self {
|
Ok(Self {
|
||||||
skybox_vert: create_shader("skybox-vert", ShaderKind::Vertex)?,
|
skybox_vert: create_shader("skybox-vert", ShaderKind::Vertex)?,
|
||||||
skybox_frag: create_shader("skybox-frag", ShaderKind::Fragment)?,
|
skybox_frag: create_shader("skybox-frag", ShaderKind::Fragment)?,
|
||||||
|
debug_vert: create_shader("debug-vert", ShaderKind::Vertex)?,
|
||||||
|
debug_frag: create_shader("debug-frag", ShaderKind::Fragment)?,
|
||||||
figure_vert: create_shader("figure-vert", ShaderKind::Vertex)?,
|
figure_vert: create_shader("figure-vert", ShaderKind::Vertex)?,
|
||||||
figure_frag: create_shader("figure-frag", ShaderKind::Fragment)?,
|
figure_frag: create_shader("figure-frag", ShaderKind::Fragment)?,
|
||||||
terrain_vert: create_shader("terrain-vert", ShaderKind::Vertex)?,
|
terrain_vert: create_shader("terrain-vert", ShaderKind::Vertex)?,
|
||||||
@ -352,7 +359,7 @@ fn create_interface_pipelines(
|
|||||||
fn create_ingame_and_shadow_pipelines(
|
fn create_ingame_and_shadow_pipelines(
|
||||||
needs: PipelineNeeds,
|
needs: PipelineNeeds,
|
||||||
pool: &rayon::ThreadPool,
|
pool: &rayon::ThreadPool,
|
||||||
tasks: [Task; 12],
|
tasks: [Task; 13],
|
||||||
) -> IngameAndShadowPipelines {
|
) -> IngameAndShadowPipelines {
|
||||||
prof_span!(_guard, "create_ingame_and_shadow_pipelines");
|
prof_span!(_guard, "create_ingame_and_shadow_pipelines");
|
||||||
|
|
||||||
@ -365,6 +372,7 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
} = needs;
|
} = needs;
|
||||||
|
|
||||||
let [
|
let [
|
||||||
|
debug_task,
|
||||||
skybox_task,
|
skybox_task,
|
||||||
figure_task,
|
figure_task,
|
||||||
terrain_task,
|
terrain_task,
|
||||||
@ -384,6 +392,22 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
|
|
||||||
// TODO: pass in format of target color buffer
|
// TODO: pass in format of target color buffer
|
||||||
|
|
||||||
|
// Pipeline for rendering debug shapes
|
||||||
|
let create_debug = || {
|
||||||
|
debug_task.run(
|
||||||
|
|| {
|
||||||
|
debug::DebugPipeline::new(
|
||||||
|
device,
|
||||||
|
&shaders.debug_vert,
|
||||||
|
&shaders.debug_frag,
|
||||||
|
&layouts.global,
|
||||||
|
&layouts.debug,
|
||||||
|
mode.aa,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
"debug pipeline creation",
|
||||||
|
)
|
||||||
|
};
|
||||||
// Pipeline for rendering skyboxes
|
// Pipeline for rendering skyboxes
|
||||||
let create_skybox = || {
|
let create_skybox = || {
|
||||||
skybox_task.run(
|
skybox_task.run(
|
||||||
@ -596,7 +620,7 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let j1 = || pool.join(create_skybox, create_figure);
|
let j1 = || pool.join(create_debug, || pool.join(create_skybox, create_figure));
|
||||||
let j2 = || pool.join(create_terrain, create_fluid);
|
let j2 = || pool.join(create_terrain, create_fluid);
|
||||||
let j3 = || pool.join(create_sprite, create_particle);
|
let j3 = || pool.join(create_sprite, create_particle);
|
||||||
let j4 = || pool.join(create_lod_terrain, create_clouds);
|
let j4 = || pool.join(create_lod_terrain, create_clouds);
|
||||||
@ -610,7 +634,10 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
|
|
||||||
// Ignore this
|
// Ignore this
|
||||||
let (
|
let (
|
||||||
(((skybox, figure), (terrain, fluid)), ((sprite, particle), (lod_terrain, clouds))),
|
(
|
||||||
|
((debug, (skybox, figure)), (terrain, fluid)),
|
||||||
|
((sprite, particle), (lod_terrain, clouds)),
|
||||||
|
),
|
||||||
((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)),
|
((postprocess, point_shadow), (terrain_directed_shadow, figure_directed_shadow)),
|
||||||
) = pool.join(
|
) = pool.join(
|
||||||
|| pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)),
|
|| pool.join(|| pool.join(j1, j2), || pool.join(j3, j4)),
|
||||||
@ -619,6 +646,7 @@ fn create_ingame_and_shadow_pipelines(
|
|||||||
|
|
||||||
IngameAndShadowPipelines {
|
IngameAndShadowPipelines {
|
||||||
ingame: IngamePipelines {
|
ingame: IngamePipelines {
|
||||||
|
debug,
|
||||||
figure,
|
figure,
|
||||||
fluid,
|
fluid,
|
||||||
lod_terrain,
|
lod_terrain,
|
||||||
|
@ -50,6 +50,8 @@ impl assets::Compound for Shaders {
|
|||||||
"point-light-shadows-vert",
|
"point-light-shadows-vert",
|
||||||
"skybox-vert",
|
"skybox-vert",
|
||||||
"skybox-frag",
|
"skybox-frag",
|
||||||
|
"debug-vert",
|
||||||
|
"debug-frag",
|
||||||
"figure-frag",
|
"figure-frag",
|
||||||
"terrain-vert",
|
"terrain-vert",
|
||||||
"terrain-frag",
|
"terrain-frag",
|
||||||
|
133
voxygen/src/scene/debug.rs
Normal file
133
voxygen/src/scene/debug.rs
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
use crate::render::{
|
||||||
|
Bound, Consts, DebugLocals, DebugVertex, FirstPassDrawer, Mesh,
|
||||||
|
Model, Quad, Renderer, Tri,
|
||||||
|
};
|
||||||
|
use hashbrown::{HashMap, HashSet};
|
||||||
|
use vek::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum DebugShape {
|
||||||
|
Line([Vec3<f32>; 2]),
|
||||||
|
Cylinder { radius: f32, height: f32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DebugShape {
|
||||||
|
pub fn mesh(&self) -> Mesh<DebugVertex> {
|
||||||
|
use core::f32::consts::PI;
|
||||||
|
use DebugShape::*;
|
||||||
|
let mut mesh = Mesh::new();
|
||||||
|
let tri = |x: Vec3<f32>, y: Vec3<f32>, z: Vec3<f32>| {
|
||||||
|
Tri::<DebugVertex>::new(x.into(), y.into(), z.into())
|
||||||
|
};
|
||||||
|
let quad = |x: Vec3<f32>, y: Vec3<f32>, z: Vec3<f32>, w: Vec3<f32>| {
|
||||||
|
Quad::<DebugVertex>::new(x.into(), y.into(), z.into(), w.into())
|
||||||
|
};
|
||||||
|
match self {
|
||||||
|
Line([a, b]) => {
|
||||||
|
let h = Vec3::new(0.0, 1.0, 0.0);
|
||||||
|
mesh.push_quad(quad(*a, a + h, b + h, *b));
|
||||||
|
},
|
||||||
|
Cylinder { radius, height } => {
|
||||||
|
const SUBDIVISIONS: usize = 16;
|
||||||
|
for i in 0..SUBDIVISIONS {
|
||||||
|
let angle = |j: usize| (j as f32 / SUBDIVISIONS as f32) * 2.0 * PI;
|
||||||
|
let a = Vec3::zero();
|
||||||
|
let b = Vec3::new(radius * angle(i).cos(), radius * angle(i).sin(), 0.0);
|
||||||
|
let c = Vec3::new(
|
||||||
|
radius * angle(i + 1).cos(),
|
||||||
|
radius * angle(i + 1).sin(),
|
||||||
|
0.0,
|
||||||
|
);
|
||||||
|
let h = Vec3::new(0.0, 0.0, *height);
|
||||||
|
mesh.push_tri(tri(a, b, c));
|
||||||
|
mesh.push_quad(quad(b, c, c + h, b + h));
|
||||||
|
mesh.push_tri(tri(a + h, b + h, c + h));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
mesh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
|
||||||
|
pub struct DebugShapeId(usize);
|
||||||
|
|
||||||
|
pub struct Debug {
|
||||||
|
next_shape_id: DebugShapeId,
|
||||||
|
pending_shapes: HashMap<DebugShapeId, DebugShape>,
|
||||||
|
pending_locals: HashMap<DebugShapeId, ([f32; 4], [f32; 4])>,
|
||||||
|
pending_deletes: HashSet<DebugShapeId>,
|
||||||
|
models: HashMap<DebugShapeId, Model<DebugVertex>>,
|
||||||
|
//locals: HashMap<DebugShapeId, Consts<DebugLocals>>,
|
||||||
|
locals: HashMap<DebugShapeId, Bound<Consts<DebugLocals>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug {
|
||||||
|
pub fn new() -> Debug {
|
||||||
|
Debug {
|
||||||
|
next_shape_id: DebugShapeId(0),
|
||||||
|
pending_shapes: HashMap::new(),
|
||||||
|
pending_locals: HashMap::new(),
|
||||||
|
pending_deletes: HashSet::new(),
|
||||||
|
models: HashMap::new(),
|
||||||
|
locals: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_shape(&mut self, shape: DebugShape) -> DebugShapeId {
|
||||||
|
let id = DebugShapeId(self.next_shape_id.0);
|
||||||
|
self.next_shape_id.0 += 1;
|
||||||
|
self.pending_shapes.insert(id, shape);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_pos_and_color(&mut self, id: DebugShapeId, pos: [f32; 4], color: [f32; 4]) {
|
||||||
|
self.pending_locals.insert(id, (pos, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_shape(&mut self, id: DebugShapeId) { self.pending_deletes.insert(id); }
|
||||||
|
|
||||||
|
pub fn maintain(&mut self, renderer: &mut Renderer) {
|
||||||
|
for (id, shape) in self.pending_shapes.drain() {
|
||||||
|
self.models
|
||||||
|
.insert(id, renderer.create_model(&shape.mesh()).unwrap());
|
||||||
|
/*self.locals.insert(
|
||||||
|
id,
|
||||||
|
renderer.create_consts(&[DebugLocals {
|
||||||
|
pos: [0.0; 4],
|
||||||
|
color: [1.0, 0.0, 0.0, 1.0],
|
||||||
|
}]),
|
||||||
|
);*/
|
||||||
|
}
|
||||||
|
for (id, (pos, color)) in self.pending_locals.drain() {
|
||||||
|
// TODO: what are the efficiency ramifications of creating the constants each
|
||||||
|
// time instead of caching them and binding them? UI seems to
|
||||||
|
// recreate them each time they change?
|
||||||
|
/*if let Some(locals) = self.locals.get_mut(&id) {
|
||||||
|
let new_locals = [DebugLocals { pos, color }];
|
||||||
|
renderer.update_consts(locals, &new_locals);
|
||||||
|
renderer.create_debug_bound_locals(new_locals);
|
||||||
|
}*/
|
||||||
|
let new_locals = [DebugLocals { pos, color }];
|
||||||
|
self.locals
|
||||||
|
.insert(id, renderer.create_debug_bound_locals(&new_locals));
|
||||||
|
}
|
||||||
|
for id in self.pending_deletes.drain() {
|
||||||
|
self.models.remove(&id);
|
||||||
|
self.locals.remove(&id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>) {
|
||||||
|
let mut debug_drawer = drawer.draw_debug();
|
||||||
|
for (id, model) in self.models.iter() {
|
||||||
|
if let Some(locals) = self.locals.get(id) {
|
||||||
|
debug_drawer.draw(model, locals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Debug {
|
||||||
|
fn default() -> Debug { Debug::new() }
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
pub mod camera;
|
pub mod camera;
|
||||||
|
pub mod debug;
|
||||||
pub mod figure;
|
pub mod figure;
|
||||||
pub mod lod;
|
pub mod lod;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
@ -8,6 +9,7 @@ pub mod terrain;
|
|||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
camera::{Camera, CameraMode},
|
camera::{Camera, CameraMode},
|
||||||
|
debug::{Debug, DebugShape, DebugShapeId},
|
||||||
figure::FigureMgr,
|
figure::FigureMgr,
|
||||||
lod::Lod,
|
lod::Lod,
|
||||||
particle::ParticleMgr,
|
particle::ParticleMgr,
|
||||||
@ -79,6 +81,7 @@ pub struct Scene {
|
|||||||
|
|
||||||
skybox: Skybox,
|
skybox: Skybox,
|
||||||
terrain: Terrain<TerrainChunk>,
|
terrain: Terrain<TerrainChunk>,
|
||||||
|
pub debug: Debug,
|
||||||
pub lod: Lod,
|
pub lod: Lod,
|
||||||
loaded_distance: f32,
|
loaded_distance: f32,
|
||||||
/// x coordinate is sea level (minimum height for any land chunk), and y
|
/// x coordinate is sea level (minimum height for any land chunk), and y
|
||||||
@ -289,6 +292,7 @@ impl Scene {
|
|||||||
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
model: renderer.create_model(&create_skybox_mesh()).unwrap(),
|
||||||
},
|
},
|
||||||
terrain,
|
terrain,
|
||||||
|
debug: Debug::new(),
|
||||||
lod,
|
lod,
|
||||||
loaded_distance: 0.0,
|
loaded_distance: 0.0,
|
||||||
map_bounds: Vec2::new(
|
map_bounds: Vec2::new(
|
||||||
@ -653,6 +657,9 @@ impl Scene {
|
|||||||
// Maintain LoD.
|
// Maintain LoD.
|
||||||
self.lod.maintain(renderer);
|
self.lod.maintain(renderer);
|
||||||
|
|
||||||
|
// Maintain debug shapes
|
||||||
|
self.debug.maintain(renderer);
|
||||||
|
|
||||||
// Maintain the terrain.
|
// Maintain the terrain.
|
||||||
let (_visible_bounds, visible_light_volume, visible_psr_bounds) = self.terrain.maintain(
|
let (_visible_bounds, visible_light_volume, visible_psr_bounds) = self.terrain.maintain(
|
||||||
renderer,
|
renderer,
|
||||||
@ -1109,6 +1116,9 @@ impl Scene {
|
|||||||
// Render particle effects.
|
// Render particle effects.
|
||||||
self.particle_mgr
|
self.particle_mgr
|
||||||
.render(&mut first_pass.draw_particles(), scene_data);
|
.render(&mut first_pass.draw_particles(), scene_data);
|
||||||
|
|
||||||
|
// Render debug shapes
|
||||||
|
self.debug.render(&mut first_pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ use crate::{
|
|||||||
key_state::KeyState,
|
key_state::KeyState,
|
||||||
menu::char_selection::CharSelectionState,
|
menu::char_selection::CharSelectionState,
|
||||||
render::Renderer,
|
render::Renderer,
|
||||||
scene::{camera, terrain::Interaction, CameraMode, Scene, SceneData},
|
scene::{camera, terrain::Interaction, CameraMode, DebugShape, DebugShapeId, Scene, SceneData},
|
||||||
settings::Settings,
|
settings::Settings,
|
||||||
window::{AnalogGameInput, Event, GameInput},
|
window::{AnalogGameInput, Event, GameInput},
|
||||||
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
Direction, Error, GlobalState, PlayState, PlayStateResult,
|
||||||
@ -73,6 +73,7 @@ pub struct SessionState {
|
|||||||
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
selected_entity: Option<(specs::Entity, std::time::Instant)>,
|
||||||
interactable: Option<Interactable>,
|
interactable: Option<Interactable>,
|
||||||
saved_zoom_dist: Option<f32>,
|
saved_zoom_dist: Option<f32>,
|
||||||
|
player_hitbox: DebugShapeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents an active game session (i.e., the one being played).
|
/// Represents an active game session (i.e., the one being played).
|
||||||
@ -100,6 +101,10 @@ impl SessionState {
|
|||||||
let hud = Hud::new(global_state, &client.borrow());
|
let hud = Hud::new(global_state, &client.borrow());
|
||||||
let walk_forward_dir = scene.camera().forward_xy();
|
let walk_forward_dir = scene.camera().forward_xy();
|
||||||
let walk_right_dir = scene.camera().right_xy();
|
let walk_right_dir = scene.camera().right_xy();
|
||||||
|
let player_hitbox = scene.debug.add_shape(DebugShape::Cylinder {
|
||||||
|
radius: 0.4,
|
||||||
|
height: 1.75,
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
scene,
|
scene,
|
||||||
@ -120,6 +125,7 @@ impl SessionState {
|
|||||||
selected_entity: None,
|
selected_entity: None,
|
||||||
interactable: None,
|
interactable: None,
|
||||||
saved_zoom_dist: None,
|
saved_zoom_dist: None,
|
||||||
|
player_hitbox,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,6 +145,17 @@ impl SessionState {
|
|||||||
span!(_guard, "tick", "Session::tick");
|
span!(_guard, "tick", "Session::tick");
|
||||||
|
|
||||||
let mut client = self.client.borrow_mut();
|
let mut client = self.client.borrow_mut();
|
||||||
|
if let Some(player_pos) = client
|
||||||
|
.state()
|
||||||
|
.ecs()
|
||||||
|
.read_component::<Pos>()
|
||||||
|
.get(client.entity())
|
||||||
|
{
|
||||||
|
let pos = [player_pos.0.x, player_pos.0.y, player_pos.0.z, 0.0];
|
||||||
|
self.scene
|
||||||
|
.debug
|
||||||
|
.set_pos_and_color(self.player_hitbox, pos, [1.0, 0.0, 0.0, 0.5]);
|
||||||
|
}
|
||||||
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? {
|
for event in client.tick(self.inputs.clone(), dt, crate::ecs::sys::add_local_systems)? {
|
||||||
match event {
|
match event {
|
||||||
client::Event::Chat(m) => {
|
client::Event::Chat(m) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user