GravitationalField multiplier & space gravity do not equate?

Discuss any questions about BEPUphysics or problems encountered.
Post Reply
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

GravitationalField multiplier & space gravity do not equate?

Post by Spankenstein »

I'm creating a GravitationalField with a custom shape for the vector field.

Code: Select all

            gravField = new GravitationalField(
                localSettings.ForceFieldShape.Load(game, this),
                localSettings.Position,
                localSettings.GravitationalFieldStrength,
                30
                );
If I remove all the gravity from the physics space (0, 0, 0) and set the gravitational field's multiplier to 10

Code: Select all

gravField.Multiplier = 10;
then the resultant motion of the objects affected by the vector field is not the same as using a gravitational force of (0, -10, 0) in the same space

Code: Select all

space.ForceUpdater.Gravity = new Vector3(0, -10, 0);
How can I make sure that they equate?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: GravitationalField multiplier & space gravity do not equ

Post by Norbo »

GravitationalField impulses are calculated like so:

Code: Select all

            Vector3 r = e.Position - Origin;
            float length = r.Length();
            if (length > Toolbox.BigEpsilon)
            {
                float force = dt * e.Mass * Math.Min(MaxAcceleration, Multiplier / (length * length));
                impulse = -(force / length) * r; //Extra division by length normalizes the direction.
            }
            else
                impulse = new Vector3();
The force falls off with the square of the distance from the origin.

Consider the usual equation for gravitational force between two bodies. The GravitationalField's Multiplier can be thought of as a stand-in for the gravitational constant and the mass of the gravity source multiplied together. Note that two bodies in space do not accelerate towards each other at a constant rate. The acceleration varies with distance. So, no single value of Multiplier can make the default GravitationalField equal to a Space.Gravity constant acceleration in all cases.

If you want a constant acceleration rate, then the impulse to apply would be:

Code: Select all

Vector3 r = e.Position - Origin;
r.Normalize();
impulse = r * (GravitationalAcceleration * e.Mass * dt);
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: GravitationalField multiplier & space gravity do not equ

Post by Spankenstein »

Is it possible to override the impulse calculation stage and apply a linear impulse?

Forcefield CalculateImpulse method doesn't appear as it is protected:

Code: Select all

protected abstract void CalculateImpulse
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: GravitationalField multiplier & space gravity do not equ

Post by Norbo »

Yup. Check out the GravitationalField source. It's from the BEPUphysicsDemos; it has no special access to stuff internal to the engine.
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: GravitationalField multiplier & space gravity do not equ

Post by Spankenstein »

When switching to GravitationalFieldAcceleration.Constant (even when changing r to Vector.UnitY) the behaviour is still not the same as under gravity.

Code: Select all

        protected override void CalculateImpulse(Entity e, float dt, out Vector3 impulse)
        {
            switch (AccelerationType)
            {
                case GravitationalFieldAcceleration.Constant:
                    {
                        Vector3 r = e.Position - Origin;
                        r.Normalize();
                        impulse = r * (-Multiplier * e.Mass * dt);

                        break;
                    }
                case GravitationalFieldAcceleration.InverseSquare:
                    {
                        // Inverse square dropoff
                        Vector3 r = e.Position - Origin;
                        float length = r.Length();

                        if (length > Toolbox.BigEpsilon)
                        {
                            float force = dt * e.Mass * Math.Min(MaxAcceleration, Multiplier / (length * length));
                            impulse = -(force / length) * r; //Extra division by length normalizes the direction.
                        }
                        else
                        {
                            impulse = Vector3.Zero;
                        }

                        break;
                    }
                case GravitationalFieldAcceleration.Linear:
                    {
                        // Could use a linear dropoff for a slightly faster calculation (divide by length^2 instead of length^3).
                        Vector3 r = e.Position - Origin;
                        float length = r.Length();

                        if (length > Toolbox.BigEpsilon)
                        {
                            float force = dt * e.Mass * Math.Min(MaxAcceleration, Multiplier / length);

                            //Extra division by length normalizes the direction
                            impulse = -(force / length) * r;
                        }
                        else
                        {
                            impulse = Vector3.Zero;
                        }

                        break;
                    }
                default: impulse = Vector3.Zero; break;
            }
        }
