BulletSim: add runtime setting of physics parameters. Update default values.
parent
82f41fdcb5
commit
fef73a1a10
|
@ -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<Scene> 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<Scene>();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>();
|
||||
private Dictionary<uint, BSPrim> m_prims = new Dictionary<uint, BSPrim>();
|
||||
private List<BSPrim> m_vehicles = new List<BSPrim>();
|
||||
|
@ -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<TaintCallback>();
|
||||
|
@ -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<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
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,22 +122,33 @@ 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);
|
||||
|
||||
|
|
|
@ -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.
Loading…
Reference in New Issue