vindast
> 2)Далее разрешить поворот еще вокруг оси аморта. Но есть вопрос как сделать сам
> рулевой механизм, по тому что просто поворот всего в лоб приведет к
> нестабильности.
Эту проблему я решил просто вращая ступицу, все ведет стабильно.
Пока буду переделывать силы трения в покрышке.
vindast
у меня сейчас период очень бурного отдыха, отвечать быстро не смогу
Suslik, я уже забеспокоился, вдруг случилось что. Я почти сделал все что планировал пока Вас не было, сам ))))))) Осталось только трение. Я его почти сделал, остался только боковой случай.
Suslik
Вроде все сделал кроме передней подвески.
Как видно хорошо передние колеса сходят с ума. Я сейчас просто снял ограничение кручения аморта спереди вокруг его оси.
Мне нужна подсказка, как бы правильно сделать поворот передних колес.
Починил переднюю подвеску, отбой ) Сделал поворот как глубина - угол поворота для псевдоскорости.
На этом проблемы с машиной кончились. (остался вармстатинг - но он вроде как простой, и по тому его в самый конец).
Сейчас такой вопрос.
Как сделать по уму систему коллизий?
Я так понимаю нужно курить сапортмапинг для обычных обычных объектов. Я вроде понял как с этим быть и пока буду пробовать сам сделать
систему коллизий на нем основанную. (пока только для бокса - для начала). Но как быть с дорогами? Сплайнами соответственно.
Не смог заимплементить gjk. Алгоритм никогда не выдает, что было найдено пересечение (почти никогда).
Делал по этой статье: https://gamedev.ru/pages/kesha/articles/gjk
Основной код:
void gjk(TOrientedBoundingBox* b1, TOrientedBoundingBox* b2, vector<vec3>& positions) { //Инициализирую точки симплекса какими-то значениями vec3 Simplex[4]; Simplex[0] = getMinkovskyDifferens( b1, b2, vec3( 0.0f, 1.0f, 0.0f)); Simplex[1] = getMinkovskyDifferens( b1, b2, vec3( 1.0f, 0.1f, 0.1f)); Simplex[2] = getMinkovskyDifferens( b1, b2, vec3( 0.4f, 0.0f, 1.0f)); Simplex[3] = getMinkovskyDifferens( b1, b2, vec3( -1.0f, -1.0f, 0.4f)); int IterationCount = 0; int id1, id2; //Id вершин грани, на которой лежит ближняя к нулю точка. vec3 MinPoint; //Содержит ближнюю к нулю точку симплекса while ( true) { //Если симплекс содержит ноль то поиск закончен. if ( isSipmlexContainsZeroPoint( Simplex)) { cout << "Collision" << endl; break; } //Ищу ближнюю к нулю точку симплекса. findClousestSimplexPointToZero( MinPoint, Simplex, id1, id2); vec3 v = getMinkovskyDifferens( b1, b2, -MinPoint); //Условие что экстремум в направелнии MinPoint (радиус-вектор) нарастает if ( dot( v, MinPoint) <= 1.0f) { cout << "Not match" << endl; break; } //Ищу куда воткнуть новую точку из CSO for ( int i = 0; i < 4; i++) { if ( i != id1 && i != id2) { Simplex[i] = v; break; } } //Защита от переполнения. Почти всегда дает именно этот результат. IterationCount++; if ( IterationCount > 10) { cout << "IterationCount overload" << endl; break; } } }
vec3 getMinkovskyDifferens(TOrientedBoundingBox* b1, TOrientedBoundingBox* b2, const vec3& dir) { return b1->getSupportPoint( dir) - b2->getSupportPoint( -dir); }
vec3 getNearToZeroPoint(const vec3& p1, const vec3& p2) { vec3 d = p2 - p1; vec3 r = vec3( 0.0f) - p1; float t = clamp( dot( r, d) , 0.0f, 1.0f); return p1 + d * t; } void computeMinPos( vec3& MinPoint, int& FirstPoint, int& SecondPoint, const vec3* Simplex3D, const int& id1, const int& id2 ) { vec3 tmpPos = getNearToZeroPoint( Simplex3D[id1], Simplex3D[id2]); if ( length( MinPoint) > length( tmpPos)) { MinPoint = tmpPos; FirstPoint = id1; SecondPoint = id2; } } void findClousestSimplexPointToZero( vec3& MinPoint, const vec3* Simplex3D, int& FirstPoint, int& SekondPoint) { MinPoint = getNearToZeroPoint( Simplex3D[0], Simplex3D[1]); FirstPoint = 0; SekondPoint = 1; computeMinPos( MinPoint, FirstPoint, SekondPoint, Simplex3D, 0, 2); computeMinPos( MinPoint, FirstPoint, SekondPoint, Simplex3D, 0, 3); computeMinPos( MinPoint, FirstPoint, SekondPoint, Simplex3D, 1, 2); computeMinPos( MinPoint, FirstPoint, SekondPoint, Simplex3D, 1, 3); computeMinPos( MinPoint, FirstPoint, SekondPoint, Simplex3D, 2, 3); }
Проверка на принадлежность точки (0) тетраэдру (симплексу) (есть подозрение что она не всегда правильно работает - на пример в случае складывания тетраэдра в плоскостную фигуру) :
bool isSipmlexContainsZeroPoint(vec3* Simplex) { vec3 Point = vec3( 0.0f) - Simplex[0]; float x = dot( Simplex[1] - Simplex[0], Point); float y = dot( Simplex[2] - Simplex[0], Point); float z = dot( Simplex[3] - Simplex[0], Point); return x >= 0.0f && x <= 1.0f && y >= 0.0f && y <= 1.0f && z >= 0.0f && z <= 1.0f; }
Сапортпоинты работают как должны.
Я думаю могу ошибаться во вставке новой точки в симплекс, нахождении ближний к нулю точки или же в проверке принадлежности нуля к тетраэдру симплекса.
Что я делаю не так?
Если есть годная статья на тему, то скиньте пожалуйста.
Третий день пошел как я с этим не могу разобраться.
vindast
бери да отлаживай, в чём проблема-то. для многоугольников алгоритм сходится за 2-3 итерации, проведи эти итерации на листочке бумаги и сравни со своей программой.
Suslik, есть вопрос с которым на бумажке не разобраться. По какому принципу нужно удалять точку из симплекса? Я оставляю ребро, к которому принадлежит точка с минимальной дистанцией до центра координат. Остаются две точки. Так вот какую откинуть и почему?
vindast
В gjk надо на каждой новой итерации ты должен строить новый симплекс путьом взятия самой дальней точки с всех возможных направлений текущего симплекса. Другими словами ты должен найти ближайшый симплекс с разницы минковского к началу координат , а потом с етого конечного симплекса берешь информацию о двух ближайшых симплексах с первого и второго тела и уже поним выщитиваешь две ближайшые точки по бариоцентрическими координатами !
vindast
> Остаются две точки. Так вот какую откинуть и почему?
Любую точку можеш удалять, видь одна и вторая точка лежать в плоскости относительно нормали ребра. Только вот зачем?
Видь gjk должен найти два ближайшых симплекса с первого и второго тела , вереней ближайшый симплекс к началу координат с разницы минковского, а там уже есть информация про двух ближайшых сисимплексах и нормали . gjk сам по себе не даст две ближайшые точки от двух тел , то бишь минемальное расстояние относительно двух тел , ну верней даст но далеко не во всех случаях . "Почти никогда" .
Так что надо так gjk+baryocentric !
P.S: Конченое ребро это тоже симплекс , но просто у него какие-то две точки совпадают , это надо учитивать в бариоцентрических расчётах . И на всякий случай скажу правильный gjk работает только с наружы , так что придётся делать GJK-SAP или GJK-EPA ну или просто MPR
vindast
>По какому принципу нужно удалять точку из симплекса?
в симплексе остаются только те точки, которые образуют ближайшую к началу координат фичу: треугольник, ребро или точка. это для классического gjk, который понимает только не пересекающиеся геометрии. чтобы искать пересечение, нужен gjk-epa и там точки из симплекса удалять вообще не получится. либо можешь попробовать мой алгоритм (не знаю, может быть, его уже кто-то до меня придумывал, но я не нашёл).
так работает gjk в моих обозначениях, выжимка из диссера:
самое главное в GJK — это критерий останова. я использовал такой:
так работает мой sgjk — расширение gjk на случай пресекающихся геометрий:
werasaimon
опять лекарства забыл принять
Suslik, спасибо. Сейчас буду читать.
Кажется я вкурил что я не так делал. Надо не только по ребрам искать ближайшее расстояние, но и по самой грани.
Позже сяду, переделаю.
Suslik
> который понимает только не пересекающиеся геометрии
А вот это не понятно. По идее он должен что-то найти если они пересекаются. То есть, если найдет симплекс к которому принадлежит начало координат, то пересечение есть, иначе нет.
gjk-epa (я чуть-чуть про него почитал) начинается с симплекса, которым закончился gjk, и должен вернуть область пересечения - контактную площадку.
Так же есть вопрос по оператору "+" - который возвращает выпуклую оболочку для множества. Так ведь симплекс должен быть из 4-х точек для трехмерного пространства. О какой выпуклой оболочке тогда идет речь? По идее даже если он сжался в одну точку, он должен оставаться вырожденным тетраэдром. Или я что-то не понимаю?
Suslik
> так работает мой sgjk — расширение gjk на случай пресекающихся геометрий
Судя по всему, у него проблема в том, что он находит локальный минимум, вместо глобального.
Стоит, наверное, дополнить алгоритмом выбора начальной точки, чтобы не возникало проблем, хотя бы, в простых случаях.
Тема в архиве.