2015-09-07 1 views
0

J'ai donc passé beaucoup de temps à essayer de travailler sur un système de détection de collision à partir de zéro pour mon propre moteur de jeu et je suis tombé sans résultat faute de temps. Finalement, j'ai décidé d'essayer d'utiliser Jbullet pour essayer de faire les choses plus rapidement. Maintenant, la documentation est fondamentalement inutile, et j'ai un peu de mal à essayer de transférer le code à java (ou ce que je transfère ne fonctionne pas). J'ai arraché mes cheveux en essayant de fouiller dans le code de la bibliothèque, mais le gain de temps que j'espérais a été presque inutile. Donc, je vais vous expliquer ce que je fais, peut-être que vous pouvez m'aider. Je cherche seulement la détection simple de collision, comme si vous frappiez quelque chose alors juste imprimez une ligne pour le moment. Le reste, je peux probablement travailler seul.Détection de collision java 3D avec Jbullet

Je crée mon monde:

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; 

J'ai donc ma classe d'entité et là j'ai une autre classe qui stocke toutes les informations de l'objet physique attaché à cette entité. Cela me permet de faire simplement:.. Entity.getPhysics() getCollisionObject()/setPosition() etc ...

Puis-je créer mon CollisionObject dans cette classe:

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; 

Je crois que ce convertit déjà rendu maillage, que j'utilise pour rendre mon entité, à partir de Vector3f de la bibliothèque LWJGL, et Jbullets Vector3f. Il crée ensuite un ConvexHullShape de ces sommets dans le maillage, et je crois que:

hull.buildHull(shape.getMargin()); 

est censé simplifier type de maillage (de la documentation). Ensuite, je viens de créer l'objet de collision. Assez simple, je pense ...

Je crée mon corps rigide (bien que je ne sois pas sûr d'avoir besoin d'un corps rigide ou juste un objet de collision, et si quelqu'un pouvait me faire savoir si cela est vrai, ce serait génial) :

//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); 

Puis je passe par ma boucle de jeu:

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); 

J'ai eu ce de quelqu'un ... j'ai oublié où bien. Donc, fondamentalement rien ne se passe ... Je ne suis pas sûr mais peut-être que je dois ajouter les objets à la variété, ou quelque chose comme ça. Je ne sais pas comment le faire. De l'aide?

EDIT: Ce que je l'ai fait est maintenant créer la forme de collision comme une boîte de taille aléatoire:

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

Puis je crée le fantôme du corps:

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); 

alors je fais comme vous avez dit, il ne revient toujours pas "frapper";

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

EDIT 2:

Je crée donc l'objet que comme dans ma classe d'entité:

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)); 
} 

et mettre à jour la position et d'autres choses:

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)); 
    } 

Okay c'est ma classe PhysicsEntity, où je l'ai mise en place:

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); 
    } 

Merci,

+0

J'ai encore modifié ma réponse. Jetez un coup d'oeil si cela vous aide. – Estiny

+0

Une clarification supplémentaire ajoutée. – Estiny

+0

Sooo ... Encore un edit. Peut-être cette fois. – Estiny

Répondre

1

Mon expérience avec Bullet est limitée à C++ mais peut-être je vais être en mesure d'aider. Que voulez-vous dire en disant que rien ne se passe? L'objet est-il correctement affecté par la gravité, mais aucun rappel de collision n'est appelé ou le problème est qu'il ne bouge pas du tout? Il ne bougera évidemment pas car sa masse est nulle donc il est statique. Un objet de masse 0 peut aussi être cinématique si vous appelez

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

Les deux objets statiques et cinématiques détectent les collisions, mais seulement avec des objets dynamiques (masse supérieure à 0). Je suggère d'utiliser une forme de collision simple pour commencer, comme une sphère. De cette façon, vous pouvez vérifier si la simulation fonctionne. Les coques convexes peuvent être difficiles. Commencez par quelque chose de simple pour produire un exemple de travail. Maintenant à propos de la méthode de détection de collision. Lorsque vous appelez dynamicsWorld.stepSimulation, toutes les forces sont appliquées et la détection et la résolution de collision se produisent. Donc juste après cela, vous pouvez parcourir PersistentManifolds comme vous le faites pour vérifier quels objets sont entrés en collision lors de cette étape de simulation. Maintenant, je ne suis pas sûr, mais quand vous appelez dynamicsWorld.performDiscreteCollisionDetection();, il est tout à fait possible qu'il n'y ait pas de collisions détectées parce qu'elles ont toutes été résolues.

