struct Projection {
float min;
float max;
};
Projection project(const std::vector<glm::vec2>& vertices, const glm::vec2& axis) {
Projection projection;
projection.min = glm::dot(axis, vertices[0]);
projection.max = projection.min;
for (int i = 1; i < vertices.size(); i++) {
float dotProduct = glm::dot(axis, vertices[i]);
if (dotProduct < projection.min) {
projection.min = dotProduct;
} else if (dotProduct > projection.max) {
projection.max = dotProduct;
}
}
return projection;
}
bool overlap(const Projection& p1, const Projection& p2) {
return p1.max >= p2.min && p2.max >= p1.min;
}
glm::vec2 getMTV(const std::vector<glm::vec2>& vertices1, const std::vector<glm::vec2>& vertices2) {
float minOverlap = std::numeric_limits<float>::max();
glm::vec2 MTV;
for (int i = 0; i < vertices1.size(); i++) {
glm::vec2 axis = glm::normalize(vertices1[(i + 1) % vertices1.size()] - vertices1[i]);
Projection p1 = project(vertices1, axis);
Projection p2 = project(vertices2, axis);
if (!overlap(p1, p2)) {
return glm::vec2(0.0f);
} else {
float overlap = std::min(p1.max, p2.max) - std::max(p1.min, p2.min);
if (overlap < minOverlap) {
minOverlap = overlap;
MTV = axis * overlap;
}
}
}
for (int i = 0; i < vertices2.size(); i++) {
glm::vec2 axis = glm::normalize(vertices2[(i + 1) % vertices2.size()] - vertices2[i]);
Projection p1 = project(vertices1, axis);
Projection p2 = project(vertices2, axis);
if (!overlap(p1, p2)) {
return glm::vec2(0.0f);
} else {
float overlap = std::min(p1.max, p2.max) - std::max(p1.min, p2.min);
if (overlap < minOverlap) {
minOverlap = overlap;
MTV = axis * overlap;
}
}
}
return MTV;
}
以上是一个简单的C++实现
C++中实现MTV算法的步骤:
- 计算两个物体在所有可能的分离轴上的投影。
- 如果两个物体在某个分离轴上的投影重叠,则它们之间没有发生碰撞。
- 如果两个物体在所有可能的分离轴上的投影都不重叠,则它们之间发生了碰撞。
- 计算出它们之间的最小平移向量(MTV),并将其中一个物体沿着MTV移动,直到两个物体不再重叠。