PhysX Cooked Mesh Raycast Code help please
by Ronald J Nelson · in Torque Game Engine · 11/04/2008 (4:16 pm) · 6 replies
I am posting this in both TGE and TGEA forums because I know not everyone owns both and I am hoping to up my chances for a successful resolution to my code problems.
I have successfully gotten Triangle Mesh Cooking working in PhysX(with help). What I am trying to get working is the TSStatic::castRay function so collisions can be detected. I have almost succeeded.
The following is everything I added to get this working. Everyone is welcome to use this I just want a fix to the castray issue.
Thanks in advance.
I have successfully gotten Triangle Mesh Cooking working in PhysX(with help). What I am trying to get working is the TSStatic::castRay function so collisions can be detected. I have almost succeeded.
The following is everything I added to get this working. Everyone is welcome to use this I just want a fix to the castray issue.
Thanks in advance.
#2
Above
add
In TSStatic::TSStatic() after
add
In TSStatic::initPersistFields()after
add
Replace the entire bool TSStatic::onAdd() function with
In U32 TSStatic::packUpdate after
add
In void TSStatic::unpackUpdate after
add
Replace the entire TSStatic::castRay function with
11/11/2008 (1:52 pm)
Next in TSStatic.cc/cppAbove
#include "game/tsStatic.h"
add
//Triangle Mesh Cooking #include "physX/PhysX.h" #include "physX/PhysXWorld.h" //Triangle Mesh Cooking
In TSStatic::TSStatic() after
mShadow = NULL;
add
mUseTriangleCook = false; mAllowPlayerStep = true;
In TSStatic::initPersistFields()after
addField("customAmbientLighting", TypeColorF, Offset(customAmbientLighting, SceneObject));
addField("lightGroupName", TypeString, Offset(lightGroupName, SceneObject));
endGroup("Lighting");add
addGroup("Collision");
addField("useTriangleCook", TypeBool, Offset(mUseTriangleCook, TSStatic));
addField("allowPlayerStep", TypeBool, Offset(mAllowPlayerStep, TSStatic));
endGroup("Collision");Replace the entire bool TSStatic::onAdd() function with
bool TSStatic::onAdd()
{
if(!Parent::onAdd())
return false;
if (!mShapeName || mShapeName[0] == '[[60c230ec27ce8]]') {
Con::errorf("TSStatic::onAdd: no shape name!");
return false;
}
mShapeHash = _StringTable::hashString(mShapeName);
mShape = ResourceManager->load(mShapeName);
if (bool(mShape) == false)
{
Con::errorf("TSStatic::onAdd: unable to load shape: %s", mShapeName);
return false;
}
if(isClientObject() && !mShape->preloadMaterialList() && NetConnection::filesWereDownloaded())
return false;
mObjBox = mShape->bounds;
resetWorldBox();
setRenderTransform(mObjToWorld);
mShapeInstance = new TSShapeInstance(mShape, isClientObject());
// Triangle Mesh Cooking
PhysXWorld *PxWorld = PhysXWorld::getWorld(isServerObject());
if(mUseTriangleCook)
{
// Cleanup any old collision data.
mCollisionDetails.clear();
mLOSDetails.clear();
}
else
{
prepCollision();
}
addToScene();
if (PxWorld)
{
if(mUseTriangleCook)
{
PxWorld->SetupCookedTSStatic(*this);
}
else
{
PxWorld->SetupTSStatic(*this);
}
}
return true;
}
void TSStatic::prepCollision()
{
// Scan out the collision hulls...
U32 i;
for (i = 0; i < mShape->details.size(); i++)
{
char* name = (char*)mShape->names[mShape->details[i].nameIndex];
if (dStrstr((const char*)dStrlwr(name), "collision-"))
{
mCollisionDetails.push_back(i);
// The way LOS works is that it will check to see if there is a LOS detail that matches
// the the collision detail + 1 + MaxCollisionShapes (this variable name should change in
// the future). If it can't find a matching LOS it will simply use the collision instead.
// We check for any "unmatched" LOS's further down
mLOSDetails.increment();
char buff[128];
dSprintf(buff, sizeof(buff), "LOS-%d", i + 1 + MaxCollisionShapes);
U32 los = mShape->findDetail(buff);
if (los == -1)
mLOSDetails.last() = i;
else
mLOSDetails.last() = los;
}
}
// Snag any "unmatched" LOS details
for (i = 0; i < mShape->details.size(); i++)
{
char* name = (char*)mShape->names[mShape->details[i].nameIndex];
if (dStrstr((const char*)dStrlwr(name), "los-"))
{
// See if we already have this LOS
bool found = false;
for (U32 j = 0; j < mLOSDetails.size(); j++)
{
if (mLOSDetails[j] == i)
{
found = true;
break;
}
}
if (!found)
mLOSDetails.push_back(i);
}
}
// Compute the hull accelerators (actually, just force the shape to compute them)
for (i = 0; i < mCollisionDetails.size(); i++)
mShapeInstance->getShape()->getAccelerator(mCollisionDetails[i]);
return;
}
// Triangle Mesh CookingIn U32 TSStatic::packUpdate after
stream->writeString(mShapeName);
add
//Triangle Mesh Cooking stream->writeFlag(mUseTriangleCook); stream->writeFlag(mAllowPlayerStep); //Triangle Mesh Cooking
In void TSStatic::unpackUpdate after
mShapeName = stream->readSTString();
add
//Triangle Mesh Cooking mUseTriangleCook = stream->readFlag(); mAllowPlayerStep = stream->readFlag(); //Triangle Mesh Cooking
Replace the entire TSStatic::castRay function with
bool TSStatic::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
{
if (!mShapeInstance)
return false;
//Triangle Mesh Cooking
if (mUseTriangleCook)
{
PhysXWorld *PxWorld = PhysXWorld::getWorld(true);
if (!PxWorld)
return false;
bool res = true;
RayInfo localInfo;
//Convert the variables
NxVec3 startTMC(start.x,start.y,start.z);
NxVec3 endTMC(end.x,end.y,end.z);
NxRaycastHit rayInfoTMC;
dMemset( &rayInfoTMC, 0, sizeof( NxRaycastHit ) );
NxRay ray;
ray.dir = NxVec3(endTMC - startTMC);
ray.orig = startTMC;
ray.dir.normalize();
PxWorld->gScene->raycastClosestShape(ray, NX_STATIC_SHAPES, rayInfoTMC);
if(!rayInfoTMC.shape)
res = false;
//Convert the variables
F32 dist = F32(rayInfoTMC.distance);
U32 face = U32(rayInfoTMC.faceID);
//F32 t = F32(rayInfoTMC.distance/maxDist);
VectorF nm;
nm.set(rayInfoTMC.worldNormal.x, rayInfoTMC.worldNormal.y, rayInfoTMC.worldNormal.z);
Point3F pnt;
pnt.set(rayInfoTMC.worldImpact.x, rayInfoTMC.worldImpact.y, rayInfoTMC.worldImpact.z);
Con::printf("Distance: %f",dist);
Con::printf("Face: %i",face);
//Con::printf("t: %f",t);
Con::printf("Normal X: %f",nm.x);
Con::printf("Normal Y: %f",nm.y);
Con::printf("Normal Z: %f",nm.z);
Con::printf("Point X: %f",pnt.x);
Con::printf("Point Y: %f",pnt.y);
Con::printf("Point Z: %f",pnt.z);
localInfo.distance = dist;
localInfo.face = face;
localInfo.HitBoxNum = 0;
localInfo.material = 0;
localInfo.normal = nm;
localInfo.point = pnt;
//localInfo.t = t;
//localInfo.texCoord = texCrd;
*info = localInfo;
info->object = this;
if(!res)
Con::printf("TSStatic::castRay Failed");
else
Con::printf("TSStatic::castRay Succesful");
return res;
}
//Triangle Mesh Cooking
RayInfo shortest;
shortest.t = 1e8;
info->object = NULL;
for (U32 i = 0; i < mLOSDetails.size(); i++)
{
mShapeInstance->animate(mLOSDetails[i]);
if (mShapeInstance->castRay(start, end, info, mLOSDetails[i]))
{
info->object = this;
if (info->t < shortest.t)
shortest = *info;
}
}
if (info->object == this)
{
// Copy out the shortest time...
*info = shortest;
return true;
}
return false;
}
#3
After
add
then move
Finally, below
add
11/11/2008 (1:53 pm)
In PhysXWorld.hAfter
typedef NetObject Parent;
add
friend class TSStatic;
then move
NxPhysicsSDK *gPhysicsSDK;down below
public:a few lines down.
Finally, below
void SetupTSStatic(TSStatic &);
add
void SetupCookedTSStatic(TSStatic &);
#4
Right after the void PhysXWorld::SetupTSStatic(TSStatic &tsstatic) function add the following funtion
11/11/2008 (1:53 pm)
In PhysXWorld.cc/cppRight after the void PhysXWorld::SetupTSStatic(TSStatic &tsstatic) function add the following funtion
void PhysXWorld::SetupCookedTSStatic(TSStatic &tsstatic)
{
if (mRemoteClient || isServerObject())
{
PhysXTSStatic *pxTSStatic = new PhysXTSStatic();
pxTSStatic->registerObject();
mTSStaticList.push_front(pxTSStatic);
pxTSStatic->SetupTriangleCollision(isServerObject(),tsstatic);
}
}
#5
Change
to
Finally after
add
11/11/2008 (1:54 pm)
In PhysXTSStatic.hChange
private: typedef SimObject Parent; bool mServer; S32 mNumTSStatic; NxConvexMesh *tsstaticMesh; Vector<NxConvexShapeDesc*> convexShapeDesc;
to
private: typedef SimObject Parent; bool mServer; S32 mNumTSStatic; NxConvexMesh *tsstaticMesh; NxTriangleMesh *mTriangleMesh; Vector<NxConvexShapeDesc*> convexShapeDesc; Vector<NxTriangleMeshDesc*> triangleMeshDesc;
Finally after
void SetupCollision(bool server,TSStatic &);
add
void SetupTriangleCollision(bool server,TSStatic &);
#6
Change
to
Finally at the end of the file add
Thats all of it.
11/11/2008 (1:54 pm)
In PhysXTSStatic.cc/cppChange
PhysXTSStatic::PhysXTSStatic()
{
mServer = false;
gTSStatic = NULL;
tsstaticMesh = NULL;
VECTOR_SET_ASSOCIATION(convexShapeDesc);
mNumTSStatic = 1;
nbVerts = 0;
nbFaces = 0;
verts = NULL;
faces = NULL;
}to
PhysXTSStatic::PhysXTSStatic()
{
mServer = false;
gTSStatic = NULL;
tsstaticMesh = NULL;
mTriangleMesh = NULL;
VECTOR_SET_ASSOCIATION(convexShapeDesc);
VECTOR_SET_ASSOCIATION(triangleMeshDesc);
mNumTSStatic = 1;
nbVerts = 0;
nbFaces = 0;
verts = NULL;
faces = NULL;
}Finally at the end of the file add
void PhysXTSStatic::SetupTriangleCollision(bool server, TSStatic &tsstatic)
{
mServer = server;
PhysXWorld *PxWorld = PhysXWorld::getWorld(server);
// If we don't have a PhysXWorld, just return.
if ( !PxWorld )
{
return;
}
Box3F box = tsstatic.getObjBox();
VectorF scale = tsstatic.getScale();//*10.0;
box.min.convolve(scale);
box.max.convolve(scale);
MatrixF wmat = tsstatic.getWorldTransform();
Point3F placePos = tsstatic.getPosition();
// make our matrices into Quats... for the physx engine
QuatF q(wmat);
Point3F wpos;
wmat.getColumn(3,&wpos);
NxQuat quat;
quat. setXYZW(q.x, q.y, q.z, q.w);
NxActorDesc actorDesc;
Vector<U32> indicesList;
TSShapeInstance *shapeInst = tsstatic.mShapeInstance;
if ( !shapeInst )
{
return;;
}
NxInitCooking();
// Loop through each *MeshObjectInstance* in the TSShapeInstance.
for( U32 i = 0; i < shapeInst->mMeshObjects.size(); i++ )
{
// Grab out the MeshObjectInstance.
TSShapeInstance::MeshObjectInstance *meshInst = &shapeInst->mMeshObjects[i];
// Grab out the TSMesh for that MeshObjectInstance.
TSMesh *mesh = meshInst->getMesh( 0 );
if ( !mesh )
{
continue; // Nothing left to do if no mesh.
}
// Figure out how many triangles we have...
nbFaces = 0;
const U32 base = 0;
// Loop through the TSDrawPrimitives.
for ( U32 j = 0; j < mesh->primitives.size(); j++ )
{
// Pull out the TSDrawPrimitive.
TSDrawPrimitive &draw = mesh->primitives[j];
U32 start = draw.start;
if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)
{
nbFaces += draw.numElements / 3;
}
else
{
U32 idx0 = base + mesh->indices[start + 0];
U32 idx1;
U32 idx2 = base + mesh->indices[start + 1];
U32 * nextIdx = &idx1;
for ( S32 k = 2; k < draw.numElements; k++ )
{
*nextIdx = idx2;
nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
idx2 = base + mesh->indices[start + k];
if (idx0 == idx1 || idx0 == idx2 || idx1 == idx2)
continue;
nbFaces++;
}
}
}
for ( U32 j = 0; j < mesh->primitives.size(); j++ )
{
TSDrawPrimitive &draw = mesh->primitives[j];
U32 start = draw.start;
if ( (draw.matIndex & TSDrawPrimitive::TypeMask) == TSDrawPrimitive::Triangles)
{
for ( S32 j = 0; j < draw.numElements; )
{
U32 idx0 = base + mesh->indices[start + j + 0];
U32 idx1 = base + mesh->indices[start + j + 1];
U32 idx2 = base + mesh->indices[start + j + 2];
indicesList.push_back( idx2 );
indicesList.push_back( idx1 );
indicesList.push_back( idx0 );
j += 3;
}
}
else
{
U32 idx0 = base + mesh->indices[start + 0];
U32 idx1;
U32 idx2 = base + mesh->indices[start + 1];
U32 * nextIdx = &idx1;
for (S32 j=2; j<draw.numElements; j++)
{
*nextIdx = idx2;
nextIdx = (U32*) ( (dsize_t)nextIdx ^ (dsize_t)&idx0 ^ (dsize_t)&idx1);
idx2 = base + mesh->indices[start + j];
if (idx0 == idx1 || idx0 == idx2 || idx1 == idx2)
continue;
indicesList.push_back( idx2 );
indicesList.push_back( idx1 );
indicesList.push_back( idx0 );
}
}
}
// Here you can loop through your
// indicesList and index mesh->verts
// to collect them all.
nbVerts = mesh->verts.size();
NxVec3 * verts = new NxVec3[nbVerts];
// Load vertices
for(U32 i=0; i < nbVerts; i++)
{
verts[i].x = mesh->verts[i].x;
verts[i].y = mesh->verts[i].y;
verts[i].z = mesh->verts[i].z;
}
faces = indicesList.address();
NxTriangleMeshDesc triangleDesc;
triangleDesc.numVertices = nbVerts;
triangleDesc.numTriangles = nbFaces;
triangleDesc.pointStrideBytes = sizeof(NxVec3);
triangleDesc.triangleStrideBytes = 3*sizeof(NxU32);
triangleDesc.points = verts;
triangleDesc.triangles = faces;
// cook it
MemoryWriteBuffer buf;
NxCookingParams params;
params.targetPlatform = PLATFORM_PC;
params.skinWidth=0.0f;
params.hintCollisionSpeed = false;
NxSetCookingParams(params);
bool status = NxCookTriangleMesh(triangleDesc, buf);
if (status)
{
MemoryReadBuffer readBuffer(buf.data);
mTriangleMesh = PxWorld->createTriangleMesh(readBuffer);
// Push this actor back into our actor list.
NxTriangleMeshShapeDesc staticMeshDesc;
staticMeshDesc.meshData = mTriangleMesh;
actorDesc.shapes.push_back(&staticMeshDesc);
}
else
{
return;
}
}
NxCloseCooking();
actorDesc.body = NULL;
gTSStatic = PxWorld->AddActor(actorDesc);
if(gTSStatic->active)
{
gTSStatic->actor->setGlobalOrientationQuat(quat);
gTSStatic->actor->setGlobalPosition( NxVec3(placePos) );
gTSStatic->actor->userData = (void*) static_cast<SimObject*>( this );
}
}Thats all of it.
Torque Owner Ronald J Nelson
Code Hammer Games
Change this
class TSStatic : public SceneObject { typedef SceneObject Parent; friend class TSStaticConvex;to
class TSStatic : public SceneObject { typedef SceneObject Parent; friend class TSStaticConvex; friend class PhysXTSStatic; friend class PhysXWorld;Right above
add
Right below
add
Right below
add
//Triangle Mesh Cooking bool usesTriangleCook() {return mUseTriangleCook;} bool allowPlayerStep() {return mAllowPlayerStep;} //Triangle Mesh Cooking