Dans presque tous les cas standard, vous souhaitez utiliser RigidBody. Les exceptions sont les corps mous comme les vêtements et les objets fantômes qui peuvent être utilisés pour détecter des collisions sans aucune réaction.

EDIT.

Dans une situation où aucune collision n'est nécessaire, seulement une détection de coup, vous ne voulez pas RigidBody. Il peut être statique, dynamique ou cinématique, ce qui n'est pas votre cas. Au lieu de cela, vous voulez utiliser un GhostObject. Il détecte simplement les collisions mais ne réagit pas. Vous pouvez facilement vérifier si elle chevauche quelque chose en appelant d'abord getNumOverlappingObjects() puis getOverlappingObject(int index).

EDIT2.

Il semble que vous ayez créé l'objet correctement. En supposant que les transformations sont correctes et l'objet devrait vraiment chevaucher ce que vous pourriez manquer est dynamicsWorld.addCollisionObject(body); je l'ai manqué au premier coup d'oeil mais il semble que vous ne créez que l'objet mais ne l'ajoutez pas au monde alors Bullet engine n'est pas conscient de son existence.

EDIT3.

Ok, donc quelques autres suggestions juste pour s'assurer que la collision doit être détectée. Combien d'objets physiques (fantômes ou corps rigides) avez-vous créés et ajoutés au monde (en utilisant dynamicsWorld.add...)? S'il n'y en a qu'un, il est évident qu'aucune collision ne peut être détectée. Bullet n'entrera pas en collision de l'objet physique avec la géométrie de la scène, mais uniquement avec un autre objet physique. Pourriez-vous poster votre code, où vous créez et déplacez ces objets?

EDITn.

Vous avez donc posté les fonctions de création de PhysicsEntity mais je ne sais toujours pas combien d'entités créez-vous et avec quels paramètres. Il est nécessaire de vérifier quelles sont leurs coordonnées mondiales et de vérifier si elles devraient réellement entrer en collision.

Votre utilisation de Quaternion est un peu dérangeante. Vous passez probablement les arguments x, y, z comme rotation dans les axes x, y, z respectivement. Ce n'est pas comme ça que ça fonctionne. Je conseillerais d'utiliser l'autre constucteur, qui prend l'axe de rotation et l'angle comme paramètres. Parce que le code et le problème est très complexe et je ne peux pas voir la raison directe dans le code que vous avez posté, je conseillerais d'utiliser un débogueur et parcourir le code pour voir si tous les objets sont initialisés correctement , leurs positions sont comme prévu et enfin entrer dans le code de collision pour voir, pourquoi cela n'arrive pas.

+0

Donc, quand je dis que rien ne se passe, je veux dire qu'il ne renvoie pas hit. Je ne veux pas que les entités réagissent à être touché. Finalement, je le définirai de sorte que l'entité du joueur ne puisse pas traverser les murs/objet, etc. Je veux simplement que l'objet retourne "hit" s'il entre en contact. C'est pourquoi j'ai mis la masse à zéro. J'ai juste essayé de créer une boîte, mais cela n'a pas fonctionné, a également essayé de définir les drapeaux de collision, et l'état d'activation, toujours rien. Je ne veux pas que l'objet soit affecté par la gravité, donc il n'y a pas de gravité non plus. Fondamentalement, je vais définir la réaction moi-même. – thor625

+0

J'ai ajouté une modification à ma réponse, veuillez vérifier si c'est ce dont vous avez besoin. – Estiny

+0

Ok, donc je vais aussi éditer ma réponse, pour montrer ce que j'ai essayé – thor625