Page 1 of 1

Updating Compound Bodies

Posted: Mon Dec 03, 2012 11:51 pm
by sfxman
Hello,

dl;dr: Trying to find a way to update the mass of one sub body of a compound body without recreating everything.

I need to update some of the masses on a vehicle over time, to simulate jettisoning things, or some sort of fluid level depleting over time.
Using the example of the car, I recreate the compound body with the updated weights and reassign it to the vehicle.Body property. (replacing the old one)
I make sure to update the wheel offset so everything is in the right place also.

The issue is that when I do that, the wheels sometimes sink in the ground for a second then go back to their correct place. (my vehicle is quite heavy)

Is there a better solution to update part of the compound body?
How would you go about doing this?

Thanks! :)

Re: Updating Compound Bodies

Posted: Tue Dec 04, 2012 4:51 am
by Norbo
Is there a better solution to update part of the compound body?
How would you go about doing this?
You can indeed avoid recreating the vehicle body if all you want to do is adjust the effective weight of subshapes.

The CompoundShape.Shapes list provides a read-only view of the CompoundShapeEntry objects used to create the CompoundShape. You'll probably want to keep a redundant list of CompoundShapeEntry objects handy, or just copy the list of CompoundShapeEntry objects from the CompoundShape.Shapes list into your own list when needed. Then, you can make whatever weight modifications you need to your mutable list, and give that list to the static CompoundShape.ComputeVolumeDistribution method.

The CompoundShape.ComputeVolumeDistribution method will return the new inertia tensor (unscaled by mass) and the new center of mass. Multiply the computed Matrix3x3 by the mass of the whole vehicle and set the result to the entity's LocalInertiaTensor.

Then, offset the vehicle body's shape by setting the vehicle.Body.CollisionInformation.LocalPosition to -newCenter. This will ensure that the newly computed center of the shape will be aligned with the center of mass. The collidable's offset is used by the Vehicle to position wheels, so no modifications to the wheel suspensions should be necessary.

Of course, there's still one problem to be addressed:
The issue is that when I do that, the wheels sometimes sink in the ground for a second then go back to their correct place. (my vehicle is quite heavy)
This is likely related to the fact that changing up these settings or recreating the entity with a new and different shape will actually scoot the shape around, even though the Entity.Position does not change. The Entity.Position must be scooted to compensate for changes made to the shape position.

The whole process looks like this:

Code: Select all

            var bodies = new List<CompoundShapeEntry>
            {
                new CompoundShapeEntry(new BoxShape(2.5f, .75f, 4.5f), new Vector3(0, 0, 0), 60),
                new CompoundShapeEntry(new BoxShape(2.5f, .3f, 2f), new Vector3(0, .75f / 2 + .3f / 2, .5f), 1)
            };

            compoundShape = new CompoundShape(bodies);
            var body = new Entity(compoundShape, 61);
            body.Position = position;

            defaultShapeOffset = new Vector3(0, 0.5f, 0);
            body.CollisionInformation.LocalPosition = defaultShapeOffset;

            //This will hold our mutable view of the entries for computation.
            mutableShapeEntries = new CompoundShapeEntry[compoundShape.Shapes.Count];
            
            Vehicle = new Vehicle(body);

        //... Later, at runtime, modify the effective weight... 

        private void IncreaseWeight()
        {
            compoundShape.Shapes.CopyTo(mutableShapeEntries, 0);
            //Make the car-hat super heavy relative to the base!
            mutableShapeEntries[1].Weight += (extraWeight += 20);

            Vector3 newCenter;
            var volumeDistribution = CompoundShape.ComputeVolumeDistribution(mutableShapeEntries, out newCenter);

            Vehicle.Body.LocalInertiaTensor = volumeDistribution * Vehicle.Body.Mass;
            var previousLocalPosition = Vehicle.Body.CollisionInformation.LocalPosition;
            Vehicle.Body.CollisionInformation.LocalPosition = defaultShapeOffset - newCenter;

            //Compensate for the vehicle body movement; to make sure the shape stays in the same spot, scoot the entity position itself.
            Vehicle.Body.Position -= Vector3.Transform(Vehicle.Body.CollisionInformation.LocalPosition - previousLocalPosition, Vehicle.Body.Orientation);
        }
You'll need to update to the very latest development version for this to compile/work, though.

Re: Updating Compound Bodies

Posted: Tue Dec 04, 2012 3:03 pm
by sfxman
Excellent!

Thanks, my problem is now solved! :)