aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp
downloadphysx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz
physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip
Initial commit:
PhysX 3.4.0 Update @ 21294896 APEX 1.4.0 Update @ 21275617 [CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp')
-rw-r--r--PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp504
1 files changed, 504 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp b/PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp
new file mode 100644
index 00000000..5fb356c3
--- /dev/null
+++ b/PhysX_3.4/Source/PhysXCooking/src/convex/ConvexMeshBuilder.cpp
@@ -0,0 +1,504 @@
+// This code contains NVIDIA Confidential Information and is disclosed to you
+// under a form of NVIDIA software license agreement provided separately to you.
+//
+// Notice
+// NVIDIA Corporation and its licensors retain all intellectual property and
+// proprietary rights in and to this software and related documentation and
+// any modifications thereto. Any use, reproduction, disclosure, or
+// distribution of this software and related documentation without an express
+// license agreement from NVIDIA Corporation is strictly prohibited.
+//
+// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES
+// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO
+// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT,
+// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Information and code furnished is believed to be accurate and reliable.
+// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such
+// information or for any infringement of patents or other rights of third parties that may
+// result from its use. No license is granted by implication or otherwise under any patent
+// or patent rights of NVIDIA Corporation. Details are subject to change without notice.
+// This code supersedes and replaces all information previously supplied.
+// NVIDIA Corporation products are not authorized for use as critical
+// components in life support devices or systems without express written approval of
+// NVIDIA Corporation.
+//
+// Copyright (c) 2008-2016 NVIDIA Corporation. All rights reserved.
+// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+
+#include "GuConvexMesh.h"
+#include "PsFoundation.h"
+#include "PsMathUtils.h"
+#include "Cooking.h"
+
+#include "GuHillClimbing.h"
+#include "GuBigConvexData2.h"
+#include "GuInternal.h"
+#include "GuSerialize.h"
+#include "VolumeIntegration.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#include "VolumeIntegration.h"
+#include "ConvexHullBuilder.h"
+#include "ConvexMeshBuilder.h"
+#include "BigConvexDataBuilder.h"
+
+#include "CmUtils.h"
+#include "PsVecMath.h"
+
+using namespace physx;
+using namespace Gu;
+using namespace Ps::aos;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ConvexMeshBuilder::ConvexMeshBuilder(const bool buildGRBData) : hullBuilder(&mHullData, buildGRBData), mBigConvexData(NULL), mMass(0.0f), mInertia(PxIdentity)
+{
+}
+
+ConvexMeshBuilder::~ConvexMeshBuilder()
+{
+ PX_DELETE_AND_RESET(mBigConvexData);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// load the mesh data from given polygons
+bool ConvexMeshBuilder::build(const PxConvexMeshDesc& desc, PxU32 gaussMapVertexLimit, bool validateOnly, bool userPolygons)
+{
+ if(!desc.isValid())
+ {
+ Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "Gu::ConvexMesh::loadFromDesc: desc.isValid() failed!");
+ return false;
+ }
+
+ if(!loadConvexHull(desc, gaussMapVertexLimit, userPolygons))
+ return false;
+
+ // Compute local bounds (*after* hull has been created)
+ PxBounds3 minMaxBounds;
+ computeBoundsAroundVertices(minMaxBounds, mHullData.mNbHullVertices, hullBuilder.mHullDataHullVertices);
+ mHullData.mAABB = CenterExtents(minMaxBounds);
+
+ if(mHullData.mNbHullVertices > gaussMapVertexLimit)
+ {
+ if(!computeGaussMaps())
+ {
+ return false;
+ }
+ }
+
+ if(validateOnly)
+ return true;
+
+// TEST_INTERNAL_OBJECTS
+ computeInternalObjects();
+//~TEST_INTERNAL_OBJECTS
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+PX_COMPILE_TIME_ASSERT(sizeof(PxMaterialTableIndex)==sizeof(PxU16));
+bool ConvexMeshBuilder::save(PxOutputStream& stream, bool platformMismatch) const
+{
+ // Export header
+ if(!writeHeader('C', 'V', 'X', 'M', PX_CONVEX_VERSION, platformMismatch, stream))
+ return false;
+
+ // Export serialization flags
+ PxU32 serialFlags = 0;
+
+ writeDword(serialFlags, platformMismatch, stream);
+
+ if(!hullBuilder.save(stream, platformMismatch))
+ return false;
+
+ // Export local bounds
+// writeFloat(geomEpsilon, platformMismatch, stream);
+ writeFloat(0.0f, platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMin(0), platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMin(1), platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMin(2), platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMax(0), platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMax(1), platformMismatch, stream);
+ writeFloat(mHullData.mAABB.getMax(2), platformMismatch, stream);
+
+ // Export mass info
+ writeFloat(mMass, platformMismatch, stream);
+ writeFloatBuffer(reinterpret_cast<const PxF32*>(&mInertia), 9, platformMismatch, stream);
+ writeFloatBuffer(&mHullData.mCenterOfMass.x, 3, platformMismatch, stream);
+
+ // Export gaussmaps
+ if(mBigConvexData)
+ {
+ writeFloat(1.0f, platformMismatch, stream); //gauss map flag true
+ BigConvexDataBuilder SVMB(&mHullData, mBigConvexData, hullBuilder.mHullDataHullVertices);
+ SVMB.save(stream, platformMismatch);
+ }
+ else
+ writeFloat(-1.0f, platformMismatch, stream); //gauss map flag false
+
+// TEST_INTERNAL_OBJECTS
+ writeFloat(mHullData.mInternal.mRadius, platformMismatch, stream);
+ writeFloat(mHullData.mInternal.mExtents[0], platformMismatch, stream);
+ writeFloat(mHullData.mInternal.mExtents[1], platformMismatch, stream);
+ writeFloat(mHullData.mInternal.mExtents[2], platformMismatch, stream);
+//~TEST_INTERNAL_OBJECTS
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////////
+// instead of saving the data into stream, we copy the mesh data
+// into internal Gu::ConvexMesh.
+bool ConvexMeshBuilder::copy(Gu::ConvexHullData& hullData)
+{
+ // hull builder data copy
+ hullBuilder.copy(hullData);
+
+ // mass props
+ hullData.mAABB = mHullData.mAABB;
+ hullData.mCenterOfMass = mHullData.mCenterOfMass;
+
+ // big convex data
+ if(mBigConvexData)
+ {
+ hullData.mBigConvexRawData = &mBigConvexData->mData;
+ }
+ else
+ hullData.mBigConvexRawData = NULL;
+
+ // internal data
+ hullData.mInternal.mRadius = mHullData.mInternal.mRadius;
+ hullData.mInternal.mExtents[0] = mHullData.mInternal.mExtents[0];
+ hullData.mInternal.mExtents[1] = mHullData.mInternal.mExtents[1];
+ hullData.mInternal.mExtents[2] = mHullData.mInternal.mExtents[2];
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// compute mass and inertia of the convex mesh
+void ConvexMeshBuilder::computeMassInfo(bool lowerPrecision)
+{
+ if(mMass <= 0.0f) //not yet computed.
+ {
+ PxIntegrals integrals;
+ PxConvexMeshDesc meshDesc;
+ meshDesc.points.count = mHullData.mNbHullVertices;
+ meshDesc.points.data = hullBuilder.mHullDataHullVertices;
+ meshDesc.points.stride = sizeof(PxVec3);
+
+ meshDesc.polygons.data = hullBuilder.mHullDataPolygons;
+ meshDesc.polygons.stride = sizeof(Gu::HullPolygonData);
+ meshDesc.polygons.count = hullBuilder.mHull->mNbPolygons;
+
+ meshDesc.indices.data = hullBuilder.mHullDataVertexData8;
+
+ // using the centroid of the convex for the volume integration solved accuracy issues in cases where the inertia tensor
+ // ended up close to not being positive definite and after a few further transforms the diagonalized inertia tensor ended
+ // up with negative values.
+ PxVec3 mean(0.0f);
+ for(PxU32 i=0; i < mHullData.mNbHullVertices; i++)
+ mean += hullBuilder.mHullDataHullVertices[i];
+ mean *= (1.0f / mHullData.mNbHullVertices);
+
+ bool status = lowerPrecision ?
+ computeVolumeIntegralsEberlySIMD(meshDesc, 1.0f, integrals, mean) : computeVolumeIntegralsEberly(meshDesc, 1.0f, integrals, mean);
+ if(status)
+ {
+
+ integrals.getOriginInertia(reinterpret_cast<PxMat33&>(mInertia));
+ mHullData.mCenterOfMass = integrals.COM;
+
+ //note: the mass will be negative for an inside-out mesh!
+ if(mInertia.column0.isFinite() && mInertia.column1.isFinite() && mInertia.column2.isFinite()
+ && mHullData.mCenterOfMass.isFinite() && PxIsFinite(PxReal(integrals.mass)))
+ {
+ if (integrals.mass < 0)
+ {
+ Ps::getFoundation().error(PX_WARN, "Gu::ConvexMesh: Mesh has a negative volume! Is it open or do (some) faces have reversed winding? (Taking absolute value.)");
+ integrals.mass = -integrals.mass;
+ mInertia = -mInertia;
+ }
+
+ mMass = PxReal(integrals.mass); //set mass to valid value.
+ return;
+ }
+ }
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Gu::ConvexMesh: Error computing mesh mass properties!\n");
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+#if PX_VC
+#pragma warning(push)
+#pragma warning(disable:4996) // permitting use of gatherStrided until we have a replacement.
+#endif
+
+bool ConvexMeshBuilder::loadConvexHull(const PxConvexMeshDesc& desc, PxU32 gaussMapVertexLimit, bool userPolygons)
+{
+ // gather points
+ PxVec3* geometry = reinterpret_cast<PxVec3*>(PxAlloca(sizeof(PxVec3)*desc.points.count));
+ Cooking::gatherStrided(desc.points.data, geometry, desc.points.count, sizeof(PxVec3), desc.points.stride);
+
+ PxU32* topology = NULL;
+
+ // gather indices
+ // store the indices into topology if we have the polygon data
+ if(desc.indices.data)
+ {
+ topology = reinterpret_cast<PxU32*>(PxAlloca(sizeof(PxU32)*desc.indices.count));
+ if (desc.flags & PxConvexFlag::e16_BIT_INDICES)
+ {
+ // conversion; 16 bit index -> 32 bit index & stride
+ PxU32* dest = topology;
+ const PxU32* pastLastDest = topology + desc.indices.count;
+ const PxU8* source = reinterpret_cast<const PxU8*>(desc.indices.data);
+ while (dest < pastLastDest)
+ {
+ const PxU16 * trig16 = reinterpret_cast<const PxU16*>(source);
+ *dest++ = trig16[0];
+ *dest++ = trig16[1];
+ *dest++ = trig16[2];
+ source += desc.indices.stride;
+ }
+ }
+ else
+ {
+ Cooking::gatherStrided(desc.indices.data, topology, desc.indices.count, sizeof(PxU32), desc.indices.stride);
+ }
+ }
+
+ // gather polygons
+ PxHullPolygon* hullPolygons = NULL;
+ if(desc.polygons.data)
+ {
+ hullPolygons = reinterpret_cast<PxHullPolygon*>(PxAlloca(sizeof(PxHullPolygon)*desc.polygons.count));
+ Cooking::gatherStrided(desc.polygons.data,hullPolygons,desc.polygons.count,sizeof(PxHullPolygon),desc.polygons.stride);
+
+ // if user polygons, make sure the largest one is the first one
+ if (userPolygons)
+ {
+ PxU32 largestPolygon = 0;
+ for (PxU32 i = 1; i < desc.polygons.count; i++)
+ {
+ if(hullPolygons[i].mNbVerts > hullPolygons[largestPolygon].mNbVerts)
+ largestPolygon = i;
+ }
+ if(largestPolygon != 0)
+ {
+ PxHullPolygon movedPolygon = hullPolygons[0];
+ hullPolygons[0] = hullPolygons[largestPolygon];
+ hullPolygons[largestPolygon] = movedPolygon;
+ }
+ }
+ }
+
+ const bool doValidation = desc.flags & PxConvexFlag::eDISABLE_MESH_VALIDATION ? false : true;
+ if(!hullBuilder.init(desc.points.count, geometry, topology, desc.indices.count, desc.polygons.count, hullPolygons, gaussMapVertexLimit, doValidation))
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "Gu::ConvexMesh::loadConvexHull: convex hull init failed!");
+ return false;
+ }
+ computeMassInfo(desc.flags & PxConvexFlag::eFAST_INERTIA_COMPUTATION);
+
+ return true;
+}
+
+#if PX_VC
+#pragma warning(pop)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// compute polygons from given triangles. This is support function used in extensions. We do not accept triangles as an input for convex mesh desc.
+bool ConvexMeshBuilder::computeHullPolygons(const PxU32& nbVerts,const PxVec3* verts, const PxU32& nbTriangles, const PxU32* triangles, PxAllocatorCallback& inAllocator,
+ PxU32& outNbVerts, PxVec3*& outVertices , PxU32& nbIndices, PxU32*& indices, PxU32& nbPolygons, PxHullPolygon*& polygons)
+{
+ if(!hullBuilder.computeHullPolygons(nbVerts,verts,nbTriangles,triangles))
+ {
+ Ps::getFoundation().error(PxErrorCode::eINTERNAL_ERROR, __FILE__, __LINE__, "ConvexMeshBuilder::computeHullPolygons: compute convex hull polygons failed. Provided triangles dont form a convex hull.");
+ return false;
+ }
+
+ outNbVerts = hullBuilder.mHull->mNbHullVertices;
+ nbPolygons = hullBuilder.mHull->mNbPolygons;
+
+ outVertices = reinterpret_cast<PxVec3*>(inAllocator.allocate(outNbVerts*sizeof(PxVec3),"PxVec3",__FILE__,__LINE__));
+ PxMemCopy(outVertices,hullBuilder.mHullDataHullVertices,outNbVerts*sizeof(PxVec3));
+
+ nbIndices = 0;
+ for (PxU32 i = 0; i < nbPolygons; i++)
+ {
+ nbIndices += hullBuilder.mHullDataPolygons[i].mNbVerts;
+ }
+
+ indices = reinterpret_cast<PxU32*>(inAllocator.allocate(nbIndices*sizeof(PxU32),"PxU32",__FILE__,__LINE__));
+ for (PxU32 i = 0; i < nbIndices; i++)
+ {
+ indices[i] = hullBuilder.mHullDataVertexData8[i];
+ }
+
+ polygons = reinterpret_cast<PxHullPolygon*>(inAllocator.allocate(nbPolygons*sizeof(PxHullPolygon),"PxHullPolygon",__FILE__,__LINE__));
+
+ for (PxU32 i = 0; i < nbPolygons; i++)
+ {
+ const Gu::HullPolygonData& polygonData = hullBuilder.mHullDataPolygons[i];
+ PxHullPolygon& outPolygon = polygons[i];
+ outPolygon.mPlane[0] = polygonData.mPlane.n.x;
+ outPolygon.mPlane[1] = polygonData.mPlane.n.y;
+ outPolygon.mPlane[2] = polygonData.mPlane.n.z;
+ outPolygon.mPlane[3] = polygonData.mPlane.d;
+
+ outPolygon.mNbVerts = polygonData.mNbVerts;
+ outPolygon.mIndexBase = polygonData.mVRef8;
+
+ for (PxU32 j = 0; j < polygonData.mNbVerts; j++)
+ {
+ PX_ASSERT(indices[outPolygon.mIndexBase + j] == hullBuilder.mHullDataVertexData8[polygonData.mVRef8+j]);
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// compute big convex data
+bool ConvexMeshBuilder::computeGaussMaps()
+{
+ // The number of polygons is limited to 256 because the gaussmap encode 256 polys maximum
+
+ PxU32 density = 16;
+ // density = 64;
+ // density = 8;
+ // density = 2;
+
+ PX_DELETE(mBigConvexData);
+ PX_NEW_SERIALIZED(mBigConvexData,BigConvexData);
+ BigConvexDataBuilder SVMB(&mHullData, mBigConvexData, hullBuilder.mHullDataHullVertices);
+ // valencies we need to compute first, they are needed for min/max precompute
+ SVMB.computeValencies(hullBuilder);
+ SVMB.precompute(density);
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TEST_INTERNAL_OBJECTS
+
+static void ComputeInternalExtent(Gu::ConvexHullData& data, const Gu::HullPolygonData* hullPolys)
+{
+ const PxVec3 e = data.mAABB.getMax() - data.mAABB.getMin();
+
+ // PT: For that formula, see \\sw\physx\PhysXSDK\3.4\trunk\InternalDocumentation\Cooking\InternalExtents.png
+ const float r = data.mInternal.mRadius / sqrtf(3.0f);
+
+ const float epsilon = 1E-7f;
+
+ const PxU32 largestExtent = Ps::largestAxis(e);
+ PxU32 e0 = Ps::getNextIndex3(largestExtent);
+ PxU32 e1 = Ps::getNextIndex3(e0);
+ if(e[e0] < e[e1])
+ Ps::swap<PxU32>(e0,e1);
+
+ data.mInternal.mExtents[0] = FLT_MAX;
+ data.mInternal.mExtents[1] = FLT_MAX;
+ data.mInternal.mExtents[2] = FLT_MAX;
+
+ // PT: the following code does ray-vs-plane raycasts.
+
+ // find the largest box along the largest extent, with given internal radius
+ for(PxU32 i = 0; i < data.mNbPolygons; i++)
+ {
+ // concurrent with search direction
+ const float d = hullPolys[i].mPlane.n[largestExtent];
+ if((-epsilon < d && d < epsilon))
+ continue;
+
+ const float numBase = -hullPolys[i].mPlane.d - hullPolys[i].mPlane.n.dot(data.mCenterOfMass);
+ const float denBase = 1.0f/hullPolys[i].mPlane.n[largestExtent];
+ const float numn0 = r * hullPolys[i].mPlane.n[e0];
+ const float numn1 = r * hullPolys[i].mPlane.n[e1];
+
+ float num = numBase - numn0 - numn1;
+ float ext = PxMax(fabsf(num*denBase), r);
+ if(ext < data.mInternal.mExtents[largestExtent])
+ data.mInternal.mExtents[largestExtent] = ext;
+
+ num = numBase - numn0 + numn1;
+ ext = PxMax(fabsf(num *denBase), r);
+ if(ext < data.mInternal.mExtents[largestExtent])
+ data.mInternal.mExtents[largestExtent] = ext;
+
+ num = numBase + numn0 + numn1;
+ ext = PxMax(fabsf(num *denBase), r);
+ if(ext < data.mInternal.mExtents[largestExtent])
+ data.mInternal.mExtents[largestExtent] = ext;
+
+ num = numBase + numn0 - numn1;
+ ext = PxMax(fabsf(num *denBase), r);
+ if(ext < data.mInternal.mExtents[largestExtent])
+ data.mInternal.mExtents[largestExtent] = ext;
+ }
+
+ // Refine the box along e0,e1
+ for(PxU32 i = 0; i < data.mNbPolygons; i++)
+ {
+ const float denumAdd = hullPolys[i].mPlane.n[e0] + hullPolys[i].mPlane.n[e1];
+ const float denumSub = hullPolys[i].mPlane.n[e0] - hullPolys[i].mPlane.n[e1];
+
+ const float numBase = -hullPolys[i].mPlane.d - hullPolys[i].mPlane.n.dot(data.mCenterOfMass);
+ const float numn0 = data.mInternal.mExtents[largestExtent] * hullPolys[i].mPlane.n[largestExtent];
+
+ if(!(-epsilon < denumAdd && denumAdd < epsilon))
+ {
+ float num = numBase - numn0;
+ float ext = PxMax(fabsf(num/ denumAdd), r);
+ if(ext < data.mInternal.mExtents[e0])
+ data.mInternal.mExtents[e0] = ext;
+
+ num = numBase + numn0;
+ ext = PxMax(fabsf(num / denumAdd), r);
+ if(ext < data.mInternal.mExtents[e0])
+ data.mInternal.mExtents[e0] = ext;
+ }
+
+ if(!(-epsilon < denumSub && denumSub < epsilon))
+ {
+ float num = numBase - numn0;
+ float ext = PxMax(fabsf(num / denumSub), r);
+ if(ext < data.mInternal.mExtents[e0])
+ data.mInternal.mExtents[e0] = ext;
+
+ num = numBase + numn0;
+ ext = PxMax(fabsf(num / denumSub), r);
+ if(ext < data.mInternal.mExtents[e0])
+ data.mInternal.mExtents[e0] = ext;
+ }
+ }
+ data.mInternal.mExtents[e1] = data.mInternal.mExtents[e0];
+}
+
+//////////////////////////////////////////////////////////////////////////
+// compute internal objects, get the internal extent and radius
+void ConvexMeshBuilder::computeInternalObjects()
+{
+ const Gu::HullPolygonData* hullPolys = hullBuilder.mHullDataPolygons;
+ Gu::ConvexHullData& data = mHullData;
+
+ // compute the internal radius
+ data.mInternal.mRadius = FLT_MAX;
+ for(PxU32 i=0;i<data.mNbPolygons;i++)
+ {
+ const float dist = fabsf(hullPolys[i].mPlane.distance(data.mCenterOfMass));
+ if(dist<data.mInternal.mRadius)
+ data.mInternal.mRadius = dist;
+ }
+
+ ComputeInternalExtent(data, hullPolys);
+}
+
+//~TEST_INTERNAL_OBJECTS