Skip to content

Commit acf36c3

Browse files
authored
Merge pull request #109 from orange-cpp/feature/collider_interface
Feature/collider interface
2 parents e97be8c + 27c1d14 commit acf36c3

File tree

8 files changed

+82
-58
lines changed

8 files changed

+82
-58
lines changed

include/omath/3d_primitives/mesh.hpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ namespace omath::primitives
9999
}
100100

101101
[[nodiscard]]
102-
VectorType vertex_to_world_space(const Vector3<float>& vertex_position) const
102+
VectorType vertex_position_to_world_space(const Vector3<float>& vertex_position) const
103103
requires HasPosition<VertexType>
104104
{
105-
auto abs_vec = get_to_world_matrix() * mat_column_from_vector(vertex_position);
105+
auto abs_vec = get_to_world_matrix() * mat_column_from_vector<typename Mat4X4::ContainedType, Mat4X4::get_store_ordering()>(vertex_position);
106106

107107
return {abs_vec.at(0, 0), abs_vec.at(1, 0), abs_vec.at(2, 0)};
108108
}
@@ -111,9 +111,9 @@ namespace omath::primitives
111111
Triangle<VectorType> make_face_in_world_space(const Ebo::const_iterator vao_iterator) const
112112
requires HasPosition<VertexType>
113113
{
114-
return {vertex_to_world_space(m_vertex_buffer.at(vao_iterator->x).position),
115-
vertex_to_world_space(m_vertex_buffer.at(vao_iterator->y).position),
116-
vertex_to_world_space(m_vertex_buffer.at(vao_iterator->z).position)};
114+
return {vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->x).position),
115+
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->y).position),
116+
vertex_position_to_world_space(m_vertex_buffer.at(vao_iterator->z).position)};
117117
}
118118

119119
private:
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// Created by Vladislav on 06.12.2025.
3+
//
4+
#pragma once
5+
6+
7+
namespace omath::collision
8+
{
9+
template<class VecType = Vector3<float>>
10+
class ColliderInterface
11+
{
12+
public:
13+
using VectorType = VecType;
14+
virtual ~ColliderInterface() = default;
15+
16+
[[nodiscard]]
17+
virtual VectorType find_abs_furthest_vertex_position(const VectorType& direction) const = 0;
18+
19+
[[nodiscard]]
20+
virtual const VectorType& get_origin() const = 0;
21+
virtual void set_origin(const VectorType& new_origin) = 0;
22+
};
23+
}

include/omath/collision/epa_algorithm.hpp

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
#include <cstdint>
77
#include <limits>
88
#include <memory>
9+
#include <memory_resource>
910
#include <queue>
1011
#include <utility>
1112
#include <vector>
12-
#include <memory_resource>
1313

1414
namespace omath::collision
1515
{
@@ -23,16 +23,16 @@ namespace omath::collision
2323
{ a / s } -> std::same_as<V>;
2424
};
2525

