btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices, int nvertices, bool randomizeConstraints) { HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); HullResult hres; HullLibrary hlib;/*??*/ hdsc.mMaxVertices=nvertices; hlib.CreateConvexHull(hdsc,hres); btSoftBody* psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices, &hres.m_OutputVertices[0],0); for(int i=0;i<(int)hres.mNumFaces;++i) { const int idx[]={ hres.m_Indices[i*3+0], hres.m_Indices[i*3+1], hres.m_Indices[i*3+2]}; if(idx[0]<idx[1]) psb->appendLink( idx[0],idx[1]); if(idx[1]<idx[2]) psb->appendLink( idx[1],idx[2]); if(idx[2]<idx[0]) psb->appendLink( idx[2],idx[0]); psb->appendFace(idx[0],idx[1],idx[2]); } hlib.ReleaseResult(hres); if (randomizeConstraints) { psb->randomizeConstraints(); } return(psb); }
ChUll * doMerge(ChUll *a,ChUll *b) { ChUll *ret = 0; HaU32 combinedVertexCount = a->mVertexCount + b->mVertexCount; HaF32 *combinedVertices = (HaF32 *)HACD_ALLOC(combinedVertexCount*sizeof(HaF32)*3); HaF32 *dest = combinedVertices; memcpy(dest,a->mVertices, sizeof(HaF32)*3*a->mVertexCount); dest+=a->mVertexCount*3; memcpy(dest,b->mVertices,sizeof(HaF32)*3*b->mVertexCount); HullResult hresult; HullLibrary hl; HullDesc desc; desc.mVcount = combinedVertexCount; desc.mVertices = combinedVertices; desc.mVertexStride = sizeof(hacd::HaF32)*3; desc.mMaxVertices = mMaxHullVertices; desc.mUseWuQuantizer = true; HullError hret = hl.CreateConvexHull(desc,hresult); HACD_ASSERT( hret == QE_OK ); if ( hret == QE_OK ) { ret = HACD_NEW(ChUll)(hresult.mNumOutputVertices, hresult.mOutputVertices, hresult.mNumTriangles, hresult.mIndices,mGuid++); } HACD_FREE(combinedVertices); hl.ReleaseResult(hresult); return ret; }
float generateHull(void) { release(); if ( mPoints.size() >= 3 ) // must have at least 3 vertices to create a hull. { // now generate the convex hull. HullDesc desc((uint32_t)mPoints.size(),&mPoints[0].x, sizeof(float)*3); desc.mMaxVertices = 32; desc.mSkinWidth = 0.001f; HullLibrary h; HullResult result; HullError e = h.CreateConvexHull(desc,result); if ( e == QE_OK ) { mTriCount = result.mNumTriangles; mIndices = (uint32_t *)HACD_ALLOC(sizeof(uint32_t)*mTriCount*3); memcpy(mIndices,result.mIndices,sizeof(uint32_t)*mTriCount*3); mVertexCount = result.mNumOutputVertices; mVertices = (float *)HACD_ALLOC(sizeof(float)*mVertexCount*3); memcpy(mVertices,result.mOutputVertices,sizeof(float)*mVertexCount*3); mValidHull = true; mMeshVolume = fm_computeMeshVolume( mVertices, mTriCount, mIndices ); // compute the volume of this mesh. h.ReleaseResult(result); } } return mMeshVolume; }
HaF32 canMerge(ChUll *a,ChUll *b) { if ( !a->overlap(*b) ) return 0; // if their AABB's (with a little slop) don't overlap, then return. // ok..we are going to combine both meshes into a single mesh // and then we are going to compute the concavity... HaF32 ret = 0; HaU32 combinedVertexCount = a->mVertexCount + b->mVertexCount; HaF32 *combinedVertices = (HaF32 *)HACD_ALLOC(combinedVertexCount*sizeof(HaF32)*3); HaF32 *dest = combinedVertices; memcpy(dest,a->mVertices, sizeof(HaF32)*3*a->mVertexCount); dest+=a->mVertexCount*3; memcpy(dest,b->mVertices,sizeof(HaF32)*3*b->mVertexCount); HullResult hresult; HullLibrary hl; HullDesc desc; desc.mVcount = combinedVertexCount; desc.mVertices = combinedVertices; desc.mVertexStride = sizeof(hacd::HaF32)*3; desc.mUseWuQuantizer = true; HullError hret = hl.CreateConvexHull(desc,hresult); HACD_ASSERT( hret == QE_OK ); if ( hret == QE_OK ) { ret = fm_computeMeshVolume( hresult.mOutputVertices, hresult.mNumTriangles, hresult.mIndices ); } HACD_FREE(combinedVertices); hl.ReleaseResult(hresult); return ret; }
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 ChConvexHullLibraryWrapper::ComputeHull(const std::vector<ChVector<> >& points, geometry::ChTriangleMeshConnected& vshape) { HullLibrary hl; HullResult hresult; HullDesc desc; desc.SetHullFlag(QF_TRIANGLES); btVector3* btpoints = new btVector3[points.size()]; for (unsigned int ip = 0; ip < points.size(); ++ip) { btpoints[ip].setX((btScalar)points[ip].x()); btpoints[ip].setY((btScalar)points[ip].y()); btpoints[ip].setZ((btScalar)points[ip].z()); } desc.mVcount = (unsigned int)points.size(); desc.mVertices = btpoints; desc.mVertexStride = sizeof(btVector3); HullError hret = hl.CreateConvexHull(desc, hresult); if (hret == QE_OK) { vshape.Clear(); vshape.getIndicesVertexes().resize(hresult.mNumFaces); for (unsigned int it = 0; it < hresult.mNumFaces; ++it) { vshape.getIndicesVertexes()[it] = ChVector<int>( hresult.m_Indices[it * 3 + 0], hresult.m_Indices[it * 3 + 1], hresult.m_Indices[it * 3 + 2]); } vshape.getCoordsVertices().resize(hresult.mNumOutputVertices); for (unsigned int iv = 0; iv < hresult.mNumOutputVertices; ++iv) { vshape.getCoordsVertices()[iv] = ChVector<>( hresult.m_OutputVertices[iv].x(), hresult.m_OutputVertices[iv].y(), hresult.m_OutputVertices[iv].z()); } } delete[] btpoints; hl.ReleaseResult(hresult); }
bool btShapeHull::buildHull (btScalar /*margin*/) { int numSampleDirections = NUM_UNITSPHERE_POINTS; { int numPDA = m_shape->getNumPreferredPenetrationDirections(); if (numPDA) { for (int i=0;i<numPDA;i++) { btVector3 norm; m_shape->getPreferredPenetrationDirection(i,norm); getUnitSpherePoints()[numSampleDirections] = norm; numSampleDirections++; } } } btVector3 supportPoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; int i; for (i = 0; i < numSampleDirections; i++) { supportPoints[i] = m_shape->localGetSupportingVertex(getUnitSpherePoints()[i]); } HullDesc hd; hd.mFlags = QF_TRIANGLES; hd.mVcount = static_cast<unsigned int>(numSampleDirections); #ifdef BT_USE_DOUBLE_PRECISION hd.mVertices = &supportPoints[0]; hd.mVertexStride = sizeof(btVector3); #else hd.mVertices = &supportPoints[0]; hd.mVertexStride = sizeof (btVector3); #endif HullLibrary hl; HullResult hr; if (hl.CreateConvexHull (hd, hr) == QE_FAIL) { return false; } m_vertices.resize (static_cast<int>(hr.mNumOutputVertices)); for (i = 0; i < static_cast<int>(hr.mNumOutputVertices); i++) { m_vertices[i] = hr.m_OutputVertices[i]; } m_numIndices = hr.mNumIndices; m_indices.resize(static_cast<int>(m_numIndices)); for (i = 0; i < static_cast<int>(m_numIndices); i++) { m_indices[i] = hr.m_Indices[i]; } // free temporary hull result that we just copied hl.ReleaseResult (hr); return true; }
void btSoftBodyHelpers::Draw( btSoftBody* psb, btIDebugDraw* idraw, int drawflags) { const btScalar scl=(btScalar)0.1; const btScalar nscl=scl*5; const btVector3 lcolor=btVector3(0,0,0); const btVector3 ncolor=btVector3(1,1,1); const btVector3 ccolor=btVector3(1,0,0); int i,j,nj; /* Nodes */ if(0!=(drawflags&fDrawFlags::Nodes)) { for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0)); idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0)); idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1)); } } /* Links */ if(0!=(drawflags&fDrawFlags::Links)) { for(i=0;i<psb->m_links.size();++i) { const btSoftBody::Link& l=psb->m_links[i]; if(0==(l.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,lcolor); } } /* Normals */ if(0!=(drawflags&fDrawFlags::Normals)) { for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 d=n.m_n*nscl; idraw->drawLine(n.m_x,n.m_x+d,ncolor); idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5); } } /* Contacts */ if(0!=(drawflags&fDrawFlags::Contacts)) { static const btVector3 axis[]={btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1)}; for(i=0;i<psb->m_rcontacts.size();++i) { const btSoftBody::RContact& c=psb->m_rcontacts[i]; const btVector3 o= c.m_node->m_x-c.m_cti.m_normal* (dot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset); const btVector3 x=cross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized(); const btVector3 y=cross(x,c.m_cti.m_normal).normalized(); idraw->drawLine(o-x*nscl,o+x*nscl,ccolor); idraw->drawLine(o-y*nscl,o+y*nscl,ccolor); idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0)); } } /* Anchors */ if(0!=(drawflags&fDrawFlags::Anchors)) { for(i=0;i<psb->m_anchors.size();++i) { const btSoftBody::Anchor& a=psb->m_anchors[i]; const btVector3 q=a.m_body->getWorldTransform()*a.m_local; drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0)); drawVertex(idraw,q,0.25,btVector3(0,1,0)); idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1)); } for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; if(n.m_im<=0) { drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0)); } } } /* Faces */ if(0!=(drawflags&fDrawFlags::Faces)) { const btScalar scl=(btScalar)0.8; const btScalar alp=(btScalar)1; const btVector3 col(0,(btScalar)0.7,0); for(i=0;i<psb->m_faces.size();++i) { const btSoftBody::Face& f=psb->m_faces[i]; if(0==(f.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x}; const btVector3 c=(x[0]+x[1]+x[2])/3; idraw->drawTriangle((x[0]-c)*scl+c, (x[1]-c)*scl+c, (x[2]-c)*scl+c, col,alp); } } /* Clusters */ if(0!=(drawflags&fDrawFlags::Clusters)) { srand(1806); for(i=0;i<psb->m_clusters.size();++i) { if(psb->m_clusters[i]->m_collide) { btVector3 color( rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX); color=color.normalized()*0.75; btAlignedObjectArray<btVector3> vertices; vertices.resize(psb->m_clusters[i]->m_nodes.size()); for(j=0,nj=vertices.size();j<nj;++j) { vertices[j]=psb->m_clusters[i]->m_nodes[j]->m_x; } HullDesc hdsc(QF_TRIANGLES,vertices.size(),&vertices[0]); HullResult hres; HullLibrary hlib; hdsc.mMaxVertices=vertices.size(); hlib.CreateConvexHull(hdsc,hres); const btVector3 center=average(hres.m_OutputVertices); add(hres.m_OutputVertices,-center); mul(hres.m_OutputVertices,(btScalar)1); add(hres.m_OutputVertices,center); for(j=0;j<(int)hres.mNumFaces;++j) { const int idx[]={hres.m_Indices[j*3+0],hres.m_Indices[j*3+1],hres.m_Indices[j*3+2]}; idraw->drawTriangle(hres.m_OutputVertices[idx[0]], hres.m_OutputVertices[idx[1]], hres.m_OutputVertices[idx[2]], color,1); } hlib.ReleaseResult(hres); } /* Velocities */ #if 0 for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j) { const btSoftBody::Cluster& c=psb->m_clusters[i]; const btVector3 r=c.m_nodes[j]->m_x-c.m_com; const btVector3 v=c.m_lv+cross(c.m_av,r); idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0)); } #endif /* Frame */ btSoftBody::Cluster& c=*psb->m_clusters[i]; idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0)); idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0)); idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1)); } } /* Notes */ if(0!=(drawflags&fDrawFlags::Notes)) { for(i=0;i<psb->m_notes.size();++i) { const btSoftBody::Note& n=psb->m_notes[i]; btVector3 p=n.m_offset; for(int j=0;j<n.m_rank;++j) { p+=n.m_nodes[j]->m_x*n.m_coords[j]; } idraw->draw3dText(p,n.m_text); } } /* Node tree */ if(0!=(drawflags&fDrawFlags::NodeTree)) DrawNodeTree(psb,idraw); /* Face tree */ if(0!=(drawflags&fDrawFlags::FaceTree)) DrawFaceTree(psb,idraw); /* Cluster tree */ if(0!=(drawflags&fDrawFlags::ClusterTree)) DrawClusterTree(psb,idraw); /* Joints */ if(0!=(drawflags&fDrawFlags::Joints)) { for(i=0;i<psb->m_joints.size();++i) { const btSoftBody::Joint* pj=psb->m_joints[i]; switch(pj->Type()) { case btSoftBody::Joint::eType::Linear: { const btSoftBody::LJoint* pjl=(const btSoftBody::LJoint*)pj; const btVector3 a0=pj->m_bodies[0].xform()*pjl->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform()*pjl->m_refs[1]; idraw->drawLine(pj->m_bodies[0].xform().getOrigin(),a0,btVector3(1,1,0)); idraw->drawLine(pj->m_bodies[1].xform().getOrigin(),a1,btVector3(0,1,1)); drawVertex(idraw,a0,0.25,btVector3(1,1,0)); drawVertex(idraw,a1,0.25,btVector3(0,1,1)); } break; case btSoftBody::Joint::eType::Angular: { const btSoftBody::AJoint* pja=(const btSoftBody::AJoint*)pj; const btVector3 o0=pj->m_bodies[0].xform().getOrigin(); const btVector3 o1=pj->m_bodies[1].xform().getOrigin(); const btVector3 a0=pj->m_bodies[0].xform().getBasis()*pj->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform().getBasis()*pj->m_refs[1]; idraw->drawLine(o0,o0+a0*10,btVector3(1,1,0)); idraw->drawLine(o0,o0+a1*10,btVector3(1,1,0)); idraw->drawLine(o1,o1+a0*10,btVector3(0,1,1)); idraw->drawLine(o1,o1+a1*10,btVector3(0,1,1)); } } } } }
void btSoftBodyHelpers::Draw( btSoftBody* psb, btIDebugDraw* idraw, int drawflags) { const btScalar scl=(btScalar)0.1; const btScalar nscl=scl*5; const btVector3 lcolor=btVector3(0,0,0); const btVector3 ncolor=btVector3(1,1,1); const btVector3 ccolor=btVector3(1,0,0); int i,j,nj; /* Clusters */ if(0!=(drawflags&fDrawFlags::Clusters)) { srand(1806); for(i=0;i<psb->m_clusters.size();++i) { if(psb->m_clusters[i]->m_collide) { btVector3 color( rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX); color=color.normalized()*0.75; btAlignedObjectArray<btVector3> vertices; vertices.resize(psb->m_clusters[i]->m_nodes.size()); for(j=0,nj=vertices.size();j<nj;++j) { vertices[j]=psb->m_clusters[i]->m_nodes[j]->m_x; } #define USE_NEW_CONVEX_HULL_COMPUTER #ifdef USE_NEW_CONVEX_HULL_COMPUTER btConvexHullComputer computer; int stride = sizeof(btVector3); int count = vertices.size(); btScalar shrink=0.f; btScalar shrinkClamp=0.f; computer.compute(&vertices[0].getX(),stride,count,shrink,shrinkClamp); for (int i=0;i<computer.faces.size();i++) { int face = computer.faces[i]; //printf("face=%d\n",face); const btConvexHullComputer::Edge* firstEdge = &computer.edges[face]; const btConvexHullComputer::Edge* edge = firstEdge->getNextEdgeOfFace(); int v0 = firstEdge->getSourceVertex(); int v1 = firstEdge->getTargetVertex(); while (edge!=firstEdge) { int v2 = edge->getTargetVertex(); idraw->drawTriangle(computer.vertices[v0],computer.vertices[v1],computer.vertices[v2],color,1); edge = edge->getNextEdgeOfFace(); v0=v1; v1=v2; }; } #else HullDesc hdsc(QF_TRIANGLES,vertices.size(),&vertices[0]); HullResult hres; HullLibrary hlib; hdsc.mMaxVertices=vertices.size(); hlib.CreateConvexHull(hdsc,hres); const btVector3 center=average(hres.m_OutputVertices); add(hres.m_OutputVertices,-center); mul(hres.m_OutputVertices,(btScalar)1); add(hres.m_OutputVertices,center); for(j=0;j<(int)hres.mNumFaces;++j) { const int idx[]={hres.m_Indices[j*3+0],hres.m_Indices[j*3+1],hres.m_Indices[j*3+2]}; idraw->drawTriangle(hres.m_OutputVertices[idx[0]], hres.m_OutputVertices[idx[1]], hres.m_OutputVertices[idx[2]], color,1); } hlib.ReleaseResult(hres); #endif } /* Velocities */ #if 0 for(int j=0;j<psb->m_clusters[i].m_nodes.size();++j) { const btSoftBody::Cluster& c=psb->m_clusters[i]; const btVector3 r=c.m_nodes[j]->m_x-c.m_com; const btVector3 v=c.m_lv+btCross(c.m_av,r); idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0)); } #endif /* Frame */ // btSoftBody::Cluster& c=*psb->m_clusters[i]; // idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0)); // idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0)); // idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1)); } } else { /* Nodes */ if(0!=(drawflags&fDrawFlags::Nodes)) { for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0)); idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0)); idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1)); } } /* Links */ if(0!=(drawflags&fDrawFlags::Links)) { for(i=0;i<psb->m_links.size();++i) { const btSoftBody::Link& l=psb->m_links[i]; if(0==(l.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,lcolor); } } /* Normals */ if(0!=(drawflags&fDrawFlags::Normals)) { for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 d=n.m_n*nscl; idraw->drawLine(n.m_x,n.m_x+d,ncolor); idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5); } } /* Contacts */ if(0!=(drawflags&fDrawFlags::Contacts)) { static const btVector3 axis[]={btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1)}; for(i=0;i<psb->m_rcontacts.size();++i) { const btSoftBody::RContact& c=psb->m_rcontacts[i]; const btVector3 o= c.m_node->m_x-c.m_cti.m_normal* (btDot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset); const btVector3 x=btCross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized(); const btVector3 y=btCross(x,c.m_cti.m_normal).normalized(); idraw->drawLine(o-x*nscl,o+x*nscl,ccolor); idraw->drawLine(o-y*nscl,o+y*nscl,ccolor); idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0)); } } /* Faces */ if(0!=(drawflags&fDrawFlags::Faces)) { const btScalar scl=(btScalar)0.8; const btScalar alp=(btScalar)1; const btVector3 col(0,(btScalar)0.7,0); for(i=0;i<psb->m_faces.size();++i) { const btSoftBody::Face& f=psb->m_faces[i]; if(0==(f.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x}; const btVector3 c=(x[0]+x[1]+x[2])/3; idraw->drawTriangle((x[0]-c)*scl+c, (x[1]-c)*scl+c, (x[2]-c)*scl+c, col,alp); } } /* Tetras */ if(0!=(drawflags&fDrawFlags::Tetras)) { const btScalar scl=(btScalar)0.8; const btScalar alp=(btScalar)1; const btVector3 col((btScalar)0.3,(btScalar)0.3,(btScalar)0.7); for(int i=0;i<psb->m_tetras.size();++i) { const btSoftBody::Tetra& t=psb->m_tetras[i]; if(0==(t.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 x[]={t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x}; const btVector3 c=(x[0]+x[1]+x[2]+x[3])/4; idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[2]-c)*scl+c,col,alp); idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[3]-c)*scl+c,col,alp); idraw->drawTriangle((x[1]-c)*scl+c,(x[2]-c)*scl+c,(x[3]-c)*scl+c,col,alp); idraw->drawTriangle((x[2]-c)*scl+c,(x[0]-c)*scl+c,(x[3]-c)*scl+c,col,alp); } } } /* Anchors */ if(0!=(drawflags&fDrawFlags::Anchors)) { for(i=0;i<psb->m_anchors.size();++i) { const btSoftBody::Anchor& a=psb->m_anchors[i]; const btVector3 q=a.m_body->getWorldTransform()*a.m_local; drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0)); drawVertex(idraw,q,0.25,btVector3(0,1,0)); idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1)); } for(i=0;i<psb->m_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; if(n.m_im<=0) { drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0)); } } } /* Notes */ if(0!=(drawflags&fDrawFlags::Notes)) { for(i=0;i<psb->m_notes.size();++i) { const btSoftBody::Note& n=psb->m_notes[i]; btVector3 p=n.m_offset; for(int j=0;j<n.m_rank;++j) { p+=n.m_nodes[j]->m_x*n.m_coords[j]; } idraw->draw3dText(p,n.m_text); } } /* Node tree */ if(0!=(drawflags&fDrawFlags::NodeTree)) DrawNodeTree(psb,idraw); /* Face tree */ if(0!=(drawflags&fDrawFlags::FaceTree)) DrawFaceTree(psb,idraw); /* Cluster tree */ if(0!=(drawflags&fDrawFlags::ClusterTree)) DrawClusterTree(psb,idraw); /* Joints */ if(0!=(drawflags&fDrawFlags::Joints)) { for(i=0;i<psb->m_joints.size();++i) { const btSoftBody::Joint* pj=psb->m_joints[i]; switch(pj->Type()) { case btSoftBody::Joint::eType::Linear: { const btSoftBody::LJoint* pjl=(const btSoftBody::LJoint*)pj; const btVector3 a0=pj->m_bodies[0].xform()*pjl->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform()*pjl->m_refs[1]; idraw->drawLine(pj->m_bodies[0].xform().getOrigin(),a0,btVector3(1,1,0)); idraw->drawLine(pj->m_bodies[1].xform().getOrigin(),a1,btVector3(0,1,1)); drawVertex(idraw,a0,0.25,btVector3(1,1,0)); drawVertex(idraw,a1,0.25,btVector3(0,1,1)); } break; case btSoftBody::Joint::eType::Angular: { //const btSoftBody::AJoint* pja=(const btSoftBody::AJoint*)pj; const btVector3 o0=pj->m_bodies[0].xform().getOrigin(); const btVector3 o1=pj->m_bodies[1].xform().getOrigin(); const btVector3 a0=pj->m_bodies[0].xform().getBasis()*pj->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform().getBasis()*pj->m_refs[1]; idraw->drawLine(o0,o0+a0*10,btVector3(1,1,0)); idraw->drawLine(o0,o0+a1*10,btVector3(1,1,0)); idraw->drawLine(o1,o1+a0*10,btVector3(0,1,1)); idraw->drawLine(o1,o1+a1*10,btVector3(0,1,1)); break; } default: { } } } } }
bool createHull(unsigned int vcount, const float *points,NxuGeometry &g,const NxMat34 *localPose,NxReal shrink,unsigned int maxv) { bool ret = false; g.reset(); HullLibrary hl; HullDesc desc(QF_TRIANGLES, vcount, points, sizeof(float) *3); desc.mMaxVertices = maxv; HullResult result; HullError err = hl.CreateConvexHull(desc, result); if (err == QE_OK) { ret = true; g.mVertices = new float[result.mNumOutputVertices *3]; float bmin[3]; float bmax[3]; computeAABB( result.mNumOutputVertices, result.mOutputVertices, sizeof(float)*3, bmin, bmax ); NxVec3 center; center.x = (bmax[0]-bmin[0])*0.5f + bmin[0]; center.y = (bmax[1]-bmin[1])*0.5f + bmin[1]; center.z = (bmax[2]-bmin[2])*0.5f + bmin[2]; const float *source = result.mOutputVertices; float *dest = g.mVertices; for (NxU32 i=0; i<result.mNumOutputVertices; i++) { NxVec3 v(source[0],source[1],source[2]); v-=center; v*=shrink; v+=center; if ( localPose ) { NxVec3 t; localPose->multiply(v,t); v = t; } dest[0] = v.x; dest[1] = v.y; dest[2] = v.z; source+=3; dest+=3; } g.mIndices = new unsigned int[result.mNumIndices]; memcpy(g.mIndices, result.mIndices, sizeof(unsigned int) *result.mNumIndices); g.mVcount = result.mNumOutputVertices; g.mTcount = result.mNumFaces; hl.ReleaseResult(result); } return ret; }
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; }
float computeConcavity(unsigned int vcount, const float *vertices, unsigned int tcount, const unsigned int *indices, ConvexDecompInterface *callback, float *plane, // plane equation to split on float &volume) { float cret = 0; volume = 1; HullResult result; HullLibrary hl; HullDesc desc; desc.mMaxFaces = 256; desc.mMaxVertices = 256; 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 ) { #if 0 float bmin[3]; float bmax[3]; float dx = bmax[0] - bmin[0]; float dy = bmax[1] - bmin[1]; float dz = bmax[2] - bmin[2]; Vector3d center; center.x = bmin[0] + dx*0.5f; center.y = bmin[1] + dy*0.5f; center.z = bmin[2] + dz*0.5f; #endif volume = computeMeshVolume2( result.mOutputVertices, result.mNumFaces, result.mIndices ); #if 1 // ok..now..for each triangle on the original mesh.. // we extrude the points to the nearest point on the hull. const unsigned int *source = result.mIndices; CTriVector tris; for (unsigned int i=0; i<result.mNumFaces; i++) { unsigned int i1 = *source++; unsigned int i2 = *source++; unsigned int i3 = *source++; const float *p1 = &result.mOutputVertices[i1*3]; const float *p2 = &result.mOutputVertices[i2*3]; const float *p3 = &result.mOutputVertices[i3*3]; // callback->ConvexDebugTri(p1,p2,p3,0xFFFFFF); CTri t(p1,p2,p3,i1,i2,i3); // tris.push_back(t); } // we have not pre-computed the plane equation for each triangle in the convex hull.. float totalVolume = 0; CTriVector ftris; // 'feature' triangles. const unsigned int *src = indices; float maxc=0; if ( 1 ) { CTriVector input_mesh; if ( 1 ) { const unsigned int *src = indices; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *src++; unsigned int i2 = *src++; unsigned int i3 = *src++; const float *p1 = &vertices[i1*3]; const float *p2 = &vertices[i2*3]; const float *p3 = &vertices[i3*3]; CTri t(p1,p2,p3,i1,i2,i3); input_mesh.push_back(t); } } CTri maxctri; for (unsigned int i=0; i<tcount; i++) { unsigned int i1 = *src++; unsigned int i2 = *src++; unsigned int i3 = *src++; const float *p1 = &vertices[i1*3]; const float *p2 = &vertices[i2*3]; const float *p3 = &vertices[i3*3]; CTri t(p1,p2,p3,i1,i2,i3); featureMatch(t, tris, callback, input_mesh ); if ( t.mConcavity > CONCAVE_THRESH ) { if ( t.mConcavity > maxc ) { maxc = t.mConcavity; maxctri = t; } float v = t.getVolume(0); totalVolume+=v; ftris.push_back(t); } } } if ( ftris.size() ) { // ok..now we extract the triangles which form the maximum concavity. CTriVector major_feature; float maxarea = 0; while ( maxc > CONCAVE_THRESH ) { unsigned int color = getDebugColor(); // CTriVector flist; bool found; float totalarea = 0; do { found = false; CTriVector::iterator i; for (i=ftris.begin(); i!=ftris.end(); ++i) { CTri &t = (*i); if ( isFeatureTri(t,flist,maxc,callback,color) ) { found = true; totalarea+=t.area(); } } } while ( found ); if ( totalarea > maxarea ) { major_feature = flist; maxarea = totalarea; } maxc = 0; for (unsigned int i=0; i<ftris.size(); i++) { CTri &t = ftris[i]; if ( t.mProcessed != 2 ) { t.mProcessed = 0; if ( t.mConcavity > maxc ) { maxc = t.mConcavity; } } } } unsigned int color = getDebugColor(); WpointVector list; for (unsigned int i=0; i<major_feature.size(); ++i) { major_feature[i].addWeighted(list,callback); major_feature[i].debug(color,callback); } getBestFitPlane( list.size(), &list[0].mPoint.x, sizeof(Wpoint), &list[0].mWeight, sizeof(Wpoint), plane ); computeSplitPlane( vcount, vertices, tcount, indices, callback, plane ); } else { computeSplitPlane( vcount, vertices, tcount, indices, callback, plane ); } #endif cret = totalVolume; hl.ReleaseResult(result); } return cret; }
MStatus DDConvexHullUtils::generateMayaHull(MObject &output, const MPointArray &vertices, const DDConvexHullUtils::hullOpts &hullOptions) { // Allocate and push the vert list into the new array Mem Cleanup req. uint numInputVerts = vertices.length(); double *inputVerts = new double[numInputVerts*3]; for (uint i=0; i < numInputVerts; i++) { uint offset = i*3; inputVerts[offset] = vertices[i].x; inputVerts[offset+1] = vertices[i].y; inputVerts[offset+2] = vertices[i].z; } // Setup the flags uint hullFlags = QF_DEFAULT; if (hullOptions.forceTriangles) { hullFlags |= QF_TRIANGLES; } if (hullOptions.useSkinWidth) { hullFlags |= QF_SKIN_WIDTH; } if (hullOptions.reverseTriangleOrder) { hullFlags |= QF_REVERSE_ORDER; } // Create the description HullDesc hullDescription; hullDescription.mFlags = hullFlags; hullDescription.mMaxVertices = hullOptions.maxOutputVertices; hullDescription.mSkinWidth = hullOptions.skinWidth; hullDescription.mNormalEpsilon = hullOptions.normalEpsilon; hullDescription.mVertexStride = sizeof(double)*3; hullDescription.mVcount = numInputVerts; hullDescription.mVertices = inputVerts; // Create the hull HullLibrary hullComputer; HullResult hullResult; HullError err = hullComputer.CreateConvexHull(hullDescription, hullResult); MStatus hullStat = MStatus::kSuccess; if (err == QE_OK) { // Grab the verts MPointArray outPoints; for (uint i=0; i < hullResult.mNumOutputVertices; i++) { uint offset = i*3; MPoint curPoint(hullResult.mOutputVertices[offset], hullResult.mOutputVertices[offset+1], hullResult.mOutputVertices[offset+2]); outPoints.append(curPoint); } // Check if the results are in polygons, or triangles. Depending on // which for the result is in, the way the face indices are setup // is different. MIntArray polyCounts; MIntArray vertexConnects; if (hullResult.mPolygons) { const uint *idx = hullResult.mIndices; for (uint i=0; i < hullResult.mNumFaces; i++) { uint pCount = *idx++; polyCounts.append(pCount); for (uint j=0; j < pCount; j++) { uint val = idx[0]; vertexConnects.append(val); idx++; } } } else { polyCounts.setLength(hullResult.mNumFaces); for (uint i=0; i < hullResult.mNumFaces; i++) { polyCounts[i] = 3; uint *idx = &hullResult.mIndices[i*3]; vertexConnects.append(idx[0]); vertexConnects.append(idx[1]); vertexConnects.append(idx[2]); } } // Setup the outmesh MFnMesh outMeshFn(output); outMeshFn.create(hullResult.mNumOutputVertices, hullResult.mNumFaces, outPoints, polyCounts, vertexConnects, output, &hullStat); } else { hullStat = MStatus::kFailure; } // Mem Cleanup hullComputer.ReleaseResult(hullResult); delete[] inputVerts; return hullStat; }
//----------------------------------------------------------------------- // T M e s h S h a p e //----------------------------------------------------------------------- TMeshShape::TMeshShape(IMesh* mesh, const matrix4& transform, bool isConvex) : TCollisionShape(), m_baseCount(0), m_hullCount(0) { TApplication* app = getApplication(); app->logMessage(LOG_INFO, "TMeshShape isConvex: %d", isConvex); u32 vcount=0, tcount=0; for(u32 i=0; i<mesh->getMeshBufferCount(); i++) { tcount += mesh->getMeshBuffer(i)->getIndexCount() / 3; vcount += mesh->getMeshBuffer(i)->getVertexCount(); } app->logMessage(LOG_INFO, " org vert count: %d", vcount); app->logMessage(LOG_INFO, " org tri count: %d", tcount); btQuaternion q(TMath::HALF_PI,0.f,0.f); m_localTransform = transform; m_localScale = transform.getScale(); m_triMesh = extractTriangles(mesh, true); app->logMessage(LOG_INFO, " ext tri count: %d", m_triMesh->getNumTriangles()); if(isConvex) { if(1) { // using Bullet's btShapeHull class - faster, typically produces less verts/tris btConvexShape* tmpConvexShape = new btConvexTriangleMeshShape(m_triMesh); m_shape = tmpConvexShape; btShapeHull* hull = new btShapeHull(tmpConvexShape); btScalar margin = tmpConvexShape->getMargin(); hull->buildHull(margin); tmpConvexShape->setUserPointer(hull); app->logMessage(LOG_INFO, " hull vert count: %d", hull->numVertices()); app->logMessage(LOG_INFO, " hull tri count: %d", hull->numTriangles()); //btConvexHullShape* chShape = new btConvexHullShape((const btScalar *)hull->getVertexPointer(),hull->numVertices()); btConvexHullShape* chShape = new btConvexHullShape(); const btVector3* vp = hull->getVertexPointer(); const unsigned int* ip = hull->getIndexPointer(); for (int i=0;i<hull->numTriangles();i++) { chShape->addPoint(vp[ip[i*3]]); chShape->addPoint(vp[ip[i*3+1]]); chShape->addPoint(vp[ip[i*3+2]]); } m_shape = chShape; delete hull; delete tmpConvexShape; } else { // using Bullet's hull library directly HullResult result; HullLibrary hl; HullDesc desc; desc.mMaxFaces = 256; desc.mMaxVertices = 256; desc.SetHullFlag(QF_TRIANGLES); PHY_ScalarType type, indicestype; const unsigned char* indexbase; int istride,numfaces; m_triMesh->getLockedReadOnlyVertexIndexBase((const unsigned char**)&desc.mVertices, (int&)desc.mVcount, type, (int&)desc.mVertexStride, &indexbase, istride, numfaces, indicestype); HullError ret = hl.CreateConvexHull(desc,result); if(ret == QE_OK) { app->logMessage(LOG_INFO, " hull vert count: %d", result.mNumOutputVertices); app->logMessage(LOG_INFO, " hull tri count: %d", result.mNumFaces); btConvexHullShape* chShape = new btConvexHullShape(); for (unsigned int i=0;i<result.mNumFaces;i++) { chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3]]); chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3+1]]); chShape->addPoint(result.m_OutputVertices[result.m_Indices[i*3+2]]); } m_shape = chShape; } else { m_shape = new btBvhTriangleMeshShape(m_triMesh,true,true); } hl.ReleaseResult(result); } } else { //m_shape = _decomposeTriMesh(); m_shape = new btBvhTriangleMeshShape(m_triMesh,true,true); } btVector3 scale(m_localScale.X, m_localScale.Y, m_localScale.Z); m_shape->setLocalScaling(scale); }