Столкновение сферы с полигоном

В настоящее время я работаю над небольшим физическим движком, и у меня возникла небольшая проблема с обработкой столкновений «Сфера с полигоном».

Вот что я получаю.

Как видите, сфера просто парит на краю многоугольника. Это только по краям! если я сдвину сферу немного дальше, она упадет, как и должна, я действительно не понимаю, почему это происходит. Итак, вот мой код, надеюсь, вы можете помочь (я использую теорему о разделяющей оси):

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;
            }
        }

А вершины, которые я даю для Полигона, — это просто Вершины для куба, который можно масштабировать в любом направлении.

Из того, что я заметил, вы рассматриваете только нормали лица для столкновения. Это вызывает неверную генерацию точки контакта, когда сфера находится рядом с краями или вершинами многоугольника, поскольку учитывается только контакт лицом к сфере. Вы также должны учитывать контакты между ребрами и сферами.

Kozydot 10.04.2023 08:21

эй, я пытался сделать то, что вы сказали, и я немного потерялся, так что .. не могли бы вы немного намекнуть мне, как я могу это сделать?

Yami 10.04.2023 16:54

Добавьте проверку контакта вершины со сферой, перебирая вершины каждой грани и находя ближайшую к сфере вершину. Затем, если расстояние между ближайшей вершиной и сферой меньше радиуса сферы, вы соответственно обновляете нормаль, глубину и точку контакта.

Kozydot 10.04.2023 19:30

так и должно быть так? : Vector3 cp = Vector3.Min(vA, Vector3.Min(vB, vC)); if ((cp - centerA).Length() < radiusA) { return false; }

Yami 11.04.2023 01:22
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

через неделю или около того я, наконец, понял это. все, что мне нужно было в первую очередь, это проверить крайние случаи (спасибо 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;
                }
            }

Другие вопросы по теме