26-
template<class ColliderType>
26+
template<class ColliderInterfaceType>
2727
class Epa final
2828
{
2929
public:
30-
using VectorType = ColliderType::VectorType;
30+
using VectorType = ColliderInterfaceType::VectorType;
3131
static_assert(EpaVector<VectorType>, "VertexType must satisfy EpaVector concept");
3232

3333
struct Result final
3434
{
35-
VectorType normal{}; // outward normal (from B to A)
35+
VectorType normal{}; // from A to B
3636
VectorType penetration_vector;
3737
float depth{0.0f};
3838
int iterations{0};
@@ -48,7 +48,7 @@ namespace omath::collision
4848

4949
// Precondition: simplex.size()==4 and contains the origin.
5050
[[nodiscard]]
51-
static std::optional<Result> solve(const ColliderType& a, const ColliderType& b,
51+
static std::optional<Result> solve(const ColliderInterfaceType& a, const ColliderInterfaceType& b,
5252
const Simplex<VectorType>& simplex, const Params params = {},
5353
std::shared_ptr<std::pmr::memory_resource> mem_resource = {
5454
std::shared_ptr<void>{}, std::pmr::get_default_resource()})
@@ -86,25 +86,22 @@ namespace omath::collision
8686
break;
8787

8888
const int fidx = heap.top().idx;
89-
const Face f = faces[fidx];
89+
const Face face = faces[fidx];
9090

9191
// Get the furthest point in face normal direction
92-
const VectorType p = support_point(a, b, f.n);
93-
const float p_dist = f.n.dot(p);
92+
const VectorType p = support_point(a, b, face.n);
93+
const float p_dist = face.n.dot(p);
9494

9595
// Converged if we can’t push the face closer than tolerance
96-
if (p_dist - f.d <= params.tolerance)
96+
if (p_dist - face.d <= params.tolerance)
9797
{
98-
out.normal = f.n;
99-
out.depth = f.d; // along unit normal
98+
out.normal = face.n;
99+
out.depth = face.d; // along unit normal
100100
out.iterations = it + 1;
101101
out.num_vertices = static_cast<int>(vertexes.size());
102102
out.num_faces = static_cast<int>(faces.size());
103103

104-
const auto centers = b.get_origin() - a.get_origin();
105-
const auto sign = out.normal.dot(centers) >= 0 ? 1 : -1;
106-
107-
out.penetration_vector = out.normal * out.depth * sign;
104+
out.penetration_vector = out.normal * out.depth;
108105
return out;
109106
}
110107

@@ -163,10 +160,7 @@ namespace omath::collision
163160
out.num_vertices = static_cast<int>(vertexes.size());
164161
out.num_faces = static_cast<int>(faces.size());
165162

166-
const auto centers = b.get_origin() - a.get_origin();
167-
const auto sign = out.normal.dot(centers) >= 0 ? 1 : -1;
168-
169-
out.penetration_vector = out.normal * out.depth * sign;
163+
out.penetration_vector = out.normal * out.depth;
170164

171165
return out;
172166
}
@@ -251,9 +245,10 @@ namespace omath::collision
251245
}
252246

253247
[[nodiscard]]
254-
static VectorType support_point(const ColliderType& a, const ColliderType& b, const VectorType& dir)
248+
static VectorType support_point(const ColliderInterfaceType& a, const ColliderInterfaceType& b,
249+
const VectorType& dir)
255250
{
256-
return a.find_abs_furthest_vertex(dir).position - b.find_abs_furthest_vertex(-dir).position;
251+
return a.find_abs_furthest_vertex_position(dir) - b.find_abs_furthest_vertex_position(-dir);
257252
}
258253

259254
template<class V>

include/omath/collision/gjk_algorithm.hpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,28 +14,29 @@ namespace omath::collision
1414
Simplex<VertexType> simplex; // valid only if hit == true and size==4
1515
};
1616

