From fef73a1a1011126d4df2da2279caae9cef7984d1 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 18 Aug 2011 14:32:09 -0700 Subject: BulletSim: add runtime setting of physics parameters. Update default values. --- OpenSim/Region/Framework/Scenes/SceneManager.cs | 7 + .../PhysicsParameters/PhysicsParameters.cs | 277 +++++++++++++++++++++ .../Region/Physics/BulletSPlugin/BSCharacter.cs | 31 ++- OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 10 +- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 223 ++++++++++++++++- .../Region/Physics/BulletSPlugin/BulletSimAPI.cs | 20 +- .../Region/Physics/Manager/IPhysicsParameters.cs | 73 ++++++ 7 files changed, 613 insertions(+), 28 deletions(-) create mode 100755 OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs create mode 100755 OpenSim/Region/Physics/Manager/IPhysicsParameters.cs (limited to 'OpenSim') diff --git a/OpenSim/Region/Framework/Scenes/SceneManager.cs b/OpenSim/Region/Framework/Scenes/SceneManager.cs index 86ba2aa..97ee844 100644 --- a/OpenSim/Region/Framework/Scenes/SceneManager.cs +++ b/OpenSim/Region/Framework/Scenes/SceneManager.cs @@ -47,6 +47,12 @@ namespace OpenSim.Region.Framework.Scenes public event RestartSim OnRestartSim; + private static SceneManager m_instance = null; + public static SceneManager Instance + { + get { return m_instance; } + } + private readonly List m_localScenes; private Scene m_currentScene = null; @@ -84,6 +90,7 @@ namespace OpenSim.Region.Framework.Scenes public SceneManager() { + m_instance = this; m_localScenes = new List(); } diff --git a/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs new file mode 100755 index 0000000..2a44360 --- /dev/null +++ b/OpenSim/Region/OptionalModules/PhysicsParameters/PhysicsParameters.cs @@ -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 +{ + /// + /// + /// + /// + [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 m_scenes = new List(); + 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 [|ALL]"; + private const string setInvocation = "physics set [|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); + } + } +} \ No newline at end of file diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 9f9ebcc..682eb80 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -49,8 +49,9 @@ public class BSCharacter : PhysicsActor private bool _grabbed; private bool _selected; private Vector3 _position; - private float _mass = 80f; - public float _density = 60f; + private float _mass; + public float _density; + public float _avatarVolume; private Vector3 _force; private Vector3 _velocity; private Vector3 _torque; @@ -90,13 +91,13 @@ public class BSCharacter : PhysicsActor _scene = parent_scene; _position = pos; _size = size; + _flying = isFlying; _orientation = Quaternion.Identity; _velocity = Vector3.Zero; - _buoyancy = 0f; // characters return a buoyancy of zero + _buoyancy = isFlying ? 1f : 0f; _scale = new Vector3(1f, 1f, 1f); - float AVvolume = (float) (Math.PI*Math.Pow(_scene.Params.avatarCapsuleRadius, 2)*_scene.Params.avatarCapsuleHeight); _density = _scene.Params.avatarDensity; - _mass = _density*AVvolume; + ComputeAvatarVolumeAndMass(); // set _avatarVolume and _mass based on capsule size, _density and _scale ShapeData shapeData = new ShapeData(); shapeData.ID = _localID; @@ -106,7 +107,7 @@ public class BSCharacter : PhysicsActor shapeData.Velocity = _velocity; shapeData.Scale = _scale; shapeData.Mass = _mass; - shapeData.Buoyancy = isFlying ? 1f : 0f; + shapeData.Buoyancy = _buoyancy; shapeData.Static = ShapeData.numericFalse; shapeData.Friction = _scene.Params.avatarFriction; shapeData.Restitution = _scene.Params.defaultRestitution; @@ -212,6 +213,7 @@ public class BSCharacter : PhysicsActor get { return _velocity; } set { _velocity = value; + // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); _scene.TaintedObject(delegate() { BulletSimAPI.SetObjectVelocity(_scene.WorldID, _localID, _velocity); @@ -235,6 +237,7 @@ public class BSCharacter : PhysicsActor get { return _orientation; } set { _orientation = value; + // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); _scene.TaintedObject(delegate() { // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); @@ -300,7 +303,6 @@ public class BSCharacter : PhysicsActor set { _buoyancy = value; _scene.TaintedObject(delegate() { - // simulate flying by changing the effect of gravity BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, LocalID, _buoyancy); }); } @@ -344,6 +346,7 @@ public class BSCharacter : PhysicsActor _force.X += force.X; _force.Y += force.Y; _force.Z += force.Z; + // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force); _scene.TaintedObject(delegate() { BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); @@ -370,6 +373,17 @@ public class BSCharacter : PhysicsActor 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 world that things have changed. public void UpdateProperties(EntityProperties entprop) @@ -403,6 +417,9 @@ public class BSCharacter : PhysicsActor } 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(); } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index c4999f6..cc414e9 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -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); BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; - // Let the object be scaled by Bullet (the mesh was created as a unit mesh) - _scale = _size; + // meshes are already scaled by the meshmerizer + _scale = new OMV.Vector3(1f, 1f, 1f); } return; } @@ -1138,9 +1138,7 @@ public sealed class BSPrim : PhysicsActor if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh { // 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 - OMV.Vector3 scaleFactor = new OMV.Vector3(1.0f, 1.0f, 1.0f); - _mesh = _scene.mesher.CreateMesh(_avName, _pbs, scaleFactor, _scene.MeshLOD, _isPhysical); + _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.MeshLOD, _isPhysical); } else { @@ -1225,6 +1223,8 @@ public sealed class BSPrim : PhysicsActor else { // 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) { // Assign to the local variables so the normal set action does not happen diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index de86d59..518be09 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -58,11 +58,13 @@ using OpenSim.Region.Framework; // 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 string LogHeader = "[BULLETS SCENE]"; + public string BulletSimVersion = "?"; + private Dictionary m_avatars = new Dictionary(); private Dictionary m_prims = new Dictionary(); private List m_vehicles = new List(); @@ -127,7 +129,7 @@ public class BSScene : PhysicsScene ConfigurationParameters[] m_params; GCHandle m_paramsHandle; - private BulletSimAPI.DebugLogCallback debugLogCallbackHandle; + private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; public BSScene(string identifier) { @@ -149,12 +151,17 @@ public class BSScene : PhysicsScene m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; 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 (m_log.IsDebugEnabled) { m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); - debugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); - BulletSimAPI.SetDebugLogCallback(debugLogCallbackHandle); + m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); + BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); } _taintedObjects = new List(); @@ -188,7 +195,7 @@ public class BSScene : PhysicsScene m_maxUpdatesPerFrame = 2048; m_maximumObjectMass = 10000.01f; - parms.defaultFriction = 0.70f; + parms.defaultFriction = 0.5f; parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 parms.defaultRestitution = 0f; parms.collisionMargin = 0.0f; @@ -202,10 +209,10 @@ public class BSScene : PhysicsScene parms.ccdMotionThreshold = 0.5f; // set to zero to disable parms.ccdSweptSphereRadius = 0.2f; - parms.terrainFriction = 0.85f; - parms.terrainHitFriction = 0.8f; - parms.terrainRestitution = 0.2f; - parms.avatarFriction = 0.85f; + parms.terrainFriction = 0.5f; + parms.terrainHitFraction = 0.8f; + parms.terrainRestitution = 0f; + parms.avatarFriction = 0.0f; parms.avatarDensity = 60f; parms.avatarCapsuleRadius = 0.37f; parms.avatarCapsuleHeight = 1.5f; // 2.140599f @@ -213,7 +220,8 @@ public class BSScene : PhysicsScene if (config != null) { // 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"]; if (pConfig != null) { @@ -243,7 +251,7 @@ public class BSScene : PhysicsScene parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius); 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.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction); 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; } @@ -651,5 +659,196 @@ public class BSScene : PhysicsScene } } #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 operateOn; + lock (m_prims) operateOn = new List(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 operateOn; + lock (m_avatars) operateOn = new List(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 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 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 + } } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 819fce1..bf953df 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -51,9 +51,6 @@ public struct ShapeData SHAPE_SPHERE = 4, 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 PhysicsShapeType Type; public Vector3 Position; @@ -67,6 +64,10 @@ public struct ShapeData public float Restitution; public int Collidable; 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)] public struct SweepHit @@ -121,23 +122,34 @@ public struct ConfigurationParameters public float ccdSweptSphereRadius; public float terrainFriction; - public float terrainHitFriction; + public float terrainHitFraction; public float terrainRestitution; public float avatarFriction; public float avatarDensity; public float avatarRestitution; public float avatarCapsuleRadius; public float avatarCapsuleHeight; + + public const float numericTrue = 1f; + public const float numericFalse = 0f; } static class BulletSimAPI { [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +[return: MarshalAs(UnmanagedType.LPStr)] +public static extern string GetVersion(); + +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, int maxCollisions, IntPtr collisionArray, 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] public static extern void SetHeightmap(uint worldID, [MarshalAs(UnmanagedType.LPArray)] float[] heightMap); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs new file mode 100755 index 0000000..b8676ba --- /dev/null +++ b/OpenSim/Region/Physics/Manager/IPhysicsParameters.cs @@ -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); + } +} -- cgit v1.1