Как мне реализовать объект Bullet Physics CollisionObject, который представляет мой куб как ландшафт?

8

Я успешно интегрировал библиотеку Bullet Physics в свою систему сущностей / компонентов. Сущности могут сталкиваться друг с другом. Теперь мне нужно дать им возможность столкнуться с ландшафтом, который является конечным и похожим на куб (например, InfiniMiner или его клон Minecraft ). Я только начал использовать библиотеку Bullet Physics вчера, так что, возможно, я упускаю что-то очевидное.

До сих пор я расширил RigidBodyкласс, чтобы переопределить checkCollisionWith(CollisionObject co)функцию. На данный момент это просто простая проверка происхождения, а не использование другой формы. Я повторю это позже. На данный момент это выглядит так:

@Override
public boolean checkCollideWith(CollisionObject co) {
    Transform t = new Transform();
    co.getWorldTransform(t);
    if(COLONY.SolidAtPoint(t.origin.x, t.origin.y,t.origin.z)){
        return true;
    }
    return false;
}

Это прекрасно работает, поскольку обнаруживает, когда происходят столкновения. Однако это не обрабатывает реакцию на столкновение. Кажется, что по умолчанию реакция на столкновение состоит в том, чтобы переместить сталкивающиеся объекты за пределы форм друг друга, возможно, их AABB.

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

Следует отметить, что местность динамична и часто изменяется игроком.

MichaelHouse
источник

Ответы:

8

Хотя я ценю ответ Кевина Рида, он был на уровне выше, чем тот, который задавал мой вопрос. Понятно, что без знания физики пуль трудно было бы ответить на этот вопрос. Я получил это работает и у меня есть ответ, который специфичен для Bullet Physics.

Наряду с расширением RigidBodyкласса, как я уже упоминал в своем вопросе. Мне также нужно было расширить CollisionAlgorithmкласс. Это в основном для переопределения processCollision()функции. Внутри processCollision()функции (которая принимает два сталкивающихся тела в качестве аргументов) я смог создать форму куба, соответствующую Transformкубу, с которым сталкивалась моя сущность. Затем просто позвольте коллизии по умолчанию произойти на основе сущности и конкретных кубов / кубов, с которыми она сталкивается. Чтобы использовать недавно расширенный CollisionAlgorithm, мне нужно было зарегистрировать алгоритм для работы с фигурами, которые я хочу обработать. В этом случае это в значительной степени тип местности против всего остального. Для этого я использовал registerCollisionCreateFunc()с моим CollisionDispatcher.

Так что для тех, кто следует в будущем:

  1. Продлите RigidBodyбазовую проверку столкновения с вашей местностью.
  2. Создайте экземпляр своего RigidBodyкласса и добавьте его в свой DynamicsWorldили что-либо, что PhysicsProccesorвы используете.
  3. Расширение CollisionAlgorithm, в частности, processCollision()для создания фигур и трансформаций Bullet Physics, которые соответствуют вашему месту столкновения.
  4. Зарегистрируйте вашу версию CollisionAlgorithmс вашим CollisionDispatcherиспользованием registerCollisionCreateFunc(). (Эта регистрация выполняется несколько раз, по одному разу для каждой пары фигур, которые вы хотите столкнуть.)

РЕДАКТИРОВАТЬ

Вот видео этого в действии, если кому-то интересно.

Обнаружение начального столкновения

Для моих первоначальных проверок коллизий мои расширенные функции rigidBodyпереопределяют checkCollideWithфункцию, описанную в моем вопросе. У меня есть функция для моей местности, которая может проверить, является ли мир твердым в определенной точке. По сути, я проверяю свою местность на предмет, передаваемый checkCollideWithфункцией, и проверяю , является ли моя местность твердой в пределах границ этого объекта.

Теперь в Bullet есть еще один шаг - поиск точек соприкосновения. Это происходит в processCollision()функции, которую я упомянул выше. Здесь я сделал boxShape размером с куб местности, затем, когда я обнаружил столкновение в checkCollideWithфункции, я поместил этот boxShape размером с куб местности, в месте столкновения, и позволил Bullet использовать все его стандартные алгоритмы для обнаружения точек столкновения. ,

Так что в основном, если физические объекты граничат с твердым материалом. Я помещу свое временное физическое тело в это место и скажу Булле проверять столкновения с этим временным кубом, как если бы он всегда был там. Это как супер оптимизирующее размещение boxShape для каждого куба в моей местности. Вместо миллионов коробочных форм мне нужен только тот, который телепортируется при обнаружении столкновения.

