aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.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/SimulationController/src/cloth/ScClothSim.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/SimulationController/src/cloth/ScClothSim.cpp')
-rw-r--r--PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp894
1 files changed, 894 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp
new file mode 100644
index 00000000..0306f2cc
--- /dev/null
+++ b/PhysX_3.4/Source/SimulationController/src/cloth/ScClothSim.cpp
@@ -0,0 +1,894 @@
+// 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 "ScClothSim.h"
+#if PX_USE_CLOTH_API
+
+#include "PxClothParticleData.h"
+#include "PxConvexMesh.h"
+#include "PxTriangleMesh.h"
+#include "PxHeightField.h"
+#include "PxHeightFieldSample.h"
+
+#include "ScPhysics.h"
+#include "ScScene.h"
+#include "ScClothCore.h"
+#include "ScShapeSim.h"
+
+#include "CmScaling.h"
+
+#include "Types.h"
+#include "Range.h"
+#include "Factory.h"
+#include "Cloth.h"
+
+#include "GuIntersectionTriangleBox.h"
+#include "ScNPhaseCore.h"
+#include "PsFoundation.h"
+
+using namespace physx;
+
+namespace
+{
+ template <typename D, typename S>
+ PX_FORCE_INLINE cloth::Range<D> createRange(S begin, PxU32 size)
+ {
+ D* start = reinterpret_cast<D*>(begin);
+ D* end = start + size;
+
+ return cloth::Range<D>(start, end);
+ }
+}
+
+Sc::ClothSim::ClothSim(Scene& scene, ClothCore& core) :
+ ActorSim(scene, core),
+ mClothShape(*this),
+ mNumSpheres(0),
+ mNumCapsules(0),
+ mNumPlanes(0),
+ mNumBoxes(0),
+ mNumConvexes(0),
+ mNumMeshes(0),
+ mNumHeightfields(0),
+ mNumConvexPlanes(0)
+{
+ startStep(); // sync lowlevel gravity to prevent waking up on simulate()
+}
+
+
+Sc::ClothSim::~ClothSim()
+{
+ getCore().setSim(NULL);
+}
+
+
+Sc::ClothCore& Sc::ClothSim::getCore() const
+{
+ return static_cast<ClothCore&>(getActorCore());
+}
+
+void Sc::ClothSim::updateBounds()
+{
+ mClothShape.updateBoundsInAABBMgr();
+}
+
+void Sc::ClothSim::startStep()
+{
+ updateRigidBodyPositions();
+
+ // update total external acceleration in LL
+ PxVec3 externalAcceleration = getCore().getExternalAcceleration();
+ if ((getActorCore().getActorFlags() & PxActorFlag::eDISABLE_GRAVITY) == false)
+ externalAcceleration += getScene().getGravity();
+ getCore().getLowLevelCloth()->setGravity(externalAcceleration);
+}
+
+
+void Sc::ClothSim::reinsert()
+{
+ Sc::Scene& scene = getScene();
+ Sc::ClothCore& core = getCore();
+
+ scene.removeCloth(core);
+ scene.addCloth(core);
+}
+
+bool Sc::ClothSim::addCollisionShape(const ShapeSim* shape)
+{
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eSPHERE:
+ return addCollisionSphere(shape);
+ case PxGeometryType::ePLANE:
+ return addCollisionPlane(shape);
+ case PxGeometryType::eCAPSULE:
+ return addCollisionCapsule(shape);
+ case PxGeometryType::eBOX:
+ return addCollisionBox(shape);
+ case PxGeometryType::eCONVEXMESH:
+ return addCollisionConvex(shape);
+ case PxGeometryType::eTRIANGLEMESH:
+ return addCollisionMesh(shape);
+ case PxGeometryType::eHEIGHTFIELD:
+ return addCollisionHeightfield(shape);
+ case PxGeometryType::eGEOMETRY_COUNT:
+ case PxGeometryType::eINVALID:
+ break;
+ }
+ return false;
+}
+
+void Sc::ClothSim::removeCollisionShape(const ShapeSim* shape)
+{
+ switch (shape->getGeometryType())
+ {
+ case PxGeometryType::eSPHERE:
+ removeCollisionSphere(shape);
+ break;
+ case PxGeometryType::ePLANE:
+ removeCollisionPlane(shape);
+ break;
+ case PxGeometryType::eCAPSULE:
+ removeCollisionCapsule(shape);
+ break;
+ case PxGeometryType::eBOX:
+ removeCollisionBox(shape);
+ break;
+ case PxGeometryType::eCONVEXMESH:
+ removeCollisionConvex(shape);
+ break;
+ case PxGeometryType::eTRIANGLEMESH:
+ removeCollisionMesh(shape);
+ break;
+ case PxGeometryType::eHEIGHTFIELD:
+ removeCollisionHeightfield(shape);
+ break;
+ case PxGeometryType::eGEOMETRY_COUNT:
+ case PxGeometryType::eINVALID:
+ break;
+ }
+}
+
+bool Sc::ClothSim::addCollisionSphere(const ShapeSim* shape)
+{
+ PxU32 startIndex = 0;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumSpheres; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres;
+ if(sphereIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision sphere due to 32 sphere limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry());
+
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec4 sphere(center, geometry.radius);
+
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&sphere, 1), sphereIndex, sphereIndex);
+
+ insertShapeSim(startIndex + mNumSpheres++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionSphere(const ShapeSim* shape)
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = 0;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumSpheres; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumSpheres;
+ PxU32 sphereIndex = core.mNumUserSpheres + index;
+ core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+1);
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionCapsule( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumCapsules; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 capsuleIndex = core.mNumUserCapsules + mNumCapsules;
+ if(capsuleIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 capsule limit");
+ return false;
+ }
+
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*mNumCapsules;
+ if(sphereIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision capsule due to 32 sphere limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry());
+
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0));
+ PxReal radius = geometry.radius;
+ PxVec4 spheres[2] = { PxVec4(center-direction, radius), PxVec4(center+direction, radius) } ;
+
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(&spheres, 2), sphereIndex, sphereIndex);
+ PxU32 indices[2] = { sphereIndex, sphereIndex+1 };
+ core.getLowLevelCloth()->setCapsules(createRange<PxU32>(indices, 2), capsuleIndex, capsuleIndex);
+
+ insertShapeSim(startIndex + mNumCapsules++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionCapsule( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumCapsules; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumCapsules;
+ PxU32 sphereIndex = core.mNumUserSpheres + mNumSpheres + 2*index;
+ core.getLowLevelCloth()->setSpheres(cloth::Range<const PxVec4>(), sphereIndex, sphereIndex+2);
+ // capsule is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionPlane( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumPlanes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes;
+ if(planeIndex >= 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision plane due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxPlane plane = PxPlaneEquationFromTransform(trafo);
+
+ const PxVec4* data = reinterpret_cast<const PxVec4*>(&plane);
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(data, 1), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes;
+ PxU32 convexMask = PxU32(0x1 << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ insertShapeSim(startIndex + mNumPlanes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionPlane( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumPlanes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumPlanes;
+ PxU32 planeIndex = core.mNumUserPlanes + index;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+1);
+ // convex is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionBox( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumBoxes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes;
+ if(planeIndex+6 > 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision box due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 halfExtents = geometry.halfExtents;
+ PxPlane planes[6] = {
+ trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x)),
+ trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x)),
+ trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y)),
+ trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y)),
+ trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z)),
+ trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z)),
+ };
+
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(&planes, 6), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes;
+ PxU32 convexMask = PxU32(0x3f << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ insertShapeSim(startIndex + mNumBoxes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionBox( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumBoxes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumBoxes;
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*index;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+6);
+ // convex is being removed automatically
+ break;
+ }
+ }
+}
+
+bool Sc::ClothSim::addCollisionConvex( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumConvexes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry());
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes + mNumConvexPlanes;
+ if(planeIndex+numPlanes > 32)
+ {
+ Ps::getFoundation().error(PX_WARN, "Dropping collision convex due to 32 plane limit");
+ return false;
+ }
+
+ // current position here is before simulation
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ Ps::Array<PxPlane> planes;
+ planes.reserve(numPlanes);
+
+ for(PxU32 i=0; i<numPlanes; ++i)
+ {
+ PxHullPolygon polygon;
+ geometry.convexMesh->getPolygonData(i, polygon);
+ PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane));
+ planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal)));
+ }
+
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex);
+ PxU32 convexIndex = core.mNumUserConvexes + mNumPlanes + mNumBoxes + mNumConvexes;
+ PxU32 convexMask = PxU32(((1 << numPlanes) - 1) << planeIndex);
+ core.getLowLevelCloth()->setConvexes(createRange<const PxU32>(&convexMask, 1), convexIndex, convexIndex);
+
+ mNumConvexPlanes += numPlanes;
+ insertShapeSim(startIndex + mNumConvexes++, shape);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionConvex( const ShapeSim* shape )
+{
+ ClothCore& core = getCore();
+
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ PxU32 planeIndex = core.mNumUserPlanes + mNumPlanes + 6*mNumBoxes;
+ for (PxU32 index = 0; index<mNumConvexes; ++index)
+ {
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shapeIt[index]->getCore().getGeometry());
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ --mNumConvexes;
+ core.getLowLevelCloth()->setPlanes(cloth::Range<const PxVec4>(), planeIndex, planeIndex+numPlanes);
+ mNumConvexPlanes -= numPlanes;
+ // convex is being removed automatically
+ break;
+ }
+ planeIndex += numPlanes;
+ }
+}
+
+namespace
+{
+ template <typename IndexT>
+ void gatherMeshVertices(const PxTriangleMesh& mesh, Ps::Array<PxVec3>& vertices, bool flipNormal)
+ {
+ PxU32 numTriangles = mesh.getNbTriangles();
+ const IndexT* indices = reinterpret_cast<const IndexT*>(mesh.getTriangles());
+ const PxVec3* meshVertices = mesh.getVertices();
+ for(PxU32 i=0; i<numTriangles; ++i)
+ {
+ const PxI32 winding = flipNormal ? 1 : 0;
+ vertices.pushBack(meshVertices[indices[i*3+0]]);
+ vertices.pushBack(meshVertices[indices[i*3+1 + winding]]);
+ vertices.pushBack(meshVertices[indices[i*3+2 - winding]]);
+ }
+ }
+
+ void offsetTriangles(PxVec3* it, PxVec3* end, PxReal offset)
+ {
+ for(; it < end; it += 3)
+ {
+ PxVec3 v0 = it[0];
+ PxVec3 v1 = it[1];
+ PxVec3 v2 = it[2];
+
+ PxVec3 n = (v1-v0).cross(v2-v0).getNormalized() * offset;
+
+ it[0] = v0 + n;
+ it[1] = v1 + n;
+ it[2] = v2 + n;
+ }
+ }
+
+ void transform(const Cm::Matrix34& trafo, PxVec3* first, PxVec3* last)
+ {
+ for(; first < last; ++first)
+ *first = trafo.transform(*first);
+ }
+}
+
+bool Sc::ClothSim::addCollisionMesh( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumMeshes; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ // current position here is before simulation
+ const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ insertShapeSim(startIndex + mNumMeshes++, shape);
+ mStartShapeTrafos.pushBack(trafo);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionMesh( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumMeshes; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ mStartShapeTrafos.remove(index);
+ --mNumMeshes;
+ break;
+ }
+ }
+}
+
+namespace
+{
+ void gatherHeightfieldSamples(const PxHeightField& hf, Ps::Array<PxVec3>& vertices, Ps::Array<PxHeightFieldSample>& samples)
+ {
+ const PxU32 numCols = hf.getNbColumns();
+ const PxU32 numRows = hf.getNbRows();
+ const PxU32 numVertices = numRows * numCols;
+
+ samples.resize(numVertices);
+ hf.saveCells(samples.begin(), numVertices * sizeof(PxHeightFieldSample));
+
+ vertices.reserve(numVertices);
+ for(PxU32 i = 0; i < numRows; ++i)
+ {
+ for(PxU32 j = 0; j < numCols; ++j)
+ {
+ vertices.pushBack(PxVec3(PxReal(i), PxReal(samples[j + (i*numCols)].height), PxReal(j)));
+ }
+ }
+ }
+
+ void tessellateHeightfield(const PxHeightField& hf, const PxVec3* vertices,
+ const PxHeightFieldSample* samples, Ps::Array<PxVec3>& triangles)
+ {
+ const PxU32 numCols = hf.getNbColumns();
+ const PxU32 numRows = hf.getNbRows();
+ const PxU32 numTriangles = (numRows-1) * (numCols-1) * 2;
+
+ triangles.reserve(triangles.size() + numTriangles*3);
+ for(PxU32 i = 0; i < (numCols - 1); ++i)
+ {
+ for(PxU32 j = 0; j < (numRows - 1); ++j)
+ {
+ PxU8 tessFlag = samples[i+j*numCols].tessFlag();
+
+ // i2--i3
+ // | |
+ // i0--i1
+ PxU32 i0 = i * numRows + j;
+ PxU32 i1 = i * numRows + j + 1;
+ PxU32 i2 = (i+1) * numRows + j;
+ PxU32 i3 = (i+1) * numRows + j+1;
+
+ // this is really a corner vertex index, not triangle index
+ PxU32 mat0 = hf.getTriangleMaterialIndex((j*numCols+i)*2);
+ if(mat0 != PxHeightFieldMaterial::eHOLE)
+ {
+ triangles.pushBack(vertices[i2]);
+ triangles.pushBack(vertices[i0]);
+ triangles.pushBack(vertices[tessFlag ? i3 : i1]);
+ }
+
+ PxU32 mat1 = hf.getTriangleMaterialIndex((j*numCols+i)*2+1);
+ if(mat1 != PxHeightFieldMaterial::eHOLE)
+ {
+ triangles.pushBack(vertices[i1]);
+ triangles.pushBack(vertices[i3]);
+ triangles.pushBack(vertices[tessFlag ? i0 : i2]);
+ }
+
+ // we don't handle holes yet (number of triangles < expected)
+ PX_ASSERT(mat0 != PxHeightFieldMaterial::eHOLE);
+ PX_ASSERT(mat1 != PxHeightFieldMaterial::eHOLE);
+ }
+ }
+ }
+}
+
+
+bool Sc::ClothSim::addCollisionHeightfield( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes;
+
+#if PX_DEBUG
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumHeightfields; ++index)
+ PX_ASSERT(shapeIt[index] != shape);
+#endif
+
+ ClothCore& core = getCore();
+
+ // current position here is before simulation
+ const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo(core.getGlobalPose().transformInv(globalPose));
+
+ trafo.m.column0 *= geometry.rowScale;
+ trafo.m.column1 *= geometry.heightScale;
+ trafo.m.column2 *= geometry.columnScale;
+
+ insertShapeSim(startIndex + mNumHeightfields++, shape);
+ mStartShapeTrafos.pushBack(trafo);
+ return true;
+}
+
+void Sc::ClothSim::removeCollisionHeightfield( const ShapeSim* shape )
+{
+ PxU32 startIndex = mNumSpheres + mNumCapsules + mNumPlanes + mNumBoxes + mNumConvexes + mNumMeshes;
+ const ShapeSim* const* shapeIt = mShapeSims.begin() + startIndex;
+ for (PxU32 index = 0; index<mNumHeightfields; ++index)
+ {
+ if (shapeIt[index] == shape)
+ {
+ mShapeSims.remove(startIndex + index);
+ mStartShapeTrafos.remove(mNumMeshes + index);
+ --mNumHeightfields;
+ break;
+ }
+ }
+}
+
+void Sc::ClothSim::updateRigidBodyPositions()
+{
+ ClothCore& core = getCore();
+
+ if(!(core.getClothFlags() & PxClothFlag::eSCENE_COLLISION))
+ {
+ PX_ASSERT(0 == mNumSpheres + mNumCapsules + mNumPlanes +
+ mNumBoxes + mNumConvexes + mNumMeshes + mNumHeightfields);
+ return;
+ }
+
+ PxReal restOffset = core.getRestOffset();
+
+ const ShapeSim* const* shapeIt = mShapeSims.begin();
+
+ Ps::Array<PxVec4> spheres;
+ for (PxU32 i=0; i<mNumSpheres; ++i, ++shapeIt)
+ {
+ // current position here is after simulation
+ const ShapeSim* shape = *shapeIt;
+ const PxSphereGeometry& geometry = static_cast<const PxSphereGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxVec3 p = core.getGlobalPose().transformInv(globalPose.p);
+ spheres.pushBack(PxVec4(p, geometry.radius + restOffset));
+ }
+
+ for (PxU32 i=0; i<mNumCapsules; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxCapsuleGeometry& geometry = static_cast<const PxCapsuleGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 center = trafo.p;
+ PxVec3 direction = trafo.q.rotate(PxVec3(geometry.halfHeight, 0, 0));
+ PxReal radius = geometry.radius + restOffset;
+ spheres.pushBack(PxVec4(center-direction, radius));
+ spheres.pushBack(PxVec4(center+direction, radius));
+ }
+
+ PxU32 sphereIndex = core.mNumUserSpheres, numSpheres = spheres.size();
+ core.getLowLevelCloth()->setSpheres(createRange<const PxVec4>(spheres.begin(), numSpheres), sphereIndex, sphereIndex+numSpheres);
+
+ Ps::Array<PxPlane> planes;
+ for (PxU32 i = 0; i<mNumPlanes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxPlane plane = PxPlaneEquationFromTransform(trafo);
+ plane.d -= restOffset;
+ planes.pushBack(plane);
+ }
+
+ for (PxU32 i = 0; i<mNumBoxes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxBoxGeometry& geometry = static_cast<const PxBoxGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ PxTransform trafo = core.getGlobalPose().transformInv(globalPose);
+ PxVec3 halfExtents = geometry.halfExtents + PxVec3(restOffset);
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 1.f, 0, 0), -halfExtents.x)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3(-1.f, 0, 0), -halfExtents.x)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 1.f, 0), -halfExtents.y)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, -1.f, 0), -halfExtents.y)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, 1.f), -halfExtents.z)));
+ planes.pushBack(trafo.transform(PxPlane(PxVec3( 0, 0, -1.f), -halfExtents.z)));
+ }
+
+ for (PxU32 j= 0; j<mNumConvexes; ++j, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxConvexMeshGeometry& geometry = static_cast<const PxConvexMeshGeometry&>(shape->getCore().getGeometry());
+ PX_ALIGN(16, PxTransform globalPose);
+ shape->getAbsPoseAligned(&globalPose);
+ Cm::Matrix34 trafo = core.getGlobalPose().transformInv(globalPose) * geometry.scale;
+ PxU32 numPlanes = geometry.convexMesh->getNbPolygons();
+ for(PxU32 i=0; i<numPlanes; ++i)
+ {
+ PxHullPolygon polygon;
+ geometry.convexMesh->getPolygonData(i, polygon);
+ PxVec3 normal = trafo.rotate(reinterpret_cast<const PxVec3&>(polygon.mPlane));
+ planes.pushBack(PxPlane(normal, polygon.mPlane[3] - trafo.p.dot(normal) - restOffset));
+ }
+ }
+
+ PxU32 planeIndex = core.mNumUserPlanes, numPlanes = planes.size();
+ core.getLowLevelCloth()->setPlanes(createRange<const PxVec4>(planes.begin(), numPlanes), planeIndex, planeIndex+numPlanes);
+
+ Ps::Array<PxVec3> curTriangles, prevTriangles;
+ for (PxU32 i = 0; i<mNumMeshes; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxTriangleMeshGeometry& geometry = static_cast<const PxTriangleMeshGeometry&>(shape->getCore().getGeometry());
+ PxTransform clothPose = core.getGlobalPose();
+ PX_ALIGN(16, PxTransform meshPose);
+ shape->getAbsPoseAligned(&meshPose);
+ Cm::Matrix34 trafo = clothPose.transformInv(meshPose) * geometry.scale;
+
+ PxU32 start = curTriangles.size();
+ if(geometry.triangleMesh->getTriangleMeshFlags() & PxTriangleMeshFlag::e16_BIT_INDICES)
+ gatherMeshVertices<PxU16>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant());
+ else
+ gatherMeshVertices<PxU32>(*geometry.triangleMesh, curTriangles, geometry.scale.hasNegativeDeterminant());
+
+ Cm::Matrix34 startTrafo = mStartShapeTrafos[i];
+ mStartShapeTrafos[i] = trafo;
+ for(PxU32 j=start, n=curTriangles.size(); j<n; ++j)
+ prevTriangles.pushBack(startTrafo.transform(curTriangles[j]));
+
+ transform(trafo, curTriangles.begin() + start, curTriangles.end());
+ }
+
+ Ps::Array<PxVec3> vertices;
+ Ps::Array<PxHeightFieldSample> samples;
+ for (PxU32 i = 0; i<mNumHeightfields; ++i, ++shapeIt)
+ {
+ const ShapeSim* shape = *shapeIt;
+ const PxHeightFieldGeometry& geometry = static_cast<const PxHeightFieldGeometry&>(shape->getCore().getGeometry());
+ PxTransform clothPose = core.getGlobalPose();
+ PX_ALIGN(16, PxTransform heightfieldPose);
+ shape->getAbsPoseAligned(&heightfieldPose);
+ Cm::Matrix34 trafo = Cm::Matrix34(clothPose.transformInv(heightfieldPose));
+
+ trafo.m.column0 *= geometry.rowScale;
+ trafo.m.column1 *= geometry.heightScale;
+ trafo.m.column2 *= geometry.columnScale;
+
+ gatherHeightfieldSamples(*geometry.heightField, vertices, samples);
+
+ PxU32 start = curTriangles.size();
+ tessellateHeightfield(*geometry.heightField, vertices.begin(), samples.begin(), curTriangles);
+
+ Cm::Matrix34 startTrafo = mStartShapeTrafos[mNumMeshes + i];
+ mStartShapeTrafos[mNumMeshes + i] = trafo;
+ for(PxU32 j=start, n=curTriangles.size(); j<n; ++j)
+ prevTriangles.pushBack(startTrafo.transform(curTriangles[j]));
+
+ transform(trafo, curTriangles.begin() + start, curTriangles.end());
+
+ vertices.resize(0);
+ samples.resize(0);
+ }
+
+ // cull triangles that don't intersect the cloth bounding box
+ PxVec3 bboxCenter = core.getLowLevelCloth()->getBoundingBoxCenter();
+ PxVec3 bboxScale = core.getLowLevelCloth()->getBoundingBoxScale() + PxVec3(core.getContactOffset());
+ PxU32 trianglesSize = curTriangles.size(), numVertices = 0;
+ for(PxU32 i=0; i<trianglesSize; i+=3)
+ {
+ // PT: TODO: change the code so that we can safely call the (faster) intersectTriangleBox() function
+ if (Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, curTriangles[i], curTriangles[i+1], curTriangles[i+2]) ||
+ Gu::intersectTriangleBox_ReferenceCode(bboxCenter, bboxScale, prevTriangles[i], prevTriangles[i+1], prevTriangles[i+2]))
+ {
+ curTriangles[numVertices+0] = curTriangles[i+0];
+ curTriangles[numVertices+1] = curTriangles[i+1];
+ curTriangles[numVertices+2] = curTriangles[i+2];
+
+ prevTriangles[numVertices+0] = prevTriangles[i+0];
+ prevTriangles[numVertices+1] = prevTriangles[i+1];
+ prevTriangles[numVertices+2] = prevTriangles[i+2];
+
+ numVertices += 3;
+ }
+ }
+
+ cloth::Range<PxVec3> prevRange(prevTriangles.begin(), prevTriangles.begin() + numVertices);
+ cloth::Range<PxVec3> curRange(curTriangles.begin(), curTriangles.begin() + numVertices);
+
+ offsetTriangles(prevRange.begin(), prevRange.end(), restOffset);
+ offsetTriangles(curRange.begin(), curRange.end(), restOffset);
+
+ core.getLowLevelCloth()->setTriangles(prevRange, curRange, core.mNumUserTriangles);
+
+ PX_ASSERT(shapeIt == mShapeSims.end());
+}
+
+void Sc::ClothSim::clearCollisionShapes()
+{
+ ClothCore& core = getCore();
+ cloth::Cloth* lowLevelCloth = core.getLowLevelCloth();
+
+ lowLevelCloth->setSpheres(cloth::Range<const PxVec4>(), core.mNumUserSpheres, lowLevelCloth->getNumSpheres());
+ lowLevelCloth->setPlanes(cloth::Range<const PxVec4>(), core.mNumUserPlanes, lowLevelCloth->getNumPlanes());
+ lowLevelCloth->setTriangles(cloth::Range<const PxVec3>(), core.mNumUserTriangles, lowLevelCloth->getNumTriangles());
+
+ mNumSpheres = 0;
+ mNumCapsules = 0;
+ mNumPlanes = 0;
+ mNumBoxes = 0;
+ mNumConvexes = 0;
+ mNumMeshes = 0;
+ mNumHeightfields = 0;
+ mNumConvexPlanes = 0;
+
+ NPhaseCore* narrowPhase = getScene().getNPhaseCore();
+ for(PxU32 i=0, n=mShapeSims.size(); i<n; ++i)
+ narrowPhase->removeClothOverlap(this, mShapeSims[i]);
+
+ mShapeSims.resize(0);
+}
+
+void physx::Sc::ClothSim::insertShapeSim( PxU32 index, const ShapeSim* shapeSim)
+{
+ mShapeSims.pushBack(0);
+
+ for(PxU32 i = mShapeSims.size(); --i > index; )
+ mShapeSims[i] = mShapeSims[i-1];
+
+ mShapeSims[index] = shapeSim;
+}
+
+#endif // PX_USE_CLOTH_API