Discontinuous reflection angles for sphere-sphere collisions

Post Reply
kurtle
Posts: 3
Joined: Fri Jun 07, 2019 5:38 am

Discontinuous reflection angles for sphere-sphere collisions

Post by kurtle » Fri Jun 07, 2019 6:48 am

Hello, first-time poster here, be gentle. :)

For context, I'm working on a pachinko-style game in Unity using BulletSharp, a C# wrapper around libulletc. A sphere is launched from the top of the screen and bounces off other spheres placed throughout the level, all constrained to a 2D plane. I'm using the default collision configuration, DbvtBroadphase proxy, and I have not supplied a constraint solver. Settings are otherwise at their defaults, I believe.

The specific scenario I'm concerned with here deals with a moving rigid body with a sphere collision shape and a static (mass==0) rigid body also with a sphere collision shape.

I would expect a continuous relationship between the angle of incidence of the inbound sphere and the angle of reflection after the collision. For some angles this works as expected:

Image

However, sometimes there is a discontinuity in the reflection. Here's an example with a single discontinuity:

Image

Here's an example with two discontinuities:

Image

These discontinuities are confusing to players and I'd like to get rid of them if at all possible. I'm hoping someone on these boards has a better eye for physical interactions and can point me towards a solution. I've tried reducing the timestep, but it seemed to add more, smaller discontinuities rather than get rid of the problem.

I realize the context makes remote debugging a bit tricky. Let me know if there's anything I can try on my end to add clarity to the situation.

Thanks!
Kurt

User avatar
drleviathan
Posts: 554
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Discontinuous reflection angles for sphere-sphere collisions

Post by drleviathan » Fri Jun 07, 2019 7:33 pm

That is really strange.

How fast are your spheres moving? What happens when your spheres move much slower (maybe disable gravity for that test).

Or to put it another way: What happens when you enable continuous collision detection?

I know you're using a C# wrapper, but in C++ it might look like this:

Code: Select all

        body->setCcdSweptSphereRadius(radius);
        body->setCcdMotionThreshold(radius);

kurtle
Posts: 3
Joined: Fri Jun 07, 2019 5:38 am

Re: Discontinuous reflection angles for sphere-sphere collisions

Post by kurtle » Sat Jun 08, 2019 4:20 am

Thank you for the quick reply!

It seems you may be on to something. I did some tests with various launch impulses at zero gravity, and the problem is definitely diminished at lower speeds.

With an initial impulse of 50, the response is good enough to be considered smooth:

Image

Things suffer more as I increase the impulse, though the results were never as bad as the original case with gravity applied. Here's an example w/ impulse of 100:

Image

In our game, we cap the top speed of the moving sphere at 160 units/s, and the sphere typically reaches 100-110 before colliding after being launched initially.

I attempted to enable CCD on the moving sphere, but it didn't seem to fix the issue. It also led to some strange physical responses as if the spheres were sticking or otherwise reducing restitution. Here's a shot that showcases the behavior with an example of the movement speed as well:

Image

I tried playing around with the MotionThreshold value a bit, but any values lower than the radius seemed to just make the dampening worse.

I'm not sure what the next steps might be here. Reducing the speed isn't really an option as it would dramatically affect gameplay. Enabling CCD seems like a potential lead, but I don't quite understand the adverse effects it is having. Perhaps there are other settings that would make it work better?

I'll keep poking around to see if I can manage something that works.

Thank you again for your help!

User avatar
drleviathan
Posts: 554
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: Discontinuous reflection angles for sphere-sphere collisions

Post by drleviathan » Mon Jun 10, 2019 3:38 pm

Reducing the substep is sorta equivalent to reducing the velocity. So I'm surprised your exploration of shorter substep duration didn't solve your problem. Maybe you didn't make it small enough?

Theoretically, if the problem starts to vanish at 50 units/sec but you want the projectiles to move up to 160 units/sec then the problem should start to vanish when you multiply the substep duration by a factor of 50/160 = 0.3125.

To be clear: you don't want to reduce the actual realtime step but the substepDuration passed to the:

Code: Select all

stepSimulation(step, maxSubsteps, substepDuration)
So suppose you were using the default 1/60 arguments: maxSubsteps = 1, substepDuration = 1/60: like so: stepSimulation(dt)

and your game was expected to run at least 30 Hz --> step = 33.3 msec.

Then you should try with a shorter substepDuration, but correspondingly increase the maxSubsteps like so:

Code: Select all

const btScalar defaultSubstepDuration = 1.0 / 60.0;
const btScalar substepDuration = 0.25 * defaultSubstepDuration;
const btScalar expectedGameLoopDuration = 0.03333;
const int maxSubsteps = floor(expectedGameLoopDuration / substepDuration) + 1; // truncate decimal and add one for slop

world->stepSimulation(dt, maxSubsteps, substepDuration);
I would be perplexed if that didn't fix it.

Note: reducing the substepDuration can increase the CPU cycles required for the stepSimulation() to complete since it will make repeated calls to one of the inner subroutines to make the full step. However, Bullet is pretty fast and for non-complex simulations this shouldn't show up as a problem.

Hrm... based on your evidence it may be that enabling CCD just prevents outright tunnelling but doesn't necessarily get the true contact normals right.

kurtle
Posts: 3
Joined: Fri Jun 07, 2019 5:38 am

Re: Discontinuous reflection angles for sphere-sphere collisions

Post by kurtle » Tue Jun 11, 2019 5:35 am

This seems to have cleared things up for us! I was experimenting with substepDuration, but not to the extent necessary and not while simultaneously updating maxSubsteps. It seems quite obvious in retrospect.

Thank you very much for your help! Come say hello on discord.gg/roundguard if you'd like a beta key and to see your help in action!

Post Reply