Я пишу некоторый код на C ++ для тестирования столкновений, используя теорему о разделительной оси, и в определенных ориентациях это ошибочно вызывает, что происходит столкновение
я следую этот учебник, однако учебник только в 2D, и я пытаюсь реализовать его в 3D, хотя я думаю, что он должен быть таким же.
Алгоритм, который у меня сейчас есть, не пропускает никаких столкновений, но для некоторых ориентаций двух блоков он думает, что они сталкиваются, когда они не затрагиваются. Пример можно увидеть здесь, эти два поля, очевидно, сталкиваются в соответствии с кодом ниже.
Код написан на C ++
BoxCollider.h
class BoxCollider :
public Collider
{
public:
BoxCollider(Vector3 position, Vector3 rotation, Vector3 size);~BoxCollider();
void Update();
public:
Vector3 rotation;
Vector3 size;
Matrix transformMatrix;
std::vector<Vector3> points;
Vector3 normals[3];
};
BoxCollider.cpp
BoxCollider::BoxCollider(Vector3 position, Vector3 rotation, Vector3 size) : rotation(rotation), size(size)
{
this->position = position;
points.resize(8);
}
BoxCollider::~BoxCollider()
{
}
void BoxCollider::Update()
{
Transform* eTransform = m_entity->GetComponent<Transform>();
transformMatrix.RotateYawPitchRoll(rotation + eTransform->rotation);
Vector3 ePos = eTransform->position;
points[0] = transformMatrix * (Vector3( 0.5, -0.5, -0.5) * size) + position + ePos;
points[1] = transformMatrix * (Vector3( 0.5, 0.5, -0.5) * size) + position + ePos;
points[2] = transformMatrix * (Vector3( 0.5, -0.5, 0.5) * size) + position + ePos;
points[3] = transformMatrix * (Vector3( 0.5, 0.5, 0.5) * size) + position + ePos;
points[4] = transformMatrix * (Vector3(-0.5, -0.5, -0.5) * size) + position + ePos;
points[5] = transformMatrix * (Vector3(-0.5, 0.5, -0.5) * size) + position + ePos;
points[6] = transformMatrix * (Vector3(-0.5, -0.5, 0.5) * size) + position + ePos;
points[7] = transformMatrix * (Vector3(-0.5, 0.5, 0.5) * size) + position + ePos;
normals[0] = transformMatrix * Vector3(1, 0, 0);
normals[1] = transformMatrix * Vector3(0, 1, 0);
normals[2] = transformMatrix * Vector3(0, 0, 1);
}
Алгоритм:
void EntityManager::CheckCollision(BoxCollider * col0, BoxCollider * col1)
{
for (int i = 0; i < 3; i++) //First cube
{
Vector3 axis = col0->normals[i];
axis = Vector3(axis.z, -axis.x, axis.y);Projection proj1 = GetProjection(col0->points, axis);
Projection proj2 = GetProjection(col1->points, axis);
float overlap = GetOverlap(proj1, proj2);
if (overlap > 0.0) //The projections do not overlap
return;
}
for (int i = 0; i < 3; i++) //First cube
{
Vector3 axis = col1->normals[i];
axis = Vector3(axis.z, -axis.x, axis.y);
Projection proj1 = GetProjection(col0->points, axis);
Projection proj2 = GetProjection(col1->points, axis);
float overlap = GetOverlap(proj1, proj2);
if (overlap > 0.0) //The projections do not overlap
return;
}
}
float GetOverlap(Projection proj1, Projection proj2)
{
float a = proj2.left - proj1.right;
float b = proj1.left - proj2.right;
return a > b ? a : b;
}
Projection GetProjection(std::vector<Vector3> points, Vector3 axis)
{
float tmp = 0;
float left = D3D10_FLOAT32_MAX, right = -D3D10_FLOAT32_MAX;
for (int i = 0; i < points.size(); i++)
{
tmp = DotProduct(points[i], axis.Normalize());
if (tmp < left)
{
left = tmp;
}
if (tmp > right)
{
right = tmp;
}
}
return Projection(left, right, axis);
}
учебник только в 2D, и я пытаюсь реализовать его в 3D, хотя я думаю, что он должен быть таким же
К сожалению, это не так. 3D случай немного сложнее. Чтобы проверить, сталкиваются ли две сложные фигуры в 3D, вам нужно проверить нормальное лицо (вы делаете это), и направления, которые перпендикулярны краю каждого объекта (ты скучаешь по этим).
Итак, для ящиков (A и B) с направлениями ребер A0, A1, A2 и B0, B1, B2 имеем:
Так что вам просто нужно добавить недостающие 9 чеков.
Дальнейшее примечание: вам не нужно прыгать нормалей. Я имею в виду, что эта строка не нужна:
axis = Vector3(axis.z, -axis.x, axis.y);
В этом случае это не приносит никакого вреда. Но для более сложных форм это может сделать тест некорректным.
Других решений пока нет …