Перейти к содержанию

План добавления MeshCollider

1. Цели и рамки

  • Добавить MeshCollider в C++ collision stack (Collider, CollisionWorld, bindings, ColliderComponent).
  • В первой итерации поддержать только статический triangle mesh (без динамического пересчёта topology).
  • Для динамических тел оставить Box/Sphere/Capsule/ConvexHull (если нужен) как отдельный этап.

2. Архитектурное решение

  • Добавить новый тип ColliderType::Mesh в cpp/termin/colliders/collider.hpp.
  • Реализовать MeshCollider как отдельный класс ColliderPrimitive-наследник:
  • immutable геометрия: вершины, индексы, локальный BVH по треугольникам;
  • transform берётся из существующего ColliderPrimitive::transform.
  • Не добавлять pair-specific формулы для Mesh-vs-* в стиле текущего double-dispatch.
  • Вынести mesh narrow-phase в отдельный модуль:
  • mesh_query.hpp/.cpp: raycast, closest-point, overlap query по triangle BVH;
  • mesh_contacts.hpp/.cpp: генерация контактов primitive-vs-mesh.

3. Этапы внедрения

Этап A. API и типы

  • Обновить ColliderType, forward declarations, virtual dispatch методы.
  • Добавить MeshCollider в colliders.hpp и nanobind (_colliders_native).
  • Обновить Python re-export (termin/colliders/__init__.py).
  • Обновить ColliderComponent:
  • новый collider_type = "Mesh";
  • поле mesh_asset (или handle/id) для выбора меша;
  • корректная регистрация в inspect choices.

Этап B. Геометрия и ускоряющая структура

  • В MeshCollider хранить:
  • std::vector<Vec3> vertices_local;
  • std::vector<uint32_t> indices (треугольники);
  • локальный BVH/AABB tree по треугольникам.
  • Построение BVH один раз при создании/смене меша.
  • aabb() коллайдера: трансформировать bounds локального BVH в world-space AABB.

Этап C. Запросы к Mesh

  • Реализовать:
  • closest_to_ray через ray-triangle traversal по BVH;
  • closest point from primitive to triangle set (с BVH pruning);
  • intersection primitive-vs-triangle для Box/Sphere/Capsule.
  • Контактные данные возвращать в формате ColliderHit/ContactManifold с текущим знаком penetration (negative == penetrating).

Этап D. Интеграция в CollisionWorld

  • В detect_contacts() добавить обработку пар Mesh-vs-* и *-vs-Mesh.
  • Для первой версии:
  • Sphere-vs-Mesh: полноценный и стабильный;
  • Capsule-vs-Mesh: через segment-triangle distance + penetration;
  • Box-vs-Mesh: SAT/closest-feature с ограничением числа контактных точек.
  • Mesh-vs-Mesh не включать в первую итерацию (отдельный milestone).

Этап E. AttachedCollider/UnionCollider

  • Добавить MeshCollider во все dynamic_cast ветки AttachedCollider.
  • Проверить UnionCollider на корректный выбор минимальной дистанции и нормали для mix-пар с mesh.

Этап F. Тесты

  • Unit tests (cpp/tests/tests_colliders.cpp):
  • raycast hit/miss по mesh;
  • sphere/box/capsule vs mesh (separated, touching, penetrating);
  • инвариант направления normal (A -> B).
  • Integration (cpp/tests/tests_collision.cpp):
  • CollisionWorld пары с Mesh;
  • корректный point_count, знак penetration, стабильность при update_pose.
  • Python smoke tests для bindings и ColliderComponent.

4. Алгоритмы (минимально необходимые)

  • Triangle BVH (SAH или median-split; для начала median-split достаточно).
  • Ray-triangle intersection (Moller-Trumbore).
  • Closest point point/segment/triangle.
  • Primitive-triangle overlap:
  • sphere-triangle;
  • capsule-triangle (segment-triangle distance);
  • box-triangle SAT (Akenine-Moller style).
  • Контактный manifold builder с лимитом ContactManifold::MAX_POINTS.

5. Критерии готовности (Definition of Done)

  • MeshCollider доступен в C++/Python API и выбирается в ColliderComponent.
  • CollisionWorld корректно детектирует Sphere/Capsule/Box vs Mesh.
  • Raycast по MeshCollider работает и сортируется по distance.
  • Все новые тесты зелёные локально и в CI.
  • Нет silent-fallback логики и нет проглатывания исключений/ошибок без error-лога.

6. Риски и порядок приоритета

  • Главный риск: нестабильность контактных нормалей на острых рёбрах и тонких треугольниках.
  • Второй риск: производительность без triangle BVH и без агрессивного pruning.
  • Приоритет реализации:
  • Sphere-vs-Mesh
  • Capsule-vs-Mesh
  • Box-vs-Mesh
  • Mesh-vs-Mesh (отдельный этап)