3D обнаружение столкновений Java с Jbullet

Поэтому я потратил много времени, пытаясь с нуля создать систему обнаружения столкновений для собственного игрового движка, и из-за нехватки времени оказался бесплодным. Наконец я решил попытаться использовать Jbullet, чтобы сделать вещи быстрее. Теперь документация в основном бесполезна, и у меня возникли некоторые трудности, когда я пытаюсь перенести код маркера на Java (или то, что я передаю, не работает). Я рвал на себе волосы, пытаясь найти код библиотеки, но экономия времени, на которую я надеялся, оказалась практически бесполезной. Итак, я собираюсь объяснить, что я делаю, возможно, вы, ребята, можете мне помочь. Я только ищу простое обнаружение столкновения, как будто вы нажали что-то, а затем просто напечатали строку. Остальное я, наверное, смогу решить самостоятельно.

Итак, я создаю свой мир:

BroadphaseInterface broadphase = new DbvtBroadphase();
        CollisionConfiguration collisionConfig = new DefaultCollisionConfiguration();
        Dispatcher dispatcher = new CollisionDispatcher(collisionConfig);
        ConstraintSolver solver = new SequentialImpulseConstraintSolver();
        DynamicsWorld dynamicsWorld = new DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfig);
        return dynamicsWorld;

Итак, у меня есть свой класс сущностей, и там у меня есть еще один класс, в котором хранится вся информация для физического объекта, присоединенного к этой сущности. Это позволяет мне просто сделать: entity.getPhysics(). GetCollisionObject()/. SetPosition() и т. Д.

Затем я создаю свой объект CollisionObject в этом классе:

  List<org.lwjgl.util.vector.Vector3f> mesh = model.getModel().getVertices(); 
            ObjectArrayList<javax.vecmath.Vector3f> vertices = new ObjectArrayList<javax.vecmath.Vector3f>();
            for(org.lwjgl.util.vector.Vector3f vertex:mesh){
                javax.vecmath.Vector3f v = new javax.vecmath.Vector3f(vertex.x, vertex.y, vertex.z);
                vertices.add(v);
            }
            ConvexHullShape shape = new ConvexHullShape(vertices);
            ShapeHull hull = new ShapeHull(shape);
            hull.buildHull(shape.getMargin());
            ConvexHullShape newShape = new ConvexHullShape(hull.getVertexPointer());
            CollisionObject result = newShape; 

Я считаю, что это преобразует уже созданный меш, который я использую для рендеринга своей сущности, из Vector3f библиотеки LWJGL и Jbullets Vector3f. Затем он создает ConvexHullShape из этих вершин в сетке, и я считаю, что:

hull.buildHull(shape.getMargin());

должен упрощать сетку (из документации). Тогда я просто создаю объект столкновения. Довольно просто, я думаю...

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

//mass = 0, so that there is not any gravity application?
float mass = 0;
        Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
        this.transform = transform;
        MotionState state = new DefaultMotionState(transform);
        RigidBodyConstructionInfo info = new RigidBodyConstructionInfo(mass, state, shape);
        RigidBody body = new RigidBody(info);

Затем я прохожу игровой цикл:

dynamicsWorld.stepSimulation(DisplayManager.getFrameTimeSeconds(), 7);
            dynamicsWorld.performDiscreteCollisionDetection();
            dynamicsWorld.setInternalTickCallback(new InternalTickCallback(){

            @Override
            public void internalTick(DynamicsWorld world, float delta) {
                Dispatcher dispatcher = world.getDispatcher();
                int manifoldCount = dispatcher.getNumManifolds();
                for(int i = 0; i < manifoldCount; i ++){
                    PersistentManifold manifold = dispatcher.getManifoldByIndexInternal(i);
                     RigidBody object1 = (RigidBody)manifold.getBody0();
                     RigidBody object2 = (RigidBody)manifold.getBody1();

                     CollisionObject physicsObject1 = (CollisionObject)object1.getUserPointer();
                     CollisionObject physicsObject2 = (CollisionObject)object2.getUserPointer(); 
                      boolean contact = false;
                        javax.vecmath.Vector3f normal = null;
                        for (int j = 0; j < manifold.getNumContacts(); j++) {
                            ManifoldPoint contactPoint = manifold.getContactPoint(j);
                            if (contactPoint.getDistance() < 0.0f) {
                                contact = true;
                                normal = contactPoint.normalWorldOnB;
                                break;
                            }
                        }
                        if (contact) {
                            System.out.println("hit");
                        }
                }
            }

        }, null);

Я получил это от кого-то... Я забыл, где, хотя. Итак, в основном ничего не происходит... Я не уверен, но, возможно, мне нужно добавить объекты в коллектор или что-то в этом роде. Не знаю как это сделать. Любая помощь?

РЕДАКТИРОВАТЬ: то, что я сделал сейчас, это создаю форму столкновения как окно произвольного размера:

CollisionShape result = new BoxShape(new Vector3f(10,10,10));

Затем я создаю Призрачное Тело:

Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
        this.transform = transform;
        transform.origin.set(position);
        GhostObject body = new GhostObject();
        body.setCollisionShape(shape);
        body.setWorldTransform(transform);

тогда я просто делаю, как ты сказал, он все равно не возвращает "хит";

int overlaps = player.getPhysics().getBody().getNumOverlappingObjects();
            for(int i = 0; i < overlaps; i++){
                //player.getPhysics().getBody().getOverlappingObject(i).
                System.out.println("hit");
            }

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

Поэтому я создаю объект следующим образом в моем классе сущностей:

if(collision){    
physics = new PhysicsEntity(dynamicsWorld, model,new javax.vecmath.Vector3f(position.x, position.y, position.z), new javax.vecmath.Vector3f(rotX, rotY, rotZ), scale);
                physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
                physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
}

и обновить позицию и прочее:

public void increasePosition(float dx,float dy, float dz){
        this.position.x += dx;
        this.position.y += dy;
        this.position.z += dz;
        physics.updatePosition(new javax.vecmath.Vector3f(position.x, position.y, position.z));
    }

    public void increaseRotation(float dx, float dy, float dz){
        this.rotX += dx;
        this.rotY += dy;
        this.rotZ += dz;
        physics.updateRotation(new javax.vecmath.Vector3f(rotX, rotY, rotZ));
    }

Итак, это мой класс PhysicsEntity, где я его настроил:

public PhysicsEntity(DynamicsWorld world, TexturedModel model, Vector3f position, Vector3f rotation, float scale){
        this.model = model;
        this.position = position;
        this.rotation = rotation;
        this.scale = scale;
        shape = createShape();
        body = createBody();
        object = new CollisionObject();
        object.setCollisionShape(shape);
        world.addCollisionObject(body);

    }

    private GhostObject createBody(){
        Transform transform = new Transform(new Matrix4f(new Quat4f(rotation.x, rotation.y, rotation.z, 1), position, scale));
        this.transform = transform;
        transform.origin.set(position);
        GhostObject body = new GhostObject();
        body.setCollisionShape(shape);
        body.setWorldTransform(transform);

        return body;
    }

    private CollisionShape createShape(){
 CollisionShape result = new BoxShape(new Vector3f(10,10,10));


        return result;
    }

    public void updatePosition(Vector3f position){
        transform.origin.set(position);
        body.setWorldTransform(transform);


    }

    public void updateRotation(Vector3f rotation){
        transform.basis.set(new Quat4f(rotation.x, rotation.y, rotation.z, 1));
        body.setWorldTransform(transform);
    }

Спасибо,

1 ответ

Решение

Мой опыт работы с Bullet ограничен C++, но, возможно, я смогу помочь. Что вы имеете в виду, говоря, что ничего не происходит? Правильно ли действует гравитация на объект, но не вызывается обратный вызов столкновения или проблема в том, что он вообще не движется? Очевидно, он не будет двигаться, потому что его масса равна 0, поэтому он статичен. Объект с массой 0 также может быть кинематическим, если вы вызываете

body.setCollisionFlags(body .getCollisionFlags() | CollisionFlags.KINEMATIC_OBJECT);  
body.setActivationState(CollisionObject.DISABLE_DEACTIVATION);

Как статические, так и кинематические объекты обнаруживают столкновения, но только с динамическими объектами (масса больше 0). Я предлагаю для начала использовать простую форму столкновения, такую ​​как сфера. Таким образом, вы можете проверить, работает ли симуляция вообще. Выпуклые корпуса могут быть сложными. Начните с чего-то простого, чтобы привести рабочий пример. Теперь о методе обнаружения столкновений. Когда вы звоните dynamicsWorld.stepSimulation прилагаются все силы, и происходит обнаружение и разрешение столкновений. Так что сразу после этого вы можете перебирать PersistentManifolds так же, как вы делаете, чтобы проверить, какие объекты столкнулись друг с другом на этом этапе моделирования. Теперь я не уверен, но когда вы звоните dynamicsWorld.performDiscreteCollisionDetection(); вполне возможно, что столкновения не обнаружены, потому что все они были просто решены.

Почти во всех стандартных случаях вы хотите использовать RigidBody, Исключение составляют мягкие тела, такие как одежда и призрачные объекты, которые можно использовать для обнаружения столкновений без каких-либо реакций.

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

В ситуации, когда не требуется никакого столкновения, только обнаружение удара, вы не хотите RigidBody, Он может быть статическим, динамическим или кинематическим, но это не ваш случай. Вместо этого вы хотите использовать GhostObject, Он просто обнаруживает столкновения, но не реагирует. Вы можете легко проверить, перекрывается ли это чем-то, сначала вызвав его getNumOverlappingObjects() а потом getOverlappingObject(int index),

EDIT2.

Похоже, вы правильно создали объект. Если предположить, что преобразования верны и объект действительно должен перекрываться, то, что вы можете пропустить, dynamicsWorld.addCollisionObject(body); Я пропустил это с первого взгляда, но похоже, что вы только создаете объект, но не добавляете его в мир, поэтому Bullet engine не знает о его существовании.

EDIT3.

Итак, еще несколько предложений, чтобы убедиться, что столкновение должно быть обнаружено. Сколько физических объектов (призраков или твердых тел) вы создали и добавили в мир (используя dynamicsWorld.add...)? Если есть только один, очевидно, что столкновение не может быть обнаружено. Пуля не будет сталкивать физический объект с геометрией сцены, но только с другим физическим объектом. Не могли бы вы опубликовать свой код, где вы создаете и перемещаете эти объекты?

EDITn.

Итак, вы опубликовали функции, создающие PhysicsEntity, но я все еще не знаю, сколько сущностей вы создаете и с какими параметрами. Необходимо проверить, каковы их мировые координаты и проверить, действительно ли они должны столкнуться.

Ваше использование Quaternion немного беспокоит. Вы, вероятно, передаете аргументы x,y,z как вращение по оси x,y,z соответственно. Это не так, как это работает. Я бы посоветовал использовать другой конструктор, который принимает ось вращения и угол в качестве параметров.

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

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