Merge branch 'master' into careminster
Conflicts: OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs OpenSim/Region/Physics/Meshing/Meshmerizer.csavinationmerge
commit
daa1d99513
|
@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
|
|||
/// <summary>This is a base class for testing any Data service for any DBMS.
|
||||
/// Requires NUnit 2.5 or better (to support the generics).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 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.
|
||||
/// </remarks>
|
||||
/// <typeparam name="TConn"></typeparam>
|
||||
/// <typeparam name="TService"></typeparam>
|
||||
public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase
|
||||
public class BasicDataServiceTest<TConn, TService>
|
||||
where TConn : DbConnection, new()
|
||||
where TService : class, new()
|
||||
{
|
||||
|
|
|
@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
|
|||
}
|
||||
|
||||
if (groupsConfig.GetString("Module", "Default") != "Default")
|
||||
{
|
||||
m_Enabled = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
|||
|
||||
if (mainParams.Count < 4)
|
||||
{
|
||||
m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
|
||||
//m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
|
||||
m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
|
|||
|
||||
if (mainParams.Count < 5)
|
||||
{
|
||||
//m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
|
||||
m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
|
||||
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] <name>");
|
||||
m_console.OutputFormat("Usage: show part name [--regex] <name>");
|
||||
//m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
|
||||
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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
// <materialName><Attribute>["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];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Vector3, BSTerrainPhys> kvp in m_terrains)
|
||||
lock (m_terrains)
|
||||
{
|
||||
kvp.Value.Dispose();
|
||||
foreach (KeyValuePair<Vector3, BSTerrainPhys> 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()
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue