CHull * ConvexBuilder::canMerge(CHull *a,CHull *b) { if ( !a->overlap(*b) ) return 0; // if their AABB's (with a little slop) don't overlap, then return. CHull *ret = 0; // ok..we are going to combine both meshes into a single mesh // and then we are going to compute the concavity... VertexLookup vc = Vl_createVertexLookup(); UintVector indices; getMesh( *a->mResult, vc, indices ); getMesh( *b->mResult, vc, indices ); unsigned int vcount = Vl_getVcount(vc); const float *vertices = Vl_getVertices(vc); unsigned int tcount = indices.size()/3; //don't do anything if hull is empty if (!tcount) { Vl_releaseVertexLookup (vc); return 0; } HullResult hresult; HullLibrary hl; HullDesc desc; desc.SetHullFlag(QF_TRIANGLES); desc.mVcount = vcount; desc.mVertices = vertices; desc.mVertexStride = sizeof(float)*3; HullError hret = hl.CreateConvexHull(desc,hresult); if ( hret == QE_OK ) { float combineVolume = computeMeshVolume( hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices ); float sumVolume = a->mVolume + b->mVolume; float percent = (sumVolume*100) / combineVolume; if ( percent >= (100.0f-MERGE_PERCENT) ) { ConvexResult cr(hresult.mNumOutputVertices, hresult.mOutputVertices, hresult.mNumFaces, hresult.mIndices); ret = new CHull(cr); } } Vl_releaseVertexLookup(vc); return ret; }
void ConvexBuilder::getMesh(const ConvexResult &cr,VertexLookup vc,UintVector &indices) { unsigned int *src = cr.mHullIndices; for (unsigned int i=0; i<cr.mHullTcount; i++) { unsigned int i1 = *src++; unsigned int i2 = *src++; unsigned int i3 = *src++; const float *p1 = &cr.mHullVertices[i1*3]; const float *p2 = &cr.mHullVertices[i2*3]; const float *p3 = &cr.mHullVertices[i3*3]; i1 = Vl_getIndex(vc,p1); i2 = Vl_getIndex(vc,p2); i3 = Vl_getIndex(vc,p3); #if 0 bool duplicate = false; unsigned int tcount = indices.size()/3; for (unsigned int j=0; j<tcount; j++) { unsigned int ci1 = indices[j*3+0]; unsigned int ci2 = indices[j*3+1]; unsigned int ci3 = indices[j*3+2]; if ( isDuplicate(i1,i2,i3, ci1, ci2, ci3 ) ) { duplicate = true; break; } } if ( !duplicate ) { indices.push_back(i1); indices.push_back(i2); indices.push_back(i3); } #endif } }
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); } }