From 2c5ff9399063080276a23bcd06fb696d653bef2e Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 13 Sep 2012 08:11:54 -0700 Subject: BulletSim: Way too many changes in one commit. Many changes to BSDynamic for readability and commentary. Linkset hacking for vehicles: don't over mass the root prim. Add parameter for link constraint solver iterations. Correct uses of timestep in timescale calculations for vehicles. Reorganize code/logic for making objects static and dynamic for readability and use of API2. Changed most calls in BSPrim to use API2 calls (the new way). Avatars do not generate default Bullet collision events but do call up to the simulator for every avatar. Reduces overhead. Objects added to collision list only if they are processing collisions. Reduces overhead especially for large numbers of avatars. Generalize call for water height to GetWaterHeightAtXYZ(). Catch and correct exception getting terrain height when out of bounds. Correct race condition in Terrain Manager where creation wasn't at taint-time. Add API calls for constructing compound shapes. Move NeedsMeshing() logic into object class. Reorganize logic for object meshing to reduce rebuilding of meshs/hulls. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 67 +++++++++++++++---------- 1 file changed, 41 insertions(+), 26 deletions(-) (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 4a468af..eea899f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -79,7 +79,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters private HashSet m_objectsWithCollisions = new HashSet(); // Following is a kludge and can be removed when avatar animation updating is // moved to a better place. - private HashSet m_avatarsWithCollisions = new HashSet(); + private HashSet m_avatarsWithCollisions = new HashSet(); // List of all the objects that have vehicle properties and should be called // to update each physics step. @@ -132,8 +132,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters 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 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 float PID_D { get; private set; } // derivative public float PID_P { get; private set; } // proportional @@ -153,6 +153,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters { get { return new Vector3(0f, 0f, Params.gravity); } } + // Just the Z value of the gravity + public float DefaultGravityZ + { + get { return Params.gravity; } + } public float MaximumObjectMass { get; private set; } @@ -171,8 +176,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters callback = c; } } + private Object _taintLock = new Object(); // lock for using the next object private List _taintedObjects; - private Object _taintLock = new Object(); // A pointer to an instance if this structure is passed to the C++ code // Used to pass basic configuration values to the unmanaged code. @@ -478,6 +483,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // Some of the prims operate with special vehicle properties ProcessVehicles(timeStep); + numTaints += _taintedObjects.Count; ProcessTaints(); // the vehicles might have added taints // step the physical world one interval @@ -506,6 +512,12 @@ public class BSScene : PhysicsScene, IPhysicsParameters // Get a value for 'now' so all the collision and update routines don't have to get their own SimulationNowTime = Util.EnvironmentTickCount(); + // This is a kludge to get avatar movement updates. + // ODE sends collisions for avatars even if there are have been no collisions. This updates + // avatar animations and stuff. + // If you fix avatar animation updates, remove this overhead and let collisions happen. + m_objectsWithCollisions = new HashSet(m_avatarsWithCollisions); + // If there were collisions, process them by sending the event to the prim. // Collisions must be processed before updates. if (collidersCount > 0) @@ -527,13 +539,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters bsp.SendCollisions(); m_objectsWithCollisions.Clear(); - // This is a kludge to get avatar movement updated. - // ODE sends collisions even if there are none and this is used to update - // avatar animations and stuff. - foreach (BSPhysObject bpo in m_avatarsWithCollisions) - bpo.SendCollisions(); - // m_avatarsWithCollisions.Clear(); - // If any of the objects had updated properties, tell the object it has been changed by the physics engine if (updatedEntityCount > 0) { @@ -544,7 +549,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters if (PhysObjects.TryGetValue(entprop.ID, out pobj)) { pobj.UpdateProperties(entprop); - continue; } } } @@ -600,8 +604,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); - collider.Collide(collidingWith, collidee, type, collidePoint, collideNormal, penetration); - m_objectsWithCollisions.Add(collider); + if (collider.Collide(collidingWith, collidee, type, collidePoint, collideNormal, penetration)) + { + // If a collision was posted, remember to send it to the simulator + m_objectsWithCollisions.Add(collider); + } return; } @@ -619,9 +626,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters public override void SetWaterLevel(float baseheight) { m_waterLevel = baseheight; - // TODO: pass to physics engine so things will float? } - public float GetWaterLevel() + // Someday.... + public float GetWaterLevelAtXYZ(Vector3 loc) { return m_waterLevel; } @@ -672,7 +679,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // int iPropertiesNotSupportedDefault = 0; - if (pbs.SculptEntry && !_meshSculptedPrim) + if (pbs.SculptEntry && !ShouldMeshSculptedPrim) { // Render sculpties as boxes return false; @@ -680,7 +687,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet // can use an internal representation for the prim - if (!_forceSimplePrimMeshing) + if (!ShouldForceSimplePrimMeshing) { if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 @@ -782,7 +789,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters if (!m_initialized) return; lock (_taintLock) + { _taintedObjects.Add(new TaintCallbackEntry(ident, callback)); + } + return; } @@ -919,14 +929,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters { new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties", ConfigurationParameters.numericTrue, - (s,cf,p,v) => { s._meshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); }, - (s) => { return s.NumericBool(s._meshSculptedPrim); }, - (s,p,l,v) => { s._meshSculptedPrim = s.BoolNumeric(v); } ), + (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._forceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); }, - (s) => { return s.NumericBool(s._forceSimplePrimMeshing); }, - (s,p,l,v) => { s._forceSimplePrimMeshing = s.BoolNumeric(v); } ), + (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("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)", 8f, @@ -1162,8 +1172,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters (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=none, 1=all. Default=0", - 0.0f, + 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; } ), @@ -1172,6 +1182,11 @@ public class BSScene : PhysicsScene, IPhysicsParameters (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("DetailedStats", "Frames between outputting detailed phys stats. (0 is off)", 0f, -- cgit v1.1 From d86cbe637943acde05528d0bce6dc61a77257cc0 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 13 Sep 2012 10:11:25 -0700 Subject: BulletSim: remove unused NeedsMeshing() code from BSScene. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 116 ------------------------ 1 file changed, 116 deletions(-) (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index eea899f..9c958d5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -56,7 +56,6 @@ using OpenMetaverse; // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect // Implement LockAngularMotion // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) -// Does NeedsMeshing() really need to exclude all the different shapes? // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. // Add PID movement operations. What does ScenePresence.MoveToTarget do? // Check terrain size. 128 or 127? @@ -666,121 +665,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters public override bool IsThreaded { get { return false; } } - /// - /// Routine to figure out if we need to mesh this prim with our mesher - /// - /// - /// true if the prim needs meshing - public bool NeedsMeshing(PrimitiveBaseShape pbs) - { - // most of this is redundant now as the mesher will return null if it cant mesh a prim - // but we still need to check for sculptie meshing being enabled so this is the most - // convenient place to do it for now... - - // int iPropertiesNotSupportedDefault = 0; - - if (pbs.SculptEntry && !ShouldMeshSculptedPrim) - { - // Render sculpties as boxes - return false; - } - - // if it's a standard box or sphere with no cuts, hollows, twist or top shear, return false since Bullet - // can use an internal representation for the prim - if (!ShouldForceSimplePrimMeshing) - { - if ((pbs.ProfileShape == ProfileShape.Square && pbs.PathCurve == (byte)Extrusion.Straight) - || (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 - && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)) - { - - if (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 - && pbs.ProfileHollow == 0 - && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 - && pbs.PathBegin == 0 && pbs.PathEnd == 0 - && pbs.PathTaperX == 0 && pbs.PathTaperY == 0 - && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 - && pbs.PathShearX == 0 && pbs.PathShearY == 0) - { - return false; - } - } - } - - /* TODO: verify that the mesher will now do all these shapes - if (pbs.ProfileHollow != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathBegin != 0) || pbs.PathEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathTwistBegin != 0) || (pbs.PathTwist != 0)) - iPropertiesNotSupportedDefault++; - - if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100)) - iPropertiesNotSupportedDefault++; - - if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1 && (pbs.Scale.X != pbs.Scale.Y || pbs.Scale.Y != pbs.Scale.Z || pbs.Scale.Z != pbs.Scale.X)) - iPropertiesNotSupportedDefault++; - - if (pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte) Extrusion.Curve1) - iPropertiesNotSupportedDefault++; - - // test for torus - if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Square) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.Circle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle) - { - if (pbs.PathCurve == (byte)Extrusion.Curve1 || pbs.PathCurve == (byte)Extrusion.Curve2) - { - iPropertiesNotSupportedDefault++; - } - } - else if ((pbs.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle) - { - if (pbs.PathCurve == (byte)Extrusion.Straight) - { - iPropertiesNotSupportedDefault++; - } - else if (pbs.PathCurve == (byte)Extrusion.Curve1) - { - iPropertiesNotSupportedDefault++; - } - } - if (iPropertiesNotSupportedDefault == 0) - { - return false; - } - */ - return true; - } - // Calls to the PhysicsActors can't directly call into the physics engine // because it might be busy. We delay changes to a known time. // We rely on C#'s closure to save and restore the context for the delegate. -- cgit v1.1 From 6632eb7c051e2638ea1c58c2876e7d6825398556 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 13 Sep 2012 13:51:42 -0700 Subject: BulletSim: Remove calculation and passing of unused collied object type. Fix collision code to properly sense mega-region children regions as terrain. When setting an object physical, reset all the physical properties (friction, ...). --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 26 ++++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 9c958d5..c38867f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -583,27 +583,21 @@ public class BSScene : PhysicsScene, IPhysicsParameters return; // don't send collisions to the terrain } - BSPhysObject collider = PhysObjects[localID]; - // TODO: as of this code, terrain was not in the physical object list. - // When BSTerrain is created and it will be in the list, we can remove - // the possibility that it's not there and just fetch the collidee. - BSPhysObject collidee = null; - - ActorTypes type = ActorTypes.Prim; - if (collidingWith <= TerrainManager.HighestTerrainID) + BSPhysObject collider; + if (!PhysObjects.TryGetValue(localID, out collider)) { - type = ActorTypes.Ground; - } - else - { - collidee = PhysObjects[collidingWith]; - if (collidee is BSCharacter) - type = ActorTypes.Agent; + // If the object that is colliding cannot be found, just ignore the collision. + return; } + // The terrain is not in the physical object list so 'collidee' + // can be null when Collide() is called. + BSPhysObject collidee = null; + PhysObjects.TryGetValue(collidingWith, out collidee); + // DetailLog("{0},BSScene.SendCollision,collide,id={1},with={2}", DetailLogZero, localID, collidingWith); - if (collider.Collide(collidingWith, collidee, type, collidePoint, collideNormal, penetration)) + if (collider.Collide(collidingWith, collidee, collidePoint, collideNormal, penetration)) { // If a collision was posted, remember to send it to the simulator m_objectsWithCollisions.Add(collider); -- cgit v1.1 From f35bd6eb7d5b0eb1a6d385f5f1d0147acfc3c8ef Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Fri, 14 Sep 2012 11:12:23 -0700 Subject: BulletSim: another attempt at computing physics FPS correctly. --- OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 29 +++++-------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSScene.cs') diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index c38867f..52997dd 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -110,11 +110,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters private long m_simulationStep = 0; public long SimulationStep { get { return m_simulationStep; } } - // The length of the last timestep we were asked to simulate. - // This is used by the vehicle code. Since the vehicle code is called - // once per simulation step, its constants need to be scaled by this. - public float LastSimulatedTimestep { get; private set; } - // A value of the time now so all the collision and update routines do not have to get their own // Set to 'now' just before all the prims and actors are called for collisions and updates public int SimulationNowTime { get; private set; } @@ -469,12 +464,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters int collidersCount = 0; IntPtr collidersPtr; - LastSimulatedTimestep = timeStep; - // prevent simulation until we've been initialized - if (!m_initialized) return 10.0f; - - int simulateStartTime = Util.EnvironmentTickCount(); + if (!m_initialized) return 5.0f; // update the prim states while we know the physics engine is not busy int numTaints = _taintedObjects.Count; @@ -514,7 +505,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters // This is a kludge to get avatar movement updates. // ODE sends collisions for avatars even if there are have been no collisions. This updates // avatar animations and stuff. - // If you fix avatar animation updates, remove this overhead and let collisions happen. + // If you fix avatar animation updates, remove this overhead and let normal collision processing happen. m_objectsWithCollisions = new HashSet(m_avatarsWithCollisions); // If there were collisions, process them by sending the event to the prim. @@ -561,18 +552,10 @@ public class BSScene : PhysicsScene, IPhysicsParameters } } - // this is a waste since the outside routine also calcuates the physics simulation - // period. TODO: There should be a way of computing physics frames from simulator computation. - // long simulateTotalTime = Util.EnvironmentTickCountSubtract(simulateStartTime); - // return (timeStep * (float)simulateTotalTime); - - // TODO: FIX THIS: fps calculation possibly wrong. - // This calculation says 1/timeStep is the ideal frame rate. Any time added to - // that by the physics simulation gives a slower frame rate. - long totalSimulationTime = Util.EnvironmentTickCountSubtract(simulateStartTime); - if (totalSimulationTime >= timeStep) - return 0; - return 1f / (timeStep + totalSimulationTime); + // The physics engine returns the number of milliseconds it simulated this call. + // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. + // Since Bullet normally does 5 or 6 substeps, this will normally sum to about 60 FPS. + return numSubSteps * m_fixedTimeStep; } // Something has collided -- cgit v1.1