BulletSim: add runtime setting of physics parameters. Update default values.

bulletsim
Robert Adams 2011-08-18 14:32:09 -07:00 committed by Mic Bowman
parent 82f41fdcb5
commit fef73a1a10
10 changed files with 613 additions and 28 deletions

View File

@ -47,6 +47,12 @@ namespace OpenSim.Region.Framework.Scenes
public event RestartSim OnRestartSim; public event RestartSim OnRestartSim;
private static SceneManager m_instance = null;
public static SceneManager Instance
{
get { return m_instance; }
}
private readonly List<Scene> m_localScenes; private readonly List<Scene> m_localScenes;
private Scene m_currentScene = null; private Scene m_currentScene = null;
@ -84,6 +90,7 @@ namespace OpenSim.Region.Framework.Scenes
public SceneManager() public SceneManager()
{ {
m_instance = this;
m_localScenes = new List<Scene>(); m_localScenes = new List<Scene>();
} }

View File

@ -0,0 +1,277 @@
/*
* 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 copyright
* 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.Reflection;
using System.Collections.Generic;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Physics.Manager;
namespace OpenSim.Region.OptionalModules.PhysicsParameters
{
/// <summary>
/// </summary>
/// <remarks>
/// </remarks>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "PhysicsParameters")]
public class PhysicsParameters : ISharedRegionModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[PHYSICS PARAMETERS]";
private List<Scene> m_scenes = new List<Scene>();
private static bool m_commandsLoaded = false;
#region ISharedRegionModule
public string Name { get { return "Runtime Physics Parameter Module"; } }
public Type ReplaceableInterface { get { return null; } }
public void Initialise(IConfigSource source)
{
// m_log.DebugFormat("{0}: INITIALIZED MODULE", LogHeader);
}
public void PostInitialise()
{
// m_log.DebugFormat("[{0}: POST INITIALIZED MODULE", LogHeader);
InstallInterfaces();
}
public void Close()
{
// m_log.DebugFormat("{0}: CLOSED MODULE", LogHeader);
}
public void AddRegion(Scene scene)
{
// m_log.DebugFormat("{0}: REGION {1} ADDED", LogHeader, scene.RegionInfo.RegionName);
m_scenes.Add(scene);
}
public void RemoveRegion(Scene scene)
{
// m_log.DebugFormat("{0}: REGION {1} REMOVED", LogHeader, scene.RegionInfo.RegionName);
if (m_scenes.Contains(scene))
m_scenes.Remove(scene);
}
public void RegionLoaded(Scene scene)
{
// m_log.DebugFormat("{0}: REGION {1} LOADED", LogHeader, scene.RegionInfo.RegionName);
}
#endregion INonSharedRegionModule
private const string getInvocation = "physics get [<param>|ALL]";
private const string setInvocation = "physics set <param> [<value>|TRUE|FALSE] [localID|ALL]";
private const string listInvocation = "physics list";
private void InstallInterfaces()
{
if (!m_commandsLoaded)
{
MainConsole.Instance.Commands.AddCommand("Physics", false, "physics set",
"physics set",
"Set physics parameter from currently selected region" + Environment.NewLine
+ "Invocation: " + setInvocation,
ProcessPhysicsSet);
MainConsole.Instance.Commands.AddCommand("Physics", false, "physics get",
"physics get",
"Get physics parameter from currently selected region" + Environment.NewLine
+ "Invocation: " + getInvocation,
ProcessPhysicsGet);
MainConsole.Instance.Commands.AddCommand("Physics", false, "physics list",
"physics list",
"List settable physics parameters" + Environment.NewLine
+ "Invocation: " + listInvocation,
ProcessPhysicsList);
m_commandsLoaded = true;
}
}
// TODO: extend get so you can get a value from an individual localID
private void ProcessPhysicsGet(string module, string[] cmdparms)
{
if (cmdparms.Length != 3)
{
WriteError("Parameter count error. Invocation: " + getInvocation);
return;
}
string parm = cmdparms[2];
if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null)
{
WriteError("Error: no region selected. Use 'change region' to select a region.");
return;
}
Scene scene = SceneManager.Instance.CurrentScene;
IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
if (physScene != null)
{
if (parm.ToLower() == "all")
{
foreach (PhysParameterEntry ppe in physScene.GetParameterList())
{
float val = 0.0f;
if (physScene.GetPhysicsParameter(ppe.name, out val))
{
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, val);
}
else
{
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, ppe.name, "unknown");
}
}
}
else
{
float val = 0.0f;
if (physScene.GetPhysicsParameter(parm, out val))
{
WriteOut(" {0}/{1} = {2}", scene.RegionInfo.RegionName, parm, val);
}
else
{
WriteError("Failed fetch of parameter '{0}' from region '{1}'", parm, scene.RegionInfo.RegionName);
}
}
}
else
{
WriteError("Region '{0}' physics engine has no gettable physics parameters", scene.RegionInfo.RegionName);
}
return;
}
private void ProcessPhysicsSet(string module, string[] cmdparms)
{
if (cmdparms.Length < 4 || cmdparms.Length > 5)
{
WriteError("Parameter count error. Invocation: " + getInvocation);
return;
}
string parm = "xxx";
float val = 0f;
uint localID = (uint)PhysParameterEntry.APPLY_TO_NONE; // set default value
try
{
parm = cmdparms[2];
string valparm = cmdparms[3].ToLower();
if (valparm == "true")
val = PhysParameterEntry.NUMERIC_TRUE;
else
{
if (valparm == "false")
val = PhysParameterEntry.NUMERIC_FALSE;
else
val = float.Parse(valparm, Culture.NumberFormatInfo);
}
if (cmdparms.Length > 4)
{
if (cmdparms[4].ToLower() == "all")
localID = (uint)PhysParameterEntry.APPLY_TO_ALL;
else
localID = uint.Parse(cmdparms[2], Culture.NumberFormatInfo);
}
}
catch
{
WriteError(" Error parsing parameters. Invocation: " + setInvocation);
return;
}
if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null)
{
WriteError("Error: no region selected. Use 'change region' to select a region.");
return;
}
Scene scene = SceneManager.Instance.CurrentScene;
IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
if (physScene != null)
{
if (!physScene.SetPhysicsParameter(parm, val, localID))
{
WriteError("Failed set of parameter '{0}' for region '{1}'", parm, scene.RegionInfo.RegionName);
}
}
else
{
WriteOut("Region '{0}'s physics engine has no settable physics parameters", scene.RegionInfo.RegionName);
}
return;
}
private void ProcessPhysicsList(string module, string[] cmdparms)
{
if (SceneManager.Instance == null || SceneManager.Instance.CurrentScene == null)
{
WriteError("Error: no region selected. Use 'change region' to select a region.");
return;
}
Scene scene = SceneManager.Instance.CurrentScene;
IPhysicsParameters physScene = scene.PhysicsScene as IPhysicsParameters;
if (physScene != null)
{
WriteOut("Available physics parameters:");
PhysParameterEntry[] parms = physScene.GetParameterList();
foreach (PhysParameterEntry ent in parms)
{
WriteOut(" {0}: {1}", ent.name, ent.desc);
}
}
else
{
WriteError("Current regions's physics engine has no settable physics parameters");
}
return;
}
private void WriteOut(string msg, params object[] args)
{
m_log.InfoFormat(msg, args);
// MainConsole.Instance.OutputFormat(msg, args);
}
private void WriteError(string msg, params object[] args)
{
m_log.ErrorFormat(msg, args);
// MainConsole.Instance.OutputFormat(msg, args);
}
}
}

View File

@ -49,8 +49,9 @@ public class BSCharacter : PhysicsActor
private bool _grabbed; private bool _grabbed;
private bool _selected; private bool _selected;
private Vector3 _position; private Vector3 _position;
private float _mass = 80f; private float _mass;
public float _density = 60f; public float _density;
public float _avatarVolume;
private Vector3 _force; private Vector3 _force;
private Vector3 _velocity; private Vector3 _velocity;
private Vector3 _torque; private Vector3 _torque;
@ -90,13 +91,13 @@ public class BSCharacter : PhysicsActor
_scene = parent_scene; _scene = parent_scene;
_position = pos; _position = pos;
_size = size; _size = size;
_flying = isFlying;
_orientation = Quaternion.Identity; _orientation = Quaternion.Identity;
_velocity = Vector3.Zero; _velocity = Vector3.Zero;
_buoyancy = 0f; // characters return a buoyancy of zero _buoyancy = isFlying ? 1f : 0f;
_scale = new Vector3(1f, 1f, 1f); _scale = new Vector3(1f, 1f, 1f);
float AVvolume = (float) (Math.PI*Math.Pow(_scene.Params.avatarCapsuleRadius, 2)*_scene.Params.avatarCapsuleHeight);
_density = _scene.Params.avatarDensity; _density = _scene.Params.avatarDensity;
_mass = _density*AVvolume; ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale
ShapeData shapeData = new ShapeData(); ShapeData shapeData = new ShapeData();
shapeData.ID = _localID; shapeData.ID = _localID;
@ -106,7 +107,7 @@ public class BSCharacter : PhysicsActor
shapeData.Velocity = _velocity; shapeData.Velocity = _velocity;
shapeData.Scale = _scale; shapeData.Scale = _scale;
shapeData.Mass = _mass; shapeData.Mass = _mass;
shapeData.Buoyancy = isFlying ? 1f : 0f; shapeData.Buoyancy = _buoyancy;
shapeData.Static = ShapeData.numericFalse; shapeData.Static = ShapeData.numericFalse;
shapeData.Friction = _scene.Params.avatarFriction; shapeData.Friction = _scene.Params.avatarFriction;
shapeData.Restitution = _scene.Params.defaultRestitution; shapeData.Restitution = _scene.Params.defaultRestitution;
@ -212,6 +213,7 @@ public class BSCharacter : PhysicsActor
get { return _velocity; } get { return _velocity; }
set { set {
_velocity = value; _velocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity);
@ -235,6 +237,7 @@ public class BSCharacter : PhysicsActor
get { return _orientation; } get { return _orientation; }
set { set {
_orientation = value; _orientation = value;
// m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation);
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
// _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
@ -300,7 +303,6 @@ public class BSCharacter : PhysicsActor
set { _buoyancy = value; set { _buoyancy = value;
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
// simulate flying by changing the effect of gravity
BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy);
}); });
} }
@ -344,6 +346,7 @@ public class BSCharacter : PhysicsActor
_force.X += force.X; _force.X += force.X;
_force.Y += force.Y; _force.Y += force.Y;
_force.Z += force.Z; _force.Z += force.Z;
// m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
_scene.TaintedObject(delegate() _scene.TaintedObject(delegate()
{ {
BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
@ -370,6 +373,17 @@ public class BSCharacter : PhysicsActor
return (_subscribedEventsMs > 0); return (_subscribedEventsMs > 0);
} }
// set _avatarVolume and _mass based on capsule size, _density and _scale
private void ComputeAvatarVolumeAndMass()
{
_avatarVolume = (float)(
Math.PI
* _scene.Params.avatarCapsuleRadius * _scale.X
* _scene.Params.avatarCapsuleRadius * _scale.Y
* _scene.Params.avatarCapsuleHeight * _scale.Z);
_mass = _density * _avatarVolume;
}
// The physics engine says that properties have updated. Update same and inform // The physics engine says that properties have updated. Update same and inform
// the world that things have changed. // the world that things have changed.
public void UpdateProperties(EntityProperties entprop) public void UpdateProperties(EntityProperties entprop)
@ -403,6 +417,9 @@ public class BSCharacter : PhysicsActor
} }
if (changed) if (changed)
{ {
// m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
// Avatar movement is not done by generating this event. There is a system that
// checks for avatar updates each heartbeat loop.
// base.RequestPhysicsterseUpdate(); // base.RequestPhysicsterseUpdate();
} }
} }

View File

@ -1013,8 +1013,8 @@ public sealed class BSPrim : PhysicsActor
// m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
_shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
// Let the object be scaled by Bullet (the mesh was created as a unit mesh) // meshes are already scaled by the meshmerizer
_scale = _size; _scale = new OMV.Vector3(1f, 1f, 1f);
} }
return; return;
} }
@ -1138,9 +1138,7 @@ public sealed class BSPrim : PhysicsActor
if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh
{ {
// m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader); // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader);
// Make the mesh scaled to 1 and use Bullet's scaling feature to scale it in world _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.MeshLOD, _isPhysical);
OMV.Vector3 scaleFactor = new OMV.Vector3(1.0f, 1.0f, 1.0f);
_mesh = _scene.mesher.CreateMesh(_avName, _pbs, scaleFactor, _scene.MeshLOD, _isPhysical);
} }
else else
{ {
@ -1225,6 +1223,8 @@ public sealed class BSPrim : PhysicsActor
else else
{ {
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart. // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
// Only updates only for individual prims and for the root object of a linkset.
if (this._parentPrim == null) if (this._parentPrim == null)
{ {
// Assign to the local variables so the normal set action does not happen // Assign to the local variables so the normal set action does not happen

View File

@ -58,11 +58,13 @@ using OpenSim.Region.Framework;
// //
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSScene : PhysicsScene public class BSScene : PhysicsScene, IPhysicsParameters
{ {
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[BULLETS SCENE]"; private static readonly string LogHeader = "[BULLETS SCENE]";
public string BulletSimVersion = "?";
private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>(); private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
private List<BSPrim> m_vehicles = new List<BSPrim>(); private List<BSPrim> m_vehicles = new List<BSPrim>();
@ -127,7 +129,7 @@ public class BSScene : PhysicsScene
ConfigurationParameters[] m_params; ConfigurationParameters[] m_params;
GCHandle m_paramsHandle; GCHandle m_paramsHandle;
private BulletSimAPI.DebugLogCallback debugLogCallbackHandle; private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
public BSScene(string identifier) public BSScene(string identifier)
{ {
@ -149,12 +151,17 @@ public class BSScene : PhysicsScene
m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
// Get the version of the DLL
// TODO: this doesn't work yet. Something wrong with marshaling the returned string.
// BulletSimVersion = BulletSimAPI.GetVersion();
// m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
// if Debug, enable logging from the unmanaged code // if Debug, enable logging from the unmanaged code
if (m_log.IsDebugEnabled) if (m_log.IsDebugEnabled)
{ {
m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
debugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
BulletSimAPI.SetDebugLogCallback(debugLogCallbackHandle); BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle);
} }
_taintedObjects = new List<TaintCallback>(); _taintedObjects = new List<TaintCallback>();
@ -188,7 +195,7 @@ public class BSScene : PhysicsScene
m_maxUpdatesPerFrame = 2048; m_maxUpdatesPerFrame = 2048;
m_maximumObjectMass = 10000.01f; m_maximumObjectMass = 10000.01f;
parms.defaultFriction = 0.70f; parms.defaultFriction = 0.5f;
parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 parms.defaultDensity = 10.000006836f; // Aluminum g/cm3
parms.defaultRestitution = 0f; parms.defaultRestitution = 0f;
parms.collisionMargin = 0.0f; parms.collisionMargin = 0.0f;
@ -202,10 +209,10 @@ public class BSScene : PhysicsScene
parms.ccdMotionThreshold = 0.5f; // set to zero to disable parms.ccdMotionThreshold = 0.5f; // set to zero to disable
parms.ccdSweptSphereRadius = 0.2f; parms.ccdSweptSphereRadius = 0.2f;
parms.terrainFriction = 0.85f; parms.terrainFriction = 0.5f;
parms.terrainHitFriction = 0.8f; parms.terrainHitFraction = 0.8f;
parms.terrainRestitution = 0.2f; parms.terrainRestitution = 0f;
parms.avatarFriction = 0.85f; parms.avatarFriction = 0.0f;
parms.avatarDensity = 60f; parms.avatarDensity = 60f;
parms.avatarCapsuleRadius = 0.37f; parms.avatarCapsuleRadius = 0.37f;
parms.avatarCapsuleHeight = 1.5f; // 2.140599f parms.avatarCapsuleHeight = 1.5f; // 2.140599f
@ -213,7 +220,8 @@ public class BSScene : PhysicsScene
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 ALSO UPDATE OpenSimDefaults.ini // 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)
{ {
@ -243,7 +251,7 @@ public class BSScene : PhysicsScene
parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius); parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius);
parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction); parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction);
parms.terrainHitFriction = pConfig.GetFloat("TerrainHitFriction", parms.terrainHitFriction); parms.terrainHitFraction = pConfig.GetFloat("TerrainHitFraction", parms.terrainHitFraction);
parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution); parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution);
parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction); parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction);
parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity); parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity);
@ -386,7 +394,7 @@ public class BSScene : PhysicsScene
} }
} }
// FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation. // TODO: FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation.
return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f; return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f;
} }
@ -651,5 +659,196 @@ public class BSScene : PhysicsScene
} }
} }
#endregion Vehicles #endregion Vehicles
#region Runtime settable parameters
public static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[]
{
new PhysParameterEntry("MeshLOD", "Level of detail to render meshes (Power of two. Default 32)"),
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("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)" ),
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", "" ),
// new PhysParameterEntry("CcdSweptSphereRadius", "" ),
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" )
};
#region IPhysicsParameters
// Get the list of parameters this physics engine supports
public PhysParameterEntry[] GetParameterList()
{
return SettableParameters;
}
// Set parameter on a specific or all instances.
// Return 'false' if not able to set the parameter.
// Setting the value in the m_params block will change the value the physics engine
// will use the next time since it's pinned and shared memory.
// Some of the values require calling into the physics engine to get the new
// value activated ('terrainFriction' for instance).
public bool SetPhysicsParameter(string parm, float val, uint localID)
{
bool ret = true;
string lparm = parm.ToLower();
switch (lparm)
{
case "meshlod": m_meshLOD = (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, PhysParameterEntry.APPLY_TO_NONE, 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;
// 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;
default: ret = false; break;
}
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)
{
List<uint> operateOn;
lock (m_prims) operateOn = new List<uint>(m_prims.Keys);
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
}
// 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)
{
List<uint> operateOn;
lock (m_avatars) operateOn = new List<uint>(m_avatars.Keys);
UpdateParameterSet(operateOn, ref loc, parm, localID, val);
}
// update all the localIDs specified
// 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)
{
switch (localID)
{
case PhysParameterEntry.APPLY_TO_NONE:
defaultLoc = val; // setting only the default value
break;
case PhysParameterEntry.APPLY_TO_ALL:
defaultLoc = val; // setting ALL also sets the default value
List<uint> objectIDs = lIDs;
string xparm = parm.ToLower();
float xval = val;
TaintedObject(delegate() {
foreach (uint lID in objectIDs)
{
BulletSimAPI.UpdateParameter(m_worldID, lID, xparm, xval);
}
});
break;
default:
// setting only one localID
TaintedUpdateParameter(parm, localID, val);
break;
}
}
// schedule the actual updating of the paramter to when the phys engine is not busy
private void TaintedUpdateParameter(string parm, uint localID, float val)
{
uint xlocalID = localID;
string xparm = parm.ToLower();
float xval = val;
TaintedObject(delegate() {
BulletSimAPI.UpdateParameter(m_worldID, xlocalID, xparm, xval);
});
}
// Get parameter.
// Return 'false' if not able to get the parameter.
public bool GetPhysicsParameter(string parm, out float value)
{
float val = 0f;
bool ret = true;
switch (parm.ToLower())
{
case "meshlod": val = (float)m_meshLOD; 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 "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;
default: ret = false; break;
}
value = val;
return ret;
}
#endregion IPhysicsParameters
#endregion Runtime settable parameters
} }
} }

View File

@ -51,9 +51,6 @@ public struct ShapeData
SHAPE_SPHERE = 4, SHAPE_SPHERE = 4,
SHAPE_HULL = 5 SHAPE_HULL = 5
}; };
// note that bools are passed as ints since bool size changes by language
public const int numericTrue = 1;
public const int numericFalse = 0;
public uint ID; public uint ID;
public PhysicsShapeType Type; public PhysicsShapeType Type;
public Vector3 Position; public Vector3 Position;
@ -67,6 +64,10 @@ public struct ShapeData
public float Restitution; public float Restitution;
public int Collidable; public int Collidable;
public int Static; // true if a static object. Otherwise gravity, etc. public int Static; // true if a static object. Otherwise gravity, etc.
// note that bools are passed as ints since bool size changes by language and architecture
public const int numericTrue = 1;
public const int numericFalse = 0;
} }
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct SweepHit public struct SweepHit
@ -121,22 +122,33 @@ public struct ConfigurationParameters
public float ccdSweptSphereRadius; public float ccdSweptSphereRadius;
public float terrainFriction; public float terrainFriction;
public float terrainHitFriction; public float terrainHitFraction;
public float terrainRestitution; public float terrainRestitution;
public float avatarFriction; public float avatarFriction;
public float avatarDensity; public float avatarDensity;
public float avatarRestitution; public float avatarRestitution;
public float avatarCapsuleRadius; public float avatarCapsuleRadius;
public float avatarCapsuleHeight; public float avatarCapsuleHeight;
public const float numericTrue = 1f;
public const float numericFalse = 0f;
} }
static class BulletSimAPI { static class BulletSimAPI {
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetVersion();
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, public static extern uint Initialize(Vector3 maxPosition, IntPtr parms,
int maxCollisions, IntPtr collisionArray, int maxCollisions, IntPtr collisionArray,
int maxUpdates, IntPtr updateArray); int maxUpdates, IntPtr updateArray);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool UpdateParameter(uint worldID, uint localID,
[MarshalAs(UnmanagedType.LPStr)]string paramCode, float value);
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap);

View File

@ -0,0 +1,73 @@
/*
* 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 copyright
* 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 OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Region.Physics.Manager
{
public struct PhysParameterEntry
{
// flags to say to apply to all or no instances (I wish one could put consts into interfaces)
public const uint APPLY_TO_ALL = 0xfffffff3;
public const uint APPLY_TO_NONE = 0xfffffff4;
// values that denote true and false values
public const float NUMERIC_TRUE = 1f;
public const float NUMERIC_FALSE = 0f;
public string name;
public string desc;
public PhysParameterEntry(string n, string d)
{
name = n;
desc = d;
}
}
// Interface for a physics scene that implements the runtime setting and getting of physics parameters
public interface IPhysicsParameters
{
// Get the list of parameters this physics engine supports
PhysParameterEntry[] GetParameterList();
// Set parameter on a specific or all instances.
// Return 'false' if not able to set the parameter.
bool SetPhysicsParameter(string parm, float value, uint localID);
// Get parameter.
// Return 'false' if not able to get the parameter.
bool GetPhysicsParameter(string parm, out float value);
// Get parameter from a particular object
// TODO:
// bool GetPhysicsParameter(string parm, out float value, uint localID);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.