// ----------------------------------------------------------------------- bool MyCloth::generateObjMeshDesc(NxClothMeshDesc &desc, char *filename, NxReal scale) { WavefrontObj wo; wo.loadObj(filename); if (wo.mVertexCount == 0) return false; desc.numVertices = wo.mVertexCount; desc.numTriangles = wo.mTriCount; 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 = 0; // copy positions and indices NxVec3 *vSrc = (NxVec3*)wo.mVertices; NxVec3 *vDest = (NxVec3*)desc.points; for (int i = 0; i < wo.mVertexCount; i++, vDest++, vSrc++) *vDest = (*vSrc)*scale; // resize memcpy((NxU32*)desc.triangles, wo.mIndices, sizeof(NxU32)*desc.numTriangles*3); return true; }
// ----------------------------------------------------------------------- bool MyCloth::generateObjMeshDesc(NxClothMeshDesc &desc, char *filename, NxReal scale, NxVec3* offset, bool textured) { WavefrontObj wo; wo.loadObj(filename, textured); if (wo.mVertexCount == 0) return false; NxVec3 myOffset(0.f); if (offset != NULL) myOffset = *offset; desc.numVertices = wo.mVertexCount; desc.numTriangles = wo.mTriCount; 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; //desc.numHierarchyLevels = 3; //no idea what is best here mMaxVertices = wo.mVertexCount; mMaxIndices = 3 * wo.mTriCount; // copy positions and indices NxVec3 *vSrc = (NxVec3*)wo.mVertices; NxVec3 *vDest = (NxVec3*)desc.points; for (int i = 0; i < wo.mVertexCount; i++, vDest++, vSrc++) *vDest = (*vSrc)*scale + myOffset; memcpy((NxU32*)desc.triangles, wo.mIndices, sizeof(NxU32)*desc.numTriangles*3); if (textured) { mNumTempTexCoords = desc.numVertices; mTempTexCoords = (GLfloat *)malloc(sizeof(GLfloat) * mNumTempTexCoords * 2); memcpy((NxU32*)mTempTexCoords, wo.mTexCoords, sizeof(GLfloat)*mNumTempTexCoords*2); mIndexRenderBuffer = (NxU32*)malloc(sizeof(NxU32) * mMaxIndices); memset(mIndexRenderBuffer, 0, sizeof(NxU32) * mMaxIndices); for (NxU32 i = 0; i < desc.numTriangles; i++) { assert((desc.flags & NX_CF_16_BIT_INDICES) == 0); NxU32* tri = (NxU32*)(((char*)desc.triangles) + (desc.triangleStrideBytes * i)); mIndexRenderBuffer[3*i+0] = tri[0]; mIndexRenderBuffer[3*i+1] = tri[1]; mIndexRenderBuffer[3*i+2] = tri[2]; } } else { mNumTempTexCoords = 0; mTempTexCoords = NULL; } return true; }
btCollisionShape* ObjLoader::loadObject(std::string filename, btScalar objectHeight) { WavefrontObj wo; printf("load Obj\n"); int tcount = wo.loadObj(filename.c_str()); printf("loading done.\n"); if(!tcount){ printf("Error loading obj file %s\n",filename.c_str()); // Handling return 0; } else { btTriangleMesh* trimesh = new btTriangleMesh(); btVector3 localScaling(1.f,1.f,1.f); int i; for ( i=0;i<wo.mTriCount;i++) { int index0 = wo.mIndices[i*3]; int index1 = wo.mIndices[i*3+1]; int index2 = wo.mIndices[i*3+2]; btVector3 vertex0(wo.mVertices[index0*3], wo.mVertices[index0*3+1],wo.mVertices[index0*3+2]); btVector3 vertex1(wo.mVertices[index1*3], wo.mVertices[index1*3+1],wo.mVertices[index1*3+2]); btVector3 vertex2(wo.mVertices[index2*3], wo.mVertices[index2*3+1],wo.mVertices[index2*3+2]); vertex0 *= localScaling; vertex1 *= localScaling; vertex2 *= localScaling; trimesh->addTriangle(vertex0,vertex1,vertex2); } btTransform startTransform; startTransform.setIdentity(); startTransform.setOrigin(btVector3(0,2,14)); btVector3 aabbMin, aabbMax; trimesh->calculateAabbBruteForce(aabbMin,aabbMax); float height = aabbMax.y() - aabbMin.y(); float scaling = objectHeight/height; trimesh->setScaling(btVector3(scaling,scaling,scaling)); bool useQuantization = false; btCollisionShape* concaveShape = new btBvhTriangleMeshShape(trimesh,useQuantization); return concaveShape; // return convexShape; } }
int main(int argc,const char ** argv) { if ( argc == 1 ) { printf("Usage: TestHACD <wavefront.obj> (options)\r\n"); printf("\r\n"); printf("Options:\r\n"); printf("-v <count> : Max Hull Vertices (default 64)\r\n"); printf("-m <count> : Maximum number of hulls output from HACD (default 256)\r\n"); printf("-merge <count> : Maximum number of hulls after merging the HACD result.\r\n"); printf("-mergethreshold <volume> : Threshold below which hulls are merged if they are smaller than the given volume.\r\n"); printf("-c <concavity> : Between 0 and 1 are good ranges to try; default is 0.2. The smaller the number, the more convex hulls are produced.\r\n"); printf("-b <backFaceDistanceFactor : The back face distance factor, default is 0.2\r\n"); printf("-t <threadCount> : Specifies the number of threads to use for a multi-threaded implementation\r\n"); printf("-d <decompositionDepth> : Specifies the decomposition depth; uses legacy ACD instead of HACD\r\n"); printf("-n : Normalize the input mesh.\r\n"); printf("-f : Use legacy 'fast' version of HACD\r\n"); printf("\r\n"); printf("Example: TestHACD hornbug.obj -m 40 -v 64\r\n"); printf("\r\n"); } else { HACD::HACD_API::Desc desc; const char *wavefront = argv[1]; int scan = 2; int threadCount = 0; while ( scan < argc ) { const char *option = argv[scan]; if ( strcmp(option,"-v") == 0 ) { desc.mMaxHullVertices = getIntArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-t") == 0 ) { threadCount = getIntArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-d") == 0 ) { desc.mDecompositionDepth = getIntArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-b") == 0 ) { desc.mBackFaceDistanceFactor = getFloatArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-m") == 0 ) { desc.mMaxHullCount = getIntArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-merge") == 0 ) { desc.mMaxMergeHullCount = getIntArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-mergethreshold") == 0 ) { desc.mSmallClusterThreshold = getFloatArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-c") == 0 ) { desc.mConcavity = getFloatArg(scan+1,argc,argv); scan+=2; } else if ( strcmp(option,"-n") == 0 ) { desc.mNormalizeInputMesh = true; scan++; } else if ( strcmp(option,"-f") == 0 ) { desc.mUseFastVersion = true; scan++; } else { scan++; } } HACD::gHACD = HACD::createHACD_API(); if ( HACD::gHACD ) { MyCallback callback; WavefrontObj obj; unsigned int tcount = obj.loadObj(wavefront,false); if ( tcount ) { desc.mTriangleCount = obj.mTriCount; desc.mVertexCount = obj.mVertexCount; desc.mIndices = (hacd::HaU32 *)obj.mIndices; desc.mVertices = obj.mVertices; } desc.mCallback = static_cast<hacd::ICallback*>(&callback); if ( desc.mTriangleCount ) { printf("Performing HACD on %d input triangles.\r\n", desc.mTriangleCount ); printf("\r\n"); printf("TriangleCount : %d\r\n", desc.mTriangleCount ); printf("VertexCount : %d\r\n", desc.mVertexCount ); printf("Concavity : %0.2f\r\n", desc.mConcavity ); printf("Max Hull Vertex Count : %3d\r\n", desc.mMaxHullVertices ); printf("Max Convex Hulls : %3d\r\n", desc.mMaxHullCount ); printf("Max Merged Convex Hulls : %3d\r\n", desc.mMaxMergeHullCount ); printf("Merge Threshold : %0.2f\r\n", desc.mSmallClusterThreshold); printf("Back Face Distance Factor: %0.2f\r\n", desc.mBackFaceDistanceFactor ); printf("Small Cluster Threshold : %0.2f\r\n", desc.mSmallClusterThreshold ); if ( desc.mDecompositionDepth ) { printf("DecompositionDepth : %d\r\n", desc.mDecompositionDepth ); } if ( desc.mNormalizeInputMesh ) { printf("Normalizing input mesh.\r\n"); } if ( desc.mUseFastVersion ) { printf("Using 'fast' version of HACD.\r\n"); } printf("\r\n"); desc.mJobSwarmContext = NULL; hacd::HaU32 hullCount = HACD::gHACD->performHACD(desc); if ( hullCount != 0 ) { printf("\r\n"); printf("Produced %d output convex hulls. Saving output to 'ConvexDecomposition.obj' for review.\r\n", hullCount ); FILE *fph = fopen("ConvexDecomposition.obj", "wb"); if ( fph ) { fprintf(fph,"# Input mesh '%s' produced %d convex hulls.\r\n", wavefront, hullCount ); hacd::HaU32 *baseVertex = new hacd::HaU32[hullCount]; hacd::HaU32 vertexCount = 0; for (hacd::HaU32 i=0; i<hullCount; i++) { const HACD::HACD_API::Hull *hull = HACD::gHACD->getHull(i); if ( hull ) { baseVertex[i] = vertexCount; fprintf(fph,"## Hull %d has %d vertices.\r\n", i+1, hull->mVertexCount ); for (hacd::HaU32 i=0; i<hull->mVertexCount; i++) { const hacd::HaF32 *p = &hull->mVertices[i*3]; fprintf(fph,"v %0.9f %0.9f %0.9f\r\n", p[0], p[1], p[2] ); } vertexCount+=hull->mVertexCount; } } for (hacd::HaU32 i=0; i<hullCount; i++) { const HACD::HACD_API::Hull *hull = HACD::gHACD->getHull(i); if ( hull ) { hacd::HaU32 startVertex = baseVertex[i]; fprintf(fph,"# Convex Hull %d contains %d triangles and %d vertices. Starting vertex index is: %d It has a volume of: %0.9f\r\n", i+1, hull->mTriangleCount, hull->mVertexCount, startVertex); fprintf(fph,"g convex_hull%d\r\n", i+1); for (hacd::HaU32 j=0; j<hull->mTriangleCount; j++) { hacd::HaU32 i1 = hull->mIndices[j*3+0]+startVertex+1; hacd::HaU32 i2 = hull->mIndices[j*3+1]+startVertex+1; hacd::HaU32 i3 = hull->mIndices[j*3+2]+startVertex+1; fprintf(fph,"f %d %d %d\r\n", i1, i2, i3 ); } } } } else { printf("Failed to open output file.\r\n"); } } } else { printf("Failed to load Wavefront OBJ file '%s'\r\n",wavefront); } } else { printf("Failed to load the HACD DLL\r\n"); } } return 0; }