diff --git a/Source/Engine/Physics/Actors/Cloth.h b/Source/Engine/Physics/Actors/Cloth.h index 588a4f4fd..dcc6544a8 100644 --- a/Source/Engine/Physics/Actors/Cloth.h +++ b/Source/Engine/Physics/Actors/Cloth.h @@ -100,6 +100,11 @@ API_CLASS(Attributes="ActorContextMenu(\"New/Physics/Cloth\"), ActorToolbox(\"Ph /// API_FIELD() bool ContinuousCollisionDetection = false; + /// + /// Additional thickness of the simulated cloth to prevent intersections with nearby colliders. + /// + API_FIELD(Attributes="Limit(0)") float CollisionThickness = 1.0f; + /// /// The minimum distance that the colliding cloth particles must maintain from each other in meters. 0: self collision disabled. /// diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index e33c66efe..52f6e58e4 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -152,6 +152,7 @@ struct ClothSettings { bool SceneCollisions = false; float GravityScale = 1.0f; + float CollisionThickness = 0.0f; Cloth* Actor; void UpdateBounds(const nv::cloth::Cloth* clothPhysX) const @@ -1400,6 +1401,7 @@ void PhysicsBackend::EndSimulateScene(void* scene) DynamicHitBuffer buffer; if (scenePhysX->Scene->overlap(overlapGeo, overlapPose, buffer, filterData, &QueryFilter)) { + const float collisionThickness = clothSettings.CollisionThickness; for (uint32 j = 0; j < buffer.getNbTouches(); j++) { const auto& hit = buffer.getTouch(j); @@ -1413,7 +1415,7 @@ void PhysicsBackend::EndSimulateScene(void* scene) case PxGeometryType::eSPHERE: { const PxSphereGeometry& geoSphere = (const PxSphereGeometry&)geo; - const PxVec4 packedSphere(shapeToCloth.p, geoSphere.radius); + const PxVec4 packedSphere(shapeToCloth.p, geoSphere.radius + collisionThickness); const nv::cloth::Range sphereRange(&packedSphere, &packedSphere + 1); const uint32_t spheresCount = clothPhysX->getNumSpheres(); if (spheresCount + 1 > MAX_CLOTH_SPHERE_COUNT) @@ -1425,8 +1427,8 @@ void PhysicsBackend::EndSimulateScene(void* scene) { const PxCapsuleGeometry& geomCapsule = (const PxCapsuleGeometry&)geo; const PxVec4 packedSpheres[2] = { - PxVec4(shapeToCloth.transform(PxVec3(+geomCapsule.halfHeight, 0, 0)), geomCapsule.radius), - PxVec4(shapeToCloth.transform(PxVec3(-geomCapsule.halfHeight, 0, 0)), geomCapsule.radius) + PxVec4(shapeToCloth.transform(PxVec3(+geomCapsule.halfHeight, 0, 0)), geomCapsule.radius + collisionThickness), + PxVec4(shapeToCloth.transform(PxVec3(-geomCapsule.halfHeight, 0, 0)), geomCapsule.radius + collisionThickness) }; const nv::cloth::Range sphereRange(packedSpheres, packedSpheres + 2); const uint32_t spheresCount = clothPhysX->getNumSpheres(); @@ -1445,12 +1447,12 @@ void PhysicsBackend::EndSimulateScene(void* scene) if (planesCount + 6 > MAX_CLOTH_PLANE_COUNT) break; const PxPlane packedPlanes[6] = { - PxPlane(PxVec3(1, 0, 0), -geomBox.halfExtents.x).transform(shapeToCloth), - PxPlane(PxVec3(-1, 0, 0), -geomBox.halfExtents.x).transform(shapeToCloth), - PxPlane(PxVec3(0, 1, 0), -geomBox.halfExtents.y).transform(shapeToCloth), - PxPlane(PxVec3(0, -1, 0), -geomBox.halfExtents.y).transform(shapeToCloth), - PxPlane(PxVec3(0, 0, 1), -geomBox.halfExtents.z).transform(shapeToCloth), - PxPlane(PxVec3(0, 0, -1), -geomBox.halfExtents.z).transform(shapeToCloth) + PxPlane(PxVec3(1, 0, 0), -geomBox.halfExtents.x - collisionThickness).transform(shapeToCloth), + PxPlane(PxVec3(-1, 0, 0), -geomBox.halfExtents.x - collisionThickness).transform(shapeToCloth), + PxPlane(PxVec3(0, 1, 0), -geomBox.halfExtents.y - collisionThickness).transform(shapeToCloth), + PxPlane(PxVec3(0, -1, 0), -geomBox.halfExtents.y - collisionThickness).transform(shapeToCloth), + PxPlane(PxVec3(0, 0, 1), -geomBox.halfExtents.z - collisionThickness).transform(shapeToCloth), + PxPlane(PxVec3(0, 0, -1), -geomBox.halfExtents.z - collisionThickness).transform(shapeToCloth) }; clothPhysX->setPlanes(nv::cloth::Range((const PxVec4*)packedPlanes, (const PxVec4*)packedPlanes + 6), planesCount, planesCount); const PxU32 convexMask = PxU32(0x3f << planesCount); @@ -1472,6 +1474,7 @@ void PhysicsBackend::EndSimulateScene(void* scene) { PxHullPolygon polygon; geomConvexMesh.convexMesh->getPolygonData(k, polygon); + polygon.mPlane[3] -= collisionThickness; planes[k] = transform(reinterpret_cast(polygon.mPlane), convexToShapeInv).transform(shapeToCloth); } clothPhysX->setPlanes(nv::cloth::Range((const PxVec4*)planes, (const PxVec4*)planes + convexPlanesCount), planesCount, planesCount); @@ -3371,6 +3374,7 @@ void PhysicsBackend::SetClothCollisionSettings(void* cloth, const void* settings clothPhysX->setTriangles(nv::cloth::Range(), 0, clothPhysX->getNumTriangles()); } clothSettings.SceneCollisions = settings.SceneCollisions; + clothSettings.CollisionThickness = settings.CollisionThickness; } void PhysicsBackend::SetClothSimulationSettings(void* cloth, const void* settingsPtr)