bepu / bepuphysics2

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

Spin/Friction Issues with the Character Demo #305

Closed Vercidium closed 3 months ago

Vercidium commented 4 months ago

I'm having some strange issues with cylinders, where they spin quickly and take a while to fall down. I'm using the Characters demo from this Github repo.

Video of the issue

I've played around with different dampening, friction and spring settings but can't figure out why this is happening. I'd like the cylinder to fall down regularly, have a tiny bit of bounce, and roll around a bit.

I have the following Contact settings:

public bool ConfigureContactManifold<TManifold>(int workerIndex, CollidablePair pair, ref TManifold manifold, out PairMaterialProperties pairMaterial) where TManifold : unmanaged, IContactManifold<TManifold>
{
    pairMaterial = new PairMaterialProperties { FrictionCoefficient = 1.0f, MaximumRecoveryVelocity = 2, SpringSettings = new SpringSettings(30, 1) };
    Characters.TryReportContacts(pair, ref manifold, workerIndex, ref pairMaterial);
    return true;
}

Simulation settings:

simulation = Simulation.Create(bufferPool, new CharacterNarrowphaseCallbacks(characters), new DemoPoseIntegratorCallbacks(new Vector3(0, -1, 0)), new SolveDescription(10, 10));

Dampening settings:

public DemoPoseIntegratorCallbacks(Vector3 gravity) : this()
{
    Gravity = gravity;
    LinearDamping = 0.03f;
    AngularDamping = 0.03f;
}

public void PrepareForIntegration(float dt)
{
    linearDampingDt = new Vector<float>(MathF.Pow(MathHelper.Clamp(1 - LinearDamping, 0, 1), dt));
    angularDampingDt = new Vector<float>(MathF.Pow(MathHelper.Clamp(1 - AngularDamping, 0, 1), dt));
    gravityWideDt = Vector3Wide.Broadcast(Gravity * dt);
}

Cylinder creation:

var cylinder = new Cylinder(0.8f, 22.0f);
var inertia = cylinder.ComputeInertia(50.0f);
var body = BodyDescription.CreateDynamic(pos, inertia, simulation.Shapes.Add(cylinder), 0.1f);
var handle = simulation.Bodies.Add(body);

Terrain creation:

var meshShape = new Mesh(triangles, new System.Numerics.Vector3(1, 1, 1), demo.bufferPool);
var index = demo.simulation.Shapes.Add(meshShape);

var description = new StaticDescription(
    new System.Numerics.Vector3(worldPosX, 0, worldPosZ),
    System.Numerics.Quaternion.Identity,
    index
);
demo.simulation.Statics.Add(description);
Vercidium commented 4 months ago

I came across this post that the old Bepu forums which suggested modifying the InverseInertiaTensor of the cylinder:

var cylinder = new Cylinder(0.8f, 22.0f);
var inertia = cylinder.ComputeInertia(50.0f);
inertia.InverseInertiaTensor.YY *= 0.1f; // <------- Fix here
var body = BodyDescription.CreateDynamic(pos, inertia, simulation.Shapes.Add(cylinder), 0.1f);
var handle = simulation.Bodies.Add(body);

This worked perfectly! Video here. I then changed the SpringSettings from (30, 1) to (1, 30) to reduce how much it bounces when it lands.

This post about rigid bodies also explains why this issue occurs. Their solution was to set the angular velocity back to zero every frame, or adjust the angular drag. I don't think adjusting the drag is possible is it?

For future reference, things that didn't fix the spinning:

Possible workaround:

RossNordby commented 4 months ago

You're correct that this is related to inertia, in particular how highly nondiagonal inertias interact with angular integration. The default demos callbacks specify AngularIntegrationMode.Nonconserving since it's usually fine, stable, and quick.

For long shapes like a tree, it's less good. Changing it to AngularIntegrationMode.ConserveMomentumWithGyroscopicTorque should help.

Of course, beefing up the axis of minimum inertia (by scaling down the inverse) is a perfectly cromulent workaround for games.