The objects move faster when using a space gravity of (0, -10, 0) than when using GravitationalFieldAcceleration.Constant with a multiplier of 10 and no space gravity.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: GravitationalField multiplier & space gravity do not equ

Post by Norbo »

Are you sure it is truly not the same? I tried two parallel spaces; one with a Space.Gravity, and one with a gravity field modified to operate on the Y axis. They moved the same way (within the limits of multithreading-induced nondeterminism), as expected.

Further, there's no conceptual reason why they would be different speeds so long as the computed impulses are the same. The force field updates once per time step, and the force updater (responsible for applying gravity) updates once per time step. Both integrate by the same time step duration (Space.TimeStepSettings.TimeStepDuration).

There's nothing particularly special about the force field stuff, either. It is just a convenient interface for automatically multithreading impulse application. You can do the same thing externally if you'd like to isolate the system more.
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: GravitationalField multiplier & space gravity do not equ

Post by Spankenstein »

I've uploaded two videos to demonstrate

The first video shows the objects influenced by Space.Gravity (0, -10, 0)

http://youtu.be/V51vRNmzOrw

The second video shows the objects influenced by the individual gravitational fields (the vector field shapes are shown as a white wireframe)

http://youtu.be/YNosnChBfl4

The spherical object behaviour is not the same for both cases.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: GravitationalField multiplier & space gravity do not equ

Post by Norbo »

There's too many variables to figure it out based upon videos unfortunately. Can you reproduce and isolate the issue in the BEPUphysicsDemos, preferably with two parallel spaces updating simultaneously with elements from both spaces added to the drawer? That eliminates all the other extra systems and environmental conditions as confounding factors.

Here's an example demo, showing Space.Gravity's equivalence with the ConstantLinearGravityField by running two simulations next to each other:

Code: Select all

using BEPUphysics;
using BEPUphysics.Entities;
using BEPUphysics.Entities.Prefabs;
using BEPUphysics.UpdateableSystems.ForceFields;
using BEPUphysicsDemos.SampleCode;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using BEPUphysics.NarrowPhaseSystems;

namespace BEPUphysicsDemos.Demos
{
    /// <summary>
    /// Boxes fall on a planetoid.
    /// </summary>
    public class PlanetDemo : StandardDemo
    {
        private Space secondSpace;
        /// <summary>
        /// Constructs a new demo.
        /// </summary>
        /// <param name="game">Game owning this demo.</param>
        public PlanetDemo(DemosGame game)
            : base(game)
        {
            Space.ForceUpdater.Gravity = Vector3.Zero;

            //By pre-allocating a bunch of box-box pair handlers, the simulation will avoid having to allocate new ones at runtime.
            NarrowPhaseHelper.Factories.BoxBox.EnsureCount(1000);

            //Set up the first simulation.
            Entity planet = new Box(new Vector3(0, 0, 0), 100, 5, 100);
            Space.Add(planet);

            //The first simulation uses a gravity field which emulates Space.ForceUpdater.Gravity.
            var field = new ConstantLinearGravityField(new InfiniteForceFieldShape(), 9.81f);
            Space.Add(field);

            //Drop the "meteorites" on the planet.
            Entity toAdd;
            int numColumns = 10;
            int numRows = 10;
            int numHigh = 10;
            float separation = 5;
            for (int i = 0; i < numRows; i++)
                for (int j = 0; j < numColumns; j++)
                    for (int k = 0; k < numHigh; k++)
                    {
                        toAdd = new Box(new Vector3(separation * i - numRows * separation / 2, 40 + k * separation, separation * j - numColumns * separation / 2), 1f, 1f, 1f, 5);
                        //toAdd.LinearVelocity = new Vector3(30, 0, 0);
                        toAdd.LinearDamping = 0;
                        toAdd.AngularDamping = 0;
                        Space.Add(toAdd);
                    }

            //Set up the identical second parallel simulation.
            secondSpace = new Space(Space.ThreadManager);
            planet = new Box(new Vector3(0, 0, 0), 100, 5, 100);
            secondSpace.Add(planet);

            //The second simulation uses regular old gravity.
            secondSpace.ForceUpdater.Gravity = new Vector3(0, -9.81f, 0);

            //Drop the "meteorites" on the planet.
            for (int i = 0; i < numRows; i++)
                for (int j = 0; j < numColumns; j++)
                    for (int k = 0; k < numHigh; k++)
                    {
                        toAdd = new Box(new Vector3(separation * i - numRows * separation / 2, 40 + k * separation, separation * j - numColumns * separation / 2), 1f, 1f, 1f, 5);
                        //toAdd.LinearVelocity = new Vector3(30, 0, 0);
                        toAdd.LinearDamping = 0;
                        toAdd.AngularDamping = 0;
                        secondSpace.Add(toAdd);
                        game.ModelDrawer.Add(toAdd);
                    }

            game.Camera.Position = new Vector3(0, 0, 150);
        }

