From 9f3622850bae75900b7e394b05782b3e1eb18cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 25 Oct 2023 10:15:21 +0200 Subject: [PATCH 1/5] Mesh can be scaled --- CHANGELOG.md | 3 +++ examples/3d_columns.rs | 4 ++-- examples/a_star.rs | 7 +++++-- examples/chunks.rs | 7 +++++-- examples/field_of_movement.rs | 2 +- examples/field_of_view.rs | 7 +++++-- examples/hex_grid.rs | 7 +++++-- examples/mesh_builder.rs | 3 +++ src/mesh/column_builder.rs | 33 ++++++++++++++++++++++++++++----- src/mesh/plane_builder.rs | 31 +++++++++++++++++++++++++++---- 10 files changed, 84 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56b2efc..f772a34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## [Unreleased] +* Added `PlaneMeshBuilder::with_scale` option to scale generated mesh (#121) +* Added `ColumnMeshBuilder::with_scale` option to scale generated mesh (#121) + ## 0.11.0 * Reduced vertice and tri count of mesh generation (#119) diff --git a/examples/3d_columns.rs b/examples/3d_columns.rs index 5fcfbe5..bfc13eb 100644 --- a/examples/3d_columns.rs +++ b/examples/3d_columns.rs @@ -75,8 +75,7 @@ fn setup_grid( let pos = layout.hex_to_world_pos(hex); let id = commands .spawn(PbrBundle { - transform: Transform::from_xyz(pos.x, hex.length() as f32 / 2.0, pos.y) - .with_scale(Vec3::splat(0.9)), + transform: Transform::from_xyz(pos.x, hex.length() as f32 / 2.0, pos.y), mesh: mesh_handle.clone(), material: default_material.clone(), ..default() @@ -124,6 +123,7 @@ fn animate_rings( fn hexagonal_column(hex_layout: &HexLayout) -> Mesh { let mesh_info = ColumnMeshBuilder::new(hex_layout, COLUMN_HEIGHT) .without_bottom_face() + .with_scale(Vec3::splat(0.9)) .build(); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices); diff --git a/examples/a_star.rs b/examples/a_star.rs index d985b84..60cae00 100644 --- a/examples/a_star.rs +++ b/examples/a_star.rs @@ -71,7 +71,7 @@ fn setup_grid( .spawn(ColorMesh2dBundle { mesh: mesh.clone().into(), material, - transform: Transform::from_xyz(pos.x, pos.y, 0.0).with_scale(Vec3::splat(0.9)), + transform: Transform::from_xyz(pos.x, pos.y, 0.0), ..default() }) .id(); @@ -151,7 +151,10 @@ fn handle_input( /// Compute a bevy mesh from the layout fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout).facing(Vec3::Z).build(); + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_scale(Vec3::splat(0.9)) + .build(); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices); mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals); diff --git a/examples/chunks.rs b/examples/chunks.rs index c19fed3..e4e507a 100644 --- a/examples/chunks.rs +++ b/examples/chunks.rs @@ -48,7 +48,7 @@ fn setup_grid( let hex_mod = hex.to_lower_res(CHUNK_SIZE); let color_index = (hex_mod.x - hex_mod.y).rem_euclid(3); commands.spawn(ColorMesh2dBundle { - transform: Transform::from_xyz(pos.x, pos.y, 0.0).with_scale(Vec3::splat(0.9)), + transform: Transform::from_xyz(pos.x, pos.y, 0.0), mesh: mesh_handle.clone().into(), material: materials[color_index as usize].clone(), ..default() @@ -58,7 +58,10 @@ fn setup_grid( /// Compute a bevy mesh from the layout fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout).facing(Vec3::Z).build(); + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .with_scale(Vec3::splat(0.9)) + .facing(Vec3::Z) + .build(); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices); mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals); diff --git a/examples/field_of_movement.rs b/examples/field_of_movement.rs index 7995ae6..6d64d29 100644 --- a/examples/field_of_movement.rs +++ b/examples/field_of_movement.rs @@ -119,7 +119,7 @@ fn setup_grid( .spawn(ColorMesh2dBundle { mesh: mesh.clone().into(), material, - transform: Transform::from_xyz(pos.x, pos.y, 0.0).with_scale(Vec3::splat(1.)), + transform: Transform::from_xyz(pos.x, pos.y, 0.0), ..default() }) .id(); diff --git a/examples/field_of_view.rs b/examples/field_of_view.rs index f6c06a2..2492677 100644 --- a/examples/field_of_view.rs +++ b/examples/field_of_view.rs @@ -70,7 +70,7 @@ fn setup_grid( .spawn(ColorMesh2dBundle { mesh: mesh.clone().into(), material, - transform: Transform::from_xyz(pos.x, pos.y, 0.0).with_scale(Vec3::splat(0.9)), + transform: Transform::from_xyz(pos.x, pos.y, 0.0), ..default() }) .id(); @@ -141,7 +141,10 @@ fn handle_input( /// Compute a bevy mesh from the layout fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout).facing(Vec3::Z).build(); + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_scale(Vec3::splat(0.9)) + .build(); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices); mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals); diff --git a/examples/hex_grid.rs b/examples/hex_grid.rs index 1fee56c..dd4a049 100644 --- a/examples/hex_grid.rs +++ b/examples/hex_grid.rs @@ -81,7 +81,7 @@ fn setup_grid( let pos = layout.hex_to_world_pos(hex); let id = commands .spawn(ColorMesh2dBundle { - transform: Transform::from_xyz(pos.x, pos.y, 0.0).with_scale(Vec3::splat(0.95)), + transform: Transform::from_xyz(pos.x, pos.y, 0.0), mesh: mesh_handle.clone().into(), material: default_material.clone(), ..default() @@ -199,7 +199,10 @@ fn handle_input( /// Compute a bevy mesh from the layout fn hexagonal_plane(hex_layout: &HexLayout) -> Mesh { - let mesh_info = PlaneMeshBuilder::new(hex_layout).facing(Vec3::Z).build(); + let mesh_info = PlaneMeshBuilder::new(hex_layout) + .facing(Vec3::Z) + .with_scale(Vec3::splat(0.95)) + .build(); let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, mesh_info.vertices); mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, mesh_info.normals); diff --git a/examples/mesh_builder.rs b/examples/mesh_builder.rs index f2d6b54..4d1505f 100644 --- a/examples/mesh_builder.rs +++ b/examples/mesh_builder.rs @@ -26,6 +26,7 @@ struct BuilderParams { pub bottom_face: bool, pub sides_uvs: UVOptions, pub caps_uvs: UVOptions, + pub scale: Vec3, } pub fn main() { @@ -111,6 +112,7 @@ fn update_mesh(params: Res, info: Res, mut meshes: ResMu let mut new_mesh = ColumnMeshBuilder::new(&info.layout, params.height) .with_subdivisions(params.subdivisions) .with_offset(Vec3::NEG_Y * params.height / 2.0) + .with_scale(params.scale) .with_caps_uv_options(params.caps_uvs.clone()) .with_sides_uv_options(params.sides_uvs.clone()); if !params.top_face { @@ -144,6 +146,7 @@ impl Default for BuilderParams { bottom_face: true, sides_uvs: UVOptions::quad_default().with_scale_factor(vec2(1.0, 0.3)), caps_uvs: UVOptions::cap_default().with_scale_factor(vec2(0.5, 0.5)), + scale: Vec3::ONE, } } } diff --git a/src/mesh/column_builder.rs b/src/mesh/column_builder.rs index 6f8c781..37226fe 100644 --- a/src/mesh/column_builder.rs +++ b/src/mesh/column_builder.rs @@ -36,9 +36,13 @@ pub struct ColumnMeshBuilder<'l> { pub pos: Hex, /// Optional custom offset for the mesh vertex positions pub offset: Option, + /// Optional custom scale factor for the mesh vertex positions + pub scale: Option, /// Optional custom facing direction, useful to have the mesh already /// rotated /// + /// Note that the `scale` factor will be applied before the rotation + /// /// By default the mesh is *facing* up (**Y** axis) pub facing: Option, /// Amount of quads to be generated on the sides of the column @@ -64,6 +68,7 @@ impl<'l> ColumnMeshBuilder<'l> { facing: None, subdivisions: None, offset: None, + scale: None, top_face: true, bottom_face: true, sides_uv_options: UVOptions::quad_default(), @@ -86,6 +91,8 @@ impl<'l> ColumnMeshBuilder<'l> { /// Specify a custom *facing* direction for the mesh, by default the column /// is vertical (facing up) + /// + /// Note that the `scale` factor will be applied before the rotation #[must_use] #[inline] pub const fn facing(mut self, facing: Vec3) -> Self { @@ -116,6 +123,13 @@ impl<'l> ColumnMeshBuilder<'l> { self } + /// Specify a custom scale factor for the whole mesh + #[must_use] + pub const fn with_scale(mut self, scale: Vec3) -> Self { + self.scale = Some(scale); + self + } + /// Defines the column side quads amount #[must_use] #[inline] @@ -164,19 +178,21 @@ impl<'l> ColumnMeshBuilder<'l> { #[allow(clippy::many_single_char_names)] /// Comsumes the builder to return the computed mesh data pub fn build(self) -> MeshInfo { + // We compute the mesh at the origin to allow scaling let cap_mesh = PlaneMeshBuilder::new(self.layout) - .at(self.pos) .with_uv_options(self.caps_uv_options) .build(); + // We store the offset to match the `self.pos` + let mut offset = self.layout.hex_to_world_pos(self.pos).extend(0.0); + // We create the final mesh let mut mesh = MeshInfo::default(); // Column sides let subidivisions = self.subdivisions.unwrap_or(0).max(1); let delta = self.height / subidivisions as f32; - let center = self.layout.hex_to_world_pos(self.pos); let [a, b, c, d, e, f] = self.layout.hex_corners(self.pos); let corners = [[a, b], [b, c], [c, d], [d, e], [e, f], [f, a]]; for [left, right] in corners { - let normal = (left - center + right - center).normalize(); + let normal = (left + right).normalize(); for div in 0..subidivisions { let height = delta * div as f32; let left = Vec3::new(left.x, height, left.y); @@ -194,14 +210,21 @@ impl<'l> ColumnMeshBuilder<'l> { let bottom_face = cap_mesh.rotated(rotation); mesh.merge_with(bottom_face); } - if let Some(offset) = self.offset { - mesh = mesh.with_offset(offset); + // We apply optional scale + if let Some(scale) = self.scale { + mesh.vertices.iter_mut().for_each(|p| *p *= scale); } + // We rotate the mesh to face the given direction if let Some(facing) = self.facing { let facing = facing.normalize(); let rotation = Quat::from_rotation_arc(BASE_FACING, facing); mesh = mesh.rotated(rotation); } + // We offset the vertex positions after scaling and rotating + if let Some(custom_offset) = self.offset { + offset += custom_offset; + } + mesh = mesh.with_offset(offset); mesh } } diff --git a/src/mesh/plane_builder.rs b/src/mesh/plane_builder.rs index 96f7c05..0ff57dc 100644 --- a/src/mesh/plane_builder.rs +++ b/src/mesh/plane_builder.rs @@ -15,8 +15,12 @@ pub struct PlaneMeshBuilder<'l> { pub pos: Hex, /// Optional custom offset for the mesh vertex positions pub offset: Option, + /// Optional custom scale factor for the mesh vertex positions + pub scale: Option, /// Optional custom facing direction, useful to have the mesh already - /// rotated + /// rotated. + /// + /// Note that the `scale` factor will be applied before the rotation /// /// By default the mesh is *facing* up (**Y** axis) pub facing: Option, @@ -33,6 +37,7 @@ impl<'l> PlaneMeshBuilder<'l> { pos: Hex::ZERO, facing: None, offset: None, + scale: None, uv_options: UVOptions::cap_default(), } } @@ -51,6 +56,8 @@ impl<'l> PlaneMeshBuilder<'l> { /// Specify a custom *facing* direction for the mesh, by default the column /// is vertical (facing up) + /// + /// Note that the `scale` factor will be applied before the rotation #[must_use] pub const fn facing(mut self, facing: Vec3) -> Self { self.facing = Some(facing); @@ -64,6 +71,13 @@ impl<'l> PlaneMeshBuilder<'l> { self } + /// Specify a custom scale factor for the whole mesh + #[must_use] + pub const fn with_scale(mut self, scale: Vec3) -> Self { + self.scale = Some(scale); + self + } + /// Specify custom UV mapping options #[must_use] pub const fn with_uv_options(mut self, uv_options: UVOptions) -> Self { @@ -74,10 +88,19 @@ impl<'l> PlaneMeshBuilder<'l> { /// Comsumes the builder to return the computed mesh data #[must_use] pub fn build(self) -> MeshInfo { - let mut mesh = MeshInfo::hexagonal_plane(self.layout, self.pos); - if let Some(offset) = self.offset { - mesh = mesh.with_offset(offset); + // We compute the mesh at the origin to allow scaling + let mut mesh = MeshInfo::hexagonal_plane(self.layout, Hex::ZERO); + // We store the offset to match the `self.pos` + let mut offset = self.layout.hex_to_world_pos(self.pos).extend(0.0); + // We apply optional scale + if let Some(scale) = self.scale { + mesh.vertices.iter_mut().for_each(|p| *p *= scale); + } + // We offset the vertex positions + if let Some(custom_offset) = self.offset { + offset += custom_offset; } + mesh = mesh.with_offset(offset); if let Some(facing) = self.facing { let facing = facing.normalize(); let rotation = Quat::from_rotation_arc(BASE_FACING, facing); From e31beb920ecbaeb05243af5ad98344200500f4d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 25 Oct 2023 11:29:19 +0200 Subject: [PATCH 2/5] Fixed issue in positioned meshes --- examples/merged_columns.rs | 6 +++++- src/mesh/column_builder.rs | 5 +++-- src/mesh/plane_builder.rs | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/examples/merged_columns.rs b/examples/merged_columns.rs index f579b67..bae0bb0 100644 --- a/examples/merged_columns.rs +++ b/examples/merged_columns.rs @@ -94,7 +94,11 @@ fn setup_grid( // We compute the merged mesh with all children columns let mesh = children.fold(MeshInfo::default(), |mut mesh, c| { let [min, max] = settings.column_heights; - let height = rng.gen_range(min..=max); + let height = if min < max { + rng.gen_range(min..=max) + } else { + min + }; let info = ColumnMeshBuilder::new(&layout, height) .at(c) .without_bottom_face() diff --git a/src/mesh/column_builder.rs b/src/mesh/column_builder.rs index 37226fe..5dbc4bb 100644 --- a/src/mesh/column_builder.rs +++ b/src/mesh/column_builder.rs @@ -183,13 +183,14 @@ impl<'l> ColumnMeshBuilder<'l> { .with_uv_options(self.caps_uv_options) .build(); // We store the offset to match the `self.pos` - let mut offset = self.layout.hex_to_world_pos(self.pos).extend(0.0); + let pos = self.layout.hex_to_world_pos(self.pos); + let mut offset = Vec3::new(pos.x, 0.0, pos.y); // We create the final mesh let mut mesh = MeshInfo::default(); // Column sides let subidivisions = self.subdivisions.unwrap_or(0).max(1); let delta = self.height / subidivisions as f32; - let [a, b, c, d, e, f] = self.layout.hex_corners(self.pos); + let [a, b, c, d, e, f] = self.layout.hex_corners(Hex::ZERO); let corners = [[a, b], [b, c], [c, d], [d, e], [e, f], [f, a]]; for [left, right] in corners { let normal = (left + right).normalize(); diff --git a/src/mesh/plane_builder.rs b/src/mesh/plane_builder.rs index 0ff57dc..e7ac546 100644 --- a/src/mesh/plane_builder.rs +++ b/src/mesh/plane_builder.rs @@ -91,7 +91,8 @@ impl<'l> PlaneMeshBuilder<'l> { // We compute the mesh at the origin to allow scaling let mut mesh = MeshInfo::hexagonal_plane(self.layout, Hex::ZERO); // We store the offset to match the `self.pos` - let mut offset = self.layout.hex_to_world_pos(self.pos).extend(0.0); + let pos = self.layout.hex_to_world_pos(self.pos); + let mut offset = Vec3::new(pos.x, 0.0, pos.y); // We apply optional scale if let Some(scale) = self.scale { mesh.vertices.iter_mut().for_each(|p| *p *= scale); From 2a32b4380803321934c1b8158f92ca775911d5c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 25 Oct 2023 17:42:07 +0200 Subject: [PATCH 3/5] Custm rotation, SRT order of transformation --- src/mesh/column_builder.rs | 41 +++++++++++++++++++++---------- src/mesh/plane_builder.rs | 49 +++++++++++++++++++++++++------------- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/mesh/column_builder.rs b/src/mesh/column_builder.rs index 5dbc4bb..1098477 100644 --- a/src/mesh/column_builder.rs +++ b/src/mesh/column_builder.rs @@ -25,6 +25,16 @@ use crate::{Hex, HexLayout, PlaneMeshBuilder, UVOptions}; /// .without_top_face() /// .build(); /// ``` +/// +/// # Note +/// +/// Transform operations (Scale, Rotate, Translate) through the methods +/// +/// - Scale: [`Self::with_scale`] +/// - Rotate": [`Self::with_rotation`], [`Self::facing`] +/// - Translate: [`Self::with_offset`], [`Self::at`] +/// +/// Are executed in that order, or **SRT** #[derive(Debug, Clone)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct ColumnMeshBuilder<'l> { @@ -38,13 +48,13 @@ pub struct ColumnMeshBuilder<'l> { pub offset: Option, /// Optional custom scale factor for the mesh vertex positions pub scale: Option, - /// Optional custom facing direction, useful to have the mesh already + /// Optional rotation quaternion, useful to have the mesh already /// rotated /// /// Note that the `scale` factor will be applied before the rotation /// /// By default the mesh is *facing* up (**Y** axis) - pub facing: Option, + pub rotation: Option, /// Amount of quads to be generated on the sides of the column pub subdivisions: Option, /// Should the top hexagonal face be present @@ -65,7 +75,7 @@ impl<'l> ColumnMeshBuilder<'l> { layout, height, pos: Hex::ZERO, - facing: None, + rotation: None, subdivisions: None, offset: None, scale: None, @@ -92,11 +102,20 @@ impl<'l> ColumnMeshBuilder<'l> { /// Specify a custom *facing* direction for the mesh, by default the column /// is vertical (facing up) /// - /// Note that the `scale` factor will be applied before the rotation + /// # Panics + /// + /// Will panic if `facing` is zero length #[must_use] #[inline] - pub const fn facing(mut self, facing: Vec3) -> Self { - self.facing = Some(facing); + pub fn facing(mut self, facing: Vec3) -> Self { + self.rotation = Some(Quat::from_rotation_arc(BASE_FACING, facing)); + self + } + + /// Specify a custom rotation for the whole mesh + #[must_use] + pub const fn with_rotation(mut self, rotation: Quat) -> Self { + self.rotation = Some(rotation); self } @@ -211,17 +230,15 @@ impl<'l> ColumnMeshBuilder<'l> { let bottom_face = cap_mesh.rotated(rotation); mesh.merge_with(bottom_face); } - // We apply optional scale + // **S** - We apply optional scale if let Some(scale) = self.scale { mesh.vertices.iter_mut().for_each(|p| *p *= scale); } - // We rotate the mesh to face the given direction - if let Some(facing) = self.facing { - let facing = facing.normalize(); - let rotation = Quat::from_rotation_arc(BASE_FACING, facing); + // **R** - We rotate the mesh to face the given direction + if let Some(rotation) = self.rotation { mesh = mesh.rotated(rotation); } - // We offset the vertex positions after scaling and rotating + // **T** - We offset the vertex positions after scaling and rotating if let Some(custom_offset) = self.offset { offset += custom_offset; } diff --git a/src/mesh/plane_builder.rs b/src/mesh/plane_builder.rs index e7ac546..84eefa1 100644 --- a/src/mesh/plane_builder.rs +++ b/src/mesh/plane_builder.rs @@ -6,6 +6,16 @@ use glam::{Quat, Vec3}; /// /// The mesh will be anchored at the center of the hexagon, use offsets to /// cutomize anchor/pivot position. +/// +/// # Note +/// +/// Transform operations (Scale, Rotate, Translate) through the methods +/// +/// - Scale: [`Self::with_scale`] +/// - Rotate": [`Self::with_rotation`], [`Self::facing`] +/// - Translate: [`Self::with_offset`], [`Self::at`] +/// +/// Are executed in that order, or **SRT** #[derive(Debug, Clone)] #[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))] pub struct PlaneMeshBuilder<'l> { @@ -17,13 +27,11 @@ pub struct PlaneMeshBuilder<'l> { pub offset: Option, /// Optional custom scale factor for the mesh vertex positions pub scale: Option, - /// Optional custom facing direction, useful to have the mesh already - /// rotated. - /// - /// Note that the `scale` factor will be applied before the rotation + /// Optional custom rotation, useful to have the mesh already + /// rotated /// /// By default the mesh is *facing* up (**Y** axis) - pub facing: Option, + pub rotation: Option, /// UV mapping options pub uv_options: UVOptions, } @@ -35,7 +43,7 @@ impl<'l> PlaneMeshBuilder<'l> { Self { layout, pos: Hex::ZERO, - facing: None, + rotation: None, offset: None, scale: None, uv_options: UVOptions::cap_default(), @@ -57,10 +65,19 @@ impl<'l> PlaneMeshBuilder<'l> { /// Specify a custom *facing* direction for the mesh, by default the column /// is vertical (facing up) /// - /// Note that the `scale` factor will be applied before the rotation + /// # Panics + /// + /// Will panic if `facing` is zero length + #[must_use] + pub fn facing(mut self, facing: Vec3) -> Self { + self.rotation = Some(Quat::from_rotation_arc(BASE_FACING, facing.normalize())); + self + } + + /// Specify a custom rotation for the whole mesh #[must_use] - pub const fn facing(mut self, facing: Vec3) -> Self { - self.facing = Some(facing); + pub const fn with_rotation(mut self, rotation: Quat) -> Self { + self.rotation = Some(rotation); self } @@ -93,20 +110,18 @@ impl<'l> PlaneMeshBuilder<'l> { // We store the offset to match the `self.pos` let pos = self.layout.hex_to_world_pos(self.pos); let mut offset = Vec3::new(pos.x, 0.0, pos.y); - // We apply optional scale + // **S** - We apply optional scale if let Some(scale) = self.scale { mesh.vertices.iter_mut().for_each(|p| *p *= scale); } - // We offset the vertex positions + // **R** - We rotate the mesh to face the given direction + if let Some(rotation) = self.rotation { + mesh = mesh.rotated(rotation); + } + // **T** - We offset the vertex positions after scaling and rotating if let Some(custom_offset) = self.offset { offset += custom_offset; } - mesh = mesh.with_offset(offset); - if let Some(facing) = self.facing { - let facing = facing.normalize(); - let rotation = Quat::from_rotation_arc(BASE_FACING, facing); - mesh = mesh.rotated(rotation); - } self.uv_options.alter_uvs(&mut mesh.uvs); mesh } From 3bd69278750ce8ad2bbcba057a89c0c39921709f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 25 Oct 2023 17:45:57 +0200 Subject: [PATCH 4/5] CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f772a34..4d9271b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,10 @@ ## [Unreleased] * Added `PlaneMeshBuilder::with_scale` option to scale generated mesh (#121) +* Added `PlaneMeshBuilder::with_rotation` option to rotate generated mesh (#121) * Added `ColumnMeshBuilder::with_scale` option to scale generated mesh (#121) +* Added `ColumnMeshBuilder::with_rotation` option to rotate generated mesh (#121) +* Mesh transformation follow the SRT order of operations (#121) ## 0.11.0 From 3b952c2bf57d271d3802d6bef0c2bdff6e378750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Thu, 26 Oct 2023 14:18:35 +0200 Subject: [PATCH 5/5] Typos --- src/mesh/column_builder.rs | 4 +--- src/mesh/plane_builder.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mesh/column_builder.rs b/src/mesh/column_builder.rs index 1098477..15c8a5b 100644 --- a/src/mesh/column_builder.rs +++ b/src/mesh/column_builder.rs @@ -31,7 +31,7 @@ use crate::{Hex, HexLayout, PlaneMeshBuilder, UVOptions}; /// Transform operations (Scale, Rotate, Translate) through the methods /// /// - Scale: [`Self::with_scale`] -/// - Rotate": [`Self::with_rotation`], [`Self::facing`] +/// - Rotate: [`Self::with_rotation`], [`Self::facing`] /// - Translate: [`Self::with_offset`], [`Self::at`] /// /// Are executed in that order, or **SRT** @@ -51,8 +51,6 @@ pub struct ColumnMeshBuilder<'l> { /// Optional rotation quaternion, useful to have the mesh already /// rotated /// - /// Note that the `scale` factor will be applied before the rotation - /// /// By default the mesh is *facing* up (**Y** axis) pub rotation: Option, /// Amount of quads to be generated on the sides of the column diff --git a/src/mesh/plane_builder.rs b/src/mesh/plane_builder.rs index 84eefa1..19b02af 100644 --- a/src/mesh/plane_builder.rs +++ b/src/mesh/plane_builder.rs @@ -12,7 +12,7 @@ use glam::{Quat, Vec3}; /// Transform operations (Scale, Rotate, Translate) through the methods /// /// - Scale: [`Self::with_scale`] -/// - Rotate": [`Self::with_rotation`], [`Self::facing`] +/// - Rotate: [`Self::with_rotation`], [`Self::facing`] /// - Translate: [`Self::with_offset`], [`Self::at`] /// /// Are executed in that order, or **SRT**