Refactor coordinate system such that it is simpler

This commit is contained in:
Maximilian Ammann 2022-01-13 17:12:49 +01:00
parent 3a230010ca
commit 600a404516
9 changed files with 82 additions and 42 deletions

View File

@ -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]

View File

@ -11,6 +11,14 @@ pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f64> = cgmath::Matrix4::new(
0.0, 0.0, 0.5, 1.0,
);
#[rustfmt::skip]
pub const FLIP_Y: cgmath::Matrix4<f64> = 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<f64>,
@ -35,7 +43,7 @@ impl Camera {
}
}
pub fn calc_matrix(&self) -> cgmath::Matrix4<f64> {
fn calc_matrix(&self) -> cgmath::Matrix4<f64> {
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<f64> {
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<f64> {
fn calc_matrix(&self) -> cgmath::Matrix4<f64> {
OPENGL_TO_WGPU_MATRIX * cgmath::perspective(self.fovy, self.aspect, self.znear, self.zfar)
}
}

View File

@ -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;

1
src/render/options.rs Normal file
View File

@ -0,0 +1 @@
pub const DEBUG_STENCIL_PATTERN: bool = false;

View File

@ -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,

View File

@ -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,

View File

@ -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()
}
}
}

View File

@ -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<f32>(1.0, -1.0, 1.0) * vec3<f32>(position + normal * width, z) + translate;
let world_pos = vec3<f32>(position + normal * width, z) + translate;
let position = globals.camera.view_proj * vec4<f32>(world_pos, 1.0);

View File

@ -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);