BulletSim: Move all the parameter variables, tables and get and fetch logic to a separate, static class for easier addition and to remove all that bulk from the BSScene class.

0.7.5-pf-bulletsim
Robert Adams 2012-12-21 13:35:44 -08:00
parent 2e3e95e846
commit ae4d932e7f
13 changed files with 678 additions and 603 deletions

View File

@ -88,8 +88,8 @@ public sealed class BSCharacter : BSPhysObject
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
_size = size;
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
// A motor to control the acceleration and deceleration of the avatar movement.
// _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
@ -108,8 +108,8 @@ public sealed class BSCharacter : BSPhysObject
_velocity = OMV.Vector3.Zero;
_appliedVelocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
_avatarDensity = PhysicsScene.Params.avatarDensity;
_currentFriction = BSParam.AvatarStandingFriction;
_avatarDensity = BSParam.AvatarDensity;
// The dimensions of the avatar capsule are kept in the scale.
// Physics creates a unit capsule which is scaled by the physics engine.
@ -161,14 +161,14 @@ public sealed class BSCharacter : BSPhysObject
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
Flying = _flying;
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution);
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
if (BSParam.CcdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
}
UpdatePhysicalMassProperties(RawMass);
@ -208,8 +208,8 @@ public sealed class BSCharacter : BSPhysObject
_size = value;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values.
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
ComputeAvatarScale(_size);
ComputeAvatarVolumeAndMass();
@ -468,18 +468,18 @@ public sealed class BSCharacter : BSPhysObject
// to keep the avatar from slipping around
if (_velocity.Length() == 0)
{
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
if (_currentFriction != BSParam.AvatarStandingFriction)
{
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
_currentFriction = BSParam.AvatarStandingFriction;
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}
}
else
{
if (_currentFriction != PhysicsScene.Params.avatarFriction)
if (_currentFriction != BSParam.AvatarFriction)
{
_currentFriction = PhysicsScene.Params.avatarFriction;
_currentFriction = BSParam.AvatarFriction;
if (PhysBody.HasPhysicalBody)
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
}

View File

@ -122,7 +122,7 @@ public abstract class BSConstraint : IDisposable
// Setting an object's mass to zero (making it static like when it's selected)
// automatically disables the constraints.
// If the link is enabled, be sure to set the constraint itself to enabled.
BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true));
}
else
{

View File

@ -563,7 +563,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Moderate angular movement introduced by Bullet.
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
// Maybe compute linear and angular factor and damping from params.
float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
float angularDamping = BSParam.VehicleAngularDamping;
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
// Vehicles report collision events so we know when it's on the ground

View File

@ -56,7 +56,7 @@ public abstract class BSLinkset
{
BSLinkset ret = null;
switch ((int)physScene.Params.linksetImplementation)
switch ((int)BSParam.LinksetImplementation)
{
case (int)LinksetImplementation.Constraint:
ret = new BSLinksetConstraints(physScene, parent);

View File

@ -226,14 +226,14 @@ public sealed class BSLinksetConstraints : BSLinkset
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
// tweek the constraint to increase stability
constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
PhysicsScene.Params.linkConstraintTransMotorMaxVel,
PhysicsScene.Params.linkConstraintTransMotorMaxForce);
constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
BSParam.LinkConstraintTransMotorMaxVel,
BSParam.LinkConstraintTransMotorMaxForce);
constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
if (BSParam.LinkConstraintSolverIterations != 0f)
{
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
}
return constrain;
}

View File

