From 1b4e653b0b09fbd9fdc861ce65a50b43a9adc973 Mon Sep 17 00:00:00 2001 From: Adrien Bon <63343541+adrien-bon@users.noreply.github.com> Date: Wed, 24 Jul 2024 10:34:24 +0000 Subject: [PATCH] feat: add a new TilemapRenderSettings to control chunks RenderOrder --- examples/3d_iso.rs | 3 +- src/map.rs | 72 +++++++++++++++++++++++++++++++++++++++++- src/render/chunk.rs | 6 ++++ src/render/material.rs | 6 +++- src/render/prepare.rs | 1 + 5 files changed, 85 insertions(+), 3 deletions(-) diff --git a/examples/3d_iso.rs b/examples/3d_iso.rs index b8219cd3..49814641 100644 --- a/examples/3d_iso.rs +++ b/examples/3d_iso.rs @@ -14,7 +14,8 @@ fn startup(mut commands: Commands, asset_server: Res) { // Map size is 12x12 so we'll have render chunks that are: // 12 tiles wide and 1 tile tall. render_chunk_size: UVec2::new(3, 1), - y_sort: true, + y_sort: true, // equivalent to render_order: RenderOrder::YReverseThenX + ..Default::default() }, ..Default::default() }); diff --git a/src/map.rs b/src/map.rs index 3fcf1f4b..276532c9 100644 --- a/src/map.rs +++ b/src/map.rs @@ -4,13 +4,80 @@ use bevy::ecs::reflect::ReflectMapEntities; use bevy::prelude::{ReflectComponent, Res, ResMut}; use bevy::render::render_resource::TextureUsages; use bevy::{ - math::{UVec2, Vec2}, + math::{UVec2, Vec2, Vec3}, prelude::{Component, Deref, DerefMut, Entity, Handle, Image, Reflect}, }; /// The default chunk_size (in tiles) used per mesh. pub const CHUNK_SIZE_2D: UVec2 = UVec2::from_array([64, 64]); +/// The order in which we want to perform the render +#[derive(Clone, Debug, Copy, Default)] +pub enum RenderOrder { + #[default] + None, + XThenY, + XReverseThenY, + XThenYReverse, + XReverseThenYReverse, + YThenX, + YReverseThenX, + YThenXReverse, + YReverseThenXReverse, +} + +impl RenderOrder { + /// Compute a new Z translation value based upon the selected render order + /// Returned Z value will have an offset between 0 and 11 + pub fn compute_z_translation( + &self, + translation: &Vec3, + tilemap_size: TilemapSize, + tile_size: TilemapTileSize, + ) -> f32 { + let scaling_factor = 10.; + let map_size_x = tilemap_size.x as f32 * tile_size.x; + let map_size_y = tilemap_size.y as f32 * tile_size.y; + let mut z_value = translation.z; + match self { + Self::XThenY => { + z_value += scaling_factor * (translation.x / map_size_x); + z_value += translation.y / map_size_y; + } + Self::XReverseThenY => { + z_value += scaling_factor * (1. - (translation.x / map_size_x)); + z_value += translation.y / map_size_y; + } + Self::XThenYReverse => { + z_value += scaling_factor * (translation.x / map_size_x); + z_value += 1. - (translation.y / map_size_y); + } + Self::XReverseThenYReverse => { + z_value += scaling_factor * (1. - (translation.x / map_size_x)); + z_value += 1. - (translation.y / map_size_y); + } + Self::YThenX => { + z_value += translation.x / map_size_x; + z_value += scaling_factor * (translation.y / map_size_y); + } + Self::YReverseThenX => { + z_value += translation.x / map_size_x; + z_value += scaling_factor * (1. - (translation.y / map_size_y)); + } + Self::YThenXReverse => { + z_value += 1. - (translation.x / map_size_x); + z_value += scaling_factor * (translation.y / map_size_y); + } + Self::YReverseThenXReverse => { + z_value += 1. - (translation.x / map_size_x); + z_value += scaling_factor * (1. - (translation.y / map_size_y)); + } + _ => {} + }; + z_value + } +} + /// Custom parameters for the render pipeline. /// /// It must be added as a component to the tilemap entity. @@ -30,6 +97,8 @@ pub struct TilemapRenderSettings { /// /// `render_chunk_size`'s `z` value should be `1` when using this for 3d isometric tilemaps. pub y_sort: bool, + /// The order in which we will render each chunk relative to each other + pub render_chunk_order: RenderOrder, } impl Default for TilemapRenderSettings { @@ -37,6 +106,7 @@ impl Default for TilemapRenderSettings { Self { render_chunk_size: CHUNK_SIZE_2D, y_sort: false, + render_chunk_order: RenderOrder::None, } } } diff --git a/src/render/chunk.rs b/src/render/chunk.rs index 93319f58..66df531d 100644 --- a/src/render/chunk.rs +++ b/src/render/chunk.rs @@ -18,6 +18,7 @@ use bevy::{ render::mesh::MeshVertexBufferLayouts, }; +use crate::map::RenderOrder; use crate::prelude::helpers::transform::{chunk_aabb, chunk_index_to_world_space}; use crate::render::extract::ExtractedFrustum; use crate::{ @@ -59,6 +60,7 @@ impl RenderChunk2dStorage { frustum_culling: &FrustumCulling, render_size: RenderChunkSize, y_sort: bool, + render_order: RenderOrder, ) -> &mut RenderChunk2d { let pos = position.xyz(); @@ -96,6 +98,7 @@ impl RenderChunk2dStorage { **frustum_culling, render_size, y_sort, + render_order, ); self.entity_to_chunk.insert(chunk_entity, pos); chunk_storage.insert(pos, chunk); @@ -220,6 +223,7 @@ pub struct RenderChunk2d { pub frustum_culling: bool, pub render_size: RenderChunkSize, pub y_sort: bool, + pub render_chunk_order: RenderOrder, } impl RenderChunk2d { @@ -241,6 +245,7 @@ impl RenderChunk2d { frustum_culling: bool, render_size: RenderChunkSize, y_sort: bool, + render_chunk_order: RenderOrder, ) -> Self { let position = chunk_index_to_world_space(index.xy(), size_in_tiles, &grid_size, &map_type); let local_transform = Transform::from_translation(position.extend(0.0)); @@ -277,6 +282,7 @@ impl RenderChunk2d { frustum_culling, render_size, y_sort, + render_chunk_order, } } diff --git a/src/render/material.rs b/src/render/material.rs index c2d14141..a35ad1d9 100644 --- a/src/render/material.rs +++ b/src/render/material.rs @@ -470,7 +470,11 @@ pub fn queue_material_tilemap_meshes( - (transform.translation.y / (chunk.map_size.y as f32 * chunk.tile_size.y))) } else { - transform.translation.z + chunk.render_chunk_order.compute_z_translation( + &transform.translation, + chunk.map_size, + chunk.tile_size, + ) }; transparent_phase.add(Transparent2d { entity, diff --git a/src/render/prepare.rs b/src/render/prepare.rs index afdb602f..944e9c12 100644 --- a/src/render/prepare.rs +++ b/src/render/prepare.rs @@ -114,6 +114,7 @@ pub(crate) fn prepare( frustum_culling, chunk_size, tilemap_render_settings.y_sort, + tilemap_render_settings.render_chunk_order, ); chunk.set( &in_chunk_tile_index.into(),