diff --git a/OpenSim/Data/Tests/BasicDataServiceTest.cs b/OpenSim/Data/Tests/BasicDataServiceTest.cs
index d8019ba9b4..69b79bf6e0 100644
--- a/OpenSim/Data/Tests/BasicDataServiceTest.cs
+++ b/OpenSim/Data/Tests/BasicDataServiceTest.cs
@@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
/// This is a base class for testing any Data service for any DBMS.
/// Requires NUnit 2.5 or better (to support the generics).
///
+ ///
+ /// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
+ /// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
+ /// and similar on EstateTests, InventoryTests and RegionTests.
+ /// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
+ ///
///
///
- public class BasicDataServiceTest : OpenSimTestCase
+ public class BasicDataServiceTest
where TConn : DbConnection, new()
where TService : class, new()
{
diff --git a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
index af54c1a1de..b735c611bb 100644
--- a/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Groups/GroupsModule.cs
@@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
}
if (groupsConfig.GetString("Module", "Default") != "Default")
+ {
+ m_Enabled = false;
return;
+ }
}
}
diff --git a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
index 3a44cc5ee1..2d46276274 100644
--- a/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
@@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{
foreach (GridInstantMessage im in msglist)
{
- // client.SendInstantMessage(im);
+ if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
+ // send it directly or else the item will be given twice
+ client.SendInstantMessage(im);
+ else
+ {
+ // Send through scene event manager so all modules get a chance
+ // to look at this message before it gets delivered.
+ //
+ // Needed for proper state management for stored group
+ // invitations
+ //
- // Send through scene event manager so all modules get a chance
- // to look at this message before it gets delivered.
- //
- // Needed for proper state management for stored group
- // invitations
- //
+ im.offline = 1;
- im.offline = 1;
-
- Scene s = FindScene(client.AgentId);
- if (s != null)
- s.EventManager.TriggerIncomingInstantMessage(im);
+ Scene s = FindScene(client.AgentId);
+ if (s != null)
+ s.EventManager.TriggerIncomingInstantMessage(im);
+ }
}
}
}
diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
index ab8f14344b..7b235aef74 100644
--- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs
@@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4)
{
- m_console.OutputFormat("Usage: show part id [--full] ");
+ //m_console.OutputFormat("Usage: show part id [--full] ");
+ m_console.OutputFormat("Usage: show part id ");
return;
}
@@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 5)
{
+ //m_console.OutputFormat("Usage: show part pos to ");
m_console.OutputFormat("Usage: show part pos [--full] to ");
return;
}
@@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4)
{
- m_console.OutputFormat("Usage: show part name [--full] [--regex] ");
+ m_console.OutputFormat("Usage: show part name [--regex] ");
+ //m_console.OutputFormat("Usage: show part name [--full] [--regex] ");
return;
}
@@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("Link number", sop.LinkNum);
cdl.AddRow("Flags", sop.Flags);
+ if (showFull)
+ {
+ PrimitiveBaseShape s = sop.Shape;
+ cdl.AddRow("FlexiDrag", s.FlexiDrag);
+ cdl.AddRow("FlexiEntry", s.FlexiEntry);
+ cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
+ cdl.AddRow("FlexiGravity", s.FlexiGravity);
+ cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
+ cdl.AddRow("HollowShape", s.HollowShape);
+ cdl.AddRow(
+ "LightColor",
+ string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
+ cdl.AddRow("FlexiDrag", s.LightCutoff);
+ cdl.AddRow("FlexiDrag", s.LightEntry);
+ cdl.AddRow("FlexiDrag", s.LightFalloff);
+ cdl.AddRow("FlexiDrag", s.LightIntensity);
+ cdl.AddRow("FlexiDrag", s.LightRadius);
+ cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
+ cdl.AddRow("PathBegin", s.PathBegin);
+ cdl.AddRow("PathEnd", s.PathEnd);
+ cdl.AddRow("PathCurve", s.PathCurve);
+ cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
+ cdl.AddRow("PathRevolutions", s.PathRevolutions);
+ cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
+ cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
+ cdl.AddRow("FlexiDrag", s.PathSkew);
+ cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
+ cdl.AddRow("PathTwist", s.PathTwist);
+ cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
+ cdl.AddRow("PCode", s.PCode);
+ cdl.AddRow("ProfileBegin", s.ProfileBegin);
+ cdl.AddRow("ProfileEnd", s.ProfileEnd);
+ cdl.AddRow("ProfileHollow", s.ProfileHollow);
+ cdl.AddRow("ProfileShape", s.ProfileShape);
+ cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
+ cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
+ cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
+ cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
+ cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
+ cdl.AddRow("Scale", s.Scale);
+ cdl.AddRow(
+ "SculptData",
+ string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
+ cdl.AddRow("SculptEntry", s.SculptEntry);
+ cdl.AddRow("SculptTexture", s.SculptTexture);
+ cdl.AddRow("SculptType", s.SculptType);
+ cdl.AddRow("State", s.State);
+
+ // TODO, unpack and display texture entries
+ //cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
+ }
+
object itemsOutput;
if (showFull)
{
@@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
itemsOutput = sop.Inventory.Count;
}
-
cdl.AddRow("Items", itemsOutput);
return sb.Append(cdl.ToString());
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1cfc..1dfc4204dd 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
}
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{
- float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
+ float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
if (Position.Z < waterHeight)
{
_position.Z = waterHeight;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039705..3a73fba7b8 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private Quaternion m_referenceFrame = Quaternion.Identity;
// Linear properties
+ private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
- private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
private Vector3 m_linearFrictionTimescale = Vector3.Zero;
private float m_linearMotorDecayTimescale = 0;
private float m_linearMotorTimescale = 0;
@@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// private Vector3 m_linearMotorOffset = Vector3.Zero;
//Angular properties
+ private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
// private int m_angularMotorApply = 0; // application frame counter
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
@@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
//Attractor properties
+ private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
private float m_verticalAttractionEfficiency = 1.0f; // damped
private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
@@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
break;
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
- m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
+ m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
+ m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
break;
case Vehicle.ANGULAR_MOTOR_TIMESCALE:
m_angularMotorTimescale = Math.Max(pValue, 0.01f);
+ m_angularMotor.TimeScale = m_angularMotorTimescale;
break;
case Vehicle.BANKING_EFFICIENCY:
m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
@@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
break;
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
- m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
+ m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
+ m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
break;
case Vehicle.LINEAR_MOTOR_TIMESCALE:
m_linearMotorTimescale = Math.Max(pValue, 0.01f);
+ m_linearMotor.TimeScale = m_linearMotorTimescale;
break;
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
+ m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
break;
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
+ m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
break;
// These are vector properties but the engine lets you use a single float value to
// set all of the components to the same value
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
+ m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
- // m_angularMotorApply = 100;
+ m_angularMotor.SetTarget(m_angularMotorDirection);
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
+ m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
+ m_linearMotor.SetTarget(m_linearMotorDirection);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
// Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
- // m_angularMotorApply = 100;
+ m_angularMotor.SetTarget(m_angularMotorDirection);
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
+ m_linearMotor.SetTarget(m_linearMotorDirection);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_VhoverEfficiency = 0;
m_VhoverTimescale = 0;
m_VehicleBuoyancy = 0;
-
+
m_linearDeflectionEfficiency = 1;
m_linearDeflectionTimescale = 1;
@@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_referenceFrame = Quaternion.Identity;
m_flags = (VehicleFlag)0;
+
break;
case Vehicle.TYPE_SLED:
@@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_bankingMix = 1;
m_referenceFrame = Quaternion.Identity;
- m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
- m_flags &=
- ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
- VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
+ m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
+ | VehicleFlag.HOVER_TERRAIN_ONLY
+ | VehicleFlag.HOVER_GLOBAL_HEIGHT
+ | VehicleFlag.HOVER_UP_ONLY);
+ m_flags |= (VehicleFlag.NO_DEFLECTION_UP
+ | VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.LIMIT_MOTOR_UP);
break;
case Vehicle.TYPE_CAR:
m_linearMotorDirection = Vector3.Zero;
@@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
| VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.LIMIT_ROLL_ONLY
+ | VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
- | VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_WATER_ONLY);
break;
case Vehicle.TYPE_AIRPLANE:
@@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
| VehicleFlag.HOVER_GLOBAL_HEIGHT);
break;
}
+
+ // Update any physical parameters based on this type.
+ Refresh();
+
+ m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
+ m_linearMotorDecayTimescale, m_linearFrictionTimescale,
+ 1f);
+ m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+
+ m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
+ m_angularMotorDecayTimescale, m_angularFrictionTimescale,
+ 1f);
+ m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+
+ m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
+ BSMotor.Infinite, BSMotor.InfiniteVector,
+ m_verticalAttractionEfficiency);
+ // Z goes away and we keep X and Y
+ m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
+ m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
+
+ // m_bankingMotor = new BSVMotor("BankingMotor", ...);
}
// Some of the properties of this prim may have changed.
@@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
if (IsActive)
{
+ m_vehicleMass = Prim.Linkset.LinksetMass;
+
// Friction effects are handled by this vehicle code
- BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
- BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
+ float friction = 0f;
+ BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
- // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
+ // 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;
+ BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
- VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
+ // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
+ // Vector3 localInertia = new Vector3(1f, 1f, 1f);
+ Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
+ BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
+
+ VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
+ Prim.LocalID, friction, localInertia, angularDamping);
}
}
@@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
if (!IsActive) return;
- // DEBUG
- // Because Bullet does apply forces to the vehicle, our last computed
- // linear and angular velocities are not what is happening now.
- // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
- // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
- // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
- // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
- // END DEBUG
-
- m_vehicleMass = Prim.Linkset.LinksetMass;
-
MoveLinear(pTimestep);
- // Commented out for debug
MoveAngular(pTimestep);
- // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
- // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
LimitRotation(pTimestep);
// remember the position so next step we can limit absolute movement effects
m_lastPositionVector = Prim.ForcePosition;
- VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
- Prim.LocalID,
- BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
- BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
- Prim.Inertia,
- m_vehicleMass
- );
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
- }// end Step
+ }
// Apply the effect of the linear motor.
// Also does hover and float.
private void MoveLinear(float pTimestep)
{
- // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
- // m_lastLinearVelocityVector is the current speed we are moving in that direction
- if (m_linearMotorDirection.LengthSquared() > 0.001f)
- {
- Vector3 origDir = m_linearMotorDirection; // DEBUG
- Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
- // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
- Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
+ Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
- // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
- Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
- m_lastLinearVelocityVector += addAmount;
-
- float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
- m_linearMotorDirection *= (1f - decayFactor);
-
- // Rotate new object velocity from vehicle relative to world coordinates
- m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
-
- // Apply friction for next time
- Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
- m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
-
- VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
- Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
- m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
- }
- else
- {
- // if what remains of direction is very small, zero it.
- m_linearMotorDirection = Vector3.Zero;
- m_lastLinearVelocityVector = Vector3.Zero;
- m_newVelocity = Vector3.Zero;
-
- VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
- }
-
- // m_newVelocity is velocity computed from linear motor in world coordinates
+ // Rotate new object velocity from vehicle relative to world coordinates
+ linearMotorContribution *= Prim.ForceOrientation;
+ // ==================================================================
// Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
- /*
- * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
- // Preserve the current Z velocity
- Vector3 vel_now = m_prim.Velocity;
- m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
- */
-
Vector3 pos = Prim.ForcePosition;
-// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
-
- // If below the terrain, move us above the ground a little.
float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
+
+ Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
+
+ Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
+
+ ComputeLinearBlockingEndPoint(pTimestep, ref pos);
+
+ Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
+
+ // ==================================================================
+ Vector3 newVelocity = linearMotorContribution
+ + terrainHeightContribution
+ + hoverContribution
+ + limitMotorUpContribution;
+
+ // If not changing some axis, reduce out velocity
+ if ((m_flags & (VehicleFlag.NO_X)) != 0)
+ newVelocity.X = 0;
+ if ((m_flags & (VehicleFlag.NO_Y)) != 0)
+ newVelocity.Y = 0;
+ if ((m_flags & (VehicleFlag.NO_Z)) != 0)
+ newVelocity.Z = 0;
+
+ // ==================================================================
+ // Clamp REALLY high or low velocities
+ float newVelocityLengthSq = newVelocity.LengthSquared();
+ if (newVelocityLengthSq > 1e6f)
+ {
+ newVelocity /= newVelocity.Length();
+ newVelocity *= 1000f;
+ }
+ else if (newVelocityLengthSq < 1e-6f)
+ newVelocity = Vector3.Zero;
+
+ // ==================================================================
+ // Stuff new linear velocity into the vehicle
+ Prim.ForceVelocity = newVelocity;
+ // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
+
+ // Other linear forces are applied as forces.
+ Vector3 totalDownForce = grav * m_vehicleMass;
+ if (totalDownForce != Vector3.Zero)
+ {
+ Prim.AddForce(totalDownForce, false);
+ }
+
+ VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
+ Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
+ newVelocity, Prim.Velocity, totalDownForce);
+
+ } // end MoveLinear()
+
+ public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
+ {
+ Vector3 ret = Vector3.Zero;
+ // If below the terrain, move us above the ground a little.
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
// TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
// if (rotatedSize.Z < terrainHeight)
if (pos.Z < terrainHeight)
{
+ // TODO: correct position by applying force rather than forcing position.
pos.Z = terrainHeight + 2;
Prim.ForcePosition = pos;
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
}
+ return ret;
+ }
+
+ public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
+ {
+ Vector3 ret = Vector3.Zero;
- // Check if hovering
// m_VhoverEfficiency: 0=bouncy, 1=totally damped
// m_VhoverTimescale: time to achieve height
if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,7 +713,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{
- m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
+ m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
}
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
@@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (pos.Z > m_VhoverTargetHeight)
m_VhoverTargetHeight = pos.Z;
}
+
if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
{
if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
@@ -694,28 +745,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// RA: where does the 50 come from?
float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
// Replace Vertical speed with correction figure if significant
- if (Math.Abs(verticalError) > 0.01f)
+ if (verticalError > 0.01f)
{
- m_newVelocity.Z += verticalCorrectionVelocity;
+ ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
//KF: m_VhoverEfficiency is not yet implemented
}
else if (verticalError < -0.01)
{
- m_newVelocity.Z -= verticalCorrectionVelocity;
- }
- else
- {
- m_newVelocity.Z = 0f;
+ ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
}
}
- VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
+ VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
+ Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
}
+ return ret;
+ }
+
+ public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
+ {
+ bool changed = false;
+
Vector3 posChange = pos - m_lastPositionVector;
if (m_BlockingEndPoint != Vector3.Zero)
{
- bool changed = false;
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
{
pos.X -= posChange.X + 1;
@@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Prim.LocalID, m_BlockingEndPoint, posChange, pos);
}
}
+ return changed;
+ }
- #region downForce
- Vector3 downForce = Vector3.Zero;
-
+ // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
+ // Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when
+ // used with conjunction with banking: the strength of the banking will decay when the
+ // vehicle no longer experiences collisions. The decay timescale is the same as
+ // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
+ // when they are in mid jump.
+ // TODO: this code is wrong. Also, what should it do for boats?
+ public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
+ {
+ Vector3 ret = Vector3.Zero;
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
{
// If the vehicle is motoring into the sky, get it going back down.
- // Is this an angular force or both linear and angular??
float distanceAboveGround = pos.Z - terrainHeight;
- if (distanceAboveGround > 2f)
+ if (distanceAboveGround > 1f)
{
// downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
- downForce = new Vector3(0, 0, -distanceAboveGround);
+ ret = new Vector3(0, 0, -distanceAboveGround);
}
- // TODO: this calculation is all wrong. From the description at
+ // TODO: this calculation is wrong. From the description at
// (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
// has a decay factor. This says this force should
// be computed with a motor.
- VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
- Prim.LocalID, distanceAboveGround, downForce);
+ // TODO: add interaction with banking.
+ VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
+ Prim.LocalID, distanceAboveGround, ret);
}
- #endregion // downForce
-
- // If not changing some axis, reduce out velocity
- if ((m_flags & (VehicleFlag.NO_X)) != 0)
- m_newVelocity.X = 0;
- if ((m_flags & (VehicleFlag.NO_Y)) != 0)
- m_newVelocity.Y = 0;
- if ((m_flags & (VehicleFlag.NO_Z)) != 0)
- m_newVelocity.Z = 0;
-
- // Clamp REALLY high or low velocities
- if (m_newVelocity.LengthSquared() > 1e6f)
- {
- m_newVelocity /= m_newVelocity.Length();
- m_newVelocity *= 1000f;
- }
- else if (m_newVelocity.LengthSquared() < 1e-6f)
- m_newVelocity = Vector3.Zero;
-
- // Stuff new linear velocity into the vehicle
- Prim.ForceVelocity = m_newVelocity;
- // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
-
- Vector3 totalDownForce = downForce + grav;
- if (totalDownForce != Vector3.Zero)
- {
- Prim.AddForce(totalDownForce * m_vehicleMass, false);
- // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
- }
-
- VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
- Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
-
- } // end MoveLinear()
+ return ret;
+ }
+ // =======================================================================
// =======================================================================
// Apply the effect of the angular motor.
private void MoveAngular(float pTimestep)
{
// m_angularMotorDirection // angular velocity requested by LSL motor
- // m_angularMotorApply // application frame counter
// m_angularMotorVelocity // current angular motor velocity (ramps up and down)
- // m_angularMotorTimescale // motor angular velocity ramp up rate
+ // m_angularMotorTimescale // motor angular velocity ramp up time
// m_angularMotorDecayTimescale // motor angular velocity decay rate
// m_angularFrictionTimescale // body angular velocity decay rate
// m_lastAngularVelocity // what was last applied to body
+ /*
if (m_angularMotorDirection.LengthSquared() > 0.0001)
{
Vector3 origVel = m_angularMotorVelocity;
@@ -835,141 +867,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
m_angularMotorVelocity = Vector3.Zero;
}
+ */
- #region Vertical attactor
+ Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
- Vector3 vertattr = Vector3.Zero;
- Vector3 deflection = Vector3.Zero;
- Vector3 banking = Vector3.Zero;
-
- // If vertical attaction timescale is reasonable and we applied an angular force last time...
- if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
+ // ==================================================================
+ // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
+ // This flag prevents linear deflection parallel to world z-axis. This is useful
+ // for preventing ground vehicles with large linear deflection, like bumper cars,
+ // from climbing their linear deflection into the sky.
+ // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
+ if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
- float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
- if (Prim.IsColliding)
- VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
-
- VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
-
- // Create a vector of the vehicle "up" in world coordinates
- Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
- // verticalError.X and .Y are the World error amounts. They are 0 when there is no
- // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
- // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
- // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
- // modulated to prevent a stable inverted body.
-
- // Error is 0 (no error) to +/- 2 (max error)
- if (verticalError.Z < 0.0f)
- {
- verticalError.X = 2.0f - verticalError.X;
- verticalError.Y = 2.0f - verticalError.Y;
- }
- // scale it by VAservo (timestep and timescale)
- verticalError = verticalError * VAservo;
-
- // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
- // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
- // Z is not changed.
- vertattr.X = verticalError.Y;
- vertattr.Y = - verticalError.X;
- vertattr.Z = 0f;
-
- // scaling appears better usingsquare-law
- Vector3 angularVelocity = Prim.ForceRotationalVelocity;
- float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
- vertattr.X += bounce * angularVelocity.X;
- vertattr.Y += bounce * angularVelocity.Y;
-
- VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
- Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
-
- }
- #endregion // Vertical attactor
-
- #region Deflection
-
- if (m_angularDeflectionEfficiency != 0)
- {
- // Compute a scaled vector that points in the preferred axis (X direction)
- Vector3 scaledDefaultDirection =
- new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
- // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
- // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
- Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
-
- // Scale by efficiency and timescale
- deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
-
- VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
- Prim.LocalID, preferredAxisOfMotion, deflection);
- // This deflection computation is not correct.
- deflection = Vector3.Zero;
+ angularMotorContribution.X = 0f;
+ angularMotorContribution.Y = 0f;
+ VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
}
- #endregion
+ Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
- #region Banking
+ Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
- if (m_bankingEfficiency != 0)
- {
- Vector3 dir = Vector3.One * Prim.ForceOrientation;
- float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
- //Changes which way it banks in and out of turns
+ Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
- //Use the square of the efficiency, as it looks much more how SL banking works
- float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
- if (m_bankingEfficiency < 0)
- effSquared *= -1; //Keep the negative!
-
- float mix = Math.Abs(m_bankingMix);
- if (m_angularMotorVelocity.X == 0)
- {
- /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
- {
- Vector3 axisAngle;
- float angle;
- parent.Orientation.GetAxisAngle(out axisAngle, out angle);
- Vector3 rotatedVel = parent.Velocity * parent.Orientation;
- if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
- m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
- else
- m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
- }*/
- }
- else
- banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
- if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
- //If they are colliding, we probably shouldn't shove the prim around... probably
- {
- float angVelZ = m_angularMotorVelocity.X*-1;
- /*if(angVelZ > mix)
- angVelZ = mix;
- else if(angVelZ < -mix)
- angVelZ = -mix;*/
- //This controls how fast and how far the banking occurs
- Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
- if (bankingRot.X > 3)
- bankingRot.X = 3;
- else if (bankingRot.X < -3)
- bankingRot.X = -3;
- bankingRot *= Prim.ForceOrientation;
- banking += bankingRot;
- }
- m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
- VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
- Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
- }
-
- #endregion
-
- m_lastVertAttractor = vertattr;
+ // ==================================================================
+ m_lastVertAttractor = verticalAttractionContribution;
// Sum velocities
- m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
-
- #region Linear Motor Offset
+ m_lastAngularVelocity = angularMotorContribution
+ + verticalAttractionContribution
+ + deflectionContribution
+ + bankingContribution;
+ // ==================================================================
//Offset section
if (m_linearMotorOffset != Vector3.Zero)
{
@@ -985,8 +915,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
//
// The torque created is the linear velocity crossed with the offset
- // NOTE: this computation does should be in the linear section
- // because there we know the impulse being applied.
+ // TODO: this computation should be in the linear section
+ // because that is where we know the impulse being applied.
Vector3 torqueFromOffset = Vector3.Zero;
// torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
if (float.IsNaN(torqueFromOffset.X))
@@ -1000,20 +930,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
}
- #endregion
-
- if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
- {
- m_lastAngularVelocity.X = 0;
- m_lastAngularVelocity.Y = 0;
- VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
- }
-
+ // ==================================================================
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
- Prim.ZeroAngularMotion(true);
+ // TODO: zeroing is good but it also sets values in unmanaged code. Remove the stores when idle.
VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
+ Prim.ZeroAngularMotion(true);
}
else
{
@@ -1021,18 +944,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// The above calculates the absolute angular velocity needed. Angular velocity is massless.
// Since we are stuffing the angular velocity directly into the object, the computed
// velocity needs to be scaled by the timestep.
- Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
+ // Also remove any motion that is on the object so added motion is only from vehicle.
+ Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
+ - Prim.ForceRotationalVelocity);
+ // Unscale the force by the angular factor so it overwhelmes the Bullet additions.
Prim.ForceRotationalVelocity = applyAngularForce;
- // Decay the angular movement for next time
- Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
- m_lastAngularVelocity *= Vector3.One - decayamount;
-
- VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
- Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
+ VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
+ Prim.LocalID,
+ angularMotorContribution, verticalAttractionContribution,
+ bankingContribution, deflectionContribution,
+ applyAngularForce, m_lastAngularVelocity
+ );
}
- } //end MoveAngular
+ }
+ public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
+ {
+ Vector3 ret = Vector3.Zero;
+
+ // If vertical attaction timescale is reasonable and we applied an angular force last time...
+ if (m_verticalAttractionTimescale < 500)
+ {
+ Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
+ verticalError.Normalize();
+ m_verticalAttractionMotor.SetCurrent(verticalError);
+ m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
+ ret = m_verticalAttractionMotor.Step(pTimestep);
+ /*
+ // Take a vector pointing up and convert it from world to vehicle relative coords.
+ Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
+ verticalError.Normalize();
+
+ // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
+ // is now leaning to one side (rotated around the X axis) and the Y value will
+ // go from zero (nearly straight up) to one (completely to the side) or leaning
+ // front-to-back (rotated around the Y axis) and the value of X will be between
+ // zero and one.
+ // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
+
+ // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
+ if (verticalError.Z < 0f)
+ {
+ verticalError.X = 2f - verticalError.X;
+ verticalError.Y = 2f - verticalError.Y;
+ }
+
+ // Y error means needed rotation around X axis and visa versa.
+ verticalAttractionContribution.X = verticalError.Y;
+ verticalAttractionContribution.Y = - verticalError.X;
+ verticalAttractionContribution.Z = 0f;
+
+ // scale by the time scale and timestep
+ Vector3 unscaledContrib = verticalAttractionContribution;
+ verticalAttractionContribution /= m_verticalAttractionTimescale;
+ verticalAttractionContribution *= pTimestep;
+
+ // apply efficiency
+ Vector3 preEfficiencyContrib = verticalAttractionContribution;
+ float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
+ verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
+
+ VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
+ Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
+ m_verticalAttractionEfficiency, efficencySquared,
+ verticalAttractionContribution);
+ */
+
+ }
+ return ret;
+ }
+
+ public Vector3 ComputeAngularDeflection(float pTimestep)
+ {
+ Vector3 ret = Vector3.Zero;
+
+ if (m_angularDeflectionEfficiency != 0)
+ {
+ // Compute a scaled vector that points in the preferred axis (X direction)
+ Vector3 scaledDefaultDirection =
+ new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
+ // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
+ // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
+ Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
+
+ // Scale by efficiency and timescale
+ ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
+
+ VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
+
+ // This deflection computation is not correct.
+ ret = Vector3.Zero;
+ }
+ return ret;
+ }
+
+ public Vector3 ComputeAngularBanking(float pTimestep)
+ {
+ Vector3 ret = Vector3.Zero;
+
+ if (m_bankingEfficiency != 0)
+ {
+ Vector3 dir = Vector3.One * Prim.ForceOrientation;
+ float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
+ //Changes which way it banks in and out of turns
+
+ //Use the square of the efficiency, as it looks much more how SL banking works
+ float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
+ if (m_bankingEfficiency < 0)
+ effSquared *= -1; //Keep the negative!
+
+ float mix = Math.Abs(m_bankingMix);
+ if (m_angularMotorVelocity.X == 0)
+ {
+ // The vehicle is stopped
+ /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
+ {
+ Vector3 axisAngle;
+ float angle;
+ parent.Orientation.GetAxisAngle(out axisAngle, out angle);
+ Vector3 rotatedVel = parent.Velocity * parent.Orientation;
+ if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
+ m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
+ else
+ m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
+ }*/
+ }
+ else
+ {
+ ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
+ }
+
+ //If they are colliding, we probably shouldn't shove the prim around... probably
+ if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
+ {
+ float angVelZ = m_angularMotorVelocity.X * -1;
+ /*if(angVelZ > mix)
+ angVelZ = mix;
+ else if(angVelZ < -mix)
+ angVelZ = -mix;*/
+ //This controls how fast and how far the banking occurs
+ Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
+ if (bankingRot.X > 3)
+ bankingRot.X = 3;
+ else if (bankingRot.X < -3)
+ bankingRot.X = -3;
+ bankingRot *= Prim.ForceOrientation;
+ ret += bankingRot;
+ }
+ m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
+ VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
+ Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
+ }
+ return ret;
+ }
+
+
+ // This is from previous instantiations of XXXDynamics.cs.
+ // Applies roll reference frame.
+ // TODO: is this the right way to separate the code to do this operation?
+ // Should this be in MoveAngular()?
internal void LimitRotation(float timestep)
{
Quaternion rotq = Prim.ForceOrientation;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000000..663b6f44b7
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,191 @@
+/*
+ * 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 System.Reflection;
+using Nini.Config;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+
+public struct MaterialAttributes
+{
+ // Material type values that correspond with definitions for LSL
+ public enum Material : int
+ {
+ Stone = 0,
+ Metal,
+ Glass,
+ Wood,
+ Flesh,
+ Plastic,
+ Rubber,
+ Light,
+ // Hereafter are BulletSim additions
+ Avatar,
+ NumberOfTypes // the count of types in the enum.
+ }
+ // Names must be in the order of the above enum.
+ public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
+ "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
+ public static string[] MaterialAttribs = { "Density", "Friction", "Restitution",
+ "ccdMotionThreshold", "ccdSweptSphereRadius" };
+
+ public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS)
+ {
+ type = t;
+ density = d;
+ friction = f;
+ restitution = r;
+ ccdMotionThreshold = ccdM;
+ ccdSweptSphereRadius = ccdS;
+ }
+ public string type;
+ public float density;
+ public float friction;
+ public float restitution;
+ public float ccdMotionThreshold;
+ public float ccdSweptSphereRadius;
+}
+
+public static class BSMaterials
+{
+ public static MaterialAttributes[] Attributes;
+
+ static BSMaterials()
+ {
+ // Attribute sets for both the non-physical and physical instances of materials.
+ Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
+ }
+
+ // This is where all the default material attributes are defined.
+ public static void InitializeFromDefaults(ConfigurationParameters parms)
+ {
+ // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood",
+ // "Flesh", "Plastic", "Rubber", "Light", "Avatar" };
+ float dFriction = parms.defaultFriction;
+ float dRestitution = parms.defaultRestitution;
+ float dDensity = parms.defaultDensity;
+ float dCcdM = parms.ccdMotionThreshold;
+ float dCcdS = parms.ccdSweptSphereRadius;
+ Attributes[(int)MaterialAttributes.Material.Stone] =
+ new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Metal] =
+ new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Glass] =
+ new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Wood] =
+ new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Flesh] =
+ new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Plastic] =
+ new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Rubber] =
+ new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Light] =
+ new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Avatar] =
+ new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+
+ Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
+ new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS);
+ }
+
+ // Under the [BulletSim] section, one can change the individual material
+ // attribute values. The format of the configuration parameter is:
+ // ["Physical"] = floatValue
+ // For instance:
+ // [BulletSim]
+ // StoneFriction = 0.2
+ // FleshRestitutionPhysical = 0.8
+ // Materials can have different parameters for their static and
+ // physical instantiations. When setting the non-physical value,
+ // both values are changed. Setting the physical value only changes
+ // the physical value.
+ public static void InitializefromParameters(IConfig pConfig)
+ {
+ int matType = 0;
+ foreach (string matName in MaterialAttributes.MaterialNames)
+ {
+ foreach (string attribName in MaterialAttributes.MaterialAttribs)
+ {
+ string paramName = matName + attribName;
+ if (pConfig.Contains(paramName))
+ {
+ float paramValue = pConfig.GetFloat(paramName);
+ SetAttributeValue(matType, attribName, paramValue);
+ // set the physical value also
+ SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
+ }
+ paramName += "Physical";
+ if (pConfig.Contains(paramName))
+ {
+ float paramValue = pConfig.GetFloat(paramName);
+ SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
+ }
+ }
+ matType++;
+ }
+ }
+
+ private static void SetAttributeValue(int matType, string attribName, float val)
+ {
+ MaterialAttributes thisAttrib = Attributes[matType];
+ FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName);
+ if (fieldInfo != null)
+ {
+ fieldInfo.SetValue(thisAttrib, val);
+ Attributes[matType] = thisAttrib;
+ }
+ }
+
+ public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
+ {
+ int ind = (int)type;
+ if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
+ return Attributes[ind];
+ }
+
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c452b..e91bfa8496 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,169 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using OpenMetaverse;
-
-namespace OpenSim.Region.Physics.BulletSPlugin
-{
-public abstract class BSMotor
-{
- public virtual void Reset() { }
- public virtual void Zero() { }
-}
-// Can all the incremental stepping be replaced with motor classes?
-public class BSVMotor : BSMotor
-{
- public Vector3 FrameOfReference { get; set; }
- public Vector3 Offset { get; set; }
-
- public float TimeScale { get; set; }
- public float TargetValueDecayTimeScale { get; set; }
- public Vector3 CurrentValueReductionTimescale { get; set; }
- public float Efficiency { get; set; }
-
- public Vector3 TargetValue { get; private set; }
- public Vector3 CurrentValue { get; private set; }
-
-
-
- BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
- {
- TimeScale = timeScale;
- TargetValueDecayTimeScale = decayTimeScale;
- CurrentValueReductionTimescale = frictionTimeScale;
- Efficiency = efficiency;
- }
- public void SetCurrent(Vector3 current)
- {
- CurrentValue = current;
- }
- public void SetTarget(Vector3 target)
- {
- TargetValue = target;
- }
- public Vector3 Step(float timeStep)
- {
- if (CurrentValue.LengthSquared() > 0.001f)
- {
- // Vector3 origDir = Target; // DEBUG
- // Vector3 origVel = CurrentValue; // DEBUG
-
- // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
- Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
- CurrentValue += addAmount;
-
- float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
- TargetValue *= (1f - decayFactor);
-
- Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
- CurrentValue *= (Vector3.One - frictionFactor);
- }
- else
- {
- // if what remains of direction is very small, zero it.
- TargetValue = Vector3.Zero;
- CurrentValue = Vector3.Zero;
-
- // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
- }
- return CurrentValue;
- }
-}
-
-public class BSFMotor : BSMotor
-{
- public float TimeScale { get; set; }
- public float DecayTimeScale { get; set; }
- public float Friction { get; set; }
- public float Efficiency { get; set; }
-
- public float Target { get; private set; }
- public float CurrentValue { get; private set; }
-
- BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
- {
- }
- public void SetCurrent(float target)
- {
- }
- public void SetTarget(float target)
- {
- }
- public float Step(float timeStep)
- {
- return 0f;
- }
-}
-public class BSPIDMotor : BSMotor
-{
- // TODO: write and use this one
- BSPIDMotor()
- {
- }
-}
-}
+using System;
+using System.Collections.Generic;
+using System.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Physics.BulletSPlugin
+{
+public abstract class BSMotor
+{
+ // Timescales and other things can be turned off by setting them to 'infinite'.
+ public const float Infinite = 10000f;
+ public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
+
+ public BSMotor(string useName)
+ {
+ UseName = useName;
+ PhysicsScene = null;
+ }
+ public virtual void Reset() { }
+ public virtual void Zero() { }
+
+ public string UseName { get; private set; }
+ // Used only for outputting debug information. Might not be set so check for null.
+ public BSScene PhysicsScene { get; set; }
+ protected void MDetailLog(string msg, params Object[] parms)
+ {
+ if (PhysicsScene != null)
+ {
+ if (PhysicsScene.VehicleLoggingEnabled)
+ {
+ PhysicsScene.DetailLog(msg, parms);
+ }
+ }
+ }
+}
+// Can all the incremental stepping be replaced with motor classes?
+public class BSVMotor : BSMotor
+{
+ public Vector3 FrameOfReference { get; set; }
+ public Vector3 Offset { get; set; }
+
+ public float TimeScale { get; set; }
+ public float TargetValueDecayTimeScale { get; set; }
+ public Vector3 FrictionTimescale { get; set; }
+ public float Efficiency { get; set; }
+
+ public Vector3 TargetValue { get; private set; }
+ public Vector3 CurrentValue { get; private set; }
+
+ public BSVMotor(string useName)
+ : base(useName)
+ {
+ TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
+ Efficiency = 1f;
+ FrictionTimescale = BSMotor.InfiniteVector;
+ CurrentValue = TargetValue = Vector3.Zero;
+ }
+ public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
+ : this(useName)
+ {
+ TimeScale = timeScale;
+ TargetValueDecayTimeScale = decayTimeScale;
+ FrictionTimescale = frictionTimeScale;
+ Efficiency = efficiency;
+ CurrentValue = TargetValue = Vector3.Zero;
+ }
+ public void SetCurrent(Vector3 current)
+ {
+ CurrentValue = current;
+ }
+ public void SetTarget(Vector3 target)
+ {
+ TargetValue = target;
+ }
+ public Vector3 Step(float timeStep)
+ {
+ Vector3 returnCurrent = Vector3.Zero;
+ if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
+ {
+ Vector3 origTarget = TargetValue; // DEBUG
+ Vector3 origCurrVal = CurrentValue; // DEBUG
+
+ // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
+ Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
+ CurrentValue += addAmount;
+
+ returnCurrent = CurrentValue;
+
+ // The desired value reduces to zero which also reduces the difference with current.
+ // If the decay time is infinite, don't decay at all.
+ float decayFactor = 0f;
+ if (TargetValueDecayTimeScale != BSMotor.Infinite)
+ {
+ decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
+ TargetValue *= (1f - decayFactor);
+ }
+
+ Vector3 frictionFactor = Vector3.Zero;
+ if (FrictionTimescale != BSMotor.InfiniteVector)
+ {
+ // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
+ frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
+ frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
+ frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
+ CurrentValue *= (Vector3.One - frictionFactor);
+ }
+
+ MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
+ BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
+ timeStep, TimeScale, addAmount,
+ TargetValueDecayTimeScale, decayFactor,
+ FrictionTimescale, frictionFactor);
+ MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
+ BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
+ addAmount, decayFactor, frictionFactor, returnCurrent);
+ }
+ else
+ {
+ // Difference between what we have and target is small. Motor is done.
+ CurrentValue = Vector3.Zero;
+ TargetValue = Vector3.Zero;
+
+ MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
+ BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
+
+ }
+ return returnCurrent;
+ }
+ public override string ToString()
+ {
+ return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
+ UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
+ }
+}
+
+public class BSFMotor : BSMotor
+{
+ public float TimeScale { get; set; }
+ public float DecayTimeScale { get; set; }
+ public float Friction { get; set; }
+ public float Efficiency { get; set; }
+
+ public float Target { get; private set; }
+ public float CurrentValue { get; private set; }
+
+ public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
+ : base(useName)
+ {
+ }
+ public void SetCurrent(float target)
+ {
+ }
+ public void SetTarget(float target)
+ {
+ }
+ public float Step(float timeStep)
+ {
+ return 0f;
+ }
+}
+public class BSPIDMotor : BSMotor
+{
+ // TODO: write and use this one
+ public BSPIDMotor(string useName)
+ : base(useName)
+ {
+ }
+}
+}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa2580b..3fb0300cfc 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
// Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
- BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
- BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
+ // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
+ BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
+ BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
});
}
@@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{
- float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
+ float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
// TODO: a floating motor so object will bob in the water
if (Math.Abs(Position.Z - waterHeight) > 0.1f)
{
@@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject
// TODO: check for out of bounds
// The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
+ // TODO: This should be intergrated with a geneal physics action mechanism.
+ // TODO: This should be moderated with PID'ness.
if (ret)
{
- PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
- {
- // Apply upforce and overcome gravity.
- ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
- });
+ // Apply upforce and overcome gravity.
+ AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
}
return ret;
}
@@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
public override 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 (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
- {
- _position = entprop.Position;
- changed |= UpdatedProperties.Position;
- }
- // if (_orientation != entprop.Rotation)
- if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
- {
- _orientation = entprop.Rotation;
- changed |= UpdatedProperties.Rotation;
- }
- // if (_velocity != entprop.Velocity)
- if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
- {
- _velocity = entprop.Velocity;
- changed |= UpdatedProperties.Velocity;
- }
- // if (_acceleration != entprop.Acceleration)
- if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
- {
- _acceleration = entprop.Acceleration;
- changed |= UpdatedProperties.Acceleration;
- }
- // if (_rotationalVelocity != entprop.RotationalVelocity)
- if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
- {
- _rotationalVelocity = entprop.RotationalVelocity;
- changed |= UpdatedProperties.RotationalVel;
- }
- if (changed != 0)
- {
- // Only update the position of single objects and linkset roots
- if (Linkset.IsRoot(this))
- {
- base.RequestPhysicsterseUpdate();
- }
- }
- */
-
- // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
-
// Updates only for individual prims and for the root object of a linkset.
if (Linkset.IsRoot(this))
{
+ // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
+ // TODO: handle physics introduced by Bullet with computed vehicle physics.
+ if (_vehicle.IsActive)
+ {
+ entprop.RotationalVelocity = OMV.Vector3.Zero;
+ }
+
// Assign directly to the local variables so the normal set action does not happen
_position = entprop.Position;
_orientation = entprop.Rotation;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1f2a..0c806118cc 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -39,23 +39,10 @@ using log4net;
using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
-// Test sculpties (verified that they don't work)
-// Compute physics FPS reasonably
// Based on material, set density and friction
-// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
-// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
-// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
-// At the moment, physical and phantom causes object to drop through the terrain
-// Physical phantom objects and related typing (collision options )
-// Check out llVolumeDetect. Must do something for that.
-// Use collision masks for collision with terrain and phantom objects
// More efficient memory usage when passing hull information from BSPrim to BulletSim
-// Should prim.link() and prim.delink() membership checking happen at taint time?
-// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
// 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)
-// 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?
// Raycast
@@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public const uint GROUNDPLANE_ID = 1;
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
- private float m_waterLevel;
+ public float SimpleWaterLevel { get; set; }
public BSTerrainManager TerrainManager { get; private set; }
public ConfigurationParameters Params
@@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes;
+ private bool m_physicsLoggingDoFlush;
// 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; }
@@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (m_physicsLoggingEnabled)
{
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
+ PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
}
else
{
@@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
+ m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
// Very detailed logging for vehicle debugging
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
// Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
}
+
+ // The material characteristics.
+ BSMaterials.InitializeFromDefaults(Params);
+ if (pConfig != null)
+ {
+ BSMaterials.InitializefromParameters(pConfig);
+ }
}
}
@@ -499,7 +496,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
try
{
- if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
+ // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@@ -508,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
- if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
+ // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
}
catch (Exception e)
{
@@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
collidersCount = 0;
}
- // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
+ // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
- // Get a value for 'now' so all the collision and update routines don't have to get their own
+ // Get a value for 'now' so all the collision and update routines don't have to get their own.
SimulationNowTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim.
@@ -568,6 +565,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear();
}
+ // Done with collisions.
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0)
@@ -591,9 +589,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// 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.
- // We multiply by 55 to give a recognizable running rate (55 or less).
- return numSubSteps * m_fixedTimeStep * 1000 * 55;
- // return timeStep * 1000 * 55;
+ // Multiply by 55 to give a nominal frame rate of 55.
+ return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
}
// Something has collided
@@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override void SetWaterLevel(float baseheight)
{
- m_waterLevel = baseheight;
- }
- // Someday....
- public float GetWaterLevelAtXYZ(Vector3 loc)
- {
- return m_waterLevel;
+ SimpleWaterLevel = baseheight;
}
public override void DeleteTerrain()
@@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.PID_P = v; } ),
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
- 0.5f,
+ 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; } ),
@@ -1084,7 +1076,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(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!)",
- 0f,
+ 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; } ),
@@ -1151,7 +1143,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(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.5f,
+ 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 */} ),
@@ -1165,13 +1157,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(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.",
- 10f,
+ 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; } ),
@@ -1206,6 +1204,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(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,
@@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes. Gets all the messages written out.
- // PhysicsLogging.Flush();
+ if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
}
// Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756cba9..0cb151e285 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -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, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
+ m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin);
// Create the terrain shape from the mapInfo
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
@@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
}
// The passed position is relative to the base of the region.
- public override float GetHeightAtXYZ(Vector3 pos)
+ public override float GetTerrainHeightAtXYZ(Vector3 pos)
{
float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
@@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
}
return ret;
}
+
+ // The passed position is relative to the base of the region.
+ public override float GetWaterLevelAtXYZ(Vector3 pos)
+ {
+ return PhysicsScene.SimpleWaterLevel;
+ }
}
}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd33aa..17d9536c42 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
ID = id;
}
public abstract void Dispose();
- public abstract float GetHeightAtXYZ(Vector3 pos);
+ public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
+ public abstract float GetWaterLevelAtXYZ(Vector3 pos);
}
// ==========================================================================================
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager
public const float HEIGHT_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f;
+ public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
// If the min and max height are equal, we reduce the min by this
// amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
- public const float TERRAIN_COLLISION_MARGIN = 0.0f;
-
// Until the whole simulator is changed to pass us the region size, we rely on constants.
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
@@ -129,7 +129,8 @@ public sealed class BSTerrainManager
{
// 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, TERRAIN_COLLISION_MARGIN),
+ BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
+ PhysicsScene.Params.terrainCollisionMargin),
BSPhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@@ -165,17 +166,22 @@ public sealed class BSTerrainManager
// Release all the terrain we have allocated
public void ReleaseTerrain()
{
- foreach (KeyValuePair kvp in m_terrains)
+ lock (m_terrains)
{
- kvp.Value.Dispose();
+ foreach (KeyValuePair kvp in m_terrains)
+ {
+ kvp.Value.Dispose();
+ }
+ m_terrains.Clear();
}
- m_terrains.Clear();
}
// The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) {
float[] localHeightMap = heightMap;
- PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
+ // If there are multiple requests for changes to the same terrain between ticks,
+ // only do that last one.
+ PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
{
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
{
@@ -211,6 +217,7 @@ public sealed class BSTerrainManager
// terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain.
// (The above does suggest that some simplification/refactoring is in order.)
+ // Called during taint-time.
private void UpdateTerrain(uint id, float[] heightMap,
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{
@@ -220,7 +227,7 @@ public sealed class BSTerrainManager
// Find high and low points of passed heightmap.
// The min and max passed in is usually the area objects can be in (maximum
// object height, for instance). The terrain wants the bounding box for the
- // terrain so we replace passed min and max Z with the actual terrain min/max Z.
+ // terrain so replace passed min and max Z with the actual terrain min/max Z.
float minZ = float.MaxValue;
float maxZ = float.MinValue;
foreach (float height in heightMap)
@@ -238,15 +245,15 @@ public sealed class BSTerrainManager
Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
- BSTerrainPhys terrainPhys;
- if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
+ lock (m_terrains)
{
- // There is already a terrain in this spot. Free the old and build the new.
- DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
- BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
-
- PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
+ BSTerrainPhys terrainPhys;
+ if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{
+ // There is already a terrain in this spot. Free the old and build the new.
+ DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
+ BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
+
// Remove old terrain from the collection
m_terrains.Remove(terrainRegionBase);
// Release any physical memory it may be using.
@@ -271,35 +278,24 @@ public sealed class BSTerrainManager
// I hate doing this, but just bail
return;
}
- });
- }
- else
- {
- // We don't know about this terrain so either we are creating a new terrain or
- // our mega-prim child is giving us a new terrain to add to the phys world
-
- // if this is a child terrain, calculate a unique terrain id
- uint newTerrainID = id;
- if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
- newTerrainID = ++m_terrainCount;
-
- float[] heightMapX = heightMap;
- Vector3 minCoordsX = minCoords;
- Vector3 maxCoordsX = maxCoords;
-
- DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
- BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
-
- // Code that must happen at taint-time
- PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
+ }
+ else
{
- DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
- BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
+ // We don't know about this terrain so either we are creating a new terrain or
+ // our mega-prim child is giving us a new terrain to add to the phys world
+
+ // if this is a child terrain, calculate a unique terrain id
+ uint newTerrainID = id;
+ if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
+ newTerrainID = ++m_terrainCount;
+
+ DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
+ BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys);
m_terrainModified = true;
- });
+ }
}
}
@@ -349,6 +345,7 @@ public sealed class BSTerrainManager
// with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight;
+ m_terrainModified = false;
lastHeightTX = tX;
lastHeightTY = tY;
@@ -358,23 +355,50 @@ public sealed class BSTerrainManager
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
- BSTerrainPhys physTerrain;
- if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
+ lock (m_terrains)
{
- ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
- DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
- BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
+ BSTerrainPhys physTerrain;
+ if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
+ {
+ ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
+ }
+ else
+ {
+ PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
+ LogHeader, PhysicsScene.RegionName, tX, tY);
+ }
}
- else
- {
- PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
- LogHeader, PhysicsScene.RegionName, tX, tY);
- }
- m_terrainModified = false;
lastHeight = ret;
return ret;
}
+ public float GetWaterLevelAtXYZ(Vector3 pos)
+ {
+ float ret = WATER_HEIGHT_GETHEIGHT_RET;
+
+ float tX = pos.X;
+ float tY = pos.Y;
+
+ Vector3 terrainBaseXYZ = Vector3.Zero;
+ terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
+ terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
+
+ lock (m_terrains)
+ {
+ BSTerrainPhys physTerrain;
+ if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
+ {
+ ret = physTerrain.GetWaterLevelAtXYZ(pos);
+ }
+ else
+ {
+ PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
+ LogHeader, PhysicsScene.RegionName, tX, tY);
+ }
+ }
+ return ret;
+ }
+
// Although no one seems to check this, I do support combining.
public bool SupportsCombining()
{
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150931..7e93ab4623 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future.
return;
}
+ PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
+ ID, indicesCount, indices.Length, verticesCount, vertices.Length);
m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
- indicesCount, indices, verticesCount, vertices),
+ indicesCount, indices, verticesCount, vertices),
BSPhysicsShapeType.SHAPE_MESH);
if (m_terrainShape.ptr == IntPtr.Zero)
{
@@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Static objects are not very massive.
BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
- // Return the new terrain to the world of physical objects
+ // Put the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
- // redo its bounding box now that it is in the world
+ // Redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
@@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
}
- public override float GetHeightAtXYZ(Vector3 pos)
+ public override float GetTerrainHeightAtXYZ(Vector3 pos)
{
// For the moment use the saved heightmap to get the terrain height.
// TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
return ret;
}
+ // The passed position is relative to the base of the region.
+ public override float GetWaterLevelAtXYZ(Vector3 pos)
+ {
+ return PhysicsScene.SimpleWaterLevel;
+ }
+
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
// Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh(
@@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Simple mesh creation which assumes magnification == 1.
// TODO: do a more general solution that scales, adds new vertices and smoothes the result.
+ // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
+ // from zero to <= sizeX). The triangle indices are then generated as two triangles
+ // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
+ // column of vertices are used to complete the triangles of the last row and column
+ // of the heightmap.
try
{
// One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
float magY = (float)sizeY / extentY;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
+ float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region.
for (int yy = 0; yy <= sizeY; yy++)
{
- for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times
+ for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
{
int offset = yy * sizeX + xx;
- // Extend the height from the height from the last row or column
+ // Extend the height with the height from the last row or column
if (yy == sizeY) offset -= sizeX;
if (xx == sizeX) offset -= 1;
float height = heightMap[offset];
+ minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z;
@@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
}
verticesCount = verticesCount / 3;
- physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
- BSScene.DetailLogZero, verticesCount);
for (int yy = 0; yy < sizeY; yy++)
{
for (int xx = 0; xx < sizeX; xx++)
{
- int offset = yy * sizeX + xx;
+ int offset = yy * (sizeX + 1) + xx;
// Each vertices is presumed to be the upper left corner of a box of two triangles
indices[indicesCount + 0] = offset;
indices[indicesCount + 1] = offset + 1;
@@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
indicesCount += 6;
}
}
- physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
- LogHeader, indicesCount); // DEBUG
+
ret = true;
}
catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
index e60a7604a8..1e003e6e8c 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
@@ -287,6 +287,8 @@ public struct ConfigurationParameters
public float terrainFriction;
public float terrainHitFraction;
public float terrainRestitution;
+ public float terrainCollisionMargin;
+
public float avatarFriction;
public float avatarStandingFriction;
public float avatarDensity;
@@ -296,6 +298,8 @@ public struct ConfigurationParameters
public float avatarCapsuleHeight;
public float avatarContactProcessingThreshold;
+ public float vehicleAngularDamping;
+
public float maxPersistantManifoldPoolSize;
public float maxCollisionAlgorithmPoolSize;
public float shouldDisableContactPoolDynamicAllocation;
@@ -353,7 +357,7 @@ public enum CollisionFlags : uint
CF_CHARACTER_OBJECT = 1 << 4,
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
- // Following used by BulletSim to control collisions
+ // Following used by BulletSim to control collisions and updates
BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
BS_FLOATS_ON_WATER = 1 << 11,
BS_NONE = 0,
@@ -481,6 +485,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool IsNativeShape2(IntPtr shape);
+[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
+public static extern void SetShapeCollisionMargin(IntPtr shape, float margin);
+
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
index f629c4d60b..9262a9e936 100644
--- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
+++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs
@@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0)
{
+ // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
+ // method twice - once before it has loaded sculpt data from the asset service and once afterwards.
+ // The first time will always call with unloaded SculptData if this needs to be uploaded.
// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
return false;
}
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
index a59f63fcdd..d09aa628c3 100644
--- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
+++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs
@@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
_pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(_pbs.SculptData, 0);
// m_assetFailed = false;
+
+// m_log.DebugFormat(
+// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
+// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
+
m_taintshape = true;
_parent_scene.AddPhysicsActorTaint(this);
}
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 3c4110b78c..d83896e1b8 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -217,10 +217,10 @@
; to false if you have compatibility problems.
;CacheSculptMaps = true
- ; Choose one of the physics engines below
- ; OpenDynamicsEngine is by some distance the most developed physics engine
- ; basicphysics effectively does not model physics at all, making all objects phantom
-
+ ; Choose one of the physics engines below.
+ ; OpenDynamicsEngine is by some distance the most developed physics engine.
+ ; BulletSim is a high performance, up-and-coming physics engine.
+ ; basicphysics effectively does not model physics at all, making all objects phantom.
physics = OpenDynamicsEngine
;physics = basicphysics
;physics = POS
@@ -904,15 +904,18 @@
[BulletSim]
; World parameters
- DefaultFriction = 0.50
+ DefaultFriction = 0.20
DefaultDensity = 10.000006836
DefaultRestitution = 0.0
Gravity = -9.80665
- TerrainFriction = 0.50
- TerrainHitFriction = 0.8
+ TerrainFriction = 0.30
+ TerrainHitFraction = 0.8
TerrainRestitution = 0
+ TerrainCollisionMargin = 0.04
+
AvatarFriction = 0.2
+ AvatarStandingFriction = 0.99
AvatarRestitution = 0.0
AvatarDensity = 60.0
AvatarCapsuleWidth = 0.6
@@ -926,27 +929,15 @@
LinearDamping = 0.0
AngularDamping = 0.0
DeactivationTime = 0.2
- LinearSleepingThreshold = 0.8
- AngularSleepingThreshold = 1.0
- CcdMotionThreshold = 0.0
- CcdSweptSphereRadius = 0.0
- ContactProcessingThreshold = 0.1
- ; If setting a pool size, also disable dynamic allocation (default pool size is 4096 with dynamic alloc)
- MaxPersistantManifoldPoolSize = 0
- ShouldDisableContactPoolDynamicAllocation = False
- ShouldForceUpdateAllAabbs = False
- ShouldRandomizeSolverOrder = True
- ShouldSplitSimulationIslands = True
- ShouldEnableFrictionCaching = False
- NumberOfSolverIterations = 0
+ CollisionMargin = 0.04
; Linkset constraint parameters
+ LinkImplementation = 1 ; 0=constraint, 1=compound
LinkConstraintUseFrameOffset = False
LinkConstraintEnableTransMotor = True
LinkConstraintTransMotorMaxVel = 5.0
LinkConstraintTransMotorMaxForce = 0.1
-
; Whether to mesh sculpties
MeshSculptedPrim = true
diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll
index 2ae1c75e3d..3f5011a928 100755
Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ
diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so
index d4852a55bd..46d40feb89 100755
Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ
diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll
index 77cf7e3f28..27a807cd50 100755
Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ
diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so
index 4ec62b2a66..1e82b3d37e 100755
Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