From 600a40451697f523bd86731839b5d7be2b941cbd Mon Sep 17 00:00:00 2001 From: Maximilian Ammann Date: Thu, 13 Jan 2022 17:12:49 +0100 Subject: [PATCH] Refactor coordinate system such that it is simpler --- src/coords.rs | 48 +++++++++++++++++++++++------ src/render/camera.rs | 14 +++++++-- src/render/mod.rs | 2 ++ src/render/options.rs | 1 + src/render/piplines.rs | 17 ++++------ src/render/render_state.rs | 7 +---- src/render/shaders/mod.rs | 12 +++++++- src/render/shaders/tile.vertex.wgsl | 3 +- src/render/stencil_pattern.rs | 20 ++++++------ 9 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 src/render/options.rs diff --git a/src/coords.rs b/src/coords.rs index ad968390..fd502799 100644 --- a/src/coords.rs +++ b/src/coords.rs @@ -1,7 +1,15 @@ +//! File which exposes all kinds of coordinates used throughout mapr + use std::fmt; use crate::render::shader_ffi::Vec3f32; +/// Every tile has tile coordinates. These tile coordinates are also called +/// [Slippy map tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). +/// +/// # Coordinate System Origin +/// +/// For Web Mercator the origin of the coordinate system is in the upper-left corner. #[derive(Clone, Copy, Debug)] pub struct TileCoords { pub x: u32, @@ -10,10 +18,12 @@ pub struct TileCoords { } impl TileCoords { + /// Transforms the tile coordinates as defined by the tile grid into a representation which is + /// used in the 3d-world. pub fn into_world_tile(self) -> WorldTileCoords { WorldTileCoords { x: self.x as i32 - crate::example::MUNICH_X as i32, - y: (self.y as i32 - crate::example::MUNICH_Y as i32 + 1) * -1, + y: self.y as i32 - crate::example::MUNICH_Y as i32, z: 0, } } @@ -35,6 +45,13 @@ impl From<(u32, u32, u8)> for TileCoords { } } +/// Every tile has tile coordinates. Every tile coordinate can be mapped to a coordinate within +/// the world. This provides the freedom to map from [TMS](https://wiki.openstreetmap.org/wiki/TMS) +/// to [Slippy_map_tilenames](https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames). +/// +/// # Coordinate System Origin +/// +/// The origin of the coordinate system is in the upper-left corner. #[derive(Clone, Copy, Debug)] pub struct WorldTileCoords { pub x: i32, @@ -46,7 +63,7 @@ impl WorldTileCoords { pub fn into_world(self, extent: f32) -> WorldCoords { WorldCoords { x: self.x as f32 * extent, - y: self.y as f32 * extent + extent, // We add extent here as we want the upper left corner + y: self.y as f32 * extent, z: self.z as f32, } } @@ -54,7 +71,7 @@ impl WorldTileCoords { pub fn into_aligned(self) -> AlignedWorldTileCoords { AlignedWorldTileCoords(WorldTileCoords { x: self.x / 2 * 2, - y: self.y / 2 * 2 - 1, + y: self.y / 2 * 2, z: self.z, }) } @@ -76,6 +93,14 @@ impl From<(i32, i32, u8)> for WorldTileCoords { } } +/// An aligned world tile coordinate aligns a world coordinate at a 4x4 tile raster within the +/// world. The aligned coordinates is defined by the coordinates of the upper left tile in the 4x4 +/// tile raster divided by 2 and rounding to the ceiling. +/// +/// +/// # Coordinate System Origin +/// +/// The origin of the coordinate system is in the upper-left corner. pub struct AlignedWorldTileCoords(pub WorldTileCoords); impl AlignedWorldTileCoords { @@ -83,15 +108,15 @@ impl AlignedWorldTileCoords { self.0 } - pub fn to_upper_right(&self) -> WorldTileCoords { + pub fn upper_right(&self) -> WorldTileCoords { WorldTileCoords { x: self.0.x + 1, - y: self.0.y + 1, + y: self.0.y, z: self.0.z, } } - pub fn to_lower_left(&self) -> WorldTileCoords { + pub fn lower_left(&self) -> WorldTileCoords { WorldTileCoords { x: self.0.x, y: self.0.y - 1, @@ -99,10 +124,10 @@ impl AlignedWorldTileCoords { } } - pub fn to_lower_right(&self) -> WorldTileCoords { + pub fn lower_right(&self) -> WorldTileCoords { WorldTileCoords { - x: self.0.x - 1, - y: self.0.y - 1, + x: self.0.x + 1, + y: self.0.y + 1, z: self.0.z, } } @@ -115,6 +140,11 @@ pub struct WorldCoords { pub z: f32, } +/// Actual coordinates within the 3d world. +/// +/// # Coordinate System Origin +/// +/// The origin of the coordinate system is in the upper-left corner. impl WorldCoords { pub fn into_shader_coords(self) -> Vec3f32 { [self.x, self.y, self.z] diff --git a/src/render/camera.rs b/src/render/camera.rs index 23612c16..f18985c9 100644 --- a/src/render/camera.rs +++ b/src/render/camera.rs @@ -11,6 +11,14 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( 0.0, 0.0, 0.5, 1.0, ); +#[rustfmt::skip] +pub const FLIP_Y: cgmath::Matrix4 = cgmath::Matrix4::new( + 1.0, 0.0, 0.0, 0.0, + 0.0, -1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, +); + #[derive(Debug)] pub struct Camera { pub position: cgmath::Point3, @@ -35,7 +43,7 @@ impl Camera { } } - pub fn calc_matrix(&self) -> cgmath::Matrix4 { + fn calc_matrix(&self) -> cgmath::Matrix4 { cgmath::Matrix4::look_to_rh( self.position, cgmath::Vector3::new(self.yaw.0.cos(), self.pitch.0.sin(), self.yaw.0.sin()) @@ -45,7 +53,7 @@ impl Camera { } pub fn calc_view_proj(&self, perspective: &Perspective) -> Matrix4 { - perspective.calc_matrix() * self.calc_matrix() + FLIP_Y * perspective.calc_matrix() * self.calc_matrix() } pub fn create_camera_uniform(&self, perspective: &Perspective) -> CameraUniform { @@ -84,7 +92,7 @@ impl Perspective { self.aspect = width as f64 / height as f64; } - pub fn calc_matrix(&self) -> cgmath::Matrix4 { + fn calc_matrix(&self) -> cgmath::Matrix4 { OPENGL_TO_WGPU_MATRIX * cgmath::perspective(self.fovy, self.aspect, self.znear, self.zfar) } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 80f926f0..656feb0d 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -1,9 +1,11 @@ mod buffer_pool; + mod piplines; mod shaders; mod stencil_pattern; mod texture; pub mod camera; +pub mod options; pub mod render_state; pub mod shader_ffi; diff --git a/src/render/options.rs b/src/render/options.rs new file mode 100644 index 00000000..90e2f542 --- /dev/null +++ b/src/render/options.rs @@ -0,0 +1 @@ +pub const DEBUG_STENCIL_PATTERN: bool = false; diff --git a/src/render/piplines.rs b/src/render/piplines.rs index 33cb9376..a98d09ad 100644 --- a/src/render/piplines.rs +++ b/src/render/piplines.rs @@ -1,3 +1,4 @@ +use crate::render::options::DEBUG_STENCIL_PATTERN; use wgpu::{FragmentState, PipelineLayout, RenderPipelineDescriptor, VertexState}; use super::texture::DEPTH_TEXTURE_FORMAT; @@ -7,20 +8,10 @@ use super::texture::DEPTH_TEXTURE_FORMAT; /// /// # Arguments /// -/// * `pipeline_layout`: -/// * `vertex_state`: -/// * `fragment_state`: -/// * `sample_count`: /// * `update_stencil`: Fragments passing through the pipeline will be able to update the stencil /// buffer. This is used for masking /// /// returns: RenderPipelineDescriptor -/// -/// # Examples -/// -/// ``` -/// -/// ``` pub fn create_map_render_pipeline_description<'a>( pipeline_layout: &'a PipelineLayout, vertex_state: VertexState<'a>, @@ -37,7 +28,11 @@ pub fn create_map_render_pipeline_description<'a>( } } else { wgpu::StencilFaceState { - compare: wgpu::CompareFunction::Equal, + compare: if DEBUG_STENCIL_PATTERN { + wgpu::CompareFunction::Always + } else { + wgpu::CompareFunction::Equal + }, fail_op: wgpu::StencilOperation::Keep, depth_fail_op: wgpu::StencilOperation::Keep, pass_op: wgpu::StencilOperation::Keep, diff --git a/src/render/render_state.rs b/src/render/render_state.rs index 6d1f58b8..727b224d 100644 --- a/src/render/render_state.rs +++ b/src/render/render_state.rs @@ -6,14 +6,13 @@ use wgpu::{Buffer, BufferAddress, Limits, Queue}; use winit::dpi::PhysicalSize; use winit::window::Window; -use crate::fps_meter::FPSMeter; use crate::io::cache::Cache; use crate::platform::{COLOR_TEXTURE_FORMAT, MIN_BUFFER_SIZE}; use crate::render::buffer_pool::{BackingBufferDescriptor, BufferPool}; use crate::render::stencil_pattern::TileMaskPattern; use crate::render::{camera, shaders}; use crate::tesselation::IndexDataType; -use crate::util::measure::Measure; +use crate::util::FPSMeter; use super::piplines::*; use super::shader_ffi::*; @@ -82,8 +81,6 @@ impl SceneParams { impl RenderState { pub async fn new(window: &Window) -> Self { - let mut measure = Measure::time(); - let sample_count = 4; let size = if cfg!(target_os = "android") { @@ -271,8 +268,6 @@ impl RenderState { 100000.0, ); - measure.breadcrumb("initialized"); - Self { instance, surface, diff --git a/src/render/shaders/mod.rs b/src/render/shaders/mod.rs index e7fe6284..5a84b77a 100644 --- a/src/render/shaders/mod.rs +++ b/src/render/shaders/mod.rs @@ -123,7 +123,9 @@ pub mod tile { pub mod tile_mask { use crate::platform::COLOR_TEXTURE_FORMAT; + use crate::render::options::DEBUG_STENCIL_PATTERN; use crate::render::shader_ffi::MaskInstanceUniform; + use wgpu::ColorWrites; use super::{FragmentShaderState, VertexShaderState}; @@ -168,7 +170,15 @@ pub mod tile_mask { &[wgpu::ColorTargetState { format: COLOR_TEXTURE_FORMAT, blend: None, - write_mask: wgpu::ColorWrites::empty(), + write_mask: mask_write_mask(), }], ); + + pub const fn mask_write_mask() -> ColorWrites { + if DEBUG_STENCIL_PATTERN { + wgpu::ColorWrites::ALL + } else { + wgpu::ColorWrites::empty() + } + } } diff --git a/src/render/shaders/tile.vertex.wgsl b/src/render/shaders/tile.vertex.wgsl index b61b5981..9cda90c6 100644 --- a/src/render/shaders/tile.vertex.wgsl +++ b/src/render/shaders/tile.vertex.wgsl @@ -26,8 +26,7 @@ fn main( let z = 0.0; let width = 3.0; - // position the anchor of a tile at the top left, instead of bottom right - let world_pos = vec3(1.0, -1.0, 1.0) * vec3(position + normal * width, z) + translate; + let world_pos = vec3(position + normal * width, z) + translate; let position = globals.camera.view_proj * vec4(world_pos, 1.0); diff --git a/src/render/stencil_pattern.rs b/src/render/stencil_pattern.rs index 631bd494..d6ce11c5 100644 --- a/src/render/stencil_pattern.rs +++ b/src/render/stencil_pattern.rs @@ -71,7 +71,7 @@ impl TileMaskPattern { } fn vertical(&mut self, dx: i32, dy: i32, anchor_x: f32, anchor_y: f32, extent: f32) { - for i in 0..(dx.abs() / 2) { + for i in 0..(dx.abs() / 2 + 1) { self.pattern.push(MaskInstanceUniform::new( [anchor_x + ((i * 2) + 1) as f32 * extent, anchor_y], 1.0, @@ -82,9 +82,9 @@ impl TileMaskPattern { } fn horizontal(&mut self, dx: i32, dy: i32, anchor_x: f32, anchor_y: f32, extent: f32) { - for i in 0..(dy.abs() / 2) { + for i in 0..(dy.abs() / 2 + 1) { self.pattern.push(MaskInstanceUniform::new( - [anchor_x, anchor_y - extent - (i * 2) as f32 * extent], + [anchor_x, anchor_y + (i * 2) as f32 * extent], dx as f32, 1.0, [0.0, 0.0, 1.0, 1.0], @@ -94,10 +94,10 @@ impl TileMaskPattern { pub fn stencil_reference_value(&self, world_coords: &WorldTileCoords) -> u8 { match (world_coords.x, world_coords.y) { - (x, y) if x % 2 == 0 && y % 2 == 0 => 1, - (x, y) if x % 2 == 0 && y % 2 != 0 => 2, - (x, y) if x % 2 != 0 && y % 2 == 0 => 3, - (x, y) if x % 2 != 0 && y % 2 != 0 => 4, + (x, y) if x % 2 == 0 && y % 2 == 0 => 2, + (x, y) if x % 2 == 0 && y % 2 != 0 => 1, + (x, y) if x % 2 != 0 && y % 2 == 0 => 4, + (x, y) if x % 2 != 0 && y % 2 != 0 => 3, _ => unreachable!(), } } @@ -109,11 +109,11 @@ impl TileMaskPattern { self.pattern.clear(); - let start: WorldTileCoords = (self.bounding_box.min_x, self.bounding_box.max_y, z).into(); // upper left corner - let end: WorldTileCoords = (self.bounding_box.max_x, self.bounding_box.min_y, z).into(); // lower right corner + let start: WorldTileCoords = (self.bounding_box.min_x, self.bounding_box.min_y, z).into(); // upper left corner + let end: WorldTileCoords = (self.bounding_box.max_x, self.bounding_box.max_y, z).into(); // lower right corner let aligned_start = start.into_aligned(); - let aligned_end = end.into_aligned().to_lower_right(); + let aligned_end = end.into_aligned().lower_right(); let start_world = start.into_world(extent);