17-
template<class ColliderType>
17+
template<class ColliderInterfaceType>
1818
class GjkAlgorithm final
1919
{
20-
using VertexType = ColliderType::VertexType;
21-
using VectorType = VertexType::VectorType;
20+
using VectorType = ColliderInterfaceType::VectorType;
21+
2222
public:
2323
[[nodiscard]]
24-
static VectorType find_support_vertex(const ColliderType& collider_a, const ColliderType& collider_b,
25-
const VectorType& direction)
24+
static VectorType find_support_vertex(const ColliderInterfaceType& collider_a,
25+
const ColliderInterfaceType& collider_b, const VectorType& direction)
2626
{
27-
return collider_a.find_abs_furthest_vertex(direction).position - collider_b.find_abs_furthest_vertex(-direction).position;
27+
return collider_a.find_abs_furthest_vertex_position(direction)
28+
- collider_b.find_abs_furthest_vertex_position(-direction);
2829
}
2930

3031
[[nodiscard]]
31-
static bool is_collide(const ColliderType& collider_a, const ColliderType& collider_b)
32+
static bool is_collide(const ColliderInterfaceType& collider_a, const ColliderInterfaceType& collider_b)
3233
{
3334
return is_collide_with_simplex_info(collider_a, collider_b).hit;
3435
}
3536

3637
[[nodiscard]]
37-
static GjkHitInfo<VectorType> is_collide_with_simplex_info(const ColliderType& collider_a,
38-
const ColliderType& collider_b)
38+
static GjkHitInfo<VectorType> is_collide_with_simplex_info(const ColliderInterfaceType& collider_a,
39+
const ColliderInterfaceType& collider_b)
3940
{
4041
auto support = find_support_vertex(collider_a, collider_b, VectorType{1, 0, 0});
4142

include/omath/collision/mesh_collider.hpp

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,53 @@
33
//
44

55
#pragma once
6+
#include "collider_interface.hpp"
67
#include "omath/linear_algebra/vector3.hpp"
78

9+
#ifdef OMATH_BUILD_TESTS
10+
// ReSharper disable once CppInconsistentNaming
11+
class UnitTestColider_FindFurthestVertex_Test;
12+
#endif
13+
814
namespace omath::collision
915
{
1016
template<class MeshType>
11-
class MeshCollider
17+
class MeshCollider final : public ColliderInterface<typename MeshType::VertexType::VectorType>
1218
{
19+
#ifdef OMATH_BUILD_TESTS
20+
friend UnitTestColider_FindFurthestVertex_Test;
21+
#endif
1322
public:
1423
using VertexType = MeshType::VertexType;
15-
using VectorType = VertexType::VectorType;
24+
using VectorType = MeshType::VertexType::VectorType;
1625
explicit MeshCollider(MeshType mesh): m_mesh(std::move(mesh))
1726
{
1827
}
1928

2029
[[nodiscard]]
21-
const VertexType& find_furthest_vertex(const VectorType& direction) const
30+
VectorType find_abs_furthest_vertex_position(const VectorType& direction) const override
2231
{
23-
return *std::ranges::max_element(
24-
m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second)
25-
{ return first.position.dot(direction) < second.position.dot(direction); });
32+
return m_mesh.vertex_position_to_world_space(find_furthest_vertex(direction).position);
2633
}
2734

2835
[[nodiscard]]
29-
VertexType find_abs_furthest_vertex(const VectorType& direction) const
36+
const VectorType& get_origin() const override
3037
{
31-
const auto& vertex = find_furthest_vertex(direction);
32-
auto new_vertex = vertex;
33-
new_vertex.position = m_mesh.vertex_to_world_space(find_furthest_vertex(direction).position);
34-
return new_vertex;
38+
return m_mesh.get_origin();
3539
}
36-
37-
[[nodiscard]]
38-
const VectorType& get_origin() const
40+
void set_origin(const VectorType& new_origin) override
3941
{
40-
return m_mesh.get_origin();
42+
m_mesh.set_origin(new_origin);
4143
}
4244

4345
private:
46+
[[nodiscard]]
47+
const VertexType& find_furthest_vertex(const VectorType& direction) const
48+
{
49+
return *std::ranges::max_element(
50+
m_mesh.m_vertex_buffer, [&direction](const auto& first, const auto& second)
51+
{ return first.position.dot(direction) < second.position.dot(direction); });
52+
}
4453
MeshType m_mesh;
4554
};
4655
} // namespace omath::collision

include/omath/linear_algebra/mat.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ namespace omath
4646
}
4747

4848
[[nodiscard]]
49-
constexpr static MatStoreType get_store_ordering() noexcept
49+
consteval static MatStoreType get_store_ordering() noexcept
5050
{
5151
return StoreType;
5252
}

tests/general/unit_test_colider.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ TEST(UnitTestColider, CheckToWorld)
1717
mesh.set_origin({0, 2, 0});
1818
const omath::source_engine::MeshCollider collider(mesh);
1919

20-
const auto vertex = collider.find_abs_furthest_vertex({1.f, 0.f, 0.f}).position;
20+
const auto vertex = collider.find_abs_furthest_vertex_position({1.f, 0.f, 0.f});
2121

2222
EXPECT_EQ(vertex, omath::Vector3<float>(1.f, 3.f, 1.f));
2323
}

tests/general/unit_test_epa.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ TEST(UnitTestEpa, TestCollisionTrue)
6161

6262
// Try both signs with a tiny margin (avoid grazing contacts)
6363
const float margin = 1.0f + 1e-3f;
64-
const auto pen = epa->normal * epa->depth;
64+
const auto pen = epa->penetration_vector;
6565

6666
Mesh b_plus = b;
6767
b_plus.set_origin(b_plus.get_origin() + pen * margin);
@@ -133,12 +133,8 @@ TEST(UnitTestEpa, TestCollisionTrue2)
133133
EXPECT_NEAR(epa->normal.y, 0.0f, 1e-3f);
134134
EXPECT_NEAR(epa->normal.z, 0.0f, 1e-3f);
135135

136-
// Choose a deterministic sign: orient penetration from A toward B
137-
const auto centers = b.get_origin() - a.get_origin(); // (0.5, 0, 0)
138-
float sign = (epa->normal.dot(centers) >= 0.0f) ? +1.0f : -1.0f;
139-
140136
constexpr float margin = 1.0f + 1e-3f; // tiny slack to avoid grazing
141-
const auto pen = epa->normal * epa->depth * sign;
137+
const auto pen = epa->normal * epa->depth;
142138

143139
// Apply once: B + pen must separate; the opposite must still collide
144140
Mesh b_resolved = b;

0 commit comments

Comments
 (0)