bepu / bepuphysics2

Pure C# 3D real time physics simulation library, now with a higher version number.
Apache License 2.0
2.4k stars 274 forks source link

Cylinder - Capsule collisions producing NaN's internally when RigidPose quaternion components sum up to slightly over 1 #140

Closed Frooxius closed 3 years ago

Frooxius commented 3 years ago

Hello!

I've ran into a strange edge-case with cylinder colliders and capsule when testing our content, where it would seem like the cylinder collider randomly disappears or has an odd shape. I managed to narrow this down to be caused by a quaternion whose components sum up to slightly over 1 (e.g. [1e-7, 0, 0, 1]).

To replicate this, I've added this code to the CharacterDemo.cs:

 var cylinder = new Cylinder(11.5f, 1.5f);
cylinder.ComputeInertia(1, out var cylinderInertia);
var cylinderCollidable = new CollidableDescription(Simulation.Shapes.Add(cylinder), 0.1f);

Simulation.Statics.Add(new StaticDescription(new Vector3(40f, 1.2f, -40f), new Quaternion(1e-7f, 0f, 0f, 1f), cylinderCollidable));

Additionally make the capsule very thin, it doesn't seem to occur either at all, or as much when it's wider:

      void CreateCharacter(Vector3 position)
        {
            characterActive = true;
            character = new CharacterInput(characters, position, new Capsule(0.2f, 2f), 0.1f, 1, 20, 100, 10, 4, MathF.PI * 0.3f);
        }

Simply jumping and trying to walk on the cylinder will behave very oddly. I found that some calculations in CapsuleCylinderTester produce NaN's (the localNormal at one point becomes full of NaN's, but I'm not sure if that's where exactly it originates). I'm not quite sure how the math works, so I'm not sure if/how this could be fixed.

Changing the quaternion to new Quaternion(0f, 0f, 0f, 1f) completely fixes the issue.

I've recorded a video to show how it behaves if it helps: https://www.youtube.com/watch?v=nyFrl9Lxes8

One part that was a bit tricky about this is that normalizing new Quaternion(1e-7f, 0f, 0f, 1f) doesn't actually change any of its values. To get around this, I pretty much had to implement this kind of normalization before I pass the quaternions to BEPUv2:

var sum = Abs(q.x) + Abs(q.y) + Abs(q.z) + Abs(q.w);
q /= sum;

I'm perfectly fine doing this normalization on my end, I'm not sure if fixing it within BEPUv2 is good or not (e.g. will have performance impact), but I wanted to log this finding in case it's an actual issue!

Also random thing, in case you're curious, here's me messing around trying to narrow this down with fancy debug visuals in my project :D https://www.youtube.com/watch?v=Jnd2Wx9XaWo

RossNordby commented 3 years ago

789769b6eb190d6224e7394058978f937c98058b should fix the underlying issue- an overpersnickety numerical threshold.

Thanks for the report!

https://www.youtube.com/watch?v=Jnd2Wx9XaWo

Fancy!

I suppose some people might find falling partially through the floor over and over a suboptimal VR experience :P