PhysX Implementation Questions
by Ronald J Nelson · in Torque Game Engine Advanced · 10/19/2008 (11:03 pm) · 66 replies
I have implemented PhysX into my code. With that I have some questions about some things since I have noticed no one has been updating the stuff on TDN.
1. Has anyone gotten it to work with Polysoup, since Polysoup is stock with TGEA 1.7.1 I figured someone might have by now.
2. Has anyone gotten vehicle collisions to work properly with it yet?
3. Has anyone gotten a working example of using links that they are willing to share?
Thanks in advance.
1. Has anyone gotten it to work with Polysoup, since Polysoup is stock with TGEA 1.7.1 I figured someone might have by now.
2. Has anyone gotten vehicle collisions to work properly with it yet?
3. Has anyone gotten a working example of using links that they are willing to share?
Thanks in advance.
#2
10/21/2008 (1:57 pm)
Something to keep in mind; Polysoup is using opCode, which is used with(designed for?) ODE. While ODE may not be the best physics solution, it is quite capable for games. Having Polysoup already in the base gives you a good 30-40% headstart on integrating the rest.
#3
Additionally, PhysX uses cooked meshes huh? Has anyone gotten those to work with Torque already?
10/21/2008 (2:15 pm)
Well this is very enlightening, and to be honest I should have already considered it since I have worked quite a bit with ODE, and polysoup. So what you are saying is polysoup and PhysX are not compatible due to the use of different collision libraries.Additionally, PhysX uses cooked meshes huh? Has anyone gotten those to work with Torque already?
#4
Also, yep, we got cooked meshes working in BeTheDinosaur here at Sickhead Games. It's really not too difficult. The PhysX examples are pretty much all you need to get started.
10/21/2008 (3:04 pm)
@Ron, well, what I was saying is that opcode/polysoup and PhysX's TriangleMeshes merely serve the same purpose.Also, yep, we got cooked meshes working in BeTheDinosaur here at Sickhead Games. It's really not too difficult. The PhysX examples are pretty much all you need to get started.
#5
I was never that attached to Polysoup anyway. The only reason I added it to my code base because I wanted material detection on DTS objects, I figured out how to do that without polysoup so it really doesn't offer me that much anymore in terms of what I need.
Ross, any chance you guys will be sharing that code you did to get Cooked in meshes working?
I do have one final question, where does the PhysX object update its working collision set? I wanted to integrate terrain deformation with it.
10/21/2008 (4:19 pm)
Well to be honest in terms of the vehicle portion of my question the only thing I wanted to get it to do is register collisions between a moving PhysX object and a non-moving vehicle. Right now it just passes through.I was never that attached to Polysoup anyway. The only reason I added it to my code base because I wanted material detection on DTS objects, I figured out how to do that without polysoup so it really doesn't offer me that much anymore in terms of what I need.
Ross, any chance you guys will be sharing that code you did to get Cooked in meshes working?
I do have one final question, where does the PhysX object update its working collision set? I wanted to integrate terrain deformation with it.
#6
I don't know that we'll be releasing that stuff, but I can give you some simple pointers on how to do it. You'll want to go look at the "usePolysoup" flag in TSStatic. Basically all you do is the same bits of code it does there (looping through the mesh and grapping verts, which you pass off to PhysX and tell it to cook). All you really have to do is pretty much the same exact code as in there, except you need to set up the PhysX cooking lib into your project and create the cooking object or whatever (I can't recall exactly what it is, but PhysX has good docs on it). You simply pass it the list of verts and it gives you back whatever type of shape you called to have it cook (TriangleShape, Convex etc.).
Deformable terrain is a little harder, I don't have a good solution for you there. We never got that working, though you could probably do something to update only a certain portion of a PhysXHeightfield(forget the real class name, probably NxHeightfield).
10/21/2008 (4:54 pm)
@Ron, when you say a non-moving vehicle, what sort of collision representation do you have on it? If you want it to just be static, then create it as a (um...I can't recall what the PhysX type is called, but it's just a static convex mesh).I don't know that we'll be releasing that stuff, but I can give you some simple pointers on how to do it. You'll want to go look at the "usePolysoup" flag in TSStatic. Basically all you do is the same bits of code it does there (looping through the mesh and grapping verts, which you pass off to PhysX and tell it to cook). All you really have to do is pretty much the same exact code as in there, except you need to set up the PhysX cooking lib into your project and create the cooking object or whatever (I can't recall exactly what it is, but PhysX has good docs on it). You simply pass it the list of verts and it gives you back whatever type of shape you called to have it cook (TriangleShape, Convex etc.).
Deformable terrain is a little harder, I don't have a good solution for you there. We never got that working, though you could probably do something to update only a certain portion of a PhysXHeightfield(forget the real class name, probably NxHeightfield).
#7
As for your additional information, that is very interesting. So basically I am doing a conversion of the same code I added for Polysoup into its equivalent or similar cooking versions.
If what you are telling me is true about the deformation, if you add PhysX Actor then enter the Terrain Editor and adjust the terrain height the PhysX object is not going to see the change.
10/21/2008 (7:21 pm)
Ross I mean the stock vehicle class. If my wheeled vehicle is going too slow it doesn't register collisions with PhysX Actors. If the vehicle is just sitting there and say a PhysX boulder from the resource rolls into it, it will pass right through it. This essentially means that the vehicle is processing the collision if the vehicle's velocity is high enough to trigger its collision detection routines, however the PhysX Actor is not processing the vehicle collision in any other way than the use of its impulse functions being initiated from the vehicle code.As for your additional information, that is very interesting. So basically I am doing a conversion of the same code I added for Polysoup into its equivalent or similar cooking versions.
If what you are telling me is true about the deformation, if you add PhysX Actor then enter the Terrain Editor and adjust the terrain height the PhysX object is not going to see the change.
#8
Re: Terrain changes, yes basically you'd need to set up something custom. I've seen videos of it on Vimeo so it definitely is possible, so you might ask around on the nVidia PhysX forums.
10/21/2008 (11:30 pm)
Er...That just won't work :) The stock Torque vehicle won't have any collision in PhysX, which is why all your PhysX actors will go through it. You need to set up some sort of custom PhysX actors to represent your vehicle in the PhysX simulation. I suggest looking at hooking up the PhysX Remote Debugger, it will allow you to more easily figure out what's going on in the simulation.Re: Terrain changes, yes basically you'd need to set up something custom. I've seen videos of it on Vimeo so it definitely is possible, so you might ask around on the nVidia PhysX forums.
#9
When you say I have to represent my vehicle with PhysX Actors I am a little confused as the player character seems to have totally working collisions even if they aren't moving. Can you explain to me why that is?
10/22/2008 (5:27 pm)
Thanks Ross I confirmed that in the editor that PhysX object do not update when you change the terrain around them. It wasn't a huge deal to me, but it would have been nice.When you say I have to represent my vehicle with PhysX Actors I am a little confused as the player character seems to have totally working collisions even if they aren't moving. Can you explain to me why that is?
#10
10/22/2008 (5:44 pm)
Well if you're using the PhysX resource that's out there, I'm guessing it has changes to the player to use a PhysX actor. You should probably take a look through your version control and compare before and after you implemented the resource. If you don't have version control installed, install it ASAP :)
#11
I can do without terrain deformation even if it is odd that you must not have any PhysX characters in the area when you are editting a terrain or it really messes things up. I guess while it would be really nice to have it working with the editor system a well, its not a complete must for me.
Now what I am interested in is your work with Mesh Cooking, you guys should release a resource or update the TDN articles on it, it would be a real nice additiona and gives people an alterantive to Polysoup.
10/22/2008 (7:31 pm)
Thanks Ross, I used the same method that was used for the player character and it works great for vehicles too.I can do without terrain deformation even if it is odd that you must not have any PhysX characters in the area when you are editting a terrain or it really messes things up. I guess while it would be really nice to have it working with the editor system a well, its not a complete must for me.
Now what I am interested in is your work with Mesh Cooking, you guys should release a resource or update the TDN articles on it, it would be a real nice additiona and gives people an alterantive to Polysoup.
#12
10/22/2008 (9:25 pm)
One piece of advice I could use though, the applyImpulse function seems to send things flying quite a bit further than normal. Have you done anything to tone it down abit?
#13
As to the cooking stuff, it's not really worth releasing a resource for. Just look at the cooking example and plug that in the same sort of way as I described before (look at TSStatic).
10/22/2008 (10:19 pm)
I honestly couldn't tell you why. We don't use the PhysX resource as it originally existed because we heavily rewrote it. If it is indeed applying the impulse to the PhysX actors, you should probably find where it calls apply force (can't remember the actual function name, I think it might be addForce) and check which flag it's using. You'll want to look in the PhysX docs and read up on the flags for that function and either try different ones, or determine which one is best (depending on how much you know about physics I guess).As to the cooking stuff, it's not really worth releasing a resource for. Just look at the cooking example and plug that in the same sort of way as I described before (look at TSStatic).
#14
You were right everything up til that point really does not even need the opcode libraries. As for the example I am assuming you meant cooking.h and cooking.cpp? I already have all of the libraries and includes added.
I think tsMesh.cpp is going to be the section that beats me. I admit this is my first time digging into a different physics engine.
10/23/2008 (10:50 am)
Thanks Ross. I managed to get all of the way through up until tsMesh only to find the process is ALOT different once you get to the prepcollision stuff.You were right everything up til that point really does not even need the opcode libraries. As for the example I am assuming you meant cooking.h and cooking.cpp? I already have all of the libraries and includes added.
I think tsMesh.cpp is going to be the section that beats me. I admit this is my first time digging into a different physics engine.
#15
One more question, how much do you guys want for your code? I have to admit it, much like a long distance runner, I just hit the wall.
10/23/2008 (7:26 pm)
Well heck I have more questions. Does the mesh cooking thing work the same way Polysoup whereas you don't use a collision mesh?One more question, how much do you guys want for your code? I have to admit it, much like a long distance runner, I just hit the wall.
#16
I'd say just keep trying, you'll eventually figure it out. It's really not too difficult. Basically all PhysX wants is a vector of Point3Fs for all the vertices that you want to cook, along with a couple of other parameters. All you have to do is go through the mesh you're looking at and collect them appropriately and pass them to the TriangleMeshDesc and then use the cooker to create the TriangleMesh actor.
10/23/2008 (10:23 pm)
Yeah it works about the same.I'd say just keep trying, you'll eventually figure it out. It's really not too difficult. Basically all PhysX wants is a vector of Point3Fs for all the vertices that you want to cook, along with a couple of other parameters. All you have to do is go through the mesh you're looking at and collect them appropriately and pass them to the TriangleMeshDesc and then use the cooker to create the TriangleMesh actor.
#17
Here is my function:
10/24/2008 (5:06 pm)
Maybe you can throw me a bone here. I know I am very close, but missing a thing or two.Here is my function:
void PhysXTSStatic::SetupTriangleCollision(bool server, TSStatic &tsstatic)
{
Con::errorf(ConsoleLogEntry::General, "SetupTriangleCollision called");
mServer = server;
PhysXWorld *PxWorld = PhysXWorld::getWorld(server);
if (PxWorld)
{
Box3F box = tsstatic.getObjBox();
VectorF scale = tsstatic.getScale()*10.0;
box.min.convolve(scale);
box.max.convolve(scale);
ConcretePolyList polyList;
NxActorDesc actorDesc;
if (!tsstatic.mShapeInstance)
return;
polyList.setTransform(&tsstatic.mObjToWorld, tsstatic.mObjScale);
polyList.setObject(&tsstatic);
bool found = false;
for (U32 i = 0; i < tsstatic.mCollisionDetails.size(); i++)
{
S32 dl = tsstatic.mCollisionDetails[i];
if (dl==-1)
{
//nothing to do
break;
}
AssertFatal(dl>=0 && dl<tsstatic.mShapeInstance->mShape->details.size(),"PhysXTSStatic::SetupCollision");
// get subshape and object detail
const TSDetail * detail = &tsstatic.mShapeInstance->mShape->details[dl];
S32 ss = detail->subShapeNum;
S32 od = detail->objectDetailNum;
// set up static data
tsstatic.mShapeInstance->setStatics(dl);
// nothing emitted yet...
bool emitted = false;
U32 surfaceKey = 0;
S32 start = tsstatic.mShapeInstance->mShape->subShapeFirstObject[ss];
S32 end = tsstatic.mShapeInstance->mShape->subShapeNumObjects[ss] + start;
if (start<end)
{
MatrixF initialMat;
Point3F initialScale;
polyList.getTransform(&initialMat,&initialScale);
// set up for first object's node
MatrixF mat;
MatrixF scaleMat(true);
F32* p = scaleMat;
p[0] = initialScale.x;
p[5] = initialScale.y;
p[10] = initialScale.z;
MatrixF * previousMat = tsstatic.mShapeInstance->mMeshObjects[start].getTransform();
mat.mul(initialMat,scaleMat);
mat.mul(*previousMat);
polyList.setTransform(&mat,Point3F(1, 1, 1));
int numTriangles = polyList.mPolyList.size();
triangleMeshDesc.setSize(numTriangles);
for(U32 i_tris=0; i_tris<numTriangles; i_tris++)
{
triangleMeshDesc[i_tris] = new NxTriangleMeshDesc();
}
// run through objects and collide
for (S32 i=start; i<end; i++)
{
TSShapeInstance::MeshObjectInstance * mesh = &tsstatic.mShapeInstance->mMeshObjects[i];
if (od >= mesh->object->numMeshes)
continue;
if (mesh->getTransform() != previousMat)
{
// different node from before, set up for this node
previousMat = mesh->getTransform();
if (previousMat != NULL)
{
mat.mul(initialMat,scaleMat);
mat.mul(*previousMat);
polyList.setTransform(&mat,Point3F(1, 1, 1));
}
}
// collide...
emitted |= mesh->buildPolyList(od,&polyList,surfaceKey);
int numVertices = polyList.mVertexList.size();
if (numVertices == 0) return;
NxVec3 * points = new NxVec3[numVertices];
NxArray<NxU32> * triangles = new NxArray<NxU32>[numTriangles*3];
// Load vertices
for(U32 i=0; i < numVertices; i++)
{
points[i].x = polyList.mVertexList[i].x;
points[i].y = polyList.mVertexList[i].y;
points[i].z = polyList.mVertexList[i].z;
}
// Load triangles
TSMesh * tMesh = mesh->getMesh(0);
S16 numE = tMesh->primitives.size();
NxU32 k = 0;
for(int j = 0; j < numE; j++)
{
triangles[j] = tMesh->indices[k];
triangles[j] = tMesh->indices[k++];
triangles[j] = tMesh->indices[k++];
k++;
}
NxTriangleMeshDesc triangleDesc;
triangleDesc.numVertices = numVertices;
triangleDesc.numTriangles = numTriangles;
triangleDesc.pointStrideBytes = sizeof(NxVec3);
triangleDesc.triangleStrideBytes = 3*sizeof(NxU32);
triangleDesc.points = points;
triangleDesc.triangles = &triangles[0];
triangleDesc.flags = 0;
// cook it
MemoryWriteBuffer buf;
NxInitCooking();
NxCookingParams params;
params.targetPlatform = PLATFORM_PC;
params.skinWidth=0.0f;
params.hintCollisionSpeed = false;
NxSetCookingParams(params);
bool status = NxCookTriangleMesh(triangleDesc, buf);
NxCloseCooking();
if (status)
{
MemoryReadBuffer readBuffer(buf.data);
NxTriangleMesh* staticMesh = PxWorld->createTriangleMesh(readBuffer);
NxTriangleMeshShapeDesc staticMeshDesc;
staticMeshDesc.meshData = staticMesh;
actorDesc.shapes.push_back(&staticMeshDesc);
}
polyList.clear();
} // end of for (S32 i=start; i<end; i++)
// restore original transform...
polyList.setTransform(&initialMat,initialScale);
}
tsstatic.mShapeInstance->clearStatics();
found = true;
}
if (!found) return;
actorDesc.body = NULL;
gTSStatic = PxWorld->AddActor(actorDesc);
if(gTSStatic->active)
{
Con::errorf(ConsoleLogEntry::General, "gTSStatic->active");
gTSStatic->actor->userData = (void*) static_cast<SimObject*>( this );
}
//clean up
for(U32 i=0; i<triangleMeshDesc.size(); i++)
{
if (triangleMeshDesc[i])
triangleMeshDesc[i]->~NxTriangleMeshDesc();
}
triangleMeshDesc.clear();
}
}
#18
I could really use another set of eyes from someone that has successfully done this.
10/24/2008 (9:01 pm)
OK I have officially gone through all of the examples I could find and by all accounts this should have worked. Yet, it still does not register the collision. I updated my function above to my most recent version. I know it is calling this function and it seems to be doing everything it should, yet I must be missing something.I could really use another set of eyes from someone that has successfully done this.
#19
10/25/2008 (7:42 am)
Have you stepped through that? And it gives a success status coming out of the cooking function (NXCookTriangleMesh)? If it does and you're not sure what's going on, I recommend checking out the example of how to hook up the PhysX Remote Debugger, and getting that working, connecting it and seeing what it actually generates.
#20
I have set things up as I saw in the example but have obviously missed something. If it is in the code would you mind having a quick look at what I did up to the following?
It also prompts me to ask if there is anything additional I should do in the export process? I have the plugin installed, but in this case I saw nothing that should make a difference.
Thanks for your help.
10/25/2008 (5:20 pm)
Thanks I tried everything you mentioned and I have were the process is failing but I must be honest I do not understand why. It is failing the cooking process and therefore the bool status is false.I have set things up as I saw in the example but have obviously missed something. If it is in the code would you mind having a quick look at what I did up to the following?
bool status = NxCookTriangleMesh(triangleDesc, buf);
It also prompts me to ask if there is anything additional I should do in the export process? I have the plugin installed, but in this case I saw nothing that should make a difference.
Thanks for your help.
Associate Ross Pawley
1) PhysX has "cooked meshes" including a TriangleMesh which is just a big list of triangles. You'd use PhysX instead of opcode/polysoup in most cases. One drawback to this approach is that PhysX requires you to "cook" the meshes to get them into an optimal format for collisions, but this is usually acceptable.
2) PhysX has some demos for vehicles. You'd probably just want to set up your object to use a PhysX representation (ideally serialized to xml/nxb via the NXStream functionality in the PhysX lib).
3) Links? If you mean joints, well, there are quite a few examples of joint usage in the PhysX examples. The easiest way to get a simple test is to open those up and hardcode a couple of joints and rigid bodies, then setup your ShapeInstance meshes to use the transforms of the PhysX objects to render at. If you're looking for an even simpler test than that, I suggest just drawing a box or such (check out the GFXDrawUtil) at the position of the object (use spheres in the PhysX representation so you can ignore rotations).
Hope this helps.