UPrimitiveComponent::GetClosestPointOnCollision returns points not on the UPrimitiveComponent's collision

UPrimitiveComponent::GetClosestPointOnCollision is currently returning points which are not on the collision of the Primitive Component which called GetClosestPointOnCollision, but which is on collision belonging to other components which are children of the same actor.

Repro:
In a simple first-person template map:
Add this actor (It’s a .COPY export renamed as a .txt because these forums don’t like .copys)

Hey -

Can you provide screenshots of the behavior you’re seeing and the setup you’re using? I tried to recreate the issue based on the steps provided and I am only seeing a single debug point rather than two. Here is how I’m setting up the blueprint and an image of the outcome in the editor. Let me know if you’re using a different setup for your test.

Ugh, sorry. My actual use case is done in code, which is much harder to share. I assumed the blueprint version would be equivalent, since I’m calling the same function that is exposed in blueprint. I’ll dig into this more and see if I can figure out the discrepancy between the code and the blueprint.

To clarify, though, the behavior I’m seeing isn’t that there are multiple points, it’s that the one point that’s being returned is on collision not belonging to the StaticMeshComponent I’m calling GetClosestPointOnCollision on.

Basically, I’m checking GetClosestPointOnCollision on multiple component meshes belonging to the same actor to find the sub-component closest to an external point. But instead of multiple checks to different meshes, I’m getting every sub-component returning the same distance, and when I draw the point that’s being returned, all the distance checks are being made to the same point. That point can be on any of the collisions of any of the static meshes on the object, so it’s not that I’m calling GetClosestPointOnCollision on the wrong mesh. It seems to be combining all of the collisions on all of the meshes before doing the check.

I’ll let you know if I can repro it in isolation.

Okay, I figured it out. The problem occurs when the mesh you’re checking is the child component of another mesh which is set to simulate physics. If you check for the closest point on collision of any static mesh component child of a physics simulating static mesh component, then the point returned can be on any of the children of the physics simulating mesh or on the simulating mesh itself.

So the full repro is:

  • In a simple first-person template map:
  • Create a new blueprint actor.
  • Add a static mesh component to the actor as the root component. Set its mesh to be a 1m cube, and check “simulate physics” on it.
  • Add two static mesh components to the actor as children of the cube. Set their meshes to be cylinders, and drag them apart.
  • On tick, call GetClosestPointOnCollision on one of the cylinder child components to get the closest point on one of the cylinders to the player camera. Draw a debug point there.
  • Place the blueprint in a test level and run it.
  • Move around the blueprint. Observe that the drawn debug point will draw on whichever collision is closer to the player, even though only one of the cylinder is looking for the closest point on its collision. (The point will jump back and forth between them as the player moves around.)

I believe this is due to PhysX combining all the collision primitives of physically simulated objects. If you start digging down in the GetClosestPointOnCollision code, you’ll find that it uses PhysX to provide all collision bodies on the physics actor. PhysX is presumably combining all of the bodies associated with a physics simulating component into a single physics actor for simulation purposes, so it’s returning all of the children when asked.

I added a .COPY of the test actor I used here (It’s a .COPY export renamed as a .txt because these forums don’t like .copys)

The yellow cylinder is the one which is being checked for the closest point.

Hey -

Thank you for the additional information. This does indeed appear to be tied to the simulate physics setting as calling this node for a component that is not below the simulate physics set component still function as expected. I have entered a ticket for this issue that you can find here: Unreal Engine Issues and Bug Tracker (UE-39329) . You can track the report’s status as the issue is reviewed by our development staff. Please be aware that this issue may not be prioritized or fixed soon.

Cheers

More info from my search for a workaround:

If you turn off bAutoWeld on the child components, their collision is no longer merged into the parent for the purposes of the nearest collision check.

However, their collision no longer matters at all for physics purposes when their parent simulates physics. But it’s a pretty clear indicator that the bodies being combined for physics simulation purposes is the culprit causing this problem.

There’s a function on UPrimitiveComponent called GetBodyInstance which has a “bWelded” parameter which is true by default, and looks like it should return the actual body instance of the UPrimitiveComponent rather than its weld parent (which would let me call GetDistanceToBody, which is what GetClosestPointOnCollision ultimatley calls, just on the wrong thing) but the FBodyInstance returned when bWelded is false doesn’t appear to be valid. I’m assuming this is because it never has a body created for it since everything it does would be handled by the weld parent, and I can’t seem to find any straightforward way of making it generate one anyway.

Okay, that led to an acceptable temporary workaround. Immediately before I do the collision distance check, I unweld the primitivecomponent, then do the check, and then re-weld it immediately afterwards. It’s probably bad for performance to futz with physics like that, but keeps me moving for now.