Обнаружение 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);
    }

Спасибо,


person thor625    schedule 07.09.2015    source источник
comment
Я снова отредактировал свой ответ. Посмотрите, если это поможет вам.   -  person Estiny    schedule 09.09.2015
comment
Добавлено еще одно уточнение.   -  person Estiny    schedule 09.09.2015
comment
Тааак... Еще одно редактирование. Может быть, на этот раз.   -  person Estiny    schedule 09.09.2015


Ответы (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).

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

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

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

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

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

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

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

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

person Estiny    schedule 08.09.2015
comment
Поэтому я, когда говорю, что ничего не происходит, я имею в виду, что он не возвращает удар. Однако я не хочу, чтобы сущности реагировали на удары. В конце концов я установлю его так, чтобы сущность игрока не могла пройти сквозь стены/объект и т. д. Я просто хочу, чтобы объект возвращал удар, если он вступает в контакт. Вот почему я приравнял массу к нулю. Я только что попытался создать ящик, но это не сработало, также попытался установить флаги столкновений и состояние активации, но все равно ничего. Однако я не хочу, чтобы на объект влияла гравитация, поэтому гравитации тоже нет. В основном я сам задаю реакцию. - person thor625; 09.09.2015
comment
Я добавил правку в свой ответ, пожалуйста, проверьте, нужно ли вам это. - person Estiny; 09.09.2015
comment
Хорошо, я также отредактирую свой ответ, чтобы показать, что я пытался - person thor625; 09.09.2015
comment
Ну, я чувствую себя немного глупо, да, не было этого, но это все равно не сработало. - person thor625; 09.09.2015
comment
Хорошо, я кажется знаю, что не так, по какой-то причине, когда я отлаживаю свой код, я делаю проверку, для какой модели я проверяю положение и модель каждого physicsEntity, и почему-то они выходят одинаковыми. Это странно... но я посмотрю на это. И способ, которым я выполнял вращение, был через vector3f, так что я изменю это позже, но вращение не так важно прямо сейчас. - person thor625; 10.09.2015
comment
На самом деле это очень странно, я создаю каждую отдельно, но каждая вычисляется одинаково... Не знаю, как это возможно... но теперь, когда я знаю проблему, мне просто нужно ее исправить. - person thor625; 10.09.2015