diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 82361ad686..9f9ebcce62 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs @@ -51,8 +51,6 @@ public class BSCharacter : PhysicsActor private Vector3 _position; private float _mass = 80f; public float _density = 60f; - public float CAPSULE_RADIUS = 0.37f; - public float CAPSULE_LENGTH = 2.140599f; private Vector3 _force; private Vector3 _velocity; private Vector3 _torque; @@ -96,7 +94,8 @@ public class BSCharacter : PhysicsActor _velocity = Vector3.Zero; _buoyancy = 0f; // characters return a buoyancy of zero _scale = new Vector3(1f, 1f, 1f); - float AVvolume = (float) (Math.PI*Math.Pow(CAPSULE_RADIUS, 2)*CAPSULE_LENGTH); + float AVvolume = (float) (Math.PI*Math.Pow(_scene.Params.avatarCapsuleRadius, 2)*_scene.Params.avatarCapsuleHeight); + _density = _scene.Params.avatarDensity; _mass = _density*AVvolume; ShapeData shapeData = new ShapeData(); @@ -109,6 +108,8 @@ public class BSCharacter : PhysicsActor shapeData.Mass = _mass; shapeData.Buoyancy = isFlying ? 1f : 0f; shapeData.Static = ShapeData.numericFalse; + shapeData.Friction = _scene.Params.avatarFriction; + shapeData.Restitution = _scene.Params.defaultRestitution; // do actual create at taint time _scene.TaintedObject(delegate() @@ -395,9 +396,9 @@ public class BSCharacter : PhysicsActor _acceleration = entprop.Acceleration; changed = true; } - if (_rotationalVelocity != entprop.AngularVelocity) + if (_rotationalVelocity != entprop.RotationalVelocity) { - _rotationalVelocity = entprop.AngularVelocity; + _rotationalVelocity = entprop.RotationalVelocity; changed = true; } if (changed) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index f2ab2d9e6f..04cb452b84 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -71,6 +71,7 @@ public sealed class BSPrim : PhysicsActor private bool _isPhysical; private bool _flying; private float _friction; + private float _restitution; private bool _setAlwaysRun; private bool _throttleUpdates; private bool _isColliding; @@ -101,7 +102,7 @@ public sealed class BSPrim : PhysicsActor private float _PIDHoverTao; public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, - OMV.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical) + OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) { // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID); _localID = localID; @@ -113,15 +114,16 @@ public sealed class BSPrim : PhysicsActor _orientation = rotation; _buoyancy = 1f; _velocity = OMV.Vector3.Zero; + _rotationalVelocity = OMV.Vector3.Zero; _angularVelocity = OMV.Vector3.Zero; - _mesh = mesh; _hullKey = 0; _pbs = pbs; _isPhysical = pisPhysical; _isVolumeDetect = false; _subscribedEventsMs = 0; - _friction = _scene.DefaultFriction; // TODO: compute based on object material - _density = _scene.DefaultDensity; // TODO: compute based on object material + _friction = _scene.Params.defaultFriction; // TODO: compute based on object material + _density = _scene.Params.defaultDensity; // TODO: compute based on object material + _restitution = _scene.Params.defaultRestitution; _parentPrim = null; // not a child or a parent _vehicle = new BSDynamics(this); // add vehicleness _childrenPrims = new List(); @@ -132,8 +134,7 @@ public sealed class BSPrim : PhysicsActor // do the actual object creation at taint time _scene.TaintedObject(delegate() { - CreateGeom(); - CreateObject(); + RecreateGeomAndObject(); }); } @@ -239,6 +240,7 @@ public sealed class BSPrim : PhysicsActor return; } + // I am the root of a linkset and a new child is being added public void AddChildToLinkset(BSPrim pchild) { BSPrim child = pchild; @@ -254,6 +256,8 @@ public sealed class BSPrim : PhysicsActor return; } + // I am the root of a linkset and one of my children is being removed. + // Safe to call even if the child is not really in my linkset. public void RemoveChildFromLinkset(BSPrim pchild) { BSPrim child = pchild; @@ -290,6 +294,17 @@ public sealed class BSPrim : PhysicsActor get { return (_parentPrim == null && _childrenPrims.Count != 0); } } + // Set motion values to zero. + // Do it to the properties so the values get set in the physics engine. + // Push the setting of the values to the viewer. + private void ZeroMotion() + { + Velocity = OMV.Vector3.Zero; + _acceleration = OMV.Vector3.Zero; + RotationalVelocity = OMV.Vector3.Zero; + base.RequestPhysicsterseUpdate(); + } + public override void LockAngularMotion(OMV.Vector3 axis) { return; } public override OMV.Vector3 Position { @@ -390,18 +405,6 @@ public sealed class BSPrim : PhysicsActor }); } } - public OMV.Vector3 AngularVelocity - { - get { return _angularVelocity; } - set - { - _angularVelocity = value; - _scene.TaintedObject(delegate() - { - BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _angularVelocity); - }); - } - } public override OMV.Vector3 Torque { get { return _torque; } set { _torque = value; @@ -419,11 +422,11 @@ public sealed class BSPrim : PhysicsActor get { return _orientation; } set { _orientation = value; + // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); _scene.TaintedObject(delegate() { // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); - // m_log.DebugFormat("{0}: set orientation: {1}", LogHeader, _orientation); }); } } @@ -505,8 +508,16 @@ public sealed class BSPrim : PhysicsActor get { return _rotationalVelocity; } set { _rotationalVelocity = value; // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); + _scene.TaintedObject(delegate() + { + BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); + }); } } + public OMV.Vector3 AngularVelocity { + get { return _angularVelocity; } + set { _angularVelocity = value; } + } public override bool Kinematic { get { return _kinematic; } set { _kinematic = value; @@ -866,9 +877,6 @@ public sealed class BSPrim : PhysicsActor returnMass = _density * volume; - if (returnMass <= 0) - returnMass = 0.0001f;//ckrinke: Mass must be greater then zero. - if (IsRootOfLinkset) { foreach (BSPrim prim in _childrenPrims) @@ -877,8 +885,12 @@ public sealed class BSPrim : PhysicsActor } } - if (returnMass > _scene.maximumMassObject) - returnMass = _scene.maximumMassObject; + if (returnMass <= 0) + returnMass = 0.0001f; + + if (returnMass > _scene.MaximumObjectMass) + returnMass = _scene.MaximumObjectMass; + return returnMass; }// end CalculateMass #endregion Mass Calculation @@ -887,6 +899,15 @@ public sealed class BSPrim : PhysicsActor // No locking here because this is done when we know physics is not simulating private void CreateGeom() { + // Since we're recreating new, get rid of any previously generated shape + if (_hullKey != 0) + { + // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); + BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); + _hullKey = 0; + _hulls.Clear(); + } + if (_mesh == null) { // the mesher thought this was too simple to mesh. Use a native Bullet collision shape. @@ -902,21 +923,13 @@ public sealed class BSPrim : PhysicsActor } else { - // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box of size {1}", LogHeader, _size); + // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; _scale = _size; } } else { - if (_hullKey != 0) - { - // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); - BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); - _hullKey = 0; - _hulls.Clear(); - } - int[] indices = _mesh.getIndexListAsInt(); List vertices = _mesh.getVertexList(); @@ -997,7 +1010,7 @@ public sealed class BSPrim : PhysicsActor // create the hull definition in Bullet _hullKey = (ulong)_pbs.GetHashCode(); - // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid= {1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); + // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid={1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount); BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls); _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; // meshes are already scaled by the meshmerizer @@ -1006,6 +1019,8 @@ public sealed class BSPrim : PhysicsActor return; } + // Callback from convex hull creater with a newly created hull. + // Just add it to the collection of hulls for this shape. private void HullReturn(ConvexResult result) { _hulls.Add(result); @@ -1019,13 +1034,12 @@ public sealed class BSPrim : PhysicsActor if (IsRootOfLinkset) { // Create a linkset around this object - CreateLinksetWithCompoundHull(); - // CreateLinksetWithConstraints(); + // CreateLinksetWithCompoundHull(); + CreateLinksetWithConstraints(); } else { // simple object - // m_log.DebugFormat("{0}: CreateObject. ID={1}", LogHeader, LocalID); ShapeData shape; FillShapeInfo(out shape); BulletSimAPI.CreateObject(_scene.WorldID, shape); @@ -1034,6 +1048,7 @@ public sealed class BSPrim : PhysicsActor // Create a linkset by creating a compound hull at the root prim that consists of all // the children. + // NOTE: This does not allow proper collisions with the children prims so it is not a workable solution void CreateLinksetWithCompoundHull() { // If I am the root prim of a linkset, replace my physical shape with all the @@ -1055,8 +1070,27 @@ public sealed class BSPrim : PhysicsActor BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes); } + // Copy prim's info into the BulletSim shape description structure + public void FillShapeInfo(out ShapeData shape) + { + shape.ID = _localID; + shape.Type = _shapeType; + shape.Position = _position; + shape.Rotation = _orientation; + shape.Velocity = _velocity; + shape.Scale = _scale; + shape.Mass = _isPhysical ? _mass : 0f; + shape.Buoyancy = _buoyancy; + shape.MeshKey = _hullKey; + shape.Friction = _friction; + shape.Restitution = _restitution; + shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; + shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; + } + // Create the linkset by putting constraints between the objects of the set so they cannot move // relative to each other. + // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added void CreateLinksetWithConstraints() { // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); @@ -1070,76 +1104,48 @@ public sealed class BSPrim : PhysicsActor // create constraints between the root prim and each of the children foreach (BSPrim prim in _childrenPrims) { - // this is a constraint that allows no freedom of movement between the two objects - // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // m_log.DebugFormat("{0}: CreateObject: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); + // Zero motion for children so they don't interpolate + prim.ZeroMotion(); + // relative position normalized to the root prim OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); - // OMV.Quaternion relativeRotation = OMV.Quaternion.Identity; - // rotation is pointing up the vector between the object centers - OMV.Quaternion relativeRotation = OMV.Quaternion.CreateFromAxisAngle(childRelativePosition, 0f); - - /* // the logic for relative rotation from http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=6391 - OMV.Vector3 rrn = childRelativePosition; - rrn.Normalize(); - rrn /= rrn.X; - OMV.Matrix4 rotmat = new OMV.Matrix4(rrn.X, rrn.Y, rrn.Z, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); - OMV.Quaternion relativeRotation = OMV.Quaternion.CreateFromRotationMatrix(rotmat); - */ + // relative rotation of the child to the parent + OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; + // this is a constraint that allows no freedom of movement between the two objects + // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, - childRelativePosition / 2, - relativeRotation, - -childRelativePosition / 2, + childRelativePosition, relativeRotation, + OMV.Vector3.Zero, + OMV.Quaternion.Identity, OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero); } } - // Copy prim's info into the BulletSim shape description structure - public void FillShapeInfo(out ShapeData shape) - { - shape.ID = _localID; - shape.Type = _shapeType; - shape.Position = _position; - shape.Rotation = _orientation; - shape.Velocity = _velocity; - shape.Scale = _scale; - shape.Mass = _isPhysical ? _mass : 0f; - shape.Buoyancy = _buoyancy; - shape.MeshKey = _hullKey; - shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse; - shape.Friction = _friction; - shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue; - } - // Rebuild the geometry and object. // This is called when the shape changes so we need to recreate the mesh/hull. // No locking here because this is done when the physics engine is not simulating private void RecreateGeomAndObject() { - if (_hullKey != 0) - { - // if a hull already exists, delete the old one - BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); - _hullKey = 0; - } // If this object is complex or we are the root of a linkset, build a mesh. // The root of a linkset must be a mesh so we can create the linked compound object. - if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset ) + // if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset ) + if (_scene.NeedsMeshing(_pbs)) // linksets with constraints don't need a root mesh { // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader); - _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.meshLOD, _isPhysical); + _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.MeshLOD, _isPhysical); } else { - // it's a BulletSim native shape. + // implement the shape with a Bullet native shape. _mesh = null; } - CreateGeom(); // create the geometry for this prim + CreateGeom(); CreateObject(); return; } @@ -1152,48 +1158,82 @@ public sealed class BSPrim : PhysicsActor Rotation = 1 << 1, Velocity = 1 << 2, Acceleration = 1 << 3, - AngularVel = 1 << 4 + RotationalVel = 1 << 4 } + const float ROTATION_TOLERANCE = 0.01f; + const float VELOCITY_TOLERANCE = 0.001f; + const float POSITION_TOLERANCE = 0.05f; + const float ACCELERATION_TOLERANCE = 0.01f; + const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; + const bool SHOULD_DAMP_UPDATES = false; + public void UpdateProperties(EntityProperties entprop) { UpdatedProperties changed = 0; - // assign to the local variables so the normal set action does not happen - if (_position != entprop.Position) + if (SHOULD_DAMP_UPDATES) { - _position = entprop.Position; - // m_log.DebugFormat("{0}: UpdateProperties: position = {1}", LogHeader, _position); - changed |= UpdatedProperties.Position; + // assign to the local variables so the normal set action does not happen + // if (_position != entprop.Position) + if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) + { + _position = entprop.Position; + // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position); + changed |= UpdatedProperties.Position; + } + // if (_orientation != entprop.Rotation) + if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) + { + _orientation = entprop.Rotation; + // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation); + changed |= UpdatedProperties.Rotation; + } + // if (_velocity != entprop.Velocity) + if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) + { + _velocity = entprop.Velocity; + // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); + changed |= UpdatedProperties.Velocity; + } + // if (_acceleration != entprop.Acceleration) + if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) + { + _acceleration = entprop.Acceleration; + // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); + changed |= UpdatedProperties.Acceleration; + } + // if (_rotationalVelocity != entprop.RotationalVelocity) + if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) + { + _rotationalVelocity = entprop.RotationalVelocity; + // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); + changed |= UpdatedProperties.RotationalVel; + } + if (changed != 0) + { + // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); + // Only update the position of single objects and linkset roots + if (this._parentPrim == null) + { + // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); + base.RequestPhysicsterseUpdate(); + } + } } - if (_orientation != entprop.Rotation) + else { - _orientation = entprop.Rotation; - // m_log.DebugFormat("{0}: UpdateProperties: rotation = {1}", LogHeader, _orientation); - changed |= UpdatedProperties.Rotation; - } - if (_velocity != entprop.Velocity) - { - _velocity = entprop.Velocity; - // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); - changed |= UpdatedProperties.Velocity; - } - if (_acceleration != entprop.Acceleration) - { - _acceleration = entprop.Acceleration; - // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); - changed |= UpdatedProperties.Acceleration; - } - if (_rotationalVelocity != entprop.AngularVelocity) - { - _rotationalVelocity = entprop.AngularVelocity; - // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); - changed |= UpdatedProperties.AngularVel; - } - if (changed != 0) - { - // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); + // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. if (this._parentPrim == null) + { + // Assign to the local variables so the normal set action does not happen + _position = entprop.Position; + _orientation = entprop.Rotation; + _velocity = entprop.Velocity; + _acceleration = entprop.Acceleration; + _rotationalVelocity = entprop.RotationalVelocity; + // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); base.RequestPhysicsterseUpdate(); + } } } @@ -1201,7 +1241,8 @@ public sealed class BSPrim : PhysicsActor public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth) { // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith); - // The following makes IsColliding() and IsCollidingGround() work + + // The following lines make IsColliding() and IsCollidingGround() work _collidingStep = _scene.SimulationStep; if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID) { diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 7c11f2bf9c..de86d59af3 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -71,11 +71,17 @@ public class BSScene : PhysicsScene private uint m_worldID; public uint WorldID { get { return m_worldID; } } - public IMesher mesher; - public int meshLOD = 32; + private bool m_initialized = false; - private int m_maxSubSteps = 10; - private float m_fixedTimeStep = 1f / 60f; + public IMesher mesher; + private int m_meshLOD; + public int MeshLOD + { + get { return m_meshLOD; } + } + + private int m_maxSubSteps; + private float m_fixedTimeStep; private long m_simulationStep = 0; public long SimulationStep { get { return m_simulationStep; } } @@ -84,68 +90,65 @@ public class BSScene : PhysicsScene private int m_simulationNowTime; public int SimulationNowTime { get { return m_simulationNowTime; } } - private int m_maxCollisionsPerFrame = 2048; + private int m_maxCollisionsPerFrame; private CollisionDesc[] m_collisionArray; private GCHandle m_collisionArrayPinnedHandle; - private int m_maxUpdatesPerFrame = 2048; + private int m_maxUpdatesPerFrame; private EntityProperties[] m_updateArray; private GCHandle m_updateArrayPinnedHandle; private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes - public float maximumMassObject = 10000.01f; - public const uint TERRAIN_ID = 0; + public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero public const uint GROUNDPLANE_ID = 1; - public float DefaultFriction = 0.70f; - public float DefaultDensity = 10.000006836f; // Aluminum g/cm3; TODO: compute based on object material - public Vector3 DefaultGravity = new Vector3(0, 0, -9.80665f); + public ConfigurationParameters Params + { + get { return m_params[0]; } + } + public Vector3 DefaultGravity + { + get { return new Vector3(0f, 0f, Params.gravity); } + } + + private float m_maximumObjectMass; + public float MaximumObjectMass + { + get { return m_maximumObjectMass; } + } public delegate void TaintCallback(); private List _taintedObjects; private Object _taintLock = new Object(); // A pointer to an instance if this structure is passed to the C++ code - // Format of this structure must match the definition in the C++ code - private struct ConfigurationParameters - { - public float defaultFriction; - public float defaultDensity; - public float collisionMargin; - public float gravity; - - public float linearDamping; - public float angularDamping; - public float deactivationTime; - public float linearSleepingThreshold; - public float angularSleepingThreshold; - - public float terrainFriction; - public float terrainHitFriction; - public float terrainRestitution; - public float avatarFriction; - public float avatarCapsuleRadius; - public float avatarCapsuleHeight; - } - ConfigurationParameters m_params; + ConfigurationParameters[] m_params; GCHandle m_paramsHandle; private BulletSimAPI.DebugLogCallback debugLogCallbackHandle; public BSScene(string identifier) { + m_initialized = false; } public override void Initialise(IMesher meshmerizer, IConfigSource config) { - m_params = new ConfigurationParameters(); + // Allocate pinned memory to pass parameters. + m_params = new ConfigurationParameters[1]; m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned); // Set default values for physics parameters plus any overrides from the ini file GetInitialParameterValues(config); + // allocate more pinned memory close to the above in an attempt to get the memory all together + m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; + m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); + m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; + m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); + // if Debug, enable logging from the unmanaged code if (m_log.IsDebugEnabled) { @@ -160,68 +163,95 @@ public class BSScene : PhysicsScene // The bounding box for the simulated world Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, 4096f); - // Allocate pinned memory to pass back object property updates and collisions from simulation step - m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; - m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned); - m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; - m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); - // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); - m_worldID = BulletSimAPI.Initialize(worldExtent, + m_worldID = BulletSimAPI.Initialize(worldExtent, m_paramsHandle.AddrOfPinnedObject(), m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(), m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject()); + + m_initialized = true; } + // All default parameter values are set here. There should be no values set in the + // variable definitions. private void GetInitialParameterValues(IConfigSource config) { + ConfigurationParameters parms = new ConfigurationParameters(); + _meshSculptedPrim = true; // mesh sculpted prims _forceSimplePrimMeshing = false; // use complex meshing if called for - // Set the default values for the physics parameters - m_params.defaultFriction = 0.70f; - m_params.defaultDensity = 10.000006836f; // Aluminum g/cm3 - m_params.collisionMargin = 0.0f; - m_params.gravity = -9.80665f; + m_meshLOD = 32; - m_params.linearDamping = 0.1f; - m_params.angularDamping = 0.85f; - m_params.deactivationTime = 0.2f; - m_params.linearSleepingThreshold = 0.8f; - m_params.angularSleepingThreshold = 1.0f; + m_maxSubSteps = 10; + m_fixedTimeStep = 1f / 60f; + m_maxCollisionsPerFrame = 2048; + m_maxUpdatesPerFrame = 2048; + m_maximumObjectMass = 10000.01f; - m_params.terrainFriction = 0.85f; - m_params.terrainHitFriction = 0.8f; - m_params.terrainRestitution = 0.2f; - m_params.avatarFriction = 0.85f; - m_params.avatarCapsuleRadius = 0.37f; - m_params.avatarCapsuleHeight = 1.5f; // 2.140599f + parms.defaultFriction = 0.70f; + parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 + parms.defaultRestitution = 0f; + parms.collisionMargin = 0.0f; + parms.gravity = -9.80665f; + + parms.linearDamping = 0.0f; + parms.angularDamping = 0.0f; + parms.deactivationTime = 0.2f; + parms.linearSleepingThreshold = 0.8f; + parms.angularSleepingThreshold = 1.0f; + parms.ccdMotionThreshold = 0.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.avatarDensity = 60f; + parms.avatarCapsuleRadius = 0.37f; + parms.avatarCapsuleHeight = 1.5f; // 2.140599f 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 IConfig pConfig = config.Configs["BulletSim"]; if (pConfig != null) { - _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", true); - _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", false); + _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); + _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); - m_params.defaultFriction = pConfig.GetFloat("DefaultFriction", m_params.defaultFriction); - m_params.defaultDensity = pConfig.GetFloat("DefaultDensity", m_params.defaultDensity); - m_params.collisionMargin = pConfig.GetFloat("CollisionMargin", m_params.collisionMargin); - m_params.gravity = pConfig.GetFloat("Gravity", m_params.gravity); - m_params.linearDamping = pConfig.GetFloat("LinearDamping", m_params.linearDamping); - m_params.angularDamping = pConfig.GetFloat("AngularDamping", m_params.angularDamping); - m_params.deactivationTime = pConfig.GetFloat("DeactivationTime", m_params.deactivationTime); - m_params.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", m_params.linearSleepingThreshold); - m_params.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", m_params.angularSleepingThreshold); - m_params.terrainFriction = pConfig.GetFloat("TerrainFriction", m_params.terrainFriction); - m_params.terrainHitFriction = pConfig.GetFloat("TerrainHitFriction", m_params.terrainHitFriction); - m_params.terrainRestitution = pConfig.GetFloat("TerrainRestitution", m_params.terrainRestitution); - m_params.avatarFriction = pConfig.GetFloat("AvatarFriction", m_params.avatarFriction); - m_params.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", m_params.avatarCapsuleRadius); - m_params.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", m_params.avatarCapsuleHeight); + m_meshLOD = pConfig.GetInt("MeshLevelOfDetail", m_meshLOD); + + m_maxSubSteps = pConfig.GetInt("MaxSubSteps", m_maxSubSteps); + m_fixedTimeStep = pConfig.GetFloat("FixedTimeStep", m_fixedTimeStep); + m_maxCollisionsPerFrame = pConfig.GetInt("MaxCollisionsPerFrame", m_maxCollisionsPerFrame); + m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); + m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); + + parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); + parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); + parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); + parms.collisionMargin = pConfig.GetFloat("CollisionMargin", parms.collisionMargin); + parms.gravity = pConfig.GetFloat("Gravity", parms.gravity); + + parms.linearDamping = pConfig.GetFloat("LinearDamping", parms.linearDamping); + parms.angularDamping = pConfig.GetFloat("AngularDamping", parms.angularDamping); + parms.deactivationTime = pConfig.GetFloat("DeactivationTime", parms.deactivationTime); + parms.linearSleepingThreshold = pConfig.GetFloat("LinearSleepingThreshold", parms.linearSleepingThreshold); + parms.angularSleepingThreshold = pConfig.GetFloat("AngularSleepingThreshold", parms.angularSleepingThreshold); + parms.ccdMotionThreshold = pConfig.GetFloat("CcdMotionThreshold", parms.ccdMotionThreshold); + parms.ccdSweptSphereRadius = pConfig.GetFloat("CcdSweptSphereRadius", parms.ccdSweptSphereRadius); + + parms.terrainFriction = pConfig.GetFloat("TerrainFriction", parms.terrainFriction); + parms.terrainHitFriction = pConfig.GetFloat("TerrainHitFriction", parms.terrainHitFriction); + parms.terrainRestitution = pConfig.GetFloat("TerrainRestitution", parms.terrainRestitution); + parms.avatarFriction = pConfig.GetFloat("AvatarFriction", parms.avatarFriction); + parms.avatarDensity = pConfig.GetFloat("AvatarDensity", parms.avatarDensity); + parms.avatarCapsuleRadius = pConfig.GetFloat("AvatarCapsuleRadius", parms.avatarCapsuleRadius); + parms.avatarCapsuleHeight = pConfig.GetFloat("AvatarCapsuleHeight", parms.avatarCapsuleHeight); } } + m_params[0] = parms; } // Called directly from unmanaged code so don't do much @@ -282,20 +312,13 @@ public class BSScene : PhysicsScene Vector3 size, Quaternion rotation, bool isPhysical, uint localID) { // m_log.DebugFormat("{0}: AddPrimShape2: {1}", LogHeader, primName); - IMesh mesh = null; - if (NeedsMeshing(pbs)) - { - // if the prim is complex, create the mesh for it. - // If simple (box or sphere) leave 'mesh' null and physics will do a native shape. - mesh = mesher.CreateMesh(primName, pbs, size, this.meshLOD, isPhysical); - } - BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, mesh, pbs, isPhysical); + BSPrim prim = new BSPrim(localID, primName, this, position, size, rotation, pbs, isPhysical); lock (m_prims) m_prims.Add(localID, prim); return prim; } // This is a call from the simulator saying that some physical property has been updated. - // The BulletS driver senses the changing of relevant properties so this taint + // The BulletSim driver senses the changing of relevant properties so this taint // information call is not needed. public override void AddPhysicsActorTaint(PhysicsActor prim) { } @@ -307,6 +330,9 @@ public class BSScene : PhysicsScene int collidersCount; IntPtr collidersPtr; + // prevent simulation until we've been initialized + if (!m_initialized) return 10.0f; + // update the prim states while we know the physics engine is not busy ProcessTaints(); @@ -360,7 +386,7 @@ public class BSScene : PhysicsScene } } - // fps calculation wrong. This calculation always returns about 1 in normal operation. + // FIX THIS: fps calculation wrong. This calculation always returns about 1 in normal operation. return timeStep / (numSubSteps * m_fixedTimeStep) * 1000f; } @@ -369,8 +395,7 @@ public class BSScene : PhysicsScene { if (localID == TERRAIN_ID || localID == GROUNDPLANE_ID) { - // we never send collisions to the terrain - return; + return; // don't send collisions to the terrain } ActorTypes type = ActorTypes.Prim; @@ -381,12 +406,12 @@ public class BSScene : PhysicsScene BSPrim prim; if (m_prims.TryGetValue(localID, out prim)) { - prim.Collide(collidingWith, type, collidePoint, collideNormal, 0.01f); + prim.Collide(collidingWith, type, collidePoint, collideNormal, penitration); return; } BSCharacter actor; if (m_avatars.TryGetValue(localID, out actor)) { - actor.Collide(collidingWith, type, collidePoint, collideNormal, 0.01f); + actor.Collide(collidingWith, type, collidePoint, collideNormal, penitration); return; } return; @@ -448,7 +473,7 @@ public class BSScene : PhysicsScene if (pbs.SculptEntry && !_meshSculptedPrim) { - // m_log.DebugFormat("{0}: NeedsMeshing: scultpy mesh", LogHeader); + // Render sculpties as boxes return false; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index ace815843c..819fce1757 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -32,12 +32,14 @@ using OpenMetaverse; namespace OpenSim.Region.Physics.BulletSPlugin { +[StructLayout(LayoutKind.Sequential)] public struct ConvexHull { Vector3 Offset; int VertexCount; Vector3[] Vertices; } +[StructLayout(LayoutKind.Sequential)] public struct ShapeData { public enum PhysicsShapeType @@ -49,6 +51,7 @@ 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; @@ -60,11 +63,12 @@ public struct ShapeData public float Mass; public float Buoyancy; public System.UInt64 MeshKey; - public int Collidable; public float Friction; + 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 } +[StructLayout(LayoutKind.Sequential)] public struct SweepHit { public uint ID; @@ -72,12 +76,14 @@ public struct SweepHit public Vector3 Normal; public Vector3 Point; } +[StructLayout(LayoutKind.Sequential)] public struct RaycastHit { public uint ID; public float Fraction; public Vector3 Normal; } +[StructLayout(LayoutKind.Sequential)] public struct CollisionDesc { public uint aID; @@ -85,6 +91,7 @@ public struct CollisionDesc public Vector3 point; public Vector3 normal; } +[StructLayout(LayoutKind.Sequential)] public struct EntityProperties { public uint ID; @@ -92,13 +99,42 @@ public struct EntityProperties public Quaternion Rotation; public Vector3 Velocity; public Vector3 Acceleration; - public Vector3 AngularVelocity; + public Vector3 RotationalVelocity; +} + +// Format of this structure must match the definition in the C++ code +[StructLayout(LayoutKind.Sequential)] +public struct ConfigurationParameters +{ + public float defaultFriction; + public float defaultDensity; + public float defaultRestitution; + 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 terrainFriction; + public float terrainHitFriction; + public float terrainRestitution; + public float avatarFriction; + public float avatarDensity; + public float avatarRestitution; + public float avatarCapsuleRadius; + public float avatarCapsuleHeight; } static class BulletSimAPI { [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] -public static extern uint Initialize(Vector3 maxPosition, int maxCollisions, IntPtr collisionArray, +public static extern uint Initialize(Vector3 maxPosition, IntPtr parms, + int maxCollisions, IntPtr collisionArray, int maxUpdates, IntPtr updateArray); [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] diff --git a/bin/BulletSim-x86_64.dll b/bin/BulletSim-x86_64.dll index bcdea44768..750b2f58cb 100755 Binary files a/bin/BulletSim-x86_64.dll and b/bin/BulletSim-x86_64.dll differ diff --git a/bin/BulletSim.dll b/bin/BulletSim.dll index 5dc51db762..d5c76da3ee 100755 Binary files a/bin/BulletSim.dll and b/bin/BulletSim.dll differ diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index bf3622828b..d487ce6312 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -159,6 +159,7 @@ ;physics = basicphysics ;physics = POS ;physics = modified_BulletX + ;physics = BulletSim ; ## ; ## PERMISSIONS @@ -725,6 +726,47 @@ ; true. Note that this will increase memory usage and region startup time. Default is false. ;force_simple_prim_meshing = true +[BulletSim] + ; World parameters + DefaultFriction = 0.70 + DefaultDensity = 10.000006836 + DefaultRestitution = 0.0 + Gravity = -9.80665 + + TerrainFriction = 0.85 + TerrainHitFriction = 0.8 + TerrainRestitution = 0.2 + AvatarFriction = 0.85 + AvatarDensity = 60.0 + AvatarCapsuleRadius = 0.37 + AvatarCapsuleHeight = 1.5 + + MaxObjectMass = 10000.01 + + ; Dynamic parameters + LinearDamping = 0.0 + AngularDamping = 0.0 + DeactivationTime = 0.2 + LinearSleepingThreshold = 0.8 + AngularSleepingThreshold = 1.0 + CcdMotionThreshold = 0.5 + CcdSweptSphereRadius = 0.2 + + ; Whether to mesh sculpties + MeshSculptedPrim = true + + ; If 'true', force simple prims (box and sphere) to be meshed + ForceSimplePrimMeshing = false + + ; number^2 non-physical level of detail of the sculpt texture. 32x32 - 1024 verticies + MeshLevelOfDetail = 32 + + ; Bullet step parameters + MaxSubSteps = 10; + FixedTimeStep = .01667 + + MaxCollisionsPerFrame = 2048 + MaxUpdatesPerFrame = 2048 [RemoteAdmin] enabled = false diff --git a/bin/libBulletSim.so b/bin/libBulletSim.so index 82d3b3432b..275355df7c 100755 Binary files a/bin/libBulletSim.so and b/bin/libBulletSim.so differ