Skip to content

Commit

Permalink
Add visual debugging for entities
Browse files Browse the repository at this point in the history
- Display rectangles and bounding boxes for the sprites of each entity.
- Highlight the center of each bounding box and create an axis to facilitate alignment verification.
- Implement a mode where billboards always faces the current camera.
- Reduce the billboard size for the player entity.
- Refactor the code to reuse existing functions.
- Convert sRGB to linear color inside AABB/Circle/Rectangle pipeline.
  • Loading branch information
kokosha committed Dec 15, 2024
1 parent 36bea90 commit 6643647
Show file tree
Hide file tree
Showing 14 changed files with 559 additions and 77 deletions.
19 changes: 18 additions & 1 deletion korangar/src/graphics/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ struct EngineContext {
#[cfg(feature = "debug")]
forward_circle_drawer: ForwardCircleDrawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer: ForwardRectangleDrawer,
#[cfg(feature = "debug")]
post_processing_buffer_drawer: PostProcessingBufferDrawer,
#[cfg(feature = "debug")]
picker_marker_drawer: PickerMarkerDrawer,
Expand Down Expand Up @@ -288,9 +290,10 @@ impl GraphicsEngine {

#[cfg(feature = "debug")]
forward_aabb_drawer,

#[cfg(feature = "debug")]
forward_circle_drawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer,
} = ForwardResources::create(
&self.capabilities,
&self.device,
Expand Down Expand Up @@ -371,6 +374,8 @@ impl GraphicsEngine {
#[cfg(feature = "debug")]
forward_circle_drawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer,
#[cfg(feature = "debug")]
post_processing_buffer_drawer,
#[cfg(feature = "debug")]
picker_marker_drawer,
Expand Down Expand Up @@ -488,6 +493,8 @@ impl GraphicsEngine {
forward_aabb_drawer,
#[cfg(feature = "debug")]
forward_circle_drawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer,
} = ForwardResources::create(
&self.capabilities,
&self.device,
Expand Down Expand Up @@ -531,6 +538,7 @@ impl GraphicsEngine {
{
engine_context.forward_aabb_drawer = forward_aabb_drawer;
engine_context.forward_circle_drawer = forward_circle_drawer;
engine_context.forward_rectangle_drawer = forward_rectangle_drawer;
engine_context.post_processing_buffer_drawer = post_processing_buffer_drawer;
}
}
Expand Down Expand Up @@ -776,6 +784,7 @@ impl GraphicsEngine {
scope.spawn(|_| {
context.post_processing_buffer_drawer.prepare(&self.device, instruction);
context.forward_circle_drawer.prepare(&self.device, instruction);
context.forward_rectangle_drawer.prepare(&self.device, instruction);
});

context.global_context.prepare(&self.device, instruction);
Expand Down Expand Up @@ -812,6 +821,7 @@ impl GraphicsEngine {
visitor.upload(&mut context.forward_aabb_drawer);
visitor.upload(&mut context.post_processing_buffer_drawer);
visitor.upload(&mut context.forward_circle_drawer);
visitor.upload(&mut context.forward_rectangle_drawer);
visitor.upload(&mut context.picker_marker_drawer);
}

Expand Down Expand Up @@ -1000,6 +1010,7 @@ impl GraphicsEngine {
{
engine_context.forward_aabb_drawer.draw(&mut render_pass, None);
engine_context.forward_circle_drawer.draw(&mut render_pass, None);
engine_context.forward_rectangle_drawer.draw(&mut render_pass, None);
}

if instruction.water.is_some() {
Expand Down Expand Up @@ -1177,6 +1188,8 @@ struct ForwardResources {
forward_aabb_drawer: ForwardAabbDrawer,
#[cfg(feature = "debug")]
forward_circle_drawer: ForwardCircleDrawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer: ForwardRectangleDrawer,
}

impl ForwardResources {
Expand All @@ -1194,6 +1207,8 @@ impl ForwardResources {
let forward_aabb_drawer = ForwardAabbDrawer::new(capabilities, device, queue, global_context, forward_pass_context);
#[cfg(feature = "debug")]
let forward_circle_drawer = ForwardCircleDrawer::new(capabilities, device, queue, global_context, forward_pass_context);
#[cfg(feature = "debug")]
let forward_rectangle_drawer = ForwardRectangleDrawer::new(capabilities, device, queue, global_context, forward_pass_context);

Self {
forward_entity_drawer,
Expand All @@ -1203,6 +1218,8 @@ impl ForwardResources {
forward_aabb_drawer,
#[cfg(feature = "debug")]
forward_circle_drawer,
#[cfg(feature = "debug")]
forward_rectangle_drawer,
}
}
}
Expand Down
9 changes: 9 additions & 0 deletions korangar/src/graphics/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ pub struct RenderInstruction<'a> {
#[cfg(feature = "debug")]
pub circles: &'a [DebugCircleInstruction],
#[cfg(feature = "debug")]
pub rectangles: &'a [DebugRectangleInstruction],
#[cfg(feature = "debug")]
pub marker: &'a [MarkerInstruction],
}

Expand Down Expand Up @@ -238,3 +240,10 @@ pub struct DebugCircleInstruction {
pub screen_position: ScreenPosition,
pub screen_size: ScreenSize,
}

#[cfg(feature = "debug")]
#[derive(Copy, Clone, Debug)]
pub struct DebugRectangleInstruction {
pub world: Matrix4<f32>,
pub color: Color,
}
2 changes: 1 addition & 1 deletion korangar/src/graphics/passes/forward/aabb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl Prepare for ForwardAabbDrawer {
for instruction in instructions.aabb.iter() {
self.instance_data.push(InstanceData {
world: instruction.world.into(),
color: instruction.color.into(),
color: instruction.color.components_linear(),
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion korangar/src/graphics/passes/forward/circle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl Prepare for ForwardCircleDrawer {
for instruction in instructions.circles.iter() {
self.instance_data.push(InstanceData {
position: instruction.position.to_homogeneous().into(),
color: instruction.color.into(),
color: instruction.color.components_linear(),
screen_position: instruction.screen_position.into(),
screen_size: instruction.screen_size.into(),
});
Expand Down
4 changes: 4 additions & 0 deletions korangar/src/graphics/passes/forward/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod circle;
mod entity;
mod indicator;
mod model;
#[cfg(feature = "debug")]
mod rectangle;

#[cfg(feature = "debug")]
pub(crate) use aabb::ForwardAabbDrawer;
Expand All @@ -13,6 +15,8 @@ pub(crate) use circle::ForwardCircleDrawer;
pub(crate) use entity::ForwardEntityDrawer;
pub(crate) use indicator::ForwardIndicatorDrawer;
pub(crate) use model::ForwardModelDrawer;
#[cfg(feature = "debug")]
pub(crate) use rectangle::ForwardRectangleDrawer;
use wgpu::{
BindGroupLayout, Color, CommandEncoder, Device, LoadOp, Operations, Queue, RenderPass, RenderPassColorAttachment,
RenderPassDepthStencilAttachment, RenderPassDescriptor, StoreOp, TextureFormat,
Expand Down
216 changes: 216 additions & 0 deletions korangar/src/graphics/passes/forward/rectangle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use std::num::NonZeroU64;

use bytemuck::{Pod, Zeroable};
use cgmath::Point3;
use wgpu::util::StagingBelt;
use wgpu::{
include_wgsl, BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
BindingType, BufferBindingType, BufferUsages, ColorTargetState, ColorWrites, CommandEncoder, CompareFunction, DepthBiasState,
DepthStencilState, Device, FragmentState, IndexFormat, MultisampleState, PipelineCompilationOptions, PipelineLayoutDescriptor,
PrimitiveState, PrimitiveTopology, Queue, RenderPass, RenderPipeline, RenderPipelineDescriptor, ShaderModuleDescriptor, ShaderStages,
StencilState, VertexState,
};

use crate::graphics::passes::{
BindGroupCount, ColorAttachmentCount, DepthAttachmentCount, Drawer, ForwardRenderPassContext, RenderPassContext,
};
use crate::graphics::{Capabilities, GlobalContext, Prepare, RenderInstruction, SimpleVertex};
use crate::Buffer;

const SHADER: ShaderModuleDescriptor = include_wgsl!("shader/rectangle.wgsl");
const DRAWER_NAME: &str = "screen rectangle";
const INITIAL_INSTRUCTION_SIZE: usize = 256;
const INDEX_COUNT: usize = 8;

#[derive(Copy, Clone, Pod, Zeroable)]
#[repr(C)]
struct InstanceData {
world: [[f32; 4]; 4],
color: [f32; 4],
}

pub(crate) struct ForwardRectangleDrawer {
vertex_buffer: Buffer<SimpleVertex>,
index_buffer: Buffer<u16>,
instance_data_buffer: Buffer<InstanceData>,
bind_group_layout: BindGroupLayout,
bind_group: BindGroup,
pipeline: RenderPipeline,
draw_count: usize,
instance_data: Vec<InstanceData>,
}

impl Drawer<{ BindGroupCount::Two }, { ColorAttachmentCount::One }, { DepthAttachmentCount::One }> for ForwardRectangleDrawer {
type Context = ForwardRenderPassContext;
type DrawData<'data> = Option<()>;

fn new(
_capabilities: &Capabilities,
device: &Device,
queue: &Queue,
global_context: &GlobalContext,
render_pass_context: &Self::Context,
) -> Self {
let shader_module = device.create_shader_module(SHADER);

// Vertices are defined in world coordinates (Same as WGPU's NDC).
let vertex_data = [
SimpleVertex::new(Point3::new(-1.0, 0.0, 1.0)),
SimpleVertex::new(Point3::new(-1.0, 2.0, 1.0)),
SimpleVertex::new(Point3::new(1.0, 0.0, 1.0)),
SimpleVertex::new(Point3::new(1.0, 2.0, 1.0)),
];

let index_data: [u16; INDEX_COUNT] = [0, 1, 2, 3, 1, 3, 0, 2];

let vertex_buffer = Buffer::with_data(
device,
queue,
format!("{DRAWER_NAME} box vertex"),
BufferUsages::VERTEX | BufferUsages::COPY_DST,
&vertex_data,
);

let index_buffer = Buffer::with_data(
device,
queue,
format!("{DRAWER_NAME} box index"),
BufferUsages::INDEX | BufferUsages::COPY_DST,
&index_data,
);

let instance_data_buffer = Buffer::with_capacity(
device,
format!("{DRAWER_NAME} instance data"),
BufferUsages::COPY_DST | BufferUsages::STORAGE,
(size_of::<InstanceData>() * INITIAL_INSTRUCTION_SIZE) as _,
);

let bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some(DRAWER_NAME),
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX_FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: NonZeroU64::new(size_of::<InstanceData>() as _),
},
count: None,
}],
});

let bind_group = Self::create_bind_group(device, &bind_group_layout, &instance_data_buffer);

let bind_group_layouts = Self::Context::bind_group_layout(device);

let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: Some(DRAWER_NAME),
bind_group_layouts: &[bind_group_layouts[0], bind_group_layouts[1], &bind_group_layout],
push_constant_ranges: &[],
});

let pipeline = device.create_render_pipeline(&RenderPipelineDescriptor {
label: Some(DRAWER_NAME),
layout: Some(&pipeline_layout),
vertex: VertexState {
module: &shader_module,
entry_point: Some("vs_main"),
compilation_options: PipelineCompilationOptions::default(),
buffers: &[SimpleVertex::buffer_layout()],
},
fragment: Some(FragmentState {
module: &shader_module,
entry_point: Some("fs_main"),
compilation_options: PipelineCompilationOptions::default(),
targets: &[Some(ColorTargetState {
format: render_pass_context.color_attachment_formats()[0],
blend: None,
write_mask: ColorWrites::default(),
})],
}),
multiview: None,
primitive: PrimitiveState {
topology: PrimitiveTopology::LineList,
..Default::default()
},
depth_stencil: Some(DepthStencilState {
format: render_pass_context.depth_attachment_output_format()[0],
depth_write_enabled: false,
depth_compare: CompareFunction::Always,
stencil: StencilState::default(),
bias: DepthBiasState::default(),
}),
multisample: MultisampleState {
count: global_context.msaa.sample_count(),
..Default::default()
},
cache: None,
});

Self {
vertex_buffer,
index_buffer,
instance_data_buffer,
bind_group_layout,
bind_group,
pipeline,
draw_count: 0,
instance_data: Vec::default(),
}
}

fn draw(&mut self, pass: &mut RenderPass<'_>, _draw_data: Self::DrawData<'_>) {
if self.draw_count == 0 {
return;
}

pass.set_pipeline(&self.pipeline);
pass.set_bind_group(2, &self.bind_group, &[]);
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint16);
pass.draw_indexed(0..INDEX_COUNT as u32, 0, 0..self.draw_count as u32);
}
}

impl Prepare for ForwardRectangleDrawer {
fn prepare(&mut self, _device: &Device, instructions: &RenderInstruction) {
self.draw_count = instructions.rectangles.len();

if self.draw_count == 0 {
return;
}

self.instance_data.clear();

for instruction in instructions.rectangles.iter() {
self.instance_data.push(InstanceData {
world: instruction.world.into(),
color: instruction.color.components_linear(),
});
}
}

fn upload(&mut self, device: &Device, staging_belt: &mut StagingBelt, command_encoder: &mut CommandEncoder) {
let recreated = self
.instance_data_buffer
.write(device, staging_belt, command_encoder, &self.instance_data);

if recreated {
self.bind_group = Self::create_bind_group(device, &self.bind_group_layout, &self.instance_data_buffer);
}
}
}

impl ForwardRectangleDrawer {
fn create_bind_group(device: &Device, bind_group_layout: &BindGroupLayout, instance_data_buffer: &Buffer<InstanceData>) -> BindGroup {
device.create_bind_group(&BindGroupDescriptor {
label: Some(DRAWER_NAME),
layout: bind_group_layout,
entries: &[BindGroupEntry {
binding: 0,
resource: instance_data_buffer.as_entire_binding(),
}],
})
}
}
Loading

0 comments on commit 6643647

Please sign in to comment.