bool physx::Gu::computePlane_ConvexMTD(const PxPlane& plane, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, PxSweepHit& hit) { const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh); const Cm::FastVertex2ShapeScaling convexScaling(convexGeom.scale); PxU32 nbVerts = convexMesh->getNbVerts(); const PxVec3* PX_RESTRICT verts = convexMesh->getVerts(); PxVec3 worldPointMin = convexPose.transform(convexScaling * verts[0]); PxReal dmin = plane.distance(worldPointMin); for(PxU32 i=1;i<nbVerts;i++) { const PxVec3 worldPoint = convexPose.transform(convexScaling * verts[i]); const PxReal d = plane.distance(worldPoint); if(dmin > d) { dmin = d; worldPointMin = worldPoint; } } hit.normal = plane.n; hit.distance = dmin; hit.position = worldPointMin - plane.n * dmin; return true; }
static bool GeomOverlapCallback_PlaneBox(GEOM_OVERLAP_CALLBACK_PARAMS) { PX_ASSERT(geom0.getType()==PxGeometryType::ePLANE); PX_ASSERT(geom1.getType()==PxGeometryType::eBOX); PX_UNUSED(cache); PX_UNUSED(geom0); // const PxPlaneGeometry& planeGeom = static_cast<const PxPlaneGeometry&>(geom0); const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom1); // I currently use the same code as for contact generation but maybe we could do something faster (in theory testing // only 2 pts is enough). const Cm::Matrix34 absPose(transform1); const PxPlane worldPlane = Gu::getPlane(transform0); for(int vx=-1; vx<=1; vx+=2) for(int vy=-1; vy<=1; vy+=2) for(int vz=-1; vz<=1; vz+=2) { const PxVec3 v = absPose.transform(PxVec3(PxReal(vx),PxReal(vy),PxReal(vz)).multiply(boxGeom.halfExtents)); if(worldPlane.distance(v) <= 0.0f) // PT: objects are defined as closed, so we return 'true' in case of equality return true; } return false; }
bool Gu::checkOverlapSphere_planeGeom(const PxGeometry& geom, const PxTransform& pose, const Gu::Sphere& sphere) { PX_ASSERT(geom.getType() == PxGeometryType::ePLANE); PX_UNUSED(geom); // const PxPlaneGeometry& planeGeom = static_cast<const PxPlaneGeometry&>(geom); const PxPlane plane = getPlane(pose); return plane.distance(sphere.center) - sphere.radius <= 0.0f; }
bool Gu::intersectPlaneCapsule(const Gu::Capsule& capsule, const PxPlane& plane) { // We handle the capsule-plane collision with 2 sphere-plane collisions. // Seems ok so far, since plane is infinite. if(plane.distance(capsule.p0) <= capsule.radius) // PT: objects are defined as closed, so we return 'true' in case of equality return true; if(plane.distance(capsule.p1) <= capsule.radius) // PT: objects are defined as closed, so we return 'true' in case of equality return true; return false; }
PxU32 physx::PxFindFaceIndex(const PxConvexMeshGeometry& convexGeom, const PxTransform& pose, const PxVec3& impactPos, const PxVec3& unitDir) { PX_ASSERT(unitDir.isFinite()); PX_ASSERT(unitDir.isNormalized()); PX_ASSERT(impactPos.isFinite()); PX_ASSERT(pose.isFinite()); const PxVec3 impact = impactPos - unitDir * gEpsilon; const PxVec3 localPoint = pose.transformInv(impact); const PxVec3 localDir = pose.rotateInv(unitDir); // Create shape to vertex scale transformation matrix const PxMeshScale& meshScale = convexGeom.scale; const PxMat33 rot(meshScale.rotation); PxMat33 shape2VertexSkew = rot.getTranspose(); const PxMat33 diagonal = PxMat33::createDiagonal(PxVec3(1.0f / meshScale.scale.x, 1.0f / meshScale.scale.y, 1.0f / meshScale.scale.z)); shape2VertexSkew = shape2VertexSkew * diagonal; shape2VertexSkew = shape2VertexSkew * rot; const PxU32 nbPolys = convexGeom.convexMesh->getNbPolygons(); PxU32 minIndex = 0; PxReal minD = PX_MAX_REAL; for (PxU32 j = 0; j < nbPolys; j++) { PxHullPolygon hullPolygon; convexGeom.convexMesh->getPolygonData(j, hullPolygon); // transform hull plane into shape space PxPlane plane; const PxVec3 tmp = shape2VertexSkew.transformTranspose(PxVec3(hullPolygon.mPlane[0],hullPolygon.mPlane[1],hullPolygon.mPlane[2])); const PxReal denom = 1.0f / tmp.magnitude(); plane.n = tmp * denom; plane.d = hullPolygon.mPlane[3] * denom; PxReal d = plane.distance(localPoint); if (d < 0.0f) continue; const PxReal tweak = plane.n.dot(localDir) * gEpsilon; d += tweak; if (d < minD) { minIndex = j; minD = d; } } return minIndex; }
static void outputPlaneToStream(PxShape* planeShape, const PxRigidActor* actor, const PxTransform& globalPose, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray, const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, Cm::RenderBuffer* renderBuffer) { PX_ASSERT(planeShape->getGeometryType() == PxGeometryType::ePLANE); const PxF32 length = (tmpBounds.maximum - tmpBounds.minimum).magnitude(); PxVec3 center = toVec3(origin); const PxPlane plane = PxPlaneEquationFromTransform(globalPose); PxVec3 right, up; Ps::computeBasis(plane.n, right, up); right *= length; up *= length; const PxVec3 p = plane.project(center); const PxVec3 p0 = p - right + up; const PxVec3 p1 = p - right - up; const PxVec3 p2 = p + right - up; const PxVec3 p3 = p + right + up; const PxU32 nbTouchedTris = 2; const PxVec3 offset(float(-origin.x), float(-origin.y), float(-origin.z)); TouchedMesh* touchedMesh = (TouchedMesh*)reserve(geomStream, sizeof(TouchedMesh)/sizeof(PxU32)); touchedMesh->mType = TouchedGeomType::eMESH; touchedMesh->mTGUserData = planeShape; touchedMesh->mActor = actor; touchedMesh->mOffset = origin; touchedMesh->mNbTris = nbTouchedTris; touchedMesh->mIndexWorldTriangles = worldTriangles.size(); // Reserve memory for incoming triangles PxTriangle* TouchedTriangles = reserve(worldTriangles, nbTouchedTris); triIndicesArray.pushBack(0); triIndicesArray.pushBack(1); TouchedTriangles[0].verts[0] = p0 + offset; TouchedTriangles[0].verts[1] = p1 + offset; TouchedTriangles[0].verts[2] = p2 + offset; TouchedTriangles[1].verts[0] = p0 + offset; TouchedTriangles[1].verts[1] = p2 + offset; TouchedTriangles[1].verts[2] = p3 + offset; if(gVisualizeTouchedTris) visualizeTouchedTriangles(touchedMesh->mNbTris, touchedMesh->mIndexWorldTriangles, &worldTriangles[0], renderBuffer, offset, params.mUpDirection); }
bool Gu::intersectPlaneBox(const PxPlane& plane, const Gu::Box& box) { PxVec3 pts[8]; box.computeBoxPoints(pts); for(PxU32 i=0;i<8;i++) { if(plane.distance(pts[i]) <= 0.0f) // PT: objects are defined as closed, so we return 'true' in case of equality return true; } return false; }
bool physx::Gu::computePlane_BoxMTD(const PxPlane& plane, const Box& box, PxSweepHit& hit) { PxVec3 pts[8]; box.computeBoxPoints(pts); PxReal dmin = plane.distance(pts[0]); PxU32 index = 0; for(PxU32 i=1;i<8;i++) { const PxReal d = plane.distance(pts[i]); if(dmin > d) { index = i; dmin = d; } } hit.normal = plane.n; hit.distance = dmin; hit.position = pts[index] - plane.n*dmin; return true; }
bool physx::Gu::computePlane_CapsuleMTD(const PxPlane& plane, const Capsule& capsule, PxSweepHit& hit) { const PxReal d0 = plane.distance(capsule.p0); const PxReal d1 = plane.distance(capsule.p1); PxReal dmin; PxVec3 point; if(d0 < d1) { dmin = d0; point = capsule.p0; } else { dmin = d1; point = capsule.p1; } hit.normal = plane.n; hit.distance = dmin - capsule.radius; hit.position = point - hit.normal * dmin; return true; }
bool sweepConvex_PlaneGeom( const PxGeometry& geom, const PxTransform& pose, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, const PxVec3& unitDir, const PxReal distance, PxSweepHit& sweepHit, PxHitFlags hintFlags, const PxReal inflation) { PX_ASSERT(geom.getType() == PxGeometryType::ePLANE); PX_UNUSED(hintFlags); PX_UNUSED(geom); FETCH_CONVEX_HULL_DATA(convexGeom) sweepHit.faceIndex = 0xFFFFffff; // spec says face index is undefined for planes const PxVec3* PX_RESTRICT hullVertices = hullData->getHullVertices(); PxU32 numHullVertices = hullData->mNbHullVertices; const bool isMtd = hintFlags & PxHitFlag::eMTD; const FastVertex2ShapeScaling convexScaling(convexGeom.scale); PxPlane plane = getPlane(pose); plane.d -=inflation; sweepHit.distance = distance; bool status = false; bool initialOverlap = false; while(numHullVertices--) { const PxVec3& vertex = *hullVertices++; const PxVec3 worldPt = convexPose.transform(convexScaling * vertex); float t; PxVec3 pointOnPlane; if(intersectRayPlane(worldPt, unitDir, plane, t, &pointOnPlane)) { if(plane.distance(worldPt) <= 0.0f) { initialOverlap = true; break; //// Convex touches plane //sweepHit.distance = 0.0f; //sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL; //sweepHit.normal = -unitDir; //return true; } if(t > 0.0f && t <= sweepHit.distance) { sweepHit.distance = t; sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL; sweepHit.position = pointOnPlane; sweepHit.normal = plane.n; status = true; } } } if(initialOverlap) { if(!(PX_IS_SPU) && isMtd) { sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL; return computePlane_ConvexMTD(plane, convexGeom, convexPose, sweepHit); } else { sweepHit.distance = 0.0f; sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL; sweepHit.normal = -unitDir; return true; } } return status; }
static PxU32 computeSweepConvexPlane( const PxConvexMeshGeometry& convexGeom, ConvexHullData* hullData, const PxU32& nbPolys, const PxTransform& pose, const PxVec3& impact_, const PxVec3& unitDir) { PX_ASSERT(nbPolys); const PxVec3 impact = impact_ - unitDir * gEpsilon; const PxVec3 localPoint = pose.transformInv(impact); const PxVec3 localDir = pose.rotateInv(unitDir); const FastVertex2ShapeScaling scaling(convexGeom.scale); // BEGIN EPIC MODIFICATION Improved selection of 'most opposing' face bool bMinIndexValid = false; PxU32 minIndex = 0; PxReal maxD = -PX_MAX_REAL; PxU32 maxDIndex = 0; PxReal minNormalDot = PX_MAX_REAL; static const float onSurfaceEpsilon = 0.2f; // tolerance to determine that an impact point is 'on' a face // Iterate over each poly for(PxU32 j=0; j<nbPolys; j++) { const PxPlane& pl = hullData->mPolygons[j].mPlane; PxPlane plane; scaling.transformPlaneToShapeSpace(pl.n, pl.d, plane.n, plane.d); // Find distance of impact point to this place PxReal d = plane.distance(localPoint); // Track plane that impact point is furthest point (will be out fallback normal) if(d>maxD) { maxDIndex = j; maxD = d; } // If impact point is 'behind' this plane, we are not interested if(d<-onSurfaceEpsilon) continue; // Calculate direction dot plane normal const PxReal normalDot = plane.n.dot(localDir); // If this is more opposing than our current 'most opposing' normal, update 'most opposing' if(normalDot<minNormalDot) { minIndex = j; bMinIndexValid = true; minNormalDot = normalDot; } } // If we found at least one face that we are considered 'on', use best normal if(bMinIndexValid) { return minIndex; } // Fallback is the face that we are most in front of else { return maxDIndex; } // END EPIC MODIFICATION }