Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

0.7.4.1
Justin Clark-Casey (justincc) 2012-07-26 23:46:54 +01:00
commit 0aaf52fca4
10 changed files with 779 additions and 271 deletions

View File

@ -0,0 +1,115 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSConstraint : IDisposable
{
private BulletSim m_world;
private BulletBody m_body1;
private BulletBody m_body2;
private BulletConstraint m_constraint;
private bool m_enabled = false;
public BSConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot
)
{
m_world = world;
m_body1 = obj1;
m_body2 = obj2;
m_constraint = new BulletConstraint(BulletSimAPI.CreateConstraint2(m_world.Ptr, m_body1.Ptr, m_body2.Ptr,
frame1, frame1rot,
frame2, frame2rot));
m_enabled = true;
}
public void Dispose()
{
if (m_enabled)
{
// BulletSimAPI.RemoveConstraint(m_world.ID, m_body1.ID, m_body2.ID);
BulletSimAPI.DestroyConstraint2(m_world.Ptr, m_constraint.Ptr);
m_enabled = false;
}
}
public BulletBody Body1 { get { return m_body1; } }
public BulletBody Body2 { get { return m_body2; } }
public bool SetLinearLimits(Vector3 low, Vector3 high)
{
bool ret = false;
if (m_enabled)
ret = BulletSimAPI.SetLinearLimits2(m_constraint.Ptr, low, high);
return ret;
}
public bool SetAngularLimits(Vector3 low, Vector3 high)
{
bool ret = false;
if (m_enabled)
ret = BulletSimAPI.SetAngularLimits2(m_constraint.Ptr, low, high);
return ret;
}
public bool UseFrameOffset(bool useOffset)
{
bool ret = false;
float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.UseFrameOffset2(m_constraint.Ptr, onOff);
return ret;
}
public bool TranslationalLimitMotor(bool enable, float targetVelocity, float maxMotorForce)
{
bool ret = false;
float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
if (m_enabled)
ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.Ptr, onOff, targetVelocity, maxMotorForce);
return ret;
}
public bool CalculateTransforms()
{
bool ret = false;
if (m_enabled)
{
BulletSimAPI.CalculateTransforms2(m_constraint.Ptr);
ret = true;
}
return ret;
}
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using log4net;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSConstraintCollection : IDisposable
{
// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
// private static readonly string LogHeader = "[CONSTRAINT COLLECTION]";
delegate bool ConstraintAction(BSConstraint constrain);
private List<BSConstraint> m_constraints;
private BulletSim m_world;
public BSConstraintCollection(BulletSim world)
{
m_world = world;
m_constraints = new List<BSConstraint>();
}
public void Dispose()
{
this.Clear();
}
public void Clear()
{
foreach (BSConstraint cons in m_constraints)
{
cons.Dispose();
}
m_constraints.Clear();
}
public BSConstraint CreateConstraint(BulletSim world, BulletBody obj1, BulletBody obj2,
Vector3 frame1, Quaternion frame1rot,
Vector3 frame2, Quaternion frame2rot)
{
BSConstraint constrain = new BSConstraint(world, obj1, obj2, frame1, frame1rot, frame2, frame2rot);
this.AddConstraint(constrain);
return constrain;
}
public bool AddConstraint(BSConstraint cons)
{
// There is only one constraint between any bodies. Remove any old just to make sure.
RemoveAndDestroyConstraint(cons.Body1, cons.Body2);
m_constraints.Add(cons);
return true;
}
// Get the constraint between two bodies. There can be only one the way we're using them.
public bool TryGetConstraint(BulletBody body1, BulletBody body2, out BSConstraint returnConstraint)
{
bool found = false;
BSConstraint foundConstraint = null;
uint lookingID1 = body1.ID;
uint lookingID2 = body2.ID;
ForEachConstraint(delegate(BSConstraint constrain)
{
if ((constrain.Body1.ID == lookingID1 && constrain.Body2.ID == lookingID2)
|| (constrain.Body1.ID == lookingID2 && constrain.Body2.ID == lookingID1))
{
foundConstraint = constrain;
found = true;
}
return found;
});
returnConstraint = foundConstraint;
return found;
}
public bool RemoveAndDestroyConstraint(BulletBody body1, BulletBody body2)
{
// return BulletSimAPI.RemoveConstraint(m_world.ID, obj1.ID, obj2.ID);
bool ret = false;
BSConstraint constrain;
if (this.TryGetConstraint(body1, body2, out constrain))
{
// remove the constraint from our collection
m_constraints.Remove(constrain);
// tell the engine that all its structures need to be freed
constrain.Dispose();
// we destroyed something
ret = true;
}
return ret;
}
public bool RemoveAndDestroyConstraint(BulletBody body1)
{
// return BulletSimAPI.RemoveConstraintByID(m_world.ID, obj.ID);
List<BSConstraint> toRemove = new List<BSConstraint>();
uint lookingID = body1.ID;
ForEachConstraint(delegate(BSConstraint constrain)
{
if (constrain.Body1.ID == lookingID || constrain.Body2.ID == lookingID)
{
toRemove.Add(constrain);
}
return false;
});
lock (m_constraints)
{
foreach (BSConstraint constrain in toRemove)
{
m_constraints.Remove(constrain);
constrain.Dispose();
}
}
return (toRemove.Count > 0);
}
public bool RecalculateAllConstraints()
{
foreach (BSConstraint constrain in m_constraints)
{
constrain.CalculateTransforms();
}
return true;
}
// Lock the constraint list and loop through it.
// The constraint action returns 'true' if it wants the loop aborted.
private void ForEachConstraint(ConstraintAction action)
{
lock (m_constraints)
{
foreach (BSConstraint constrain in m_constraints)
{
if (action(constrain))
break;
}
}
}
}
}

