mirror of
https://github.com/orange-cpp/omath.git
synced 2026-02-13 23:13:26 +00:00
108 lines
3.6 KiB
C++
108 lines
3.6 KiB
C++
// Extra collision tests: Simplex, MeshCollider, EPA
|
|
#include <gtest/gtest.h>
|
|
#include <omath/collision/epa_algorithm.hpp>
|
|
#include <omath/collision/mesh_collider.hpp>
|
|
#include <omath/collision/simplex.hpp>
|
|
#include <omath/engines/source_engine/collider.hpp>
|
|
|
|
using namespace omath;
|
|
using namespace omath::collision;
|
|
|
|
TEST(SimplexTest, HandleEmptySimplex)
|
|
{
|
|
Simplex<Vector3<float>> simplex;
|
|
Vector3<float> direction{1, 0, 0};
|
|
|
|
EXPECT_EQ(simplex.size(), 0);
|
|
EXPECT_FALSE(simplex.handle(direction));
|
|
}
|
|
|
|
TEST(SimplexTest, HandleLineCollinearWithXAxis)
|
|
{
|
|
using Vec3 = Vector3<float>;
|
|
Simplex<Vec3> simplex;
|
|
|
|
simplex.push_front(Vec3{1, 0, 0});
|
|
simplex.push_front(Vec3{-1, 0, 0});
|
|
|
|
Vec3 direction{};
|
|
std::ignore = simplex.handle(direction);
|
|
|
|
EXPECT_NEAR(direction.x, 0.f, 1e-6f);
|
|
}
|
|
|
|
TEST(CollisionExtra, SimplexLineHandle)
|
|
{
|
|
Simplex<Vector3<float>> s;
|
|
s = {Vector3<float>{1.f, 0.f, 0.f}, Vector3<float>{2.f, 0.f, 0.f}};
|
|
Vector3<float> dir{0, 0, 0};
|
|
EXPECT_FALSE(s.handle(dir));
|
|
// direction should not be zero
|
|
EXPECT_GT(dir.length_sqr(), 0.0f);
|
|
}
|
|
|
|
TEST(CollisionExtra, SimplexTriangleHandle)
|
|
{
|
|
Simplex<Vector3<float>> s;
|
|
s = {Vector3<float>{1.f, 0.f, 0.f}, Vector3<float>{0.f, 1.f, 0.f}, Vector3<float>{0.f, 0.f, 1.f}};
|
|
Vector3<float> dir{0, 0, 0};
|
|
EXPECT_FALSE(s.handle(dir));
|
|
EXPECT_GT(dir.length_sqr(), 0.0f);
|
|
}
|
|
|
|
TEST(CollisionExtra, SimplexTetrahedronInside)
|
|
{
|
|
Simplex<Vector3<float>> s;
|
|
// tetra that surrounds origin roughly
|
|
s = {Vector3<float>{1.f, 0.f, 0.f}, Vector3<float>{0.f, 1.f, 0.f}, Vector3<float>{0.f, 0.f, 1.f},
|
|
Vector3<float>{-1.f, -1.f, -1.f}};
|
|
Vector3<float> dir{0, 0, 0};
|
|
// if origin inside, handle returns true
|
|
const bool inside = s.handle(dir);
|
|
EXPECT_TRUE(inside);
|
|
}
|
|
|
|
TEST(CollisionExtra, MeshColliderOriginAndFurthest)
|
|
{
|
|
source_engine::Mesh mesh = {
|
|
std::vector<primitives::Vertex<>>{{{1.f, 1.f, 1.f}, {}, {}}, {{-1.f, -1.f, -1.f}, {}, {}}}, {}};
|
|
mesh.set_origin({0, 2, 0});
|
|
source_engine::MeshCollider collider(mesh);
|
|
|
|
EXPECT_EQ(collider.get_origin(), omath::Vector3<float>(0, 2, 0));
|
|
collider.set_origin({1, 2, 3});
|
|
EXPECT_EQ(collider.get_origin(), omath::Vector3<float>(1, 2, 3));
|
|
|
|
const auto v = collider.find_abs_furthest_vertex_position({1.f, 0.f, 0.f});
|
|
// the original vertex at (1,1,1) translated by origin (1,2,3) becomes (2,3,4)
|
|
EXPECT_EQ(v, omath::Vector3<float>(2.f, 3.f, 4.f));
|
|
}
|
|
|
|
TEST(CollisionExtra, EPAConvergesOnSimpleCase)
|
|
{
|
|
// Build two simple colliders using simple meshes that overlap
|
|
source_engine::Mesh meshA = {
|
|
std::vector<primitives::Vertex<>>{{{0.f, 0.f, 0.f}, {}, {}}, {{1.f, 0.f, 0.f}, {}, {}}}, {}};
|
|
source_engine::Mesh mesh_b = meshA;
|
|
mesh_b.set_origin({0.5f, 0.f, 0.f}); // translate to overlap
|
|
|
|
source_engine::MeshCollider a(meshA);
|
|
source_engine::MeshCollider b(mesh_b);
|
|
|
|
// Create a simplex that approximately contains the origin in Minkowski space
|
|
Simplex<Vector3<float>> simplex;
|
|
simplex = {omath::Vector3<float>{0.5f, 0.f, 0.f}, omath::Vector3<float>{-0.5f, 0.f, 0.f},
|
|
omath::Vector3<float>{0.f, 0.5f, 0.f}, omath::Vector3<float>{0.f, -0.5f, 0.f}};
|
|
|
|
auto pool = std::pmr::monotonic_buffer_resource(1024);
|
|
auto res = Epa<source_engine::MeshCollider>::solve(a, b, simplex, {}, pool);
|
|
// EPA may or may not converge depending on numerics; ensure it returns optionally
|
|
// but if it does, fields should be finite
|
|
if (res.has_value())
|
|
{
|
|
auto r = *res;
|
|
EXPECT_TRUE(std::isfinite(r.depth));
|
|
EXPECT_GT(r.normal.length_sqr(), 0.0f);
|
|
}
|
|
}
|