Skip to content

initial overlaping sphere sweep with MTD fails inside generateEEMTD #690

Description

@pkusilence

We are using PhysX 4.1.2. Our QA reports a bug, that a sphere character get stuck in a geometry and I found that is caused by initial overlap with distance = 0 (exactly), and the normal is always (-1)*(sweepDir). The sphere looks just touching the flower bed (red line in image below), which is a triangle mesh, and the contact feature should be the edge.

Image

I walked through the calculations inside physx::Gu::computeCapsule_TriangleMeshMTD, and at line 278:
hadContacts = calculateMTD(....)
it returns no contacts. So setupSweepHitForMTD report that sweepHit.normal = -unitDir;

Then I checked PCMCapsuleVsMeshContactGeneration::processTriangle, found that

  1. generateContacts returns no contact, because the sphere center's project point on the triangle is not inside (con0/con1 is false)
  2. generateEEContactsMTD also returns no contact, because for a sphere, PCMCapsuleVsMeshContactGeneration::generateEEMTD always return false at line 818, the comment says "If both points in the same side as the plane, no intersect points".

Now I just work around to check at first, if it is a sphere, just calculate contact using pcmDistancePointTriangleSquared.

	const FloatV sqInflatedRadius = FMul(inflatedRadius, inflatedRadius);

	// Sphere fast path: degenerate capsule (p0==p1). generateEEMTD always exits early for
	// this case because pq=(0,0,0) => npq=0, and generateContacts fails when the diagonal
	// projection lands outside the triangle face. Use direct point-triangle query instead.
	// W stores raw distance (consistent with generateContacts / generateEEMTD convention),
	// so the outer loop's distV = mtd - capsuleV.radius gives the correct signed penetration.
	const Vec3V capsulePQ = V3Sub(capsule.p1, capsule.p0);
	if(FAllEq(V3Dot(capsulePQ, capsulePQ), zero))
	{
		Vec3V closestP;
		bool generateContact = false, faceContact = false;
		const FloatV sqD = pcmDistancePointTriangleSquared(
			capsule.p0, p0, p1, p2, trigFlag, closestP, generateContact, faceContact);
		if(FAllGrtr(sqInflatedRadius, sqD) && generateContact)
		{
			const Vec3V contactNormal = faceContact
				? n
				: V3Normalize(V3Sub(capsule.p0, closestP));
			manifoldContacts[numContacts].mLocalPointA = capsule.p0;
			manifoldContacts[numContacts].mLocalPointB = closestP;
			manifoldContacts[numContacts].mLocalNormalPen =
				V4SetW(Vec4V_From_Vec3V(contactNormal), FSqrt(sqD));
			manifoldContacts[numContacts++].mFaceIndex = triangleIndex;
		}
		return true;
	}

	FloatV t, u, v;
	const FloatV sqDist = pcmDistanceSegmentTriangleSquared(capsule.p0, capsule.p1, p0, p1, p2, t, u, v);

But I'm not that sure, and wonder what is the best way to fix this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions