jrouwe / JoltPhysics

A multi core friendly rigid body physics and collision detection library. Written in C++. Suitable for games and VR applications. Used by Horizon Forbidden West.
MIT License
6k stars 374 forks source link

LinearCast Body missed in Sensor contact #1142

Open Qendolin opened 1 month ago

Qendolin commented 1 month ago

Hello, I've noticed an issue where rigid bodies using JPH::EMotionQuality::LinearCast do not report contacts with sensors when moving at high speed (~100 m/s).

Here is my character body creation code:

 JPH::Ref<JPH::CharacterSettings> character_settings = new JPH::CharacterSettings();
character_settings->mMaxSlopeAngle = JPH::DegreesToRadians(45.0f);
character_settings->mLayer = ph::Layers::PLAYER;
character_settings->mShape = new JPH::SphereShape(0.25f);
character_settings->mFriction = 0.0f;
character_settings->mGravityFactor = 0.0f;
body_ = new JPH::Character(character_settings, JPH::RVec3(0.0, 0.0, 0.0), JPH::Quat::sIdentity(), 0, physics().system);
physics().interface().SetMotionQuality(body_->GetBodyID(), JPH::EMotionQuality::LinearCast);
body_->AddToPhysicsSystem(JPH::EActivation::Activate);

My sensor is a static body, roughly 0.2m thick. The character body is moved using body_->SetLinearVelocity before the physics update.

Using Jolt 4.0.2, and a 60Hz update interval with 1 collision step and the single threaded job system.

jrouwe commented 1 month ago

Currently there is no support for rigid bodies with motion type LinearCast vs sensors (they will be treated as Discrete vs sensors):

https://github.com/jrouwe/JoltPhysics/blob/ebccdcbfae6b60e37480aa203d0781d26e437fbc/Jolt/Physics/PhysicsSystem.cpp#L1837-L1839

Qendolin commented 1 month ago

I see. Maybe that would we worth noting in the documentation? Thank you for your quick response.

AnuraDev commented 1 month ago

so the right approach would be to use ContactListener::OnContactValidate and do rejects there?

sensors seems to be misleading in a way (from intuition point of view) but the docs do mention what:

To create a sensor, either set BodyCreationSettings::mIsSensor to true when constructing a body or set it after construction through Body::SetIsSensor. A sensor can only use the discrete motion quality type at this moment.

overall looks like what for games you need a lightweight/fast event system in ContactListener so it does checks only for bodies with associated events/callbacks.

jrouwe commented 1 month ago

so the right approach would be to use ContactListener::OnContactValidate and do rejects there?

You could use OnContactValidate to implement a sensor, but getting this call doesn't mean that this is the closest collision. Hits are roughly sorted based on closeness, so for an object with motion type LinearCast it may be that you later receive another call to OnContactValidate with a closer collision which will result in the actual contact point.

ContactListener::OnContactAdded indicates that there is an actual contact and you can specify that that contact should be treated as a sensor by setting ContactSettings::mIsSensor. This disables the contact, but since we only store the closest contact point during the LinearCast sweep, this also means that the body could penetrate the object behind the sensor.