From 74dc2234f7b61a1489e3d89bc0eadc8c6b0389a4 Mon Sep 17 00:00:00 2001 From: orange Date: Thu, 26 Feb 2026 16:17:41 +0300 Subject: [PATCH 1/2] fixed collider when rotated --- include/omath/collision/mesh_collider.hpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/include/omath/collision/mesh_collider.hpp b/include/omath/collision/mesh_collider.hpp index a9a88704..ae287237 100644 --- a/include/omath/collision/mesh_collider.hpp +++ b/include/omath/collision/mesh_collider.hpp @@ -46,9 +46,16 @@ namespace omath::collision [[nodiscard]] const VertexType& find_furthest_vertex(const VectorType& direction) const { + // Compare vertices in world space so rotation and non-uniform scale are + // accounted for correctly. Without this the comparator uses local-space + // positions against a world-space direction, which yields the wrong support + // vertex whenever a non-identity transform is applied to the mesh. return *std::ranges::max_element( - m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second) - { return first.position.dot(direction) < second.position.dot(direction); }); + m_mesh.m_vertex_buffer, [&](const auto& first, const auto& second) + { + return m_mesh.vertex_position_to_world_space(first.position).dot(direction) + < m_mesh.vertex_position_to_world_space(second.position).dot(direction); + }); } MeshType m_mesh; }; From 211e4c3d9b2a887c55f98cfa16e6a021a88d9021 Mon Sep 17 00:00:00 2001 From: orange Date: Thu, 26 Feb 2026 16:19:54 +0300 Subject: [PATCH 2/2] optimization --- include/omath/collision/mesh_collider.hpp | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/include/omath/collision/mesh_collider.hpp b/include/omath/collision/mesh_collider.hpp index ae287237..f9f728ff 100644 --- a/include/omath/collision/mesh_collider.hpp +++ b/include/omath/collision/mesh_collider.hpp @@ -46,16 +46,27 @@ namespace omath::collision [[nodiscard]] const VertexType& find_furthest_vertex(const VectorType& direction) const { - // Compare vertices in world space so rotation and non-uniform scale are - // accounted for correctly. Without this the comparator uses local-space - // positions against a world-space direction, which yields the wrong support - // vertex whenever a non-identity transform is applied to the mesh. + // The support query arrives in world space, but vertex positions are stored + // in local space. We need argmax_v { world(v) · d }. + // + // world(v) = M·v (ignoring translation, which is constant across vertices) + // world(v) · d = v · Mᵀ·d + // + // So we transform the direction to local space once — O(1) — then compare + // raw local positions, which is far cheaper than calling + // vertex_position_to_world_space (full 4×4 multiply) for every vertex. + // + // d_local = upper-left 3×3 of M, transposed, times d_world: + // d_local[j] = sum_i M.at(i,j) * d[i] (i.e. column j of M dotted with d) + const auto& m = m_mesh.get_to_world_matrix(); + const VectorType d_local = { + m.at(0, 0) * direction.x + m.at(1, 0) * direction.y + m.at(2, 0) * direction.z, + m.at(0, 1) * direction.x + m.at(1, 1) * direction.y + m.at(2, 1) * direction.z, + m.at(0, 2) * direction.x + m.at(1, 2) * direction.y + m.at(2, 2) * direction.z, + }; return *std::ranges::max_element( - m_mesh.m_vertex_buffer, [&](const auto& first, const auto& second) - { - return m_mesh.vertex_position_to_world_space(first.position).dot(direction) - < m_mesh.vertex_position_to_world_space(second.position).dot(direction); - }); + m_mesh.m_vertex_buffer, [&d_local](const auto& first, const auto& second) + { return first.position.dot(d_local) < second.position.dot(d_local); }); } MeshType m_mesh; };