@ -0,0 +1,558 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Text;
using OpenSim.Region.Physics.Manager;
using OpenMetaverse;
using Nini.Config;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public static class BSParam
{
// Level of Detail values kept as float because that's what the Meshmerizer wants
public static float MeshLOD { get; private set; }
public static float MeshMegaPrimLOD { get; private set; }
public static float MeshMegaPrimThreshold { get; private set; }
public static float SculptLOD { get; private set; }
public static float MinimumObjectMass { get; private set; }
public static float MaximumObjectMass { get; private set; }
public static float LinearDamping { get; private set; }
public static float AngularDamping { get; private set; }
public static float DeactivationTime { get; private set; }
public static float LinearSleepingThreshold { get; private set; }
public static float AngularSleepingThreshold { get; private set; }
public static float CcdMotionThreshold { get; private set; }
public static float CcdSweptSphereRadius { get; private set; }
public static float ContactProcessingThreshold { get; private set; }
public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
public static float TerrainImplementation { get; private set; }
public static float TerrainFriction { get; private set; }
public static float TerrainHitFraction { get; private set; }
public static float TerrainRestitution { get; private set; }
public static float TerrainCollisionMargin { get; private set; }
// Avatar parameters
public static float AvatarFriction { get; private set; }
public static float AvatarStandingFriction { get; private set; }
public static float AvatarDensity { get; private set; }
public static float AvatarRestitution { get; private set; }
public static float AvatarCapsuleWidth { get; private set; }
public static float AvatarCapsuleDepth { get; private set; }
public static float AvatarCapsuleHeight { get; private set; }
public static float AvatarContactProcessingThreshold { get; private set; }
public static float VehicleAngularDamping { get; private set; }
public static float LinksetImplementation { get; private set; }
public static float LinkConstraintUseFrameOffset { get; private set; }
public static float LinkConstraintEnableTransMotor { get; private set; }
public static float LinkConstraintTransMotorMaxVel { get; private set; }
public static float LinkConstraintTransMotorMaxForce { get; private set; }
public static float LinkConstraintERP { get; private set; }
public static float LinkConstraintCFM { get; private set; }
public static float LinkConstraintSolverIterations { get; private set; }
public static float PID_D { get; private set; } // derivative
public static float PID_P { get; private set; } // proportional
public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
public delegate float ParamGet(BSScene scene);
public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
public struct ParameterDefn
{
public string name; // string name of the parameter
public string desc; // a short description of what the parameter means
public float defaultValue; // default value if not specified anywhere else
public ParamUser userParam; // get the value from the configuration file
public ParamGet getter; // return the current value stored for this parameter
public ParamSet setter; // set the current value for this parameter
public SetOnObject onObject; // set the value on an object in the physical domain
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
{
name = n;
desc = d;
defaultValue = v;
userParam = u;
getter = g;
setter = s;
onObject = null;
}
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
{
name = n;
desc = d;
defaultValue = v;
userParam = u;
getter = g;
setter = s;
onObject = o;
}
}
// List of all of the externally visible parameters.
// For each parameter, this table maps a text name to getter and setters.
// To add a new externally referencable/settable parameter, add the paramter storage
// location somewhere in the program and make an entry in this table with the
// getters and setters.
// It is easiest to find an existing definition and copy it.
// Parameter values are floats. Booleans are converted to a floating value.
//
// A ParameterDefn() takes the following parameters:
// -- the text name of the parameter. This is used for console input and ini file.
// -- a short text description of the parameter. This shows up in the console listing.
// -- a delegate for fetching the parameter from the ini file.
// Should handle fetching the right type from the ini file and converting it.
// -- a delegate for getting the value as a float
// -- a delegate for setting the value from a float
// -- an optional delegate to update the value in the world. Most often used to
// push the new value to an in-world object.
//
// The single letter parameters for the delegates are:
// s = BSScene
// o = BSPhysObject
// p = string parameter name
// l = localID of referenced object
// v = float value
// cf = parameter configuration class (for fetching values from ini file)
private static ParameterDefn[] ParameterDefinitions =
{
new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
(s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
(s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
(s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
(s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
(s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
(s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
8f,
(s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return MeshLOD; },
(s,p,l,v) => { MeshLOD = v; } ),
new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
16f,
(s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return MeshMegaPrimLOD; },
(s,p,l,v) => { MeshMegaPrimLOD = v; } ),
new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
10f,
(s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
(s) => { return MeshMegaPrimThreshold; },
(s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
32f,
(s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return SculptLOD; },
(s,p,l,v) => { SculptLOD = v; } ),
new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
10f,
(s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxSubSteps; },
(s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
1f / 60f,
(s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
(s) => { return (float)s.m_fixedTimeStep; },
(s,p,l,v) => { s.m_fixedTimeStep = v; } ),
new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
2048f,
(s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxCollisionsPerFrame; },
(s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
8000f,
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxUpdatesPerFrame; },
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
500f,
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_taintsToProcessPerStep; },
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
0.0001f,
(s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MinimumObjectMass; },
(s,p,l,v) => { MinimumObjectMass = v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)MaximumObjectMass; },
(s,p,l,v) => { MaximumObjectMass = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f,
(s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
(s) => { return (float)PID_D; },
(s,p,l,v) => { PID_D = v; } ),
new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
900f,
(s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
(s) => { return (float)PID_P; },
(s,p,l,v) => { PID_P = v; } ),
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
0.2f,
(s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].defaultFriction; },
(s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
new ParameterDefn("DefaultDensity", "Density for new objects" ,
10.000006836f, // Aluminum g/cm3
(s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].defaultDensity; },
(s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
0f,
(s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].defaultRestitution; },
(s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
0.04f,
(s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].collisionMargin; },
(s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
-9.80665f,
(s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].gravity; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
(s) => { return LinearDamping; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ),
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
(s) => { return AngularDamping; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ),
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
0.2f,
(s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
(s) => { return DeactivationTime; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
0.8f,
(s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return LinearSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1.0f,
(s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return AngularSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
0f, // set to zero to disable
(s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
(s) => { return CcdMotionThreshold; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
0f,
(s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
(s) => { return CcdSweptSphereRadius; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
0.1f,
(s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return ContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
(float)BSTerrainPhys.TerrainImplementation.Mesh,
(s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
(s) => { return TerrainImplementation; },
(s,p,l,v) => { TerrainImplementation = v; } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.3f,
(s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
(s) => { return TerrainFriction; },
(s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
0.8f,
(s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
(s) => { return TerrainHitFraction; },
(s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
0f,
(s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
(s) => { return TerrainRestitution; },
(s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
0.04f,
(s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
(s) => { return TerrainCollisionMargin; },
(s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.2f,
(s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
(s) => { return AvatarFriction; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
10.0f,
(s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return AvatarStandingFriction; },
(s,p,l,v) => { AvatarStandingFriction = v; } ),
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
60f,
(s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
(s) => { return AvatarDensity; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
0f,
(s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
(s) => { return AvatarRestitution; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
0.6f,
(s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
(s) => { return AvatarCapsuleWidth; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
0.45f,
(s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
(s) => { return AvatarCapsuleDepth; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1.5f,
(s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
(s) => { return AvatarCapsuleHeight; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
0.1f,
(s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return AvatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
0.95f,
(s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
(s) => { return VehicleAngularDamping; },
(s,p,l,v) => { VehicleAngularDamping = v; } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f,
(s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
(s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
0f,
(s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
(s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
(s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
(s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
(s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
(s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
(s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
0f, // zero says use Bullet default
(s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
(s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
(s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound,
(s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
(s) => { return LinksetImplementation; },
(s,p,l,v) => { LinksetImplementation = v; } ),
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return LinkConstraintUseFrameOffset; },
(s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
(s) => { return LinkConstraintEnableTransMotor; },
(s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
5.0f,
(s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
(s) => { return LinkConstraintTransMotorMaxVel; },
(s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
0.1f,
(s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
(s) => { return LinkConstraintTransMotorMaxForce; },
(s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
0.1f,
(s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
(s) => { return LinkConstraintCFM; },
(s,p,l,v) => { LinkConstraintCFM = v; } ),
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
0.1f,
(s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
(s) => { return LinkConstraintERP; },
(s,p,l,v) => { LinkConstraintERP = v; } ),
new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
40,
(s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
(s) => { return LinkConstraintSolverIterations; },
(s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
0f,
(s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
(s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; },
(s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ),
};
// Convert a boolean to our numeric true and false values
public static float NumericBool(bool b)
{
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
}
// Convert numeric true and false values to a boolean
public static bool BoolNumeric(float b)
{
return (b == ConfigurationParameters.numericTrue ? true : false);
}
// Search through the parameter definitions and return the matching
// ParameterDefn structure.
// Case does not matter as names are compared after converting to lower case.
// Returns 'false' if the parameter is not found.
internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
{
bool ret = false;
ParameterDefn foundDefn = new ParameterDefn();
string pName = paramName.ToLower();
foreach (ParameterDefn parm in ParameterDefinitions)
{
if (pName == parm.name.ToLower())
{
foundDefn = parm;
ret = true;
break;
}
}
defn = foundDefn;
return ret;
}
// Pass through the settable parameters and set the default values
internal static void SetParameterDefaultValues(BSScene physicsScene)
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
}
}
// Get user set values out of the ini file.
internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
}
}
internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
// This creates an array in the correct format for returning the list of
// parameters. This is used by the 'list' option of the 'physics' command.
internal static void BuildParameterTable()
{
if (SettableParameters.Length < ParameterDefinitions.Length)
{
List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
{
ParameterDefn pd = ParameterDefinitions[ii];
entries.Add(new PhysParameterEntry(pd.name, pd.desc));
}
// make the list in alphabetical order for estetic reasons
entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
{
return ppe1.name.CompareTo(ppe2.name);
});
SettableParameters = entries.ToArray();
}
}
}
}

View File

@ -720,10 +720,10 @@ public sealed class BSPrim : BSPhysObject
// Mass is zero which disables a bunch of physics stuff in Bullet
UpdatePhysicalMassProperties(0f);
// Set collision detection parameters
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
if (BSParam.CcdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
}
// The activation state is 'disabled' so Bullet will not try to act on it.
@ -761,17 +761,17 @@ public sealed class BSPrim : BSPhysObject
UpdatePhysicalMassProperties(RawMass);
// Set collision detection parameters
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
if (BSParam.CcdMotionThreshold > 0f)
{
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
}
// Various values for simulation limits
BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping);
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime);
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
// This collides like an object.
PhysBody.collisionType = CollisionType.Dynamic;
@ -1361,11 +1361,7 @@ public sealed class BSPrim : BSPhysObject
}
*/
if (returnMass <= 0)
returnMass = 0.0001f;
if (returnMass > PhysicsScene.MaximumObjectMass)
returnMass = PhysicsScene.MaximumObjectMass;
returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
return returnMass;
}// end CalculateMass

View File

@ -77,12 +77,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public ILog Logger { get { return m_log; } }
public IMesher mesher;
// Level of Detail values kept as float because that's what the Meshmerizer wants
public float MeshLOD { get; private set; }
public float MeshMegaPrimLOD { get; private set; }
public float MeshMegaPrimThreshold { get; private set; }
public float SculptLOD { get; private set; }
public uint WorldID { get; private set; }
public BulletSim World { get; private set; }
@ -90,21 +84,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public BSConstraintCollection Constraints { get; private set; }
// Simulation parameters
private int m_maxSubSteps;
private float m_fixedTimeStep;
private long m_simulationStep = 0;
internal int m_maxSubSteps;
internal float m_fixedTimeStep;
internal long m_simulationStep = 0;
public long SimulationStep { get { return m_simulationStep; } }
private int m_taintsToProcessPerStep;
// Avatar parameters
public float ParamAvatarFriction { get; private set; }
public float ParamAvatarStandingFriction { get; private set; }
public float ParamAvatarDensity { get; private set; }
public float ParamAvatarRestitution { get; private set; }
public float ParamAvatarCapsuleWidth { get; private set; }
public float ParamAvatarCapsuleDepth { get; private set; }
public float ParamAvatarCapsuleHeight { get; private set; }
public float ParamAvatarContactProcessingThreshold { get; private set; }
internal int m_taintsToProcessPerStep;
public delegate void PreStepAction(float timeStep);
public event PreStepAction BeforeStep;
@ -121,20 +105,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public bool InTaintTime { get; private set; }
// Pinned memory used to pass step information between managed and unmanaged
private int m_maxCollisionsPerFrame;
private CollisionDesc[] m_collisionArray;
private GCHandle m_collisionArrayPinnedHandle;
internal int m_maxCollisionsPerFrame;
internal CollisionDesc[] m_collisionArray;
internal GCHandle m_collisionArrayPinnedHandle;
private int m_maxUpdatesPerFrame;
private EntityProperties[] m_updateArray;
private GCHandle m_updateArrayPinnedHandle;
public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
public float PID_D { get; private set; } // derivative
public float PID_P { get; private set; } // proportional
internal int m_maxUpdatesPerFrame;
internal EntityProperties[] m_updateArray;
internal GCHandle m_updateArrayPinnedHandle;
public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
public const uint GROUNDPLANE_ID = 1;
@ -145,7 +122,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public ConfigurationParameters Params
{
get { return m_params[0]; }
get { return UnmanagedParams[0]; }
}
public Vector3 DefaultGravity
{
@ -157,8 +134,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
get { return Params.gravity; }
}
public float MaximumObjectMass { get; private set; }
// When functions in the unmanaged code must be called, it is only
// done at a known time just before the simulation step. The taint
// system saves all these function calls and executes them in
@ -181,7 +156,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// A pointer to an instance if this structure is passed to the C++ code
// Used to pass basic configuration values to the unmanaged code.
ConfigurationParameters[] m_params;
internal ConfigurationParameters[] UnmanagedParams;
GCHandle m_paramsHandle;
// Handle to the callback used by the unmanaged code to call into the managed code.
@ -218,8 +193,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
Shapes = new BSShapeCollection(this);
// Allocate pinned memory to pass parameters.
m_params = new ConfigurationParameters[1];
m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
UnmanagedParams = new ConfigurationParameters[1];
m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned);
// Set default values for physics parameters plus any overrides from the ini file
GetInitialParameterValues(config);
@ -277,7 +252,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
TerrainManager = new BSTerrainManager(this);
TerrainManager.CreateInitialGroundPlaneAndTerrain();
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
InTaintTime = false;
m_initialized = true;
@ -288,9 +263,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private void GetInitialParameterValues(IConfigSource config)
{
ConfigurationParameters parms = new ConfigurationParameters();
m_params[0] = parms;
UnmanagedParams[0] = parms;
SetParameterDefaultValues();
BSParam.SetParameterDefaultValues(this);
if (config != null)
{
@ -298,7 +273,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
IConfig pConfig = config.Configs["BulletSim"];
if (pConfig != null)
{
SetParameterConfigurationValues(pConfig);
BSParam.SetParameterConfigurationValues(this, pConfig);
// Very detailed logging for physics debugging
m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
@ -889,7 +864,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
Util.PrintCallStack(DetailLog); // Prints the stack into the DEBUG log file.
}
return InTaintTime;
}
@ -936,12 +911,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private void DoPreStepActions(float timeStep)
{
InTaintTime = true; // Only used for debugging so locking is not necessary.
ProcessVehicles(timeStep);
PreStepAction actions = BeforeStep;
if (actions != null)
actions(timeStep);
InTaintTime = false;
}
// Some prims have extra vehicle actions
@ -957,472 +935,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
#region INI and command line parameter processing
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
delegate float ParamGet(BSScene scene);
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
private struct ParameterDefn
{
public string name; // string name of the parameter
public string desc; // a short description of what the parameter means
public float defaultValue; // default value if not specified anywhere else
public ParamUser userParam; // get the value from the configuration file
public ParamGet getter; // return the current value stored for this parameter
public ParamSet setter; // set the current value for this parameter
public SetOnObject onObject; // set the value on an object in the physical domain
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
{
name = n;
desc = d;
defaultValue = v;
userParam = u;
getter = g;
setter = s;
onObject = null;
}
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
{
name = n;
desc = d;
defaultValue = v;
userParam = u;
getter = g;
setter = s;
onObject = o;
}
}
// List of all of the externally visible parameters.
// For each parameter, this table maps a text name to getter and setters.
// To add a new externally referencable/settable parameter, add the paramter storage
// location somewhere in the program and make an entry in this table with the
// getters and setters.
// It is easiest to find an existing definition and copy it.
// Parameter values are floats. Booleans are converted to a floating value.
//
// A ParameterDefn() takes the following parameters:
// -- the text name of the parameter. This is used for console input and ini file.
// -- a short text description of the parameter. This shows up in the console listing.
// -- a delegate for fetching the parameter from the ini file.
// Should handle fetching the right type from the ini file and converting it.
// -- a delegate for getting the value as a float
// -- a delegate for setting the value from a float
// -- an optional delegate to update the value in the world. Most often used to
// push the new value to an in-world object.
//
// The single letter parameters for the delegates are:
// s = BSScene
// o = BSPhysObject
// p = string parameter name
// l = localID of referenced object
// v = float value
// cf = parameter configuration class (for fetching values from ini file)
private ParameterDefn[] ParameterDefinitions =
{
new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
(s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
(s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
(s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
(s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
8f,
(s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return s.MeshLOD; },
(s,p,l,v) => { s.MeshLOD = v; } ),
new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
16f,
(s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return s.MeshMegaPrimLOD; },
(s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
10f,
(s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
(s) => { return s.MeshMegaPrimThreshold; },
(s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
32f,
(s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
(s) => { return s.SculptLOD; },
(s,p,l,v) => { s.SculptLOD = v; } ),
new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
10f,
(s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxSubSteps; },
(s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
1f / 60f,
(s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
(s) => { return (float)s.m_fixedTimeStep; },
(s,p,l,v) => { s.m_fixedTimeStep = v; } ),
new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
2048f,
(s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxCollisionsPerFrame; },
(s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
8000f,
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_maxUpdatesPerFrame; },
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
500f,
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_taintsToProcessPerStep; },
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
10000.01f,
(s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
(s) => { return (float)s.MaximumObjectMass; },
(s,p,l,v) => { s.MaximumObjectMass = v; } ),
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
2200f,
(s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
(s) => { return (float)s.PID_D; },
(s,p,l,v) => { s.PID_D = v; } ),
new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
900f,
(s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
(s) => { return (float)s.PID_P; },
(s,p,l,v) => { s.PID_P = v; } ),
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
0.2f,
(s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultFriction; },
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
new ParameterDefn("DefaultDensity", "Density for new objects" ,
10.000006836f, // Aluminum g/cm3
(s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultDensity; },
(s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
0f,
(s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultRestitution; },
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
0.04f,
(s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].collisionMargin; },
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
-9.80665f,
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].gravity; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearDamping; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
0f,
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularDamping; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
0.2f,
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].deactivationTime; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
0.8f,
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linearSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1.0f,
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].angularSleepingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
0f, // set to zero to disable
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdMotionThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
0f,
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
(s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
0.1f,
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].contactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
(float)BSTerrainPhys.TerrainImplementation.Mesh,
(s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
(s) => { return s.m_params[0].terrainImplementation; },
(s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.3f,
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainFriction; },
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
0.8f,
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainHitFraction; },
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
0f,
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainRestitution; },
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
0.04f,
(s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainCollisionMargin; },
(s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.2f,
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
10.0f,
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarStandingFriction; },
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
60f,
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarDensity; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
0f,
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarRestitution; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
0.6f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleWidth; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
0.45f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleDepth; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1.5f,
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarCapsuleHeight; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
0.1f,
(s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
0.95f,
(s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].vehicleAngularDamping; },
(s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f,
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
(s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
0f,
(s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
(s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
(s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
(s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldSplitSimulationIslands; },
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].shouldEnableFrictionCaching; },
(s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
0f, // zero says use Bullet default
(s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].numberOfSolverIterations; },
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
(float)BSLinkset.LinksetImplementation.Compound,
(s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
(s) => { return s.m_params[0].linksetImplementation; },
(s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
ConfigurationParameters.numericFalse,
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
(s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
ConfigurationParameters.numericTrue,
(s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
(s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
(s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
5.0f,
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintCFM; },
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
0.1f,
(s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintERP; },
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
40,
(s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].linkConstraintSolverIterations; },
(s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
0f,
(s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
(s) => { return (float)s.m_params[0].physicsLoggingFrames; },
(s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
};
// Convert a boolean to our numeric true and false values
public float NumericBool(bool b)
{
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
}
// Convert numeric true and false values to a boolean
public bool BoolNumeric(float b)
{
return (b == ConfigurationParameters.numericTrue ? true : false);
}
// Search through the parameter definitions and return the matching
// ParameterDefn structure.
// Case does not matter as names are compared after converting to lower case.
// Returns 'false' if the parameter is not found.
private bool TryGetParameter(string paramName, out ParameterDefn defn)
{
bool ret = false;
ParameterDefn foundDefn = new ParameterDefn();
string pName = paramName.ToLower();
foreach (ParameterDefn parm in ParameterDefinitions)
{
if (pName == parm.name.ToLower())
{
foundDefn = parm;
ret = true;
break;
}
}
defn = foundDefn;
return ret;
}
// Pass through the settable parameters and set the default values
private void SetParameterDefaultValues()
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
}
}
// Get user set values out of the ini file.
private void SetParameterConfigurationValues(IConfig cfg)
{
foreach (ParameterDefn parm in ParameterDefinitions)
{
parm.userParam(this, cfg, parm.name, parm.defaultValue);
}
}
private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
// This creates an array in the correct format for returning the list of
// parameters. This is used by the 'list' option of the 'physics' command.
private void BuildParameterTable()
{
if (SettableParameters.Length < ParameterDefinitions.Length)
{
List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
{
ParameterDefn pd = ParameterDefinitions[ii];
entries.Add(new PhysParameterEntry(pd.name, pd.desc));
}
// make the list in alphabetical order for estetic reasons
entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
{
return ppe1.name.CompareTo(ppe2.name);
});
SettableParameters = entries.ToArray();
}
}
#region IPhysicsParameters
// Get the list of parameters this physics engine supports
public PhysParameterEntry[] GetParameterList()
{
BuildParameterTable();
return SettableParameters;
BSParam.BuildParameterTable();
return BSParam.SettableParameters;
}
// Set parameter on a specific or all instances.
@ -1434,8 +952,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public bool SetPhysicsParameter(string parm, float val, uint localID)
{
bool ret = false;
ParameterDefn theParam;
if (TryGetParameter(parm, out theParam))
BSParam.ParameterDefn theParam;
if (BSParam.TryGetParameter(parm, out theParam))
{
theParam.setter(this, parm, localID, val);
ret = true;
@ -1447,19 +965,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// If the local ID is APPLY_TO_NONE, just change the default value
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
// If the localID is a specific object, apply the parameter change to only that object
private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
internal delegate void AssignVal(float x);
internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
{
List<uint> objectIDs = new List<uint>();
switch (localID)
{
case PhysParameterEntry.APPLY_TO_NONE:
defaultLoc = val; // setting only the default value
setDefault(val); // setting only the default value
// This will cause a call into the physical world if some operation is specified (SetOnObject).
objectIDs.Add(TERRAIN_ID);
TaintedUpdateParameter(parm, objectIDs, val);
break;
case PhysParameterEntry.APPLY_TO_ALL:
defaultLoc = val; // setting ALL also sets the default value
setDefault(val); // setting ALL also sets the default value
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
TaintedUpdateParameter(parm, objectIDs, val);
break;
@ -1478,8 +997,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
List<uint> xlIDs = lIDs;
string xparm = parm;
TaintedObject("BSScene.UpdateParameterSet", delegate() {
ParameterDefn thisParam;
if (TryGetParameter(xparm, out thisParam))
BSParam.ParameterDefn thisParam;
if (BSParam.TryGetParameter(xparm, out thisParam))
{
if (thisParam.onObject != null)
{
@ -1500,8 +1019,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
float val = 0f;
bool ret = false;
ParameterDefn theParam;
if (TryGetParameter(parm, out theParam))
BSParam.ParameterDefn theParam;
if (BSParam.TryGetParameter(parm, out theParam))
{
val = theParam.getter(this);
ret = true;

View File

@ -456,7 +456,7 @@ public sealed class BSShapeCollection : IDisposable
if (!haveShape
&& pbs != null
&& nativeShapePossible
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
&& ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
&& pbs.ProfileHollow == 0
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
@ -520,7 +520,7 @@ public sealed class BSShapeCollection : IDisposable
bool ret = false;
// Note that if it's a native shape, the check for physical/non-physical is not
// made. Native shapes work in either case.
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
{
// Update prim.BSShape to reference a hull of this shape.
ret = GetReferenceToHull(prim,shapeCallback);
@ -836,14 +836,14 @@ public sealed class BSShapeCollection : IDisposable
private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
{
// level of detail based on size and type of the object
float lod = PhysicsScene.MeshLOD;
float lod = BSParam.MeshLOD;
if (pbs.SculptEntry)
lod = PhysicsScene.SculptLOD;
lod = BSParam.SculptLOD;
// Mega prims usually get more detail because one can interact with shape approximations at this size.
float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
lod = PhysicsScene.MeshMegaPrimLOD;
if (maxAxis > BSParam.MeshMegaPrimThreshold)
lod = BSParam.MeshMegaPrimLOD;
retLod = lod;
return pbs.GetMeshKey(size, lod);

View File

@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
{
m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
m_mapInfo.minCoords, m_mapInfo.maxCoords,
m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
m_mapInfo.heightMap, BSParam.TerrainCollisionMargin);
// Create the terrain shape from the mapInfo
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
@ -110,9 +110,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
m_mapInfo.ID, centerPos, Quaternion.Identity));
// Set current terrain attributes
BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction);
BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction);
BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution);
BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
// Return the new terrain to the world of physical objects

View File

@ -135,7 +135,7 @@ public sealed class BSTerrainManager : IDisposable
// The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape(
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
PhysicsScene.Params.terrainCollisionMargin),
BSParam.TerrainCollisionMargin),
BSPhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@ -309,9 +309,9 @@ public sealed class BSTerrainManager : IDisposable
{
PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
LogHeader, PhysicsScene.RegionName, terrainRegionBase,
(BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
(BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
BSTerrainPhys newTerrainPhys = null;
switch ((int)PhysicsScene.Params.terrainImplementation)
switch ((int)BSParam.TerrainImplementation)
{
case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@ -324,8 +324,8 @@ public sealed class BSTerrainManager : IDisposable
default:
PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
LogHeader,
(int)PhysicsScene.Params.terrainImplementation,
PhysicsScene.Params.terrainImplementation,
(int)BSParam.TerrainImplementation,
BSParam.TerrainImplementation,
PhysicsScene.RegionName, terrainRegionBase);
break;
}

View File

@ -116,9 +116,9 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
// Set current terrain attributes
BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction);
BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction);
BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution);
BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
// Static objects are not very massive.

View File

@ -141,6 +141,8 @@ public struct EntityProperties
}
// Format of this structure must match the definition in the C++ code
// NOTE: adding the X causes compile breaks if used. These are unused symbols
// that can be removed from both here and the unmanaged definition of this structure.
[StructLayout(LayoutKind.Sequential)]
public struct ConfigurationParameters
{
@ -150,31 +152,31 @@ public struct ConfigurationParameters
public float collisionMargin;
public float gravity;
public float linearDamping;
public float angularDamping;
public float deactivationTime;
public float linearSleepingThreshold;
public float angularSleepingThreshold;
public float ccdMotionThreshold;
public float ccdSweptSphereRadius;
public float contactProcessingThreshold;
public float XlinearDamping;
public float XangularDamping;
public float XdeactivationTime;
public float XlinearSleepingThreshold;
public float XangularSleepingThreshold;
public float XccdMotionThreshold;
public float XccdSweptSphereRadius;
public float XcontactProcessingThreshold;
public float terrainImplementation;
public float terrainFriction;
public float terrainHitFraction;
public float terrainRestitution;
public float terrainCollisionMargin;
public float XterrainImplementation;
public float XterrainFriction;
public float XterrainHitFraction;
public float XterrainRestitution;
public float XterrainCollisionMargin;
public float avatarFriction;
public float avatarStandingFriction;
public float avatarDensity;
public float avatarRestitution;
public float avatarCapsuleWidth;
public float avatarCapsuleDepth;
public float avatarCapsuleHeight;
public float avatarContactProcessingThreshold;
public float XavatarFriction;
public float XavatarStandingFriction;
public float XavatarDensity;
public float XavatarRestitution;
public float XavatarCapsuleWidth;
public float XavatarCapsuleDepth;
public float XavatarCapsuleHeight;
public float XavatarContactProcessingThreshold;
public float vehicleAngularDamping;
public float XvehicleAngularDamping;
public float maxPersistantManifoldPoolSize;
public float maxCollisionAlgorithmPoolSize;
@ -185,14 +187,14 @@ public struct ConfigurationParameters
public float shouldEnableFrictionCaching;
public float numberOfSolverIterations;
public float linksetImplementation;
public float linkConstraintUseFrameOffset;
public float linkConstraintEnableTransMotor;
public float linkConstraintTransMotorMaxVel;
public float linkConstraintTransMotorMaxForce;
public float linkConstraintERP;
public float linkConstraintCFM;
public float linkConstraintSolverIterations;
public float XlinksetImplementation;
public float XlinkConstraintUseFrameOffset;
public float XlinkConstraintEnableTransMotor;
public float XlinkConstraintTransMotorMaxVel;
public float XlinkConstraintTransMotorMaxForce;
public float XlinkConstraintERP;
public float XlinkConstraintCFM;
public float XlinkConstraintSolverIterations;
public float physicsLoggingFrames;