View File

@ -97,6 +97,9 @@ public sealed class BSPrim : PhysicsActor
long _collidingStep;
long _collidingGroundStep;
private BulletBody m_body;
public BulletBody Body { get { return m_body; } }
private BSDynamics _vehicle;
private OMV.Vector3 _PIDTarget;
@ -138,6 +141,11 @@ public sealed class BSPrim : PhysicsActor
_scene.TaintedObject(delegate()
{
RecreateGeomAndObject();
// Get the pointer to the physical body for this object.
// At the moment, we're still letting BulletSim manage the creation and destruction
// of the object. Someday we'll move that into the C# code.
m_body = new BulletBody(LocalID, BulletSimAPI.GetBodyHandle2(_scene.World.Ptr, LocalID));
});
}
@ -161,7 +169,7 @@ public sealed class BSPrim : PhysicsActor
_parentPrim = null;
}
// make sure there are no possible children depending on me
// make sure there are no other prims linked to me
UnlinkAllChildren();
// everything in the C# world will get garbage collected. Tell the C++ world to free stuff.
@ -333,11 +341,10 @@ public sealed class BSPrim : PhysicsActor
_rotationalVelocity = OMV.Vector3.Zero;
// Zero some other properties directly into the physics engine
IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID);
BulletSimAPI.SetVelocity2(obj, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(obj, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolation2(obj, OMV.Vector3.Zero, OMV.Vector3.Zero);
BulletSimAPI.ClearForces2(obj);
BulletSimAPI.SetVelocity2(Body.Ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(Body.Ptr, OMV.Vector3.Zero);
BulletSimAPI.SetInterpolation2(Body.Ptr, OMV.Vector3.Zero, OMV.Vector3.Zero);
BulletSimAPI.ClearForces2(Body.Ptr);
}
public override void LockAngularMotion(OMV.Vector3 axis)
@ -383,7 +390,8 @@ public sealed class BSPrim : PhysicsActor
_scene.TaintedObject(delegate()
{
DetailLog("{0},SetForce,taint,force={1}", LocalID, _force);
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
// BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
BulletSimAPI.SetObjectForce2(Body.Ptr, _force);
});
}
}
@ -407,8 +415,7 @@ public sealed class BSPrim : PhysicsActor
_scene.TaintedObject(delegate()
{
// Tell the physics engine to clear state
IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID);
BulletSimAPI.ClearForces2(obj);
BulletSimAPI.ClearForces2(this.Body.Ptr);
});
// make it so the scene will call us each tick to do vehicle things
@ -420,7 +427,6 @@ public sealed class BSPrim : PhysicsActor
}
public override void VehicleFloatParam(int param, float value)
{
m_log.DebugFormat("{0} VehicleFloatParam. {1} <= {2}", LogHeader, param, value);
_scene.TaintedObject(delegate()
{
_vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
@ -428,7 +434,6 @@ public sealed class BSPrim : PhysicsActor
}
public override void VehicleVectorParam(int param, OMV.Vector3 value)
{
m_log.DebugFormat("{0} VehicleVectorParam. {1} <= {2}", LogHeader, param, value);
_scene.TaintedObject(delegate()
{
_vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep);
@ -436,7 +441,6 @@ public sealed class BSPrim : PhysicsActor
}
public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
{
m_log.DebugFormat("{0} VehicleRotationParam. {1} <= {2}", LogHeader, param, rotation);
_scene.TaintedObject(delegate()
{
_vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
@ -444,7 +448,6 @@ public sealed class BSPrim : PhysicsActor
}
public override void VehicleFlags(int param, bool remove)
{
m_log.DebugFormat("{0} VehicleFlags. {1}. Remove={2}", LogHeader, param, remove);
_scene.TaintedObject(delegate()
{
_vehicle.ProcessVehicleFlags(param, remove);
@ -1292,11 +1295,10 @@ public sealed class BSPrim : PhysicsActor
// relative to each other.
void CreateLinkset()
{
DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
// DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
// remove any constraints that might be in place
DebugLog("{0}: CreateLinkset: RemoveConstraints between me and any children", LogHeader, LocalID);
BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
UnlinkAllChildren();
// create constraints between the root prim and each of the children
foreach (BSPrim prim in _childrenPrims)
@ -1321,15 +1323,25 @@ public sealed class BSPrim : PhysicsActor
// create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
// DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},LinkAChildToMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, childPrim.LocalID,
childRelativePosition,
childRelativeRotation,
OMV.Vector3.Zero,
OMV.Quaternion.Identity,
OMV.Vector3.Zero, OMV.Vector3.Zero,
OMV.Vector3.Zero, OMV.Vector3.Zero);
BSConstraint constrain = _scene.Constraints.CreateConstraint(
_scene.World, this.Body, childPrim.Body,
childRelativePosition,
childRelativeRotation,
OMV.Vector3.Zero,
OMV.Quaternion.Identity);
constrain.SetLinearLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(_scene.BoolNumeric(_scene.Params.linkConstraintUseFrameOffset));
if (_scene.BoolNumeric(_scene.Params.linkConstraintEnableTransMotor))
{
constrain.TranslationalLimitMotor(true,
_scene.Params.linkConstraintTransMotorMaxVel,
_scene.Params.linkConstraintTransMotorMaxForce);
}
}
// Remove linkage between myself and a particular child
@ -1339,7 +1351,8 @@ public sealed class BSPrim : PhysicsActor
DebugLog("{0}: UnlinkAChildFromMe: RemoveConstraint between root prim {1} and child prim {2}",
LogHeader, LocalID, childPrim.LocalID);
DetailLog("{0},UnlinkAChildFromMe,taint,root={1},child={2}", LocalID, LocalID, childPrim.LocalID);
BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
// BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, childPrim.LocalID);
_scene.Constraints.RemoveAndDestroyConstraint(this.Body, childPrim.Body);
}
// Remove linkage between myself and any possible children I might have
@ -1348,7 +1361,8 @@ public sealed class BSPrim : PhysicsActor
{
DebugLog("{0}: UnlinkAllChildren:", LogHeader);
DetailLog("{0},UnlinkAllChildren,taint", LocalID);
BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
_scene.Constraints.RemoveAndDestroyConstraint(this.Body);
// BulletSimAPI.RemoveConstraintByID(_scene.WorldID, LocalID);
}
#endregion // Linkset creation and destruction

View File

@ -103,6 +103,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
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 float m_fixedTimeStep;
private long m_simulationStep = 0;
@ -229,6 +240,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters
m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.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;
}
@ -237,116 +253,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters
private void GetInitialParameterValues(IConfigSource config)
{
ConfigurationParameters parms = new ConfigurationParameters();
m_params[0] = parms;
_meshSculptedPrim = true; // mesh sculpted prims
_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
SetParameterDefaultValues();
if (config != null)
{
// 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"];
if (pConfig != null)
{
_meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim);
_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);
SetParameterConfigurationValues(pConfig);
// Very detailed logging for physics debugging
m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
@ -357,7 +274,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters
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
@ -634,6 +550,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// make sure no stepping happens while we're deleting stuff
m_initialized = false;
if (m_constraintCollection != null)
{
m_constraintCollection.Dispose();
m_constraintCollection = null;
}
foreach (KeyValuePair<uint, BSCharacter> kvp in m_avatars)
{
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
// 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.
public void TaintedObject(TaintCallback callback)
{
if (!m_initialized) return;
lock (_taintLock)
_taintedObjects.Add(callback);
return;
@ -853,61 +777,371 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
#endregion Vehicles
#region Runtime settable parameters
public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
#region Parameters
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)"),
new PhysParameterEntry("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)"),
new PhysParameterEntry("MaxSubStep", "In simulation step, maximum number of substeps"),
new PhysParameterEntry("FixedTimeStep", "In simulation step, seconds of one substep (1/60)"),
new PhysParameterEntry("MaxObjectMass", "Maximum object mass (10000.01)"),
new PhysParameterEntry("DetailedStats", "Frames between outputting detailed phys stats. Zero is off"),
public string name;
public string desc;
public float defaultValue;
public ParamUser userParam;
public ParamGet getter;
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"),
new PhysParameterEntry("DefaultDensity", "Density for new objects" ),
new PhysParameterEntry("DefaultRestitution", "Bouncyness of an object" ),
// new PhysParameterEntry("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!!)" ),
new PhysParameterEntry("Gravity", "Vertical force of gravity (negative means down)" ),
// List of all of the externally visible parameters.
// For each parameter, this table maps a text name to getter and setters.
// A ParameterDefn() takes the following parameters:
// -- the text name of the parameter. This is used for console input and ini file.
// -- 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 PhysParameterEntry("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)" ),
new PhysParameterEntry("DeactivationTime", "Seconds before considering an object potentially static" ),
new PhysParameterEntry("LinearSleepingThreshold", "Seconds to measure linear movement before considering static" ),
new PhysParameterEntry("AngularSleepingThreshold", "Seconds to measure angular movement before considering static" ),
new PhysParameterEntry("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ),
new PhysParameterEntry("CcdSweptSphereRadius", "Continuious collision detection test radius" ),
new PhysParameterEntry("ContactProcessingThreshold", "Distance between contacts before doing collision check" ),
// Can only change the following at initialization time. Change the INI file and reboot.
new PhysParameterEntry("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default)"),
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 ParameterDefn("MeshLOD", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
8f,
(s,cf,p,v) => { s.m_meshLOD = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_meshLOD; },
(s,p,l,v) => { s.m_meshLOD = (int)v; } ),
new ParameterDefn("SculptLOD", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
32,
(s,cf,p,v) => { s.m_sculptLOD = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_sculptLOD; },
(s,p,l,v) => { s.m_sculptLOD = (int)v; } ),
new PhysParameterEntry("Friction", "Set friction parameter for a specific object" ),
new PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
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 PhysParameterEntry("Restitution", "Set restitution parameter for a specific object" ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
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 PhysParameterEntry("TerrainHitFraction", "Distance to measure hit collisions" ),
new PhysParameterEntry("TerrainRestitution", "Bouncyness" ),
new PhysParameterEntry("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation." ),
new PhysParameterEntry("AvatarDensity", "Density of an avatar. Changed on avatar recreation." ),
new PhysParameterEntry("AvatarRestitution", "Bouncyness. Changed on avatar recreation." ),
new PhysParameterEntry("AvatarCapsuleRadius", "Radius of space around an avatar" ),
new PhysParameterEntry("AvatarCapsuleHeight", "Default height of space around avatar" ),
new PhysParameterEntry("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions")
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
0.5f,
(s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultFriction; },
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
new ParameterDefn("DefaultDensity", "Density for new objects" ,
10.000006836f, // Aluminum g/cm3
(s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
(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("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
(s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
(s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
5.0f,
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = 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
public float NumericBool(bool b)
{
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
}
// Convert numeric true and false values to a boolean
public 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
// Get the list of parameters this physics engine supports
public PhysParameterEntry[] GetParameterList()
{
BuildParameterTable();
return SettableParameters;
}
@ -919,63 +1153,18 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// value activated ('terrainFriction' for instance).
public bool SetPhysicsParameter(string parm, float val, uint localID)
{
bool ret = true;
string lparm = parm.ToLower();
switch (lparm)
bool ret = false;
ParameterDefn theParam;
if (TryGetParameter(parm, out theParam))
{
case "detailedstats": m_detailedStatsStep = (int)val; break;
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;
theParam.setter(this, parm, localID, val);
ret = true;
}
return ret;
}
// 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;
lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
@ -983,7 +1172,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// 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;
lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
@ -994,7 +1183,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// 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 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)
{
@ -1021,7 +1210,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters
}
// 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;
string xparm = parm.ToLower();
@ -1036,50 +1225,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters
public bool GetPhysicsParameter(string parm, out float value)
{
float val = 0f;
bool ret = true;
switch (parm.ToLower())
bool ret = false;
ParameterDefn theParam;
if (TryGetParameter(parm, out theParam))
{
case "detailedstats": val = (int)m_detailedStatsStep; break;
case "meshlod": val = (float)m_meshLOD; break;
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;
val = theParam.getter(this);
ret = true;
}
value = val;
return ret;

View File

@ -32,6 +32,28 @@ using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin {
// Classes to allow some type checking for the API
public struct BulletSim
{
public BulletSim(uint id, IntPtr xx) { ID = id; Ptr = xx; }
public IntPtr Ptr;
public uint ID;
}
public struct BulletBody
{
public BulletBody(uint id, IntPtr xx) { ID = id; Ptr = xx; }
public IntPtr Ptr;
public uint ID;
}
public struct BulletConstraint
{
public BulletConstraint(IntPtr xx) { Ptr = xx; }
public IntPtr Ptr;
}
// ===============================================================================
[StructLayout(LayoutKind.Sequential)]
public struct ConvexHull
{
@ -142,6 +164,11 @@ public struct ConfigurationParameters
public float shouldEnableFrictionCaching;
public float numberOfSolverIterations;
public float linkConstraintUseFrameOffset;
public float linkConstraintEnableTransMotor;
public float linkConstraintTransMotorMaxVel;
public float linkConstraintTransMotorMaxForce;
public const float numericTrue = 1f;
public const float numericFalse = 0f;
}
@ -162,6 +189,7 @@ public enum CollisionFlags : uint
PHYSICAL_OBJECT = 1 << 12,
};
// ===============================================================================
static class BulletSimAPI {
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
@ -214,6 +242,7 @@ public static extern bool CreateObject(uint worldID, ShapeData shapeData);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void CreateLinkset(uint worldID, int objectCount, ShapeData[] shapeDatas);
/* Remove old functionality
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void AddConstraint(uint worldID, uint id1, uint id2,
Vector3 frame1, Quaternion frame1rot,
@ -225,6 +254,7 @@ public static extern bool RemoveConstraintByID(uint worldID, uint id1);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2);
*/
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern Vector3 GetObjectPosition(uint WorldID, uint id);
@ -350,8 +380,22 @@ public static extern IntPtr CreateObject2(IntPtr sim, ShapeData shapeData);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateConstraint2(IntPtr sim, IntPtr obj1, IntPtr obj2,
Vector3 frame1loc, Quaternion frame1rot,
Vector3 frame2loc, Quaternion frame2rot,
Vector3 lowLinear, Vector3 hiLinear, Vector3 lowAngular, Vector3 hiAngular);
Vector3 frame2loc, Quaternion frame2rot);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool CalculateTransforms2(IntPtr constrain);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool DestroyConstraint2(IntPtr sim, IntPtr constrain);

View File

@ -914,6 +914,12 @@
ShouldEnableFrictionCaching = False;
NumberOfSolverIterations = 0;
; Linkset constraint parameters
LinkConstraintUseFrameOffset = True;
LinkConstraintEnableTransMotor = True;
LinkConstraintTransMotorMaxVel = 5.0;
LinkConstraintTransMotorMaxForce = 0.1;
; Whether to mesh sculpties
MeshSculptedPrim = true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.