Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sweep query penetrates triangle mesh #501

Open
nikita-one opened this issue Nov 22, 2021 · 15 comments
Open

Sweep query penetrates triangle mesh #501

nikita-one opened this issue Nov 22, 2021 · 15 comments

Comments

@nikita-one
Copy link

Hi, again! I have noticed a strange behavior of sweep queries that I struggle to understand. The setup is simple: I perform a capsule sweep against a scene with a single static one-sided triangle mesh. The capsule is vertically aligned, and the cast direction is down, aka (0, -1, 0):
image
However the blocking hit reported by sweep query does not look correct. If I move the capsule at reported distance, the capsule penetrates the mesh considerably. On image below the shortest depenetration distance is ~0.06m, and if i try to depenetrate parallel to the cast direction, it would take a good ~0.5m (= the capsule's radius):
image

I've checked that normals are correct, tried using a double sided mesh, tried precise sweep option, tried all combinations of cooking options, nothing seemed to help with the issue.

What did help is tilting the mesh like 0.01 degrees around X axis. Apparently doing that helps PhysX detect the edge correctly and results in no penetration:
image

So my questions are:

  1. Is this a know/expected behavior, or am I doing something wrong?
  2. If this is a known limitation, and I want to guarantee no penetration, what are my options? Do I have to basically validate every sweep with subsequent overlap query, and then handle penetration manually?
  3. What causes this? It feels like some combination of capsule size, mesh triangle size and their relative orientation plays a role, but it is hard for me to tell. Maybe this issue can be avoided, if I know how to generalize the case in my example.
@nikita-one
Copy link
Author

Here is the mesh's wireframe. I don't see anything special about it, but maybe it helps:
image

@PierreTerdiman
Copy link

That's unexpected and it looks like a bug. Would you have a repro by any chance? Like maybe that mesh as a OBJ file?

@nikita-one
Copy link
Author

That's unexpected and it looks like a bug. Would you have a repro by any chance? Like maybe that mesh as a OBJ file?

Sure. Here it is. The capsule has 1 height and 0.5 radius, and is algned with Y axis.

@PierreTerdiman
Copy link

Hmm this is what I get in my viewer. Maybe the winding is inconsistent in that mesh. I know you said you tried using a double-sided mesh but I don't know what happens in Unity when you do that. Anyway I'll investigate further asap.

image

@nikita-one
Copy link
Author

nikita-one commented Nov 24, 2021

Oh, sorry, I think I forgot to triangulate the mesh before exporting. >_< In my simulation I use triangulated version, I have uploaded it . Checked it in Blender, I think it should be ok now. Some vertices are duplicated, but that should be fixed during welding I assume, I have it enabled.

P.S. To clarify regarding Unity: I am using Unity for visualization only in this case, the physics simulation is running in a separate process and uses native physx. That being said, I can reproduce the same behaviour with default Unity physics (which uses Physx internally as I am sure you are well aware :) ).

@PierreTerdiman
Copy link

I cannot reproduce this so far. I can translate the object with the mouse and no matter what I do the swept capsules seem to be properly located.

Can you tell me:
a) which PhysX version are you using?
b) the exact dimensions of the capsule? (radius / half height)

image

@nikita-one
Copy link
Author

I am using 4.1.2 (the latest commit in 4.1 branch).
Here is what I have:

