В настоящее время я работаю над небольшим физическим движком, и у меня возникла небольшая проблема с обработкой столкновений «Сфера с полигоном».
Как видите, сфера просто парит на краю многоугольника. Это только по краям! если я сдвину сферу немного дальше, она упадет, как и должна, я действительно не понимаю, почему это происходит. Итак, вот мой код, надеюсь, вы можете помочь (я использую теорему о разделяющей оси):
public static bool SphereToPolygon(Vector3 centerA, float radiusA, Vector3[] verts, short[] inds, Vector3 centerB, out Vector3 normal, out float depth, out Vector3 contactPoint, out int contacts) {
normal = Vector3.Zero;
contactPoint = Vector3.Zero;
depth = float.MaxValue;
contacts = 0;
float minA, maxA, minB, maxB;
for (int i = 0; i < inds.Length; i += 3) {
Vector3 vA = verts[inds[i]];
Vector3 vB = verts[inds[i + 1]];
Vector3 vC = verts[inds[i + 2]];
Vector3 axis = Vector3.Cross(vA - vB, vC - vB);
axis.Normalize();
Solver.ProjectVertices(verts, axis, out minB, out maxB);
Solver.ProjectSphere(centerA, radiusA, axis, out minA, out maxA);
if (maxB < minA|| maxA < minB) {
return false;
}
float overLap = MathF.Min(maxB, maxA) - MathF.Max(minB, minA);
if (overLap < depth) {
depth = overLap;
normal = axis;
contactPoint = centerA - radiusA * axis;
contacts = 1;
}
}
Vector3 direction = centerB - centerA;
if (Vector3.Dot(normal, direction) < 0) {
normal = -normal;
}
return true;
}
А вот как я проецирую Вершины и Сферу:
private static void ProjectVertices(Vector3[] verts, Vector3 axis, out float min, out float max) {
min = float.MaxValue;
max = float.MinValue;
for(int i = 0; i < verts.Length; i++) {
float projectedPoint = Vector3.Dot(verts[i], axis);
if (projectedPoint < min) { min = projectedPoint; }
if (projectedPoint > max) { max = projectedPoint; }
}
}
private static void ProjectSphere(Vector3 center, float radius, Vector3 axis, out float min, out float max) {
min = Vector3.Dot(center, axis) - radius;
max = Vector3.Dot(center, axis) + radius;
if (min > max) {
float t = min;
min = max;
max = t;
}
}
А вершины, которые я даю для Полигона, — это просто Вершины для куба, который можно масштабировать в любом направлении.
эй, я пытался сделать то, что вы сказали, и я немного потерялся, так что .. не могли бы вы немного намекнуть мне, как я могу это сделать?
Добавьте проверку контакта вершины со сферой, перебирая вершины каждой грани и находя ближайшую к сфере вершину. Затем, если расстояние между ближайшей вершиной и сферой меньше радиуса сферы, вы соответственно обновляете нормаль, глубину и точку контакта.
так и должно быть так? : Vector3 cp = Vector3.Min(vA, Vector3.Min(vB, vC)); if ((cp - centerA).Length() < radiusA) { return false; }
через неделю или около того я, наконец, понял это. все, что мне нужно было в первую очередь, это проверить крайние случаи (спасибо Brixxon за указание на это), и мне потребовалось некоторое время, чтобы понять, как это сделать, но я, наконец, сделал это, и вот код для проверки края случаи, если кому-то интересно, «чтобы что-то работало, вы должны сделать эту проверку перед всем остальным»:
for (int i = 0; i < inds.Length; i++) {
Vector3 vA = verts[inds[i]];
Vector3 vB = verts[inds[(i + 1) % inds.Length]];
axis = vB - vA;
axis = new Vector3(axis.X, axis.Z, -axis.Y);
axis.Normalize();
Solver.ProjectVertices(verts, axis, out minB, out maxB);
Solver.ProjectSphere(centerA, radiusA, axis, out minA, out maxA);
if (maxB < minA || maxA < minB) {
return false;
}
overLap = MathF.Min(maxB, maxA) - MathF.Max(minB, minA);
if (overLap < depth) {
depth = overLap;
normal = axis;
contactPoint = (centerA - radiusA * -axis);
contacts = 1;
}
}
Из того, что я заметил, вы рассматриваете только нормали лица для столкновения. Это вызывает неверную генерацию точки контакта, когда сфера находится рядом с краями или вершинами многоугольника, поскольку учитывается только контакт лицом к сфере. Вы также должны учитывать контакты между ребрами и сферами.