BulletSim: Redo parameter specification so only one place has

to change to have a parameter show up in the ini file and
command line. Will make it much easier for the next person.
0.7.4.1
Robert Adams 2012-07-25 10:35:34 -07:00
parent 2d05e16f7e
commit bf6529db32
1 changed files with 373 additions and 243 deletions

View File

@ -103,6 +103,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
get { return m_sculptLOD; } get { return m_sculptLOD; }
} }
private BulletSim m_worldSim;
public BulletSim World
{
get { return m_worldSim; }
}
private BSConstraintCollection m_constraintCollection;
public BSConstraintCollection Constraints
{
get { return m_constraintCollection; }
}
private int m_maxSubSteps; private int m_maxSubSteps;
private float m_fixedTimeStep; private float m_fixedTimeStep;
private long m_simulationStep = 0; private long m_simulationStep = 0;
@ -229,6 +240,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject());
// Initialization to support the transition to a new API which puts most of the logic
// into the C# code so it is easier to modify and add to.
m_worldSim = new BulletSim(m_worldID, BulletSimAPI.GetSimHandle2(m_worldID));
m_constraintCollection = new BSConstraintCollection(World);
m_initialized = true; m_initialized = true;
} }
@ -237,116 +253,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private void GetInitialParameterValues(IConfigSource config) private void GetInitialParameterValues(IConfigSource config)
{ {
ConfigurationParameters parms = new ConfigurationParameters(); ConfigurationParameters parms = new ConfigurationParameters();
m_params[0] = parms;
_meshSculptedPrim = true; // mesh sculpted prims SetParameterDefaultValues();
_forceSimplePrimMeshing = false; // use complex meshing if called for
m_meshLOD = 8f;
m_sculptLOD = 32f;
shouldDebugLog = false;
m_detailedStatsStep = 0; // disabled
m_maxSubSteps = 10;
m_fixedTimeStep = 1f / 60f;
m_maxCollisionsPerFrame = 2048;
m_maxUpdatesPerFrame = 2048;
m_maximumObjectMass = 10000.01f;
PID_D = 2200f;
PID_P = 900f;
parms.defaultFriction = 0.5f;
parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
parms.defaultRestitution = 0f;
parms.collisionMargin = 0.0f;
parms.gravity = -9.80665f;
parms.linearDamping = 0.0f;
parms.angularDamping = 0.0f;
parms.deactivationTime = 0.2f;
parms.linearSleepingThreshold = 0.8f;
parms.angularSleepingThreshold = 1.0f;
parms.ccdMotionThreshold = 0.0f; // set to zero to disable
parms.ccdSweptSphereRadius = 0.0f;
parms.contactProcessingThreshold = 0.1f;
parms.terrainFriction = 0.5f;
parms.terrainHitFraction = 0.8f;
parms.terrainRestitution = 0f;
parms.avatarFriction = 0.5f;
parms.avatarRestitution = 0.0f;
parms.avatarDensity = 60f;
parms.avatarCapsuleRadius = 0.37f;
parms.avatarCapsuleHeight = 1.5f; // 2.140599f
parms.avatarContactProcessingThreshold = 0.1f;
parms.maxPersistantManifoldPoolSize = 0f;
parms.shouldDisableContactPoolDynamicAllocation = ConfigurationParameters.numericTrue;
parms.shouldForceUpdateAllAabbs = ConfigurationParameters.numericFalse;
parms.shouldRandomizeSolverOrder = ConfigurationParameters.numericFalse;
parms.shouldSplitSimulationIslands = ConfigurationParameters.numericFalse;
parms.shouldEnableFrictionCaching = ConfigurationParameters.numericFalse;
parms.numberOfSolverIterations = 0f; // means use default
if (config != null) if (config != null)
{ {
// If there are specifications in the ini file, use those values // If there are specifications in the ini file, use those values
// WHEN ADDING OR UPDATING THIS SECTION, BE SURE TO UPDATE OpenSimDefaults.ini
// ALSO REMEMBER TO UPDATE THE RUNTIME SETTING OF THE PARAMETERS.
IConfig pConfig = config.Configs["BulletSim"]; IConfig pConfig = config.Configs["BulletSim"];
if (pConfig != null) if (pConfig != null)
{ {
_meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); SetParameterConfigurationValues(pConfig);
_forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing);
shouldDebugLog = pConfig.GetBoolean("ShouldDebugLog", shouldDebugLog);
m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep);
m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD);
m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD);
m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps);
m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep);
m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame);
m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame);
m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass);
PID_D = pConfig.GetFloat("PIDDerivative", PID_D);
PID_P = pConfig.GetFloat("PIDProportional", PID_P);
parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction);
parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity);
parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution);
parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin);
parms.gravity = pConfig.GetFloat("Gravity", parms.gravity);
parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping);
parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping);
parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime);
parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold);
parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold);
parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold);
parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
parms.contactProcessingThreshold = pConfig.GetFloat("ContactProcessingThreshold", parms.contactProcessingThreshold);
parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
parms.avatarRestitution = pConfig.GetFloat("AvatarRestitution", parms.avatarRestitution);
parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius);
parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight);
parms.avatarContactProcessingThreshold = pConfig.GetFloat("AvatarContactProcessingThreshold", parms.avatarContactProcessingThreshold);
parms.maxPersistantManifoldPoolSize = pConfig.GetFloat("MaxPersistantManifoldPoolSize", parms.maxPersistantManifoldPoolSize);
parms.shouldDisableContactPoolDynamicAllocation = ParamBoolean(pConfig, "ShouldDisableContactPoolDynamicAllocation", parms.shouldDisableContactPoolDynamicAllocation);
parms.shouldForceUpdateAllAabbs = ParamBoolean(pConfig, "ShouldForceUpdateAllAabbs", parms.shouldForceUpdateAllAabbs);
parms.shouldRandomizeSolverOrder = ParamBoolean(pConfig, "ShouldRandomizeSolverOrder", parms.shouldRandomizeSolverOrder);
parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands);
parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching);
parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations);
// Very detailed logging for physics debugging // Very detailed logging for physics debugging
m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
@ -357,7 +274,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
} }
} }
m_params[0] = parms;
} }
// A helper function that handles a true/false parameter and returns the proper float number encoding // A helper function that handles a true/false parameter and returns the proper float number encoding
@ -634,6 +550,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// make sure no stepping happens while we're deleting stuff // make sure no stepping happens while we're deleting stuff
m_initialized = false; m_initialized = false;
if (m_constraintCollection != null)
{
m_constraintCollection.Dispose();
m_constraintCollection = null;
}
foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars) foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
{ {
kvp.Value.Destroy(); kvp.Value.Destroy();
@ -776,10 +698,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
// The calls to the PhysicsActors can't directly call into the physics engine // The calls to the PhysicsActors can't directly call into the physics engine
// because it might be busy. We we delay changes to a known time. // because it might be busy. We delay changes to a known time.
// We rely on C#'s closure to save and restore the context for the delegate. // We rely on C#'s closure to save and restore the context for the delegate.
public void TaintedObject(TaintCallback callback) public void TaintedObject(TaintCallback callback)
{ {
if (!m_initialized) return;
lock (_taintLock) lock (_taintLock)
_taintedObjects.Add(callback); _taintedObjects.Add(callback);
return; return;
@ -853,61 +777,350 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
#endregion Vehicles #endregion Vehicles
#region Runtime settable parameters #region Parameters
public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
delegate float ParamGet(BSScene scene);
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
private struct ParameterDefn
{ {
new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)"), public string name;
new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"), public string desc;
new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"), public float defaultValue;
new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"), public ParamUser userParam;
new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"), public ParamGet getter;
new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"), public ParamSet setter;
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
{
name = n;
desc = d;
defaultValue = v;
userParam = u;
getter = g;
setter = s;
}
}
new PhysParameterEntry("DefaultFriction", "Friction factor used on new objects"), // List of all of the externally visible parameters.
new PhysParameterEntry("DefaultDensity", "Density for new objects" ), // For each parameter, this table maps a text name to getter and setters.
new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ), // A ParameterDefn() takes the following parameters:
// new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ), // -- the text name of the parameter. This is used for console input and ini file.
new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ), // -- a short text description of the parameter. This shows up in the console listing.
// -- a delegate for fetching the parameter from the ini file.
// Should handle fetching the right type from the ini file and converting it.
// -- a delegate for getting the value as a float
// -- a delegate for setting the value from a float
//
// To add a new variable, it is best to find an existing definition and copy it.
private ParameterDefn[] ParameterDefinitions =
{
new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s._meshSculptedPrim); },
(s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ),
new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s._forceSimplePrimMeshing); },
(s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ),
new PhysParameterEntry("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)" ), new ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
new PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ), 8f,
new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ), (s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ), (s) => { return (float)s.m_meshLOD; },
new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ), (s,p,l,v) => { s.m_meshLOD = (int)v; } ),
new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ), new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ), 32,
new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ), (s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
// Can only change the following at initialization time. Change the INI file and reboot. (s) => { return (float)s.m_sculptLOD; },
new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"), (s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
new PhysParameterEntry("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count"),
new PhysParameterEntry("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step"),
new PhysParameterEntry("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction"),
new PhysParameterEntry("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands"),
new PhysParameterEntry("ShouldEnableFrictionCaching", "Enable friction computation caching"),
new PhysParameterEntry("NumberOfSolverIterations", "Number of internal iterations (0 means default)"),
new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 10f,
(s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxSubSteps; },
(s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
1f / 60f,
(s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
(s) => { return (float)s.m_fixedTimeStep; },
(s,p,l,v) => { s.m_fixedTimeStep = v; } ),
new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
2048f,
(s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxCollisionsPerFrame; },
(s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
8000f,
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxUpdatesPerFrame; },
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { s.m_maximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)s.m_maximumObjectMass; },
(s,p,l,v) => { s.m_maximumObjectMass = v; } ),
new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ), new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ), 2200f,
(s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
(s) => { return (float)s.PID_D; },
(s,p,l,v) => { s.PID_D = v; } ),
new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
900f,
(s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
(s) => { return (float)s.PID_P; },
(s,p,l,v) => { s.PID_P = v; } ),
new PhysParameterEntry("TerrainFriction", "Factor to reduce movement against terrain surface" ), new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
new PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ), 0.5f,
new PhysParameterEntry("TerrainRestitution", "Bouncyness" ), (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ), (s) => { return s.m_params[0].defaultFriction; },
new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ), (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ), new ParameterDefn("DefaultDensity", "Density for new objects" ,
new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ), 10.000006836f, // Aluminum g/cm3
new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ), (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions") (s) => { return s.m_params[0].defaultDensity; },
(s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
0f,
(s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultRestitution; },
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
0f,
(s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].collisionMargin; },
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
-9.80665f,
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].gravity; },
(s,p,l,v) => { s.m_params[0].gravity = v; s.TaintedUpdateParameter(p,l,v); } ),
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearDamping; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearDamping, p, l, v); } ),
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularDamping; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularDamping, p, l, v); } ),
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
0.2f,
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].deactivationTime; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].deactivationTime, p, l, v); } ),
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
0.8f,
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].linearSleepingThreshold, p, l, v); } ),
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1.0f,
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].angularSleepingThreshold, p, l, v); } ),
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
0f, // set to zero to disable
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdMotionThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdMotionThreshold, p, l, v); } ),
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
0f,
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); } ),
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
0.1f,
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].contactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterPrims(ref s.m_params[0].contactProcessingThreshold, p, l, v); } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.5f,
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainFriction; },
(s,p,l,v) => { s.m_params[0].terrainFriction = v; s.TaintedUpdateParameter(p,l,v); } ),
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
0.8f,
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainHitFraction; },
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; s.TaintedUpdateParameter(p,l,v); } ),
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
0f,
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainRestitution; },
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; s.TaintedUpdateParameter(p,l,v); } ),
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.5f,
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarFriction, p, l, v); } ),
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
60f,
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarDensity; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarDensity, p, l, v); } ),
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
0f,
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarRestitution; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarRestitution, p, l, v); } ),
new ParameterDefn("AvatarCapsuleRadius", "Radius of space around an avatar",
0.37f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleRadius; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleRadius, p, l, v); } ),
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1.5f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleHeight; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
0.1f,
(s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterAvatars(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)",
0f, // zero to disable
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
(s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
(s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
(s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldSplitSimulationIslands; },
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldEnableFrictionCaching; },
(s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
0f, // zero says use Bullet default
(s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].numberOfSolverIterations; },
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
new ParameterDefn("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)",
0f,
(s,cf,p,v) => { s.m_detailedStatsStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_detailedStatsStep; },
(s,p,l,v) => { s.m_detailedStatsStep = (int)v; } ),
new ParameterDefn("ShouldDebugLog", "Enables detailed DEBUG log statements",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.shouldDebugLog = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.shouldDebugLog); },
(s,p,l,v) => { s.shouldDebugLog = s.BoolNumeric(v); } ),
}; };
// Convert a boolean to our numeric true and false values
protected float NumericBool(bool b)
{
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
}
// Convert numeric true and false values to a boolean
protected bool BoolNumeric(float b)
{
return (b == ConfigurationParameters.numericTrue ? true : false);
}
// Search through the parameter definitions and return the matching
// ParameterDefn structure.
// Case does not matter as names are compared after converting to lower case.
// Returns 'false' if the parameter is not found.
private bool TryGetParameter(string paramName, out ParameterDefn defn)
{
bool ret = false;
ParameterDefn foundDefn = new ParameterDefn();
string pName = paramName.ToLower();
foreach (ParameterDefn parm in ParameterDefinitions)
{
if (pName == parm.name.ToLower())
{
foundDefn = parm;
ret = true;
break;
}
}
defn = foundDefn;
return ret;
}
// Pass through the settable parameters and set the default values
private void SetParameterDefaultValues()
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
}
}
// Get user set values out of the ini file.
private void SetParameterConfigurationValues(IConfig cfg)
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.userParam(this, cfg, parm.name, parm.defaultValue);
}
}
private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
private void BuildParameterTable()
{
if (SettableParameters.Length < ParameterDefinitions.Length)
{
List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
{
ParameterDefn pd = ParameterDefinitions[ii];
entries.Add(new PhysParameterEntry(pd.name, pd.desc));
}
// make the list in alphabetical order for estetic reasons
entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
{
return ppe1.name.CompareTo(ppe2.name);
});
SettableParameters = entries.ToArray();
}
}
#region IPhysicsParameters #region IPhysicsParameters
// Get the list of parameters this physics engine supports // Get the list of parameters this physics engine supports
public PhysParameterEntry[] GetParameterList() public PhysParameterEntry[] GetParameterList()
{ {
BuildParameterTable();
return SettableParameters; return SettableParameters;
} }
@ -919,63 +1132,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// value activated ('terrainFriction' for instance). // value activated ('terrainFriction' for instance).
public bool SetPhysicsParameter(string parm, float val, uint localID) public bool SetPhysicsParameter(string parm, float val, uint localID)
{ {
bool ret = true; bool ret = false;
string lparm = parm.ToLower(); ParameterDefn theParam;
switch (lparm) if (TryGetParameter(parm, out theParam))
{ {
case "detailedstats": m_detailedStatsStep = (int)val; break; theParam.setter(this, parm, localID, val);
ret = true;
case "meshlod": m_meshLOD = (int)val; break;
case "sculptlod": m_sculptLOD = (int)val; break;
case "maxsubstep": m_maxSubSteps = (int)val; break;
case "fixedtimestep": m_fixedTimeStep = val; break;
case "maxobjectmass": m_maximumObjectMass = val; break;
case "defaultfriction": m_params[0].defaultFriction = val; break;
case "defaultdensity": m_params[0].defaultDensity = val; break;
case "defaultrestitution": m_params[0].defaultRestitution = val; break;
case "collisionmargin": m_params[0].collisionMargin = val; break;
case "gravity": m_params[0].gravity = val; TaintedUpdateParameter(lparm, localID, val); break;
case "lineardamping": UpdateParameterPrims(ref m_params[0].linearDamping, lparm, localID, val); break;
case "angulardamping": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
case "deactivationtime": UpdateParameterPrims(ref m_params[0].deactivationTime, lparm, localID, val); break;
case "linearsleepingthreshold": UpdateParameterPrims(ref m_params[0].linearSleepingThreshold, lparm, localID, val); break;
case "angularsleepingthreshold": UpdateParameterPrims(ref m_params[0].angularDamping, lparm, localID, val); break;
case "ccdmotionthreshold": UpdateParameterPrims(ref m_params[0].ccdMotionThreshold, lparm, localID, val); break;
case "ccdsweptsphereradius": UpdateParameterPrims(ref m_params[0].ccdSweptSphereRadius, lparm, localID, val); break;
case "contactprocessingthreshold": UpdateParameterPrims(ref m_params[0].contactProcessingThreshold, lparm, localID, val); break;
// the following are used only at initialization time so setting them makes no sense
// case "maxPersistantmanifoldpoolSize": m_params[0].maxPersistantManifoldPoolSize = val; break;
// case "shoulddisablecontactpooldynamicallocation": m_params[0].shouldDisableContactPoolDynamicAllocation = val; break;
// case "shouldforceupdateallaabbs": m_params[0].shouldForceUpdateAllAabbs = val; break;
// case "shouldrandomizesolverorder": m_params[0].shouldRandomizeSolverOrder = val; break;
// case "shouldsplitsimulationislands": m_params[0].shouldSplitSimulationIslands = val; break;
// case "shouldenablefrictioncaching": m_params[0].shouldEnableFrictionCaching = val; break;
// case "numberofsolveriterations": m_params[0].numberOfSolverIterations = val; break;
case "friction": TaintedUpdateParameter(lparm, localID, val); break;
case "restitution": TaintedUpdateParameter(lparm, localID, val); break;
// set a terrain physical feature and cause terrain to be recalculated
case "terrainfriction": m_params[0].terrainFriction = val; TaintedUpdateParameter("terrain", 0, val); break;
case "terrainhitfraction": m_params[0].terrainHitFraction = val; TaintedUpdateParameter("terrain", 0, val); break;
case "terrainrestitution": m_params[0].terrainRestitution = val; TaintedUpdateParameter("terrain", 0, val); break;
// set an avatar physical feature and cause avatar(s) to be recalculated
case "avatarfriction": UpdateParameterAvatars(ref m_params[0].avatarFriction, "avatar", localID, val); break;
case "avatardensity": UpdateParameterAvatars(ref m_params[0].avatarDensity, "avatar", localID, val); break;
case "avatarrestitution": UpdateParameterAvatars(ref m_params[0].avatarRestitution, "avatar", localID, val); break;
case "avatarcapsuleradius": UpdateParameterAvatars(ref m_params[0].avatarCapsuleRadius, "avatar", localID, val); break;
case "avatarcapsuleheight": UpdateParameterAvatars(ref m_params[0].avatarCapsuleHeight, "avatar", localID, val); break;
case "avatarcontactprocessingthreshold": UpdateParameterAvatars(ref m_params[0].avatarContactProcessingThreshold, "avatar", localID, val); break;
default: ret = false; break;
} }
return ret; return ret;
} }
// check to see if we are updating a parameter for a particular or all of the prims // check to see if we are updating a parameter for a particular or all of the prims
private void UpdateParameterPrims(ref float loc, string parm, uint localID, float val) protected void UpdateParameterPrims(ref float loc, string parm, uint localID, float val)
{ {
List<uint> operateOn; List<uint> operateOn;
lock (m_prims) operateOn = new List<uint>(m_prims.Keys); lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@ -983,7 +1151,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
// check to see if we are updating a parameter for a particular or all of the avatars // check to see if we are updating a parameter for a particular or all of the avatars
private void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val) protected void UpdateParameterAvatars(ref float loc, string parm, uint localID, float val)
{ {
List<uint> operateOn; List<uint> operateOn;
lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys); lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@ -994,7 +1162,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// If the local ID is APPLY_TO_NONE, just change the default value // If the local ID is APPLY_TO_NONE, just change the default value
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
// If the localID is a specific object, apply the parameter change to only that object // If the localID is a specific object, apply the parameter change to only that object
private void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val) protected void UpdateParameterSet(List<uint> lIDs, ref float defaultLoc, string parm, uint localID, float val)
{ {
switch (localID) switch (localID)
{ {
@ -1021,7 +1189,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
} }
// schedule the actual updating of the paramter to when the phys engine is not busy // schedule the actual updating of the paramter to when the phys engine is not busy
private void TaintedUpdateParameter(string parm, uint localID, float val) protected void TaintedUpdateParameter(string parm, uint localID, float val)
{ {
uint xlocalID = localID; uint xlocalID = localID;
string xparm = parm.ToLower(); string xparm = parm.ToLower();
@ -1036,50 +1204,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public bool GetPhysicsParameter(string parm, out float value) public bool GetPhysicsParameter(string parm, out float value)
{ {
float val = 0f; float val = 0f;
bool ret = true; bool ret = false;
switch (parm.ToLower()) ParameterDefn theParam;
if (TryGetParameter(parm, out theParam))
{ {
case "detailedstats": val = (int)m_detailedStatsStep; break; val = theParam.getter(this);
case "meshlod": val = (float)m_meshLOD; break; ret = true;
case "sculptlod": val = (float)m_sculptLOD; break;
case "maxsubstep": val = (float)m_maxSubSteps; break;
case "fixedtimestep": val = m_fixedTimeStep; break;
case "maxobjectmass": val = m_maximumObjectMass; break;
case "defaultfriction": val = m_params[0].defaultFriction; break;
case "defaultdensity": val = m_params[0].defaultDensity; break;
case "defaultrestitution": val = m_params[0].defaultRestitution; break;
case "collisionmargin": val = m_params[0].collisionMargin; break;
case "gravity": val = m_params[0].gravity; break;
case "lineardamping": val = m_params[0].linearDamping; break;
case "angulardamping": val = m_params[0].angularDamping; break;
case "deactivationtime": val = m_params[0].deactivationTime; break;
case "linearsleepingthreshold": val = m_params[0].linearSleepingThreshold; break;
case "angularsleepingthreshold": val = m_params[0].angularDamping; break;
case "ccdmotionthreshold": val = m_params[0].ccdMotionThreshold; break;
case "ccdsweptsphereradius": val = m_params[0].ccdSweptSphereRadius; break;
case "contactprocessingthreshold": val = m_params[0].contactProcessingThreshold; break;
case "maxPersistantmanifoldpoolSize": val = m_params[0].maxPersistantManifoldPoolSize; break;
case "shoulddisablecontactpooldynamicallocation": val = m_params[0].shouldDisableContactPoolDynamicAllocation; break;
case "shouldforceupdateallaabbs": val = m_params[0].shouldForceUpdateAllAabbs; break;
case "shouldrandomizesolverorder": val = m_params[0].shouldRandomizeSolverOrder; break;
case "shouldsplitsimulationislands": val = m_params[0].shouldSplitSimulationIslands; break;
case "shouldenablefrictioncaching": val = m_params[0].shouldEnableFrictionCaching; break;
case "numberofsolveriterations": val = m_params[0].numberOfSolverIterations; break;
case "terrainfriction": val = m_params[0].terrainFriction; break;
case "terrainhitfraction": val = m_params[0].terrainHitFraction; break;
case "terrainrestitution": val = m_params[0].terrainRestitution; break;
case "avatarfriction": val = m_params[0].avatarFriction; break;
case "avatardensity": val = m_params[0].avatarDensity; break;
case "avatarrestitution": val = m_params[0].avatarRestitution; break;
case "avatarcapsuleradius": val = m_params[0].avatarCapsuleRadius; break;
case "avatarcapsuleheight": val = m_params[0].avatarCapsuleHeight; break;
case "avatarcontactprocessingthreshold": val = m_params[0].avatarContactProcessingThreshold; break;
default: ret = false; break;
} }
value = val; value = val;
return ret; return ret;