MichaelHouse
источник
Можете ли вы подробнее рассказать о том, как вы обнаружили столкновения?
Тимоксли
1
@timoxley Я немного обновил ответ.
MichaelHouse
Как бы вы справились с одним предметом, который сталкивается в нескольких точках, например, с лестницей, опирающейся на землю и на стену?
Тимоксли
Временный куб перемещается по всем местам, где объект касается поверхности. Он просто используется для точного обнаружения, чтобы получить контактные точки и реагировать соответствующим образом.
MichaelHouse
3

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

Таким образом, вместо изменения или переопределения любого из классов Bullet, есть альтернативный вариант использования встроенного объекта столкновения Bullet, который будет представлять ландшафт. BvhTriangleMeshShape( Док ) представляет собой встроенный в форме, которая представлена в виде треугольника сеткой.

Эта сетка может быть сгенерирована одновременно с сеткой для визуализации мира. Это означает, что физический объект может точно соответствовать визуализированному объекту.

Я создаю RigidBodyдля каждого куска в моей местности. Это тело имеет свою форму, установленную на BvhTriangleMeshShape. Когда ландшафт изменяется, в то же время я перестраиваю визуальное представление фрагмента, я также перестраиваю физическую форму. Затем, когда приходит время буферизовать визуальную форму, я также обмениваю физические формы следующим образом:

dynamicsWorld.removeRigidBody(chunk.getRigidBody());
chunk.getRigidBody().setCollisionShape(newShape);
dynamicsWorld.addRigidBody(chunk.getRigidBody());

Это гарантирует, что тело удаляется правильно, очищая точки контакта. Затем его форма меняется, и он снова добавляется.

Для того, чтобы сгенерировать BvhTriangleMeshShapeкаждый чанк, необходимо поддерживать TriangleIndexVertexArray( doc ). По сути, это два байтовых буфера. Один с позициями вершин треугольника, а другой - с индексами для построения этих треугольников. Этот массив вершин должен быть сохранен, поскольку BvhTriangleMeshShapeон не создает копию данных.

Использование всех встроенных классов физики Bullet, вероятно, быстрее, чем все, что я мог написать, и действительно работает очень быстро. Я не вижу никаких замедлений после реализации этой новой стратегии.

введите описание изображения здесь

MichaelHouse
источник
Я отмечу всем, кто читает это, что, по крайней мере, в моем тестировании, JBullet ОЧЕНЬ медленен в приготовлении сеток (то есть предварительно обрабатывает их, прежде чем их можно будет использовать для физики), по крайней мере по сравнению со временем, которое требуется для преобразования чанка. в сетку с помощью марширующих кубов. Мы говорим на порядки медленнее. Итак, я собираюсь заглянуть в PhysX и посмотреть, насколько лучше я могу получить его производительность. Если у кого-то есть информация по этому поводу, я бы хотел это услышать.
Филипп Гуин
2

Я не знаком с Bullet Physics, но я использовал ODE. Там, после теста столкновения да-или-нет, проводится более подробный тест столкновения форма-форма, который генерирует набор точек контакта.

В вашем случае ваш мир представляет собой набор коробок, так что вы можете сделать это:

  1. Возьмите AABB движущейся сущности.
  2. Итерируйте по вокселям ландшафта в том объеме, который пересекает его.
  3. Для каждого вокселя местности, которая является сплошной, постройте соответствующий прямоугольник и вычислите (предпочтительно, используя процедуры физического движка) столкновение этого прямоугольника с движущейся сущностью.
  4. Вернуть коллекцию всех полученных контактных точек.

Это не переопределение реакции на столкновение ; это слой до этого. Реакция на столкновение полностью определяется точками контакта, рассчитанными на основе столкновения.

Как я уже сказал, я не знаком с Bullet Physics, поэтому не знаю, подойдет ли его архитектура.

Кевин Рид
источник
Спасибо. Я думаю, что реакция на столкновение также связана с тестом на столкновение с формой. Он должен использовать эту информацию, чтобы решить, каким образом их раздвинуть и как далеко разнести их, правильно? Я был бы согласен с текущей реакцией на столкновение, если бы она отвечала форме моей местности.
MichaelHouse
Да; Я имел в виду, что вы не переопределяете алгоритм реакции на столкновение, а скорее переопределяете генерацию точек контакта, которые являются входными данными для этого алгоритма.
Кевин Рейд