LibGDX - Bullet - обнаружение столкновений в 3D без обнаружения столкновений

Я пытаюсь выполнить тест 3D-столкновений с помощью Bullet, который, как я ожидал, будет работать довольно просто:

@Override
public void create(){
   . . .
   /*
    * Collision
    */

   collisionConfig=new btDefaultCollisionConfiguration();
   dispatcher=new btCollisionDispatcher(collisionConfig);
   broadphase=new btDbvtBroadphase();
   world=new btCollisionWorld(dispatcher, broadphase, collisionConfig);
   contactListener=new PiscesContactListener();
   contactListener.enable();

   /*
    * Test stuff
    */

   btSphereShape sphere=new btSphereShape(2.5f);
   btCollisionObject object1=new btCollisionObject();
   btCollisionObject object2=new btCollisionObject();
   object1.setCollisionShape(sphere);
   object2.setCollisionShape(sphere);
   object1.setWorldTransform(new Matrix4(new Vector3(0f, 0f, 0f), new Quaternion(0f, 0f, 0f, 0f), new Vector3(1f, 1f, 1f)));
   object2.setWorldTransform(new Matrix4(new Vector3(1f, 0f, 0f), new Quaternion(0f, 0f, 0f, 0f), new Vector3(1f, 1f, 1f)));
   object1.setUserValue(0);
   object2.setUserValue(1);
   object1.setCollisionFlags(WorldObject.COLLISION_PRIMARY);   // 1<<9
   object2.setCollisionFlags(WorldObject.COLLISION_PRIMARY);
   world.addCollisionObject(object1, WorldObject.COLLISION_PRIMARY, WorldObject.COLLISION_EVERYTHING);   // -1
   world.addCollisionObject(object2, WorldObject.COLLISION_PRIMARY, WorldObject.COLLISION_EVERYTHING);
   . . .
}

@Override
public void render() {
   . . .
   world.performDiscreteCollisionDetection();
   . . .
}

/*
 * In a separate file
 */
public class PiscesContactListener extends ContactListener {   
    public boolean onContactAdded (int userValue0, int partId0, int index0, boolean match0, int userValue1, int partId1, int index1, boolean match1) {
        System.out.println("Collision detected between "+userValue0+" and "+userValue1);
        return true;
    }
}

(Я следовал этому руководству. , хотя я, очевидно, немного отклонился от него, чтобы попытаться сделать его еще проще.)

Сфера размером 2,5 единицы в точке (0, 0, 0) и сфера размером 2,5 единицы в точке (1, 0, 0) должны вызвать столкновение, не так ли? В окне консоли ничего не появляется.

Я несколько подозреваю, что есть что-то фундаментальное, о чем я забыл, так как я пытался сделать raycast и это тоже не работает.

Вероятно, стоит упомянуть, что вызов world.drawDebugWorld(); рисует каркасы всех объектов там, где они должны быть, поэтому теперь я подозреваю, что ошибка заключается в прослушивателе контактов или, возможно, в флагах, которые я использую (хотя у меня не было никаких удачи с любыми другими флагами столкновения). Я что-то упустил в прослушивателе контактов?

Кроме того, я пытался использовать ContactCache вместо ContactListener, но это тоже не сработало. Большая часть литературы, которую я могу найти по этому вопросу, говорит о ContactListener, поэтому мне, вероятно, лучше использовать это.

Я, очевидно, что-то забыл, так как другие люди могут это сделать, может ли кто-нибудь указать, что это может быть?


person Dragonite    schedule 08.05.2018    source источник


Ответы (1)


Вы смешиваете флаги коллизий (btCollisionObject#setCollisionFlags(int *flags*)) и фильтрацию коллизий (btCollisionWorld#addCollisionObject(object, short *group*, short *mask*)). Это две очень разные вещи.

Вы должны не вызывать метод btCollisionObject#setCollisionFlags(int) ни с чем, кроме доступных флагов (см. здесь). Флаг коллизии CF_CUSTOM_MATERIAL_CALLBACK должен быть установлен для вызываемый метод ContactListener#onContactAdded. Вот почему ваш код не работает так, как вы ожидали.

Обратите внимание, что в моем руководстве вы имеете в виду это также объясняется:

public void spawn() {
    ...
    obj.body.setUserValue(instances.size);
    obj.body.setCollisionFlags(obj.body.getCollisionFlags() | btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
    ...
}

В методе spawn мы устанавливаем это значение, используя метод setUserValue, равным индексу объекта в массиве instances. А также сообщаем Bullet, что хотим получать события коллизий для этого объекта, добавляя флаг CF_CUSTOM_MATERIAL_CALLBACK. Этот флаг необходим для вызова метода onContactAdded.

Нет причин использовать 1<<11 вместо 1<<9 для фильтрации столкновений. Вероятно, вы также изменили что-то еще (например, флаг коллизии) и ошибочно предположили, что это изменение в фильтре коллизий привело к тому, что он начал работать.

Обратите внимание, что помимо флагов столкновений и фильтрации столкновений, существует также (специфичный для libgdx) фильтрация обратного вызова контакта (объяснено в вторая часть этого руководства). Имейте в виду, что это три совершенно разные и не связанные друг с другом вещи.

person Xoppa    schedule 13.05.2018
comment
Интересно, это, вероятно, объясняет и некоторые другие проблемы, которые у меня были. Спасибо, что указали на это! - person Dragonite; 13.05.2018