Improvement in performance for imported models(.3ds) for collision detection

Hi guys,



I tried to implement collision detection using TriangleCollisionResults as I did not require extra physics but simply wanted to not go through the wall. It worked well to a degree but still sometimes it does go through the wall. I would really like to know why does this happen?



private void findCollisions()
    {
        private TriangleCollisionResults results;

        results = new TriangleCollisionResults();
        results.clear();
        player1.findCollisions(scene, results);
                    
        if (results.getNumber() == 0)
        {
            //Do nothing
        }
        else
        {
            lastPosition = new Vector3f(player1.getLocalTranslation());
            float X = lastPosition.getX();
            float Y = lastPosition.getY();
            float Z = lastPosition.getZ();
           
            for (int i = 0; i < results.getNumber(); i++)
            {                               
                if (results.getCollisionData(i).getTargetTris().size() > 0)
                {                   
                    player1.setLocalTranslation(new Vector3f(X-2.5f, Y, Z-2.5f));
                }
            }
        }
    }



This code gives good performance(speed/framerate) with a simple box. However, I imported .3ds object and it slows everything down enormously i.e. the screen updates once only 15-20 seconds. Why does this happen and how can I change it to be as close as that for a box?

Many Thanks,

Regards,

Dev

Don't use triangle accuracy for collision detection/avoidance! That will require to iterate through each and every triangle in your model. Use bounding picking instead which should be as fast as the box, regardless of the mesh.

Hi duenez,



I have just tried BoudingCollisionResults and BoundingPickingResults and its efficiency is brilliant as you say. The problem I encounter is my terrain is imagebasedheightmap (a maze to be precise), which I would like to navigate with the box/.3ds file, but when I use BoundingCollisionResults the box is thrown right out of the maze - so if I am not understanding incorrectly, while the box is in the maze although it is not physically colliding with any walls the node of the box  is still colliding with the node of the terrain which is throwing it out right? I tried the following code:



BoundingPickingResults




       Ray ray = new Ray(cam.getLocation(), cam.getDirection());
       PickResults results = new BoundingPickResults();
       terrain.findPick(ray,results);
       
              
        if(results.getNumber()>0)
        {
            lastPosition = new Vector3f(player.getLocalTranslation());
            float X = lastPosition.getX();
            float Y = lastPosition.getY();
            float Z = lastPosition.getZ();
                             
            player.setLocalTranslation(new Vector3f(X-2.5f, Y, Z-2.5f));
       
        }



BoundingCollisionResults



BoundingCollisionResults results = new BoundingCollisionResults();
        results.clear();
        player.findCollisions(terrain, results);
       
              
        if (results.getNumber() > 1)
        {
            //Do nothing
        }
        else
        {
            lastPosition = new Vector3f(player.getLocalTranslation());
            float X = lastPosition.getX();
            float Y = lastPosition.getY();
            float Z = lastPosition.getZ();
           
            for (int i = 0; i < results.getNumber(); i++)
            {                               
                if (results.getCollisionData(i).getTargetTris().size() > 0)
                {                   
                    player.setLocalTranslation(new Vector3f(X-2.5f, Y, Z-2.5f));
                }
            }
        }



How do I get around this?

Regards,

Dev

Argh, in this case you probably want a TriMesh vs Box collision, and you might be better off doing it with physics (?). Now, since you mentioned that this is a maze, one workaround would be to implement the terrain as one object, and the walls as separate objects (each convex wall) and in this way, you would be able to detect collision with the individual walls and have them be bounding boxes which still keeps the efficiency.

I agree… Physics seems the only sane idea… But the root of all damn problems is that I am generating this 3D maze from 2D maze image (imagebasedheightmap) … The physics goes haywire when the box collides with the terrain - it flies away (I am using velocities so will need to change to addForce and will need just the right force - so completely rewriting handler after lot of experimenting). I am still not ruling out this option however it is better kept to last.



