DanielChappuis / reactphysics3d

Open source C++ physics engine library in 3D
http://www.reactphysics3d.com
zlib License
1.54k stars 223 forks source link

BoxShape phases into CapsuleShape #196

Closed graphitemaster closed 1 month ago

graphitemaster commented 3 years ago

If you stack (and balance) a boxshape ontop of a capsule shape laying on it's side, the box falls into the capsule by quite a bit, being pushed out only to fall in again. Is this a generally known robustness issue?

graphitemaster commented 3 years ago

Looks like when the capsule shape has a large mass or height, anything can go through it

DanielChappuis commented 3 years ago

Thanks for reporting this. No, it's not a known issue.

Could you please give me a little bit more information so that I can reproduce the issue ? For instance, what are the size of the shapes, their positions/orientations and the masses of the bodies ?

graphitemaster commented 3 years ago

Full disclosure, I've vendored and made quite a few changes to the library so I'm not sure if it's broken as a result of something I did, going to compare to stock first before investigating further. I didn't change any of the core routines responsible for this though. That being said simple setup that does reproduce my issue is:

// static box shape collider (500, 10, 500) at (0, 0, 0)
auto ground = world->createRigidBody({{0, 0, 0}, Quaternion::identity()});
ground->setType(BodyType::STATIC);
auto box = common.createBoxShape({500.0, 10.0, 500.0});
auto collider1 = ground->addCollider(box, Transform::identity());

// capsule shape (radius=1, height=10), at (0, 10 + 10, 0)
// this also appears like a bug with capsules, their origin seems to be the cylinder's bottom
// rather than the bottom cap itself, adding 10 more here so it doesn't penetrate the ground
auto body = world->createRigidBody({{0.0, 10.0 + 10.0, 0.0}, Quaternion::identity()});
body->setMass(10.0);
auto capsule = common.createCapsuleShape(1.0, 10.0);
auto collider2 = body->addCollider(capsule, Transform::identity());

Here's what I've investigated, when the height of the capsule shape is not too tall, the capsule makes contact with the ground box collider and settles fine, when these values are anything else, the capsule just falls through the ground.

What is strange here is that contact is being made, using the DebugRenderer I can see the contacts where the capsule collides with the box.

I've attached a video:

https://user-images.githubusercontent.com/343195/110394191-011bf500-803a-11eb-888e-1d289cb218fe.mp4

graphitemaster commented 3 years ago

I dunno if this is of any help but setting the mass of the capsule to 1 and radius to 1, it behaves correctly for all height sizes up to exactly 6.5, which is when it begins to penetrate the box and behave weird, height values larger than that is where robustness issues become very evident for me.

DanielChappuis commented 3 years ago

Thanks a lot for the details.

It might be an issue in the GJK algorithm used for collision detection between a CapsuleShape and a BoxShape but if the contact is created correctly, it might be something else.

I will try to investigate this.

graphitemaster commented 3 years ago

Thanks for taking the time.

I've done some more investigation and have a finding that may be of interest.

In the function SATAlgorithm::computeCapsulePolyhedronFaceContactPoints if I remove this conditional so it always evaluates true:

// If the clipped point is one that produce this penetration depth, we keep it
if (clipPointPenDepth > penetrationDepth - capsuleRadius - decimal(0.001)) {

Always adding the contact point, regardless of the penetration depth, it kind of works. It no longer phases through the box shape but it doesn't behave correctly either (the DebugRenderer contact points don't update correctly when the object has some linear velocity, and there's some jerky movements under high velocity, but it doesn't fall through at least.)

I know this is probably the wrong approach, but I'm just trying to understand the whole thing. I'm curious, why does this function not get passed the capsule height anywhere? It only accounts for radius. I don't know the details of these algorithms that well and the codebase has been lovingly commented and I'm learning a lot here, so thanks for such a great resource.

I'm going to keep investigating, thanks again.

graphitemaster commented 3 years ago

On second review, it appears to only allow the height parameter to go a bit higher, so this is a dead end, never mind.

graphitemaster commented 3 years ago

So while that previous investigation was a dead end, I do have some new insight. If I disable the split impulse position correction method for the contact solver, it works! Like no more phasing problems. Sadly, split impulse has nicer results overall, but this does offer some insight I hope.

graphitemaster commented 3 years ago

The contacts are still not updating when under high velocity though and it still fails for very tall capsules.

DanielChappuis commented 3 years ago

Are you testing using the current "master" branch of ReactPhysics3D? If not, can you try with this branch? Do you observe the same result ?

Can I ask you what is the time step value that you use and also the number of iterations for the velocity and position solver?

The contacts are still not updating when under high velocity though and it still fails for very tall capsules.

I am not really sure I understand what you mean here

graphitemaster commented 3 years ago

Using 16ms time steps, so 60fps. I use the default iterations for velocity and position solvers.

I am not really sure I understand what you mean here

The debug contact points (rendered as spheres) do not update when the object is moving fast, they lag behind the true contact points.

This happens in the current master branch, yes.

DanielChappuis commented 3 years ago

Actually, I think it might be an issue with the inertia tensor of the rigid body with the capsule shape. Since you don't call body->updateMassPropertiesFromColliders() on your body after adding the capsule collider, the inertia tensor is not recomputed for a CapsuleShape and therefore not correct. That might be the problem.

Note that calling this method will use the mass density of the material of the rigid body and not the mass that you set with body->setMass(10.0). If you want to set the mass manually, you also need to manually set the inertia tensor using body->setLocalInertiaTensor(inertiaTensorDiag). You can use the CapsuleShape::getLocalInertiaTensor(mass) method to compute the local inertia tensor for a capsule with a given mass.

Let me know if it solves the issue or not.

DanielChappuis commented 3 years ago

Have you been able to try this change to see if it solves your issue ?

DanielChappuis commented 1 month ago

I am closing this issue. Feel free to reopen it if necessary.