===MESH INFO===
ACTOR GLOBAL POSE: [(0 0 0), (0 0 0 1)]
SHAPE LOCAL POSE: [(16 0 -17), (-0 -0 -0 1)]
SCALE: (1 1 1) (0 0 0 1)
MESH GEOMETRY FLAGS: 0
LOCAL BOUNDS: (0 0 -4) .. (8 0.75 0)
===SWEEP INFO===
SWEEP ORIGIN POSE: [(22.7555 4.433 -21.43088), (0 0 0.70710677 0.70710677)]
SWEEP DIR: (0 -1 0)
SWEEP DISTANCE: 4
CAPSULE RADIUS: 0.5
CAPSULE HALF HEIGHT: 0.5
===SWEEP RESULT===
IS BLOCKED: True
BLOCK DISTANCE: 3.6154413
BLOCK POINT: ((23 0.25 -21)
BLOCK NORMAL: ((-0.4889972 0.13511719 -0.86175704)
BLOCK FACE INDEX: 117
IS PENETRATED: True

@nikita-one
Copy link
Author

Same code but with very small rotation added to mesh actor produces correct block distance:

===MESH INFO===
ACTOR GLOBAL POSE: [(0 0 0), (5E-05 0 0 1)]
SHAPE LOCAL POSE: [(16 0 -17), (-0 -0 -0 1)]
SCALE: (1 1 1) (0 0 0 1)
MESH GEOMETRY FLAGS: 0
LOCAL BOUNDS: (0 0 -4) .. (8 0.75 0)
===SWEEP INFO===
SWEEP ORIGIN POSE: [(22.7555 4.433 -21.43088), (0 0 0.70710677 0.70710677)]
SWEEP DIR: (0 -1 0)
SWEEP DISTANCE: 4
CAPSULE RADIUS: 0.5
CAPSULE HALF HEIGHT: 0.5
===SWEEP RESULT===
IS BLOCKED: True
BLOCK DISTANCE: 3.077834
BLOCK POINT: ((22.576239 0.67586136 -20.999933)
BLOCK NORMAL: ((0.3585244 0.35860977 -0.8618929)
BLOCK FACE INDEX: 98
IS PENETRATED: False

@nikita-one
Copy link
Author

I figured out how to use pvd, so I have also uploaded a pxd2 recording, maybe that one would help with repro.

@PierreTerdiman
Copy link

I can reproduce this now. I'll need some time to investigate what's going on, as the issue is not immediately clear.

@nikita-one
Copy link
Author

Good to hear! This bug is not a show stopper for us, but it would be nice to learn what causes this, so we can come up with decent workaround (if not straight up fix the issue). Let me know if you find anything. And thanks.

@PierreTerdiman
Copy link

FYI I fixed this one in PhysX 5 now. Not sure if/when the fix would be back-ported to PhysX 4 though.

@nikita-one
Copy link
Author

nikita-one commented Jan 20, 2022

Good news. Sadly, we can not migrate any time soon. Any chance you can share some details about what caused this problem and what fixed it? Maybe it will help us come up with a workaround.

@PierreTerdiman
Copy link

This approach where we raycast against either a sphere or a capsule doesn't seem to work all the time: https://github.com/NVIDIAGameWorks/PhysX/blob/4.1/physx/source/geomutils/src/sweep/GuSweepSphereTriangle.cpp#L119

I tried several ways to improve it, nothing really worked. In the end I had to ditch it and use up to 2 raycasts-vs-capsule instead. It made the sweeps slower so I also rewrote the ray-vs-capsule code to recover lost perf.

@bleston
Copy link

bleston commented Aug 25, 2022

I think with the sweep direction, only 1 raycasts-vs-capsule needed. The code below show this.

static PX_FORCE_INLINE void chooseEdgeTest(const PxVec3& planeIntersectPoint, const PxVec3& dir, const PxVec3* PX_RESTRICT tri, PxU32 vertIntersectCandidate, PxU32 vert0, PxU32 vert1, PxU32& secondEdgeVert)
{
	const PxVec3 edge0 = tri[vertIntersectCandidate] - tri[vert0];
	{
		const PxReal edge0LengthSqr = edge0.dot(edge0);

		const PxVec3 diff = planeIntersectPoint - tri[vert0];

		if (edge0.dot(diff) < edge0LengthSqr)  // If the squared edge length is used for comparison, the edge vector does not need to be normalized
		{
			secondEdgeVert = vert0;
			return;
		}
	}

	const PxVec3 edge1 = tri[vertIntersectCandidate] - tri[vert1];
	{
		const PxReal edge1LengthSqr = edge1.dot(edge1);

		const PxVec3 diff = planeIntersectPoint - tri[vert1];

		if (edge1.dot(diff) < edge1LengthSqr)
		{
			secondEdgeVert = vert1;
			return;
		}
	}

	const PxVec3 diff = planeIntersectPoint - tri[vertIntersectCandidate];
	if (edge0.cross(edge1).cross(diff).dot(dir) >= 0.f)
	{
		secondEdgeVert = vert0;
	}
	else
	{
		secondEdgeVert = vert1;
	}
}

This approach where we raycast against either a sphere or a capsule doesn't seem to work all the time: https://github.com/NVIDIAGameWorks/PhysX/blob/4.1/physx/source/geomutils/src/sweep/GuSweepSphereTriangle.cpp#L119

I tried several ways to improve it, nothing really worked. In the end I had to ditch it and use up to 2 raycasts-vs-capsule instead. It made the sweeps slower so I also rewrote the ray-vs-capsule code to recover lost perf.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants