Forum Thread Not Found, Sorry.

Game Development Community

PhysX Cloth Assitance

by Taylor Petrick · in Torque Game Engine Advanced · 04/09/2009 (6:21 am) · 3 replies

I'm trying to implement PhysX Cloth in TGEA, based on the existing TGEA + PhysX resource. I've ran into some issues with generating the NxMesh and NxClothMesh for the cloth. Here's what I've got so far for creating the ClothMesh. A lot of the code may be un-needed; I'm basing this off the ConvexMesh generator and wasn't really sure what was needed and what wasn't. Keep in mind I'm new to this sort of thing. ;)

void PhysXCloth::SetupClothMesh(bool server, NxClothDesc &clothDesc)
{
	PhysXWorld *PxWorld = PhysXWorld::getWorld(server);
	if (PxWorld)
	{
		Box3F box = getObjBox();
		VectorF scale = getScale()*10.0;
		box.minExtents.convolve(scale);
		box.maxExtents.convolve(scale);
		ConcretePolyList list;

		if (!mShapeInstance) return;
		
		list.setTransform(&mObjToWorld, mObjScale);
		list.setObject(this);

		bool found = false;
		for (U32 i = 0; i < mDataBlock->collisionDetails.size(); i++)
		{
			S32 dl = mDataBlock->collisionDetails[i];

			if (dl == -1)
			{	
				break;
			}
			// get subshape and object detail
			const TSDetail * detail = &mShapeInstance->mShape->details[dl];
			S32 ss = detail->subShapeNum;
			S32 od = detail->objectDetailNum;

			// set up static data
			mShapeInstance->setStatics(dl);

			TSMaterialList * mMaterialList = mShapeInstance->getMaterialList();
			if (mMaterialList == NULL)
				mMaterialList = mShapeInstance->getShape()->materialList;

			// nothing emitted yet...
			bool emitted = false;
			U32 surfaceKey = 0;

			S32 start = mShapeInstance->mShape->subShapeFirstObject[ss];
			S32 end   = mShapeInstance->mShape->subShapeNumObjects[ss] + start;
			if (start<end)
			{
				MatrixF initialMat;
				Point3F initialScale;
				list.getTransform(&initialMat,&initialScale);

				// set up for first object's node
				MatrixF * previousMat = mShapeInstance->mMeshObjects[start].getTransform();
				list.setTransform(previousMat,Point3F(1, 1, 1));

				// run through objects and collide
				for (S32 i=start; i<end; i++)
				{
					TSShapeInstance::MeshObjectInstance * mesh = &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)
						{
							list.setTransform(previousMat,Point3F(1, 1, 1));
						}
					}
					// collide...
					emitted |= mesh->buildPolyList(od,&list,surfaceKey,mMaterialList);

					int vertBound = list.mVertexList.size();
					if (vertBound == 0) return;

					int polyBound = list.mPolyList.size();
					if (polyBound == 0) return;

					NxVec3 * verts = new NxVec3[vertBound];

					// Load vertices
					for(U32 k=0; k<vertBound; k++)
					{
						verts[k].x = list.mVertexList[k].x;
						verts[k].y = list.mVertexList[k].y;
						verts[k].z = list.mVertexList[k].z;
					}	 

					NxClothMeshDesc desc;
					desc.numVertices				= vertBound;
					desc.numTriangles				= polyBound;
					desc.pointStrideBytes			= sizeof(NxVec3);
					desc.triangleStrideBytes		= 3*sizeof(NxU32);
					desc.vertexMassStrideBytes		= sizeof(NxReal);
					desc.vertexFlagStrideBytes		= sizeof(NxU32);
					desc.points						= (NxVec3*)malloc(sizeof(NxVec3)*desc.numVertices);
					desc.triangles					= (NxU32*)malloc(sizeof(NxU32)*desc.numTriangles*3);
					desc.vertexMasses				= 0;
					desc.vertexFlags				= 0;
					desc.flags						= NX_CLOTH_MESH_WELD_VERTICES;
					desc.weldingDistance			= 0.0001f;

					NxInitCooking();

					// Cooking from memory
					MemoryWriteBuffer buf;
					bool status = NxCookClothMesh(desc, buf);
					if (status){
						MemoryReadBuffer readBuffer(buf.data);
						clothDesc.clothMesh = PxWorld->createClothMesh(readBuffer);
					}		
					list.clear();
				}

				// restore original transform...
				list.setTransform(&initialMat,initialScale);
			}

			mShapeInstance->clearStatics();

			found = true;
		}
		if (!found) return;
	}
}

The code will crash if PhysX tries to cook the mesh, so I'm assuming that I've set something up wrong.

Any suggestions would be helpful. :)

#1
04/09/2009 (6:50 am)
The first thing I see is that you're not actually giving it any vertices, you're just creating an empty buffer for it. That will certainly cause it to crash. The empty buffers you'll want to put in the NxMeshData structure which PhysX will use to copy the modified vertices to during the simulation.

desc.points = (NxVec3*)malloc(sizeof(NxVec3)*desc.numVertices);  
desc.triangles = (NxU32*)malloc(sizeof(NxU32)*desc.numTriangles*3);

You need to set desc.points to your vertex array, and desc.triangles to an array of indices, with 3 indices for each triangle.

You can just use the vertex array from the ConcretePolyList for your points, like this (no need to copy them to a new array):

desc.points = (NxVec3*)list.mVertexList.address();

For the triangles, you'll first have to create an array from the ConcretePolyList, since the polylist handles the indices differently. You can do something like this:

Vector<U32> indices;  
for (U32 i = 0; i < list.mPolyList.size(); i++)  
{  
   ConcretePolyList::Poly poly = list.mPolyList[i];  
  
   U32 index = poly.vertexStart;  
   indices.push_back( list.mIndexList[index++] );  
   indices.push_back( list.mIndexList[index++] );  
   indices.push_back( list.mIndexList[index++] );  
}

and then set your triangles like this:

desc.triangles = (NxU32*)indices.address();

---

I should warn you that getting cloth to work with DTS/TSShape is going to be a fairly complex problem. You'll have to create a new rendering method using a dynamic or volatile vertex buffer because the vertices are going to change every frame as a result of the cloth simulation.

Certainly doable, but if you're new to this it is probably going to take you a while. Don't get discouraged though, just don't expect to get it done right away, and feel free to ask any more questions here that you might have.

Cheers
#2
04/09/2009 (7:14 am)
Thanks for the suggestions, Gerald. I never really thought about the DTS end of the things. Since I'm mainly going to be using planar surfaces for cloth, would generating the vertices in code and rendering them with PrimBuild be a better solution? Something like the curtain demo from the PhysX SDK?
#3
04/09/2009 (7:19 am)
I'm not real familiar with PrimBuild or how it works, but I think that would probably do the trick. If your cloth is using a lot of vertices then ideally you'd not want to specify the vertices one at a time, but that would be a good way to get you started.