        public override void Update(float dt)
        {
            //Note that we are only moving forward by one time step. This is consistent with the Space.Update() call that the parent implementation will call.
            secondSpace.Update();
            base.Update(dt);
        }

        /// <summary>
        /// Gets the name of the simulation.
        /// </summary>
        public override string Name
        {
            get { return "Planet"; }
        }
    }
}
The ConstantLinearGravityField is a simple modification to the GravitationalField:

Code: Select all

using System;
using BEPUphysics.BroadPhaseSystems;
using BEPUphysics.Entities;
using BEPUphysics.UpdateableSystems.ForceFields;
using Microsoft.Xna.Framework;
using BEPUphysics;

namespace BEPUphysicsDemos.SampleCode
{

    /// <summary>
    /// Applies a constant vertical linear impulse on all entities.
    /// </summary>
    public class ConstantLinearGravityField : ForceField
    {
        /// <summary>
        /// Creates a gravitational field.
        /// </summary>
        /// <param name="shape">Shape representing the volume of the force field.</param>
        /// <param name="acceleration">Acceleration the field applies.</param>
        public ConstantLinearGravityField(ForceFieldShape shape, float acceleration)
            : base(shape)
        {
            this.Acceleration = acceleration;
        }

        /// <summary>
        /// Gets or sets the gravitational constant of the field times the effective mass at the center of the field.
        /// </summary>
        public float Acceleration { get; set; }

        /// <summary>
        /// Calculates the gravitational force to apply to the entity.
        /// </summary>
        /// <param name="e">Target of the impulse.</param>
        /// <param name="dt">Time since the last frame in simulation seconds.</param>
        /// <param name="impulse">Force to apply at the given position.</param>
        protected override void CalculateImpulse(Entity e, float dt, out Vector3 impulse)
        {
            impulse = (-dt * e.Mass * Acceleration) * Vector3.Up;
        }
    }
}
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: GravitationalField multiplier & space gravity do not equ

Post by Spankenstein »

In this case there are too many separate classes involved in order to isolate and rewrite.

Can I send you a zipped file of the current source? It will include the 2 scenarios shown in the video along with the custom meshes.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: GravitationalField multiplier & space gravity do not equ

Post by Norbo »

My preference would be to do as little work as possible ;)

To that end, it would be much better for me to have something isolated down to only the physical components that I have expertise in, rather than a bunch of other code which I have no special knowledge of. In addition, the process of isolating the issue down to the physical components will provide very strong hints about the source of the problem, if not solve it entirely. That is part of the reason why I generally ask for isolated reproduction cases earlier than a last resort.

The isolated version does not need to show the rotating containers and spheres and all that- it only needs to show a deviation from expected behavior between space.ForceUpdater.Gravity and an ostensibly equivalent force field. Modifying BEPUphysicsDemos demos is convenient for this purpose.
Spankenstein
Posts: 249
Joined: Wed Nov 17, 2010 1:49 pm

Re: GravitationalField multiplier & space gravity do not equ

Post by Spankenstein »

I'll work on something tomorrow then and see if I can isolate it after some sleep.
Post Reply