If I am understanding you correctly then you think the maze should be programmed by hand instead of imagebasedheightmap. This will allow me to have a nice looking terrain as a ground and boxes in rows and columns as wall right? Now here I can use BoundingCollisionResults and probably texturing will be far better than with imagebasedheightmaps!! Just one concern here though - because of large number of boxes will the framerate suffer and for creating walls that is the right way to go around it right?? I am really inclined at this idea and will start work on it this evening after lectures.



But in the mean time what I did was to use the method already provided: hasCollisions(…). This improved frame rate a bit and then I switched the .3d model from a really good one to an ok one which is relatively simple and that works ok. But one thing I still dont get it is even though the collisions are checked this thoroughly at traingular level why does the model still go through walls of the maze quite often?? Right now its 6.32 and I have lectures in over 7 hours so I am off and will get some sleep and resume this after lectures later!!




        if(player1.hasCollision(terrain, true))
        {
            Vector3f position = player1.getLocalTranslation();
            float X = position.getX();
            float Y = position.getY();
            float Z = position.getZ();
            player1.setLocalTranslation(X-2.5f, Y, Z-2.5f);
        }




Btw, you rock!!! Thanks a lot for all your help... I am not absolutely efficient(understatement I know  :D ) but am improving as I code more....

Dev

Good to hear it helped… What you need to do to keep the framerate up is to create a hierarchy of walls, (devided by quadrants, and each quadrant in a quadrant itself, and so on until you reach individual walls). This technique is called Quad-Tree for obvious reasons. With this your performance will decrease as the log of the number of walls, instead of linearly with the other straightforward approach of making every wall child of the root or terrain.



Implementing this should be easy enough and keep the performance in good levels.

Cheers mate!! I have been looking at boxes, quads and quad-trees and am doing a bit of reading and programming for all to find the best option… Just one final thing though… When I implemented hasCollisions(…) for imagebasedheightmap (both triangular and bounding collisions) on occasions the .3ds object would just go through the wall I thought it was because of imagebasedheightmap but it is the same for normal boxes… why is it so?? If you are detecting bounding or triangular collision for a wall 2f thick and quad you should not be just able to go through it?? I still dont get it why that occurs… is it a bug or am I doing something wrong? I mean it goes through it once and when I try go get back again it would detect collision… i.e. it will not detect while going through it but it will while trying to come back… this is the only thing messing things up - just dont get it??? To be even more precise - while going towards +ve Z the collision detection works while going towards -ve Z it doesnt!!



EDIT: Just finished the maze programmed by hand!! Absolutely sweet - not as flashy or as good as some of the work seen here but still looks good!! Did it with boxes - but still runs smooth… now I can apply good textures as well!! Just one problem still - the one mentioned above. I implemented collision detection both at bouding and triangular collisions level but it works while going one way but not another… I think it is a bug… Is anyone else aware of this???

Maybe something is updating the box's bounds when you enter the first time, and this is leading to the observed behavior… Are you calling updateModelBounds on everything before attempting to detect collisions? If everything seems correct, you could try to put up a minimal test case that exhibits the behavior, and we could have a look at it.

I think I got it! I put a System.out to see whether the collision was detected or not. The collision was detected! But the way I implemented it was subtracting x and z values when a collision occured. I mentioned earlier that the problem was in motion in -Z direction right! So when my object was in -Z direction and collision occured the value got subtracted from the -ve value. Hence the object continued to move forward and not backward! So just gonna change that implementation and that should fix it! Thanks man! Once this is sorted then shooting to implement and then I can introduce sound and a special effect or two! Then path-finding and AI. Rest of the project here I come!!!



Thank you for your help and I will look pass on my experience where I can. I know I am sucking up too much  XD but honestly this community is great… 8)



