Пример #1
0
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;
}
Пример #2
0
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);
}
Пример #3
0
HullError HullLibrary::CreateConvexHull(const HullDesc       &desc,           // describes the input request
																					HullResult           &result)         // contains the resulst
{
	HullError ret = QE_FAIL;


	PHullResult hr;

	unsigned int vcount = desc.mVcount;
	if ( vcount < 8 ) vcount = 8;

	btAlignedObjectArray<btVector3> vertexSource;
	vertexSource.resize(static_cast<int>(vcount));

	btVector3 scale;

	unsigned int ovcount;

	bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates!

	if ( ok )
	{


//		if ( 1 ) // scale vertices back to their original size.
		{
			for (unsigned int i=0; i<ovcount; i++)
			{
				btVector3& v = vertexSource[static_cast<int>(i)];
				v[0]*=scale[0];
				v[1]*=scale[1];
				v[2]*=scale[2];
			}
		}

		ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices);

		if ( ok )
		{

			// re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table.
			btAlignedObjectArray<btVector3>	vertexScratch;
			vertexScratch.resize(static_cast<int>(hr.mVcount));

			BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount );

			ret = QE_OK;

			if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle!
			{
				result.mPolygons          = false;
				result.mNumOutputVertices = ovcount;
				result.m_OutputVertices.resize(static_cast<int>(ovcount));
				result.mNumFaces          = hr.mFaceCount;
				result.mNumIndices        = hr.mIndexCount;

				result.m_Indices.resize(static_cast<int>(hr.mIndexCount));

				memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );

  			if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
				{

					const unsigned int *source = &hr.m_Indices[0];
					unsigned int *dest   = &result.m_Indices[0];

					for (unsigned int i=0; i<hr.mFaceCount; i++)
					{
						dest[0] = source[2];
						dest[1] = source[1];
						dest[2] = source[0];
						dest+=3;
						source+=3;
					}

				}
				else
				{
					memcpy(&result.m_Indices[0], &hr.m_Indices[0], sizeof(unsigned int)*hr.mIndexCount);
				}
			}
			else
			{
				result.mPolygons          = true;
				result.mNumOutputVertices = ovcount;
				result.m_OutputVertices.resize(static_cast<int>(ovcount));
				result.mNumFaces          = hr.mFaceCount;
				result.mNumIndices        = hr.mIndexCount+hr.mFaceCount;
				result.m_Indices.resize(static_cast<int>(result.mNumIndices));
				memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount );

//				if ( 1 )
				{
					const unsigned int *source = &hr.m_Indices[0];
					unsigned int *dest   = &result.m_Indices[0];
					for (unsigned int i=0; i<hr.mFaceCount; i++)
					{
						dest[0] = 3;
						if ( desc.HasHullFlag(QF_REVERSE_ORDER) )
						{
							dest[1] = source[2];
							dest[2] = source[1];
							dest[3] = source[0];
						}
						else
						{
							dest[1] = source[0];
							dest[2] = source[1];
							dest[3] = source[2];
						}

						dest+=4;
						source+=3;
					}
				}
			}
			ReleaseHull(hr);
		}
	}

	return ret;
}
Пример #4
0
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);

	}
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
    //-----------------------------------------------------------------------
    //                          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);
    }