Page 1 of 1
GravitationalField multiplier & space gravity do not equate?
Posted: Fri Sep 07, 2012 2:32 pm
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
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?
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 4:25 pm
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);
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 6:27 pm
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
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 6:31 pm
by Norbo
Yup. Check out the GravitationalField source. It's from the BEPUphysicsDemos; it has no special access to stuff internal to the engine.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 7:43 pm
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.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 8:28 pm
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.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 8:48 pm
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.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 9:05 pm
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;
}
}
}
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 9:23 pm
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.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 9:33 pm
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.
Re: GravitationalField multiplier & space gravity do not equ
Posted: Fri Sep 07, 2012 10:09 pm
by Spankenstein
I'll work on something tomorrow then and see if I can isolate it after some sleep.