Game Development Community

dev|Pro Game Development Curriculum

Faster Polysoup

by Erik Madison · 04/21/2008 (9:24 am) · 6 comments

Inspired by NeverWinterNights manner of polysoup, I added optional WalkMeshs. Some dts models are simply too complex to efficiently handle polysoup collisions, especially where a player may attempt to walk. Consider a swinging rope bridge, made up of dozens of rotting boards strung between numerous ropes. Although my testing worked, I found myself getting stuck quite often, as there were simply too many crevices etc to check against.
So, I wrapped the entire structure in a much simpler mesh that still followed the exact shape. Much like the old style Col-1 meshes, except now you're not limited to any silly rules.
A few minor code changes do the job...

First, we won't render any meshes named WalkMesh.
tsShapeInstance.cpp
about line 403. NOTE: I changed the step variable from i to x, to avoid italized viewing of code
for (i=start; i<end; i++)
   {
      smRenderData.currentObjectInstance = &mMeshObjects[x];
      // following line is handy for debugging, to see what part of the shape that it is rendering
		// Opcode change by Fafhrd
      const char *name = mShape->names[mMeshObjects[x].object->nameIndex];
      if (dStrstr(name, "WalkMesh"))
		   continue;
      mMeshObjects[x].render(od,mMaterialList);
   }

Now, upon loading, we'll check if we have a named WalkMesh (and we're using polysoup). If we do,
that's the only mesh we'll prepCollision on. Otherwise, we'll prep the entire model.
tsShapeInstance.cpp
about line 1054, replace entire function
void TSShapeInstance::prepCollision()
{
   // Iterate over all our meshes and call prepCollision on them...
	// Changed by Fafhrd;
	// Loop twice to see if any of the meshes are named WalkMesh. If so, that's the only
	// mesh we will apply opCode too. We're only doing this once at load, so 2 runs is
	// fine.
	bool hasWalkMesh = false;

	for(S32 i=0; i<hShape->meshes.size(); i++)
	{
      if(hShape->meshes[i])
      {
		   S32 nameIndex = hShape->objects[i].nameIndex;
		   const char * meshName = "";
		   if (nameIndex>=0)
		   {
		   	meshName = hShape->getName(nameIndex);
		   	if (dStrstr(meshName, "WalkMesh"))
               hasWalkMesh = true;
		   }
	   }
   }
	for(S32 i=0; i<hShape->meshes.size(); i++)
	{
      if(hShape->meshes[i])
      {
		   S32 nameIndex = hShape->objects[i].nameIndex;
		   const char * meshName = "";
		   if (nameIndex>=0)
		   {
		   	meshName = hShape->getName(nameIndex);
		   	if ((hasWalkMesh && (dStrstr(meshName, "WalkMesh"))) || !hasWalkMesh)
                  hShape->meshes[i]->prepOpcodeCollision();
		   }
	   }
   }
}

Thats it. All done.

#1
04/21/2008 (10:28 am)
Now this is damn handy. thanks a bunch!
#2
04/21/2008 (11:50 pm)
The solution I have for this is to use the collision mesh in the DTS for polysoup if they exist or the whole mesh if there are none defined. They just don't need to be convex any more. The code for this is on the original polysoup post.

www.garagegames.com/blogs/8863/11953
#3
04/23/2008 (1:12 pm)
By using the Col-x system, you lose the ability for your dts to be a non-tsstatic. There are occasions when one model may be used for both a static and a datablocked model. Running them this way, you have the best of both worlds.
An additional plus; As the walkmesh is a true mesh, simply skipping the rendering of, you can assign materials to it. Add a little Tom Spilman raycasting magic to your code, and your bullet holes, sounds, etc will be much more meaningful and realistic.
#4
04/23/2008 (7:26 pm)
Interesting. I can see how having material info for raycasting could be handy. I didn't think polysoup would be much use on animated meshes because of the lack of penetration resolution. I thought that was why Ben only implemented it on TSStatics. Have you implemented it for ShapeBase objects, If so does it work ok.
#5
04/24/2008 (2:11 pm)
I haven't... yet. Currently, we're colliding an antique (bounding box) against a dedicated collision library (opCode), so I would expect a few troubles if I push it too hard. I'd like to update a few other stock situations first, and then toss everything at opCode/ICE.
I have however just about given up on dif. My entire level is dts now, and runs much much faster. I did do some crudimentary culling which helps quite a bit...
#6
04/27/2008 (5:22 pm)
The collision system is the same for ShapeBase based classes and TSStatics they both use the features of the underlying DTS classes for collecting physics information. So my approach would work just as well for animated objects thats not the problem your going to have. The problem is you need to use something like GIMPACT from the ODE code base to generate escape vectors and forces to resolve objects when they penetrate each other rather than just get stuck. When ODE has solved all of the bugs in its collision code using OPCODE then rewriting TGE OPCODE and collision code on top of ODE primitives may be the best way forward. As it stands ODEs collision code still needs work so as far as I know there are no open source implementations of GIMPACT and OPCODE. Haven't really looked though.