EDIT Jumped a bit ahead of myself! still seems to do the similar despite changing the code…  :(  Am looking at various options and will let you know with any updates


I figured out the problem and the solution! The fundamental problem with my last code was that I was getting the X and Z co-ordinates and depending on them being positive and negative adding and subtracting the corresponding float values… I needed to find the direction

So after working and rethinking a lot I designed a solution which was obvious to a lot of people - storing the value before collision and comparing its x and z co-ordinates(as my motion is in x and z directions) to current motion and then adding or subtracting the values to x and z accordingly depending on + and - x and z motion. Also, I implemented it well this time so it works!!! Finally!!    :lol:



Thank once more(adding to the 99 times I have already mentioned  :D)

Don't use triangle accuracy for collision detection/avoidance! That will require to iterate through each and every triangle in your model. Use bounding picking instead which should be as fast as the box, regardless of the mesh.


i'm using triangle accurate collision checking for moving object (box, 12 triangles) <-> non-terrain world (many triangles) collision handling, and it's fast enough. i have no idea how i should handle these collisions properly without per-triangle accuracity. i need to know where the triangles an actor is touching are facing to to:
+ determine where "up" is when the player jumps. when i'm standing on a 45

I know you are looking for a reply for duenez but while he warms up I'll just get the ball rollin  :wink:


i'm using triangle accurate collision checking for moving object (box, 12 triangles) <-> non-terrain world (many triangles) collision handling, and it's fast enough.


My performance was slowing down as I was importing a .3ds object over 400-500Kbs which was very complex so when it was colliding with walls(large non-terrain - imagebasedheightmap using TriangleCollision) it was really slow! But your performance is fast enough so dont know why you want to fix something that works!

It might be possible to design the solution to your problem as follows:

First of all as long as your non-terrain is not an imagebasedheightmap and if it is made up of boxes or quads you can detect collision using the bounding of the two objects - which is what I am doing now.

+determine where "up" is when the player jumps. when i'm standing on a 45
HamsterofDeath said:

i'm using triangle accurate collision checking for moving object (box, 12 triangles) <-> non-terrain world (many triangles) collision handling, and it's fast enough.


My main point was that you should not use it if you will always have a collision to a high-poly model (like the terrain) and each frame you need to figure out its collision point with triangle accuracy.

Regarding your problems:

* Terrain slope is easy to calculate with the normal to the triangle you are in, and you can figure that one out with terrain page, and there is no need for triangle accuracy.
* Wall jumping, as long as it is always completely vertical is basically the same as before, and you could make it with a bounding box.

Hey,



Although the implemented collision detection works it just does not feel that smooth. I have implemented it as below but is there any other way I can improve its performance, make it more smooth or effective?? (except resorting to physics?) Is the concept below correct or generally it is done in some different way??



private void findCollisions()
    {
        //Expand the collision detection to be even more precise
        //e.g. say movement in only one direction
        BoundingCollisionResults results = new BoundingCollisionResults();
        results.clear();
        player1.findCollisions(walls, results);
       
       
        if(results.getNumber()==0)
        {
            lastPosition = new Vector3f(player1.getLocalTranslation());
            //System.out.println(lastPosition);
        }
       
        else
        {
            Vector3f position = player1.getLocalTranslation();
            float X = position.getX();
            float Y = position.getY();
            float Z = position.getZ();
           
            if(player1.getLocalTranslation().getX() > lastPosition.getX() && player1.getLocalTranslation().getZ() == lastPosition.getZ())
            {
                player1.setLocalTranslation(X-2.55f, Y, Z);
                System.out.println("Collision Detected at +X: " + player1.getLocalTranslation());
            }
           
            if(player1.getLocalTranslation().getX() < lastPosition.getX() && player1.getLocalTranslation().getZ() == lastPosition.getZ())
            {
                player1.setLocalTranslation(X+2.55f, Y, Z);
                System.out.println("Collision Detected at -X: " + player1.getLocalTranslation());
            }
           
            if(player1.getLocalTranslation().getX() == lastPosition.getX() && player1.getLocalTranslation().getZ() > lastPosition.getZ())
            {
                player1.setLocalTranslation(X, Y, Z-2.55f);
                System.out.println("Collision Detected at +Z: " + player1.getLocalTranslation());
            }
           
            if(player1.getLocalTranslation().getX() == lastPosition.getX() && player1.getLocalTranslation().getZ() < lastPosition.getZ())
            {
                player1.setLocalTranslation(X, Y, Z+2.55f);
                System.out.println("Collision Detected at -Z: " + player1.getLocalTranslation());
            }
                      
            if(player1.getLocalTranslation().getX() > lastPosition.getX() && player1.getLocalTranslation().getZ() > lastPosition.getZ())
            {
                player1.setLocalTranslation(X-2.55f, Y, Z-2.55f);
                System.out.println("Collision Detected at +X and +Z: " + player1.getLocalTranslation());
            }
           
            else if(player1.getLocalTranslation().getX() > lastPosition.getX() && player1.getLocalTranslation().getZ() < lastPosition.getZ())
            {
                player1.setLocalTranslation(X-2.55f, Y, Z+2.55f);
                System.out.println("Collision Detected at +X and -Z: " + player1.getLocalTranslation());
            }
           
            else if(player1.getLocalTranslation().getX() < lastPosition.getX() && player1.getLocalTranslation().getZ() > lastPosition.getZ())
            {
                player1.setLocalTranslation(X+2.55f, Y, Z-2.55f);
                System.out.println("Collision Detected at -X and +Z: " + player1.getLocalTranslation());
            }
           
            else if(player1.getLocalTranslation().getX() < lastPosition.getX() && player1.getLocalTranslation().getZ() < lastPosition.getZ())
            {
                player1.setLocalTranslation(X+2.55f, Y, Z+2.55f);
                System.out.println("Collision Detected at -X and -Z: " + player1.getLocalTranslation());
            }       
       
        }   
       
       
    }



Regards,

Dev

I don't quite understand what is it that you want to achieve with this. Smooth as in jerky? (i.e. it finds a collision and the character jumps back to a safe position) Well, it is not going to be smooth if you use a constant offset (2.55) on your coordinates. If everything is a box, and is axis aligned, then you can safely use the previous position's component (x, y or z) as the update value.



On the other hand, I would try to figure out some thing more along the lines of finding which object you collided with, and apply a offset proportional to the amount of violation of the coordinates of your character (walls acting like padded surfaces) if what you want is the smooth type of navigation on FPS for instance.



Unfortunately, simply knowing which direction you were moving when you collided does not give you a direction to smoothly correct your position.  ://

Its just that in this collision detection if the value is not 2.55(e.g. smaller like 0.55, 1, 1.55, etc) then it crashes sometimes - i.e. if I go into the wall it keeps buzzing and I have to use different direction keys to try and get it out and then it works. It is not ideal in a game to have this bug from the playing side but also if AI gets stuck then its finished. Also, 2.55 is such a big distance that I cannot make AI sneak or do cool things as if it collides then it will have to recalculate its path and what its doing and so on and so forth…



I just tried updating it with lastposition(e.g. player1.getLocalTranslation.set(lastPosition)) and it works just as I want(nice and smooth) but to a degree - when I go into the walls and try and come out it sticks a bit - like a tape or when you apply your glue to your finger and touch table and then try to take if off the table…(weird examples I know  :slight_smile: ) and if I keep pressing towards the wall for couple of seconds then it does not come out at all - I can rotate it but no horizontal movements… Setting it to last position is perfect but how do I iron out these small bugs?? So close yet so far…  :frowning:



EDIT



[figured it out - just have to set the velocity to zero - the thing happening here is the position is being reset but it still possesses the velocity and so it tries to keep going into the wall. The key is on collision set the velocity to zero - I will try and do it through handlers and setting the the handler velocity to 0 as follows:



private float velocity;



if(player.hasCollision(walls, false))

        {

            velocity = 0f;

            KeyNodeForwardAction forward = new KeyNodeForwardAction(node, velocity);

            addAction(forward, "forward", true);

        }

       

        else

        {

            velocity = 22f;

            KeyNodeForwardAction forward = new KeyNodeForwardAction(node, velocity);

            addAction(forward, "forward", true);

        }



This is the basic idea and work in progress so no way complete or accurate as it does not work so far but will get it fixed!! And also give physics a go now again… if it works well and good, if it doesnt then it doesnt… Thanks!