Collision Normal with Orthogonal Bounding Boxes

Hi, I've asked this question before but I thought I'd re-ask it in the physics section.



Does anyone know of anyway to detect the correct collision normal between two objects with orthogonal bounding boxes?



By correct collision normal I mean the collision normal between the two objects in the x and y planes.  The problem is that my current technique for finding the collision normal (which works fine when everything is not orthogonal) just returns the z axis as the collision normal between objects with orthogonal bounding boxes.



If anyone can give me advice on finding a possible solution it would be greatly appreciated.

Thanks.

Since bounding boxes do not rotate its hard to get it from the BoundingVolume. If you take the center of each object and the collision location you should be able to compute the collision normal from that or do I get you wrong?

No, you've got it right.  I actually have an idea similar to your suggestion as a temporary fix.  I actually don't use the bounding boxes for the collision calculations, sorry it was a bit misleading to go on about them.  I was just trying to make clear that I was using orthogonal queueing for the node renderer.  Anyway this is my code as it looks at the moment:


   for (int j=0; j < results.getNumber(); j++){
            CollisionData collisionData = results.getCollisionData(j);
         for(int k =0; k < collisionData.getTargetTris().size(); k++){
                TriMesh geom =(TriMesh)collisionData.getTargetMesh();
                int triIndex=collisionData.getTargetTris().get(k);
                int[]vertices=new int[3];
                geom.getTriangle(triIndex, vertices);
                FloatBuffer normalBuffer=geom.getWorldNormals(null);
                normalVector = new Vector3f(normalBuffer.get((vertices[0]*3)), normalBuffer.get((vertices[0]*3)+1), 0);
                if (normalBuffer.get((vertices[0]*3)+2) > 0 && !s.getName().contains("border")){

                   //Needs a proper solution
                   normalVector.setX(targetSpatial.getLocalTranslation().x - geom.getLocalTranslation().x);
                   normalVector.setY(targetSpatial.getLocalTranslation().y - geom.getLocalTranslation().y);

                   normalVector.normalizeLocal();

                }

            }
        }
      return normalVector;
   }



Thanks for you speedy response.

Forgot to mention that the reason that I see this as a temporary solution is that I have a lot of irregular shapes where some faces may not have normals facing out from the centre of the objects.  I'm currently looking at seeing if I can get information on the faces involved in the collisions and using either their normals or locations to calculate a collision normal.

I see, I dont know if theres built-in support to get that info in jme, since its more for checking overlapping than collision I suppose. Bullet physics for example reports the normals on each collision.

Will bullet physics work with orthogonal objects then?

Is there anywhere that I can find a clear example of the use of it?

I dont exactly know what you mean by "orthogonal". Orthogonal to the world (like BoundingVolumes) or just in themselves (like boxes)? jbullet-jme can report the normal of the collision of two boxes.

There is no real example code for this, but in the PhysicsCar demo there is some code to get the collisions. Basically you implement a CollisionListener Interface, register with the PhysicsSpace and then call getNormalWorldOnB() on the event you want the normal from.



http://code.google.com/p/jbullet-jme/source/browse/trunk/jbullet-jme/src/jmetest/jbullet/TestSimplePhysicsCar.java

Thanks, I'll look at that example and try implementing jbullet and post my results.



By orthogonal I mean attached to a node which has an orthogonal bounding box set as its model bound.  The items all use orthogonal bounding boxes as well.  It may be possible that some of the items are orthogonal as well.



Does anyone know anyway to clone or copy spatial objects?

I was thinking I could clone the items, attach them to a non-orthogonal node, set them to have the same z-location value and then use my current collision detection calculation there.

Ok, I managed to solve it by creating triangles that reached into the x axis for each edge of the geometry in the collision then used rays to detect where the closest intersection happened.  Its a bit expensive but it gives me the results I wanted.  Here's the code for anyone interested:


private Vector3f getCollisionNormal(Spatial s) {
      
        Vector3f normalVector = new Vector3f();
        CollisionResults results = new TriangleCollisionResults();
        targetSpatial.findCollisions(s, results);
        for (int j=0; j < results.getNumber(); j++){
           CollisionData collisionData = results.getCollisionData(j);
            for(int k =0; k < collisionData.getSourceTris().size(); k++){
              TriMesh geom =(TriMesh)collisionData.getTargetMesh();
              TriMesh geomTwo =(TriMesh)collisionData.getSourceMesh();
              int triIndex=collisionData.getSourceTris().get(k);
              int[]vertices=new int[3];
              geom.getTriangle(triIndex, vertices);
              FloatBuffer normalBuffer=geom.getWorldNormals(null);
              normalVector = new Vector3f(normalBuffer.get((vertices[0]*3)), normalBuffer.get((vertices[0]*3)+1), 0);
              if (normalBuffer.get((vertices[0]*3)+2) > 0 && !s.getName().contains("border")){
                    
                   FloatBuffer coordBuffer=geom.getWorldCoords(null);
                 
                   ArrayList<Vector3f> coords = new ArrayList<Vector3f>();
                 
                   for (int i = 0; i < coordBuffer.limit(); i += 3){
                       coords.add(new Vector3f(coordBuffer.get(i), coordBuffer.get(i+1), 0));
                   }
                  
                   FloatBuffer coordBufferTwo=geomTwo.getWorldCoords(null);
                    
                   ArrayList<Vector3f> coordsTwo = new ArrayList<Vector3f>();
                 
                   for (int i = 0; i < coordBufferTwo.limit(); i += 3){
                      coordsTwo.add(new Vector3f(coordBufferTwo.get(i), coordBufferTwo.get(i+1), 0));
                   }
                  
                   float distance = 0;
                   boolean first = true;
                  
                   Vector3f face = null;
                   Vector3f collisionPosition = null;
                  
                   ArrayList<Triangle> triangles = new ArrayList<Triangle>();
                  
                   for (int i = 0; i < coords.size()-1; i++){                     
                      for (int h = i+1; h < coords.size(); h++){
                         
                         Vector3f halfway = new Vector3f(coords.get(h).x - coords.get(i).x,coords.get(h).y - coords.get(i).y,1);
                         
                         Triangle t = new Triangle(coords.get(i), coords.get(h), halfway);                      
                         triangles.add(t);
                      }
                   }
                  
                   Vector3f reverse = new Vector3f(-linearVelocity.x, -linearVelocity.y, 0);
                  
                   for (int i = 0; i < coordsTwo.size()*2; i++){                         
                      Vector3f direction = linearVelocity;
                      Vector3f coord = new Vector3f();
                      
                      if (i >= coordsTwo.size()){
                         direction = reverse;
                         coord = coordsTwo.get(i - coordsTwo.size());
                      }else{
                         coord = coordsTwo.get(i);
                      }
                      
                      Ray ray = new Ray(coord, direction);
                      for (int h = 0; h < triangles.size(); h++){   
                         
                         Vector3f loc = new Vector3f();                  
                         
                         if (ray.intersectWhere(triangles.get(h), loc)){ 
                            if (first){                              
                               face = new Vector3f();
                                face.setX(triangles.get(h).get(1).x - triangles.get(h).get(0).x);
                                face.setY(triangles.get(h).get(1).y - triangles.get(h).get(0).y);
                                collisionPosition = loc;
                               
                               distance = targetSpatial.getWorldTranslation().distance(loc);
                               first = false;
                            }else{
                               if (targetSpatial.getWorldTranslation().distance(loc) < distance){
                                  distance = targetSpatial.getWorldTranslation().distance(loc);
                                  face = new Vector3f();
                                   face.setX(triangles.get(h).get(1).x - triangles.get(h).get(0).x);
                                   face.setY(triangles.get(h).get(1).y - triangles.get(h).get(0).y);
                                   collisionPosition = loc;
                               }
                            }
                         }
                      }
                   }                   
                                    
                   if (face != null && collisionPosition != null){    
                  
                      Vector3f possNormOne = new Vector3f(face.y, -face.x, 0);
                      Vector3f possNormTwo = new Vector3f(-face.y, face.x, 0);
                      
                      Vector3f posOne = new Vector3f(collisionPosition.x + possNormOne.x, collisionPosition.y + possNormOne.y,0);
                      Vector3f posTwo = new Vector3f(collisionPosition.x + possNormTwo.x, collisionPosition.y + possNormTwo.y,0);
                      
                      if (posOne.distance(targetSpatial.getWorldTranslation()) < posTwo.distance(targetSpatial.getWorldTranslation())){                         
                         normalVector = possNormOne;
                      }else{                         
                         normalVector = possNormTwo;
                      }
   
                   }
              
                 

                   normalVector.normalizeLocal();         
              }

            }
        }
        return normalVector;
   }



Linear velocity refers to the initial vector the moving object was traveling in before the collision.