Collision Traversers

OK, I have a bunch of bullets flying around. I’m using CollisionSegments for each bullet, so the length of the segment needs to be adjusted based on dt since last frame and bullet velocity.

If I create a single traverser to handle all the bullets, I will be limited to 32 bullets in flight, right?

So, is it reasonable to create a traverser for each bullet (bullets are stored in a list, so I would iterate through the list calling all the traversers), or would there be a significant performance hit for doing it this way?

A long long time ago, CollisionTraversers were limited to 32 objects each. Nowadays, they can handle any number of objects; they just handle them internally 32 at a time.

Using one CollisionTraverser per object is a bad idea. You will certainly lose a lot of optimization that way. I recommend just shoving them all in one traverser.

David

OK, thanks.

I tried both ways and after some very rough testing in one particular environment there doesn’t seem to be much difference. But since it’s no more difficult to implement I will go with just one collision traverser as you suggest.

I put the projectiles and traverser in a ProjectileManager class so that I can update the CollisionSegments each frame before checking for collisions.

In an environment with a pretty large geomip terrain and a few teapots I get pretty good framerates with several hundred projectiles in flight… as long as I don’t fire close to a teapot. Exactly how close seems to vary quite a bit, but the projectiles don’t even have to pass through the teapot’s bounding volume! (I have turned on bounding volumes and show collision solids to be sure I haven’t screwed up somehow) If I get close to a teapot the framerate drops below 1fps.

Now the teapots probably have a few more polys than the terrain, and maybe the terrain is better optomised for collisions, but this doesn’t seem to make much sense. Especially since the bounding volume check should fail anyway.

So what am I missing? or is this normal?

If it helps, here’s the update function for the projectile manager. It’s just some pretty rough prototype code at the moment. plist is a dictionary indexed by the actor nodepath and holds the CollisionSegment and the previous position to make updating easier.

def update(self):  
        # update collision geometry
        for p in self.plist.keys():
            ray = self.plist[p][0]
            if self.plist[p][1]!=None:
                ray.setPointA(p.getRelativePoint(render,self.plist[p][1]))
            else:
                ray.setPointA(0,0.001,0)
           
            prev = p.getPos(render)
            self.plist[p][1] = prev
        
        # handle projectile collisions 
        self.pTrav.traverse(render)
        entries = []
        for i in range(self.projectileHandler.getNumEntries()):
            entry = self.projectileHandler.getEntry(i)
            entries.append(entry)
            
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        
        for e in entries:
            np = e.getFromNodePath().getParent()
            self.kill(np)

OK, so first, whenever you enable collisions with normal geometry (such as a teapot) instead of special collision geometry, it is automatically much more expensive, like a hundred times more expensive, to perform the collision test. So you should avoid this anytime you are concerned about performance.

Second, as to the reason the collision gets expensive whenever you get near the teapots, well, it’s not just a question of the collision ray itself intersecting the teapot’s bounding volume–it’s a question of the collision ray’s bounding volume intersecting the teapot’s bounding volume. Once the bounding volumes intersect, then the full collision traversal is performed. The bounding volume of a collision segment is a sphere.

David

Yes, I realise that testing collisions with a mesh is much more expensive. But I still don’t understand why the collision checks with the teapot are 100 times more expensive than the collision test with the terrain? Is the geomip terrain mesh really that much more optomised for collisions?

[EDIT] Deleted paragraph about CollisionSegment BV. The BV of the CollisionSegment is updating correctly.

There are two reasons that collisions with renderable geometry are w-a-a-a-y more expensive that collisions with CollisionSolids (which are not to be confused with the GeoMipTerrain, a specialized geometry for terrain).

First, polygon-for-polygon, the codepath for detecting a collision against a visible triangle really is much more expensive than the codepath for detecting a collision against a CollisionPolygon. Partly this is because the CollisionPolygon can store its vertices in a way that makes it easy to compute the collision, but mainly this is because the codepath against a visible triangle is horribly inefficient. It could be rewritten to make it much faster. But we never bothered, because it would still be hundreds or even thousands of times slower to detect collisions against visible geometry, because of the second reason, which is this:

In general, models need w-a-a-a-y more polygons for visible rendering than they do for accurate collisions. The teapot model, for instance, contains 2256 triangles. That means 2,256 triangle intersection tests need to be performed when your segment comes close to the teapot. On the other hand, I bet you could construct a decent teapot model for collisions that requires only about 20 or 25 CollisionPolygons, which would perform 100 times faster, even if the visible triangles were just as fast as CollisionPolygons. But you could do even better: a teapot is very nearly a sphere, so why not just put a CollisionSphere where the teapot is? That would be only 1 primitive, which would be roughly 2,256 times faster to test against than all of the triangles in the teapot–even if the codepath for visible triangles were just as fast as that for collision solids, which it isn’t.

But you can see why we never bothered to write the many lines of code it would take to make collisions with visible triangles as fast as collision solids. It really wouldn’t help the fundamental issue, which is that models for looks and models for collisions are two completely different things.

David

I think I am not making myself clear.

I know that checking for collisions against a mesh is slow.

What I wanted to know is why checking collisions against GeoMipTerrain is so much faster. Anyway, after doing some more testing I’m guessing that it’s because GeoMipTerrain breaks the mesh up into chunks with relatively few polys and has a BV for each chunk.

Thanks for your help.

Yes, that’s one other advantage of the GeoMipTerrain: because it breaks up the terrain in small blocks, collision tests are faster since they are only performed on the block where the colliding objects are.
However, I still do not recommend colliding directly with the terrain. In most cases, for example if you want to keep your avatar’s z aligned on the terrain, you can use the getElevation call to determine the Z of the terrain at a given position.
There are a few cases where it’s inevitable, though. I might once also make a specialized collision solid for heightfields. (like ODE has.)