void calcConvexDecomposition(unsigned int vcount, const float *vertices, unsigned int tcount, const unsigned int *indices, ConvexDecompInterface *callback, float masterVolume, unsigned int depth) { float plane[4]; bool split = false; if ( depth < MAXDEPTH ) { float volume; float c = computeConcavity( vcount, vertices, tcount, indices, callback, plane, volume ); if ( depth == 0 ) { masterVolume = volume; } float percent = (c*100.0f)/masterVolume; if ( percent > CONCAVE_PERCENT ) // if great than 5% of the total volume is concave, go ahead and keep splitting. { split = true; } } if ( depth >= MAXDEPTH || !split ) { #if 1 HullResult result; HullLibrary hl; HullDesc desc; desc.SetHullFlag(QF_TRIANGLES); desc.mVcount = vcount; desc.mVertices = vertices; desc.mVertexStride = sizeof(float)*3; HullError ret = hl.CreateConvexHull(desc,result); if ( ret == QE_OK ) { ConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices); callback->ConvexDecompResult(r); } #else static unsigned int colors[8] = { 0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0x00FFFF, 0xFF00FF, 0xFFFFFF, 0xFF8040 }; static int count = 0; count++; if ( count == 8 ) count = 0; assert( count >= 0 && count < 8 ); unsigned int color = colors[count]; const unsigned int *source = indices; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *source++; unsigned int i2 = *source++; unsigned int i3 = *source++; FaceTri t(vertices, i1, i2, i3 ); callback->ConvexDebugTri( t.mP1.Ptr(), t.mP2.Ptr(), t.mP3.Ptr(), color ); } #endif return; } UintVector ifront; UintVector iback; VertexLookup vfront = Vl_createVertexLookup(); VertexLookup vback = Vl_createVertexLookup(); bool showmesh = false; #if SHOW_MESH showmesh = true; #endif if ( 0 ) { showmesh = true; for (float x=-1; x<1; x+=0.10f) { for (float y=0; y<1; y+=0.10f) { for (float z=-1; z<1; z+=0.04f) { float d = x*plane[0] + y*plane[1] + z*plane[2] + plane[3]; Vector3d p(x,y,z); if ( d >= 0 ) callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0x00FF00); else callback->ConvexDebugPoint(p.Ptr(), 0.02f, 0xFF0000); } } } } if ( 1 ) { // ok..now we are going to 'split' all of the input triangles against this plane! const unsigned int *source = indices; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *source++; unsigned int i2 = *source++; unsigned int i3 = *source++; FaceTri t(vertices, i1, i2, i3 ); Vector3d front[4]; Vector3d back[4]; unsigned int fcount=0; unsigned int bcount=0; PlaneTriResult result; result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount ); if( fcount > 4 || bcount > 4 ) { result = planeTriIntersection(plane,t.mP1.Ptr(),sizeof(Vector3d),0.00001f,front[0].Ptr(),fcount,back[0].Ptr(),bcount ); } switch ( result ) { case PTR_FRONT: assert( fcount == 3 ); if ( showmesh ) callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00FF00 ); #if MAKE_MESH addTri( vfront, ifront, front[0], front[1], front[2] ); #endif break; case PTR_BACK: assert( bcount == 3 ); if ( showmesh ) callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xFFFF00 ); #if MAKE_MESH addTri( vback, iback, back[0], back[1], back[2] ); #endif break; case PTR_SPLIT: assert( fcount >= 3 && fcount <= 4); assert( bcount >= 3 && bcount <= 4); #if MAKE_MESH addTri( vfront, ifront, front[0], front[1], front[2] ); addTri( vback, iback, back[0], back[1], back[2] ); if ( fcount == 4 ) { addTri( vfront, ifront, front[0], front[2], front[3] ); } if ( bcount == 4 ) { addTri( vback, iback, back[0], back[2], back[3] ); } #endif if ( showmesh ) { callback->ConvexDebugTri( front[0].Ptr(), front[1].Ptr(), front[2].Ptr(), 0x00D000 ); callback->ConvexDebugTri( back[0].Ptr(), back[1].Ptr(), back[2].Ptr(), 0xD0D000 ); if ( fcount == 4 ) { callback->ConvexDebugTri( front[0].Ptr(), front[2].Ptr(), front[3].Ptr(), 0x00D000 ); } if ( bcount == 4 ) { callback->ConvexDebugTri( back[0].Ptr(), back[2].Ptr(), back[3].Ptr(), 0xD0D000 ); } } break; } } unsigned int fsize = ifront.size()/3; unsigned int bsize = iback.size()/3; // ok... here we recursively call if ( ifront.size() ) { unsigned int vcount = Vl_getVcount(vfront); const float *vertices = Vl_getVertices(vfront); unsigned int tcount = ifront.size()/3; calcConvexDecomposition(vcount, vertices, tcount, &ifront[0], callback, masterVolume, depth+1); } ifront.clear(); Vl_releaseVertexLookup(vfront); if ( iback.size() ) { unsigned int vcount = Vl_getVcount(vback); const float *vertices = Vl_getVertices(vback); unsigned int tcount = iback.size()/3; calcConvexDecomposition(vcount, vertices, tcount, &iback[0], callback, masterVolume, depth+1); } iback.clear(); Vl_releaseVertexLookup(vback); } }
unsigned int ConvexBuilder::process(const DecompDesc &desc) { unsigned int ret = 0; MAXDEPTH = desc.mDepth; CONCAVE_PERCENT = desc.mCpercent; MERGE_PERCENT = desc.mPpercent; calcConvexDecomposition(desc.mVcount, desc.mVertices, desc.mTcount, desc.mIndices,this,0,0); while ( combineHulls() ); // keep combinging hulls until I can't combine any more... int i; for (i=0;i<mChulls.size();i++) { CHull *cr = mChulls[i]; // before we hand it back to the application, we need to regenerate the hull based on the // limits given by the user. const ConvexResult &c = *cr->mResult; // the high resolution hull... HullResult result; HullLibrary hl; HullDesc hdesc; hdesc.SetHullFlag(QF_TRIANGLES); hdesc.mVcount = c.mHullVcount; hdesc.mVertices = c.mHullVertices; hdesc.mVertexStride = sizeof(float)*3; hdesc.mMaxVertices = desc.mMaxVertices; // maximum number of vertices allowed in the output if ( desc.mSkinWidth ) { hdesc.mSkinWidth = desc.mSkinWidth; hdesc.SetHullFlag(QF_SKIN_WIDTH); // do skin width computation. } HullError ret = hl.CreateConvexHull(hdesc,result); if ( ret == QE_OK ) { ConvexResult r(result.mNumOutputVertices, result.mOutputVertices, result.mNumFaces, result.mIndices); r.mHullVolume = computeMeshVolume( result.mOutputVertices, result.mNumFaces, result.mIndices ); // the volume of the hull. // compute the best fit OBB computeBestFitOBB( result.mNumOutputVertices, result.mOutputVertices, sizeof(float)*3, r.mOBBSides, r.mOBBTransform ); r.mOBBVolume = r.mOBBSides[0] * r.mOBBSides[1] *r.mOBBSides[2]; // compute the OBB volume. fm_getTranslation( r.mOBBTransform, r.mOBBCenter ); // get the translation component of the 4x4 matrix. fm_matrixToQuat( r.mOBBTransform, r.mOBBOrientation ); // extract the orientation as a quaternion. r.mSphereRadius = computeBoundingSphere( result.mNumOutputVertices, result.mOutputVertices, r.mSphereCenter ); r.mSphereVolume = fm_sphereVolume( r.mSphereRadius ); mCallback->ConvexDecompResult(r); } hl.ReleaseResult (result); delete cr; } ret = mChulls.size(); mChulls.clear(); return ret; }