Compare commits

...

5 Commits

Author SHA1 Message Date
646a920e4c fixed potential deadlock 2026-02-27 08:47:46 +03:00
52687a70c7 fixed formating 2026-02-27 07:41:05 +03:00
a9eff7d320 Merge pull request #157 from orange-cpp/feature/mesh_improvement
Feature/mesh improvement
2026-02-26 16:39:21 +03:00
211e4c3d9b optimization 2026-02-26 16:19:54 +03:00
74dc2234f7 fixed collider when rotated 2026-02-26 16:17:41 +03:00
2 changed files with 30 additions and 7 deletions

View File

@@ -14,11 +14,15 @@ namespace omath::collision
Simplex<VertexType> simplex; // valid only if hit == true and size==4 Simplex<VertexType> simplex; // valid only if hit == true and size==4
}; };
struct GjkSettings final
{
float epsilon = 1e-6f;
std::size_t max_iterations = 64;
};
template<class ColliderInterfaceType> template<class ColliderInterfaceType>
class GjkAlgorithm final class GjkAlgorithm final
{ {
using VectorType = ColliderInterfaceType::VectorType; using VectorType = ColliderInterfaceType::VectorType;
public: public:
[[nodiscard]] [[nodiscard]]
static VectorType find_support_vertex(const ColliderInterfaceType& collider_a, static VectorType find_support_vertex(const ColliderInterfaceType& collider_a,
@@ -36,7 +40,8 @@ namespace omath::collision
[[nodiscard]] [[nodiscard]]
static GjkHitInfo<VectorType> is_collide_with_simplex_info(const ColliderInterfaceType& collider_a, static GjkHitInfo<VectorType> is_collide_with_simplex_info(const ColliderInterfaceType& collider_a,
const ColliderInterfaceType& collider_b) const ColliderInterfaceType& collider_b,
const GjkSettings& settings = {})
{ {
auto support = find_support_vertex(collider_a, collider_b, VectorType{1, 0, 0}); auto support = find_support_vertex(collider_a, collider_b, VectorType{1, 0, 0});
@@ -45,11 +50,11 @@ namespace omath::collision
auto direction = -support; auto direction = -support;
while (true) for (std::size_t iteration = 0; iteration < settings.max_iterations; ++iteration)
{ {
support = find_support_vertex(collider_a, collider_b, direction); support = find_support_vertex(collider_a, collider_b, direction);
if (support.dot(direction) <= 0.f) if (support.dot(direction) <= settings.epsilon)
return {false, simplex}; return {false, simplex};
simplex.push_front(support); simplex.push_front(support);
@@ -57,6 +62,7 @@ namespace omath::collision
if (simplex.handle(direction)) if (simplex.handle(direction))
return {true, simplex}; return {true, simplex};
} }
return {false, simplex};
} }
}; };
} // namespace omath::collision } // namespace omath::collision

View File

@@ -46,9 +46,26 @@ namespace omath::collision
[[nodiscard]] [[nodiscard]]
const VertexType& find_furthest_vertex(const VectorType& direction) const const VertexType& find_furthest_vertex(const VectorType& direction) const
{ {
return *std::ranges::max_element( // The support query arrives in world space, but vertex positions are stored
m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second) // in local space. We need argmax_v { world(v) · d }.
{ return first.position.dot(direction) < second.position.dot(direction); }); //
// 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[0, 0] * direction.x + m[1, 0] * direction.y + m[2, 0] * direction.z,
m[0, 1] * direction.x + m[1, 1] * direction.y + m[2, 1] * direction.z,
m[0, 2] * direction.x + m[1, 2] * direction.y + m[2, 2] * direction.z,
};
return *std::ranges::max_element(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; MeshType m_mesh;
}; };