Merge branch 'master' into careminster

Conflicts:
	OpenSim/Region/CoreModules/Avatar/InstantMessage/OfflineMessageModule.cs
	OpenSim/Region/Physics/Meshing/Meshmerizer.cs
avinationmerge
Melanie 2012-11-30 01:19:08 +00:00
commit daa1d99513
21 changed files with 983 additions and 576 deletions

View File

@ -44,9 +44,15 @@ namespace OpenSim.Data.Tests
/// <summary>This is a base class for testing any Data service for any DBMS. /// <summary>This is a base class for testing any Data service for any DBMS.
/// Requires NUnit 2.5 or better (to support the generics). /// Requires NUnit 2.5 or better (to support the generics).
/// </summary> /// </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="TConn"></typeparam>
/// <typeparam name="TService"></typeparam> /// <typeparam name="TService"></typeparam>
public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase public class BasicDataServiceTest<TConn, TService>
where TConn : DbConnection, new() where TConn : DbConnection, new()
where TService : class, new() where TService : class, new()
{ {

View File

@ -81,7 +81,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Groups
} }
if (groupsConfig.GetString("Module", "Default") != "Default") if (groupsConfig.GetString("Module", "Default") != "Default")
{
m_Enabled = false;
return; return;
}
} }
} }

View File

@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{ {
foreach (GridInstantMessage im in msglist) 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 im.offline = 1;
// to look at this message before it gets delivered.
//
// Needed for proper state management for stored group
// invitations
//
im.offline = 1; Scene s = FindScene(client.AgentId);
if (s != null)
Scene s = FindScene(client.AgentId); s.EventManager.TriggerIncomingInstantMessage(im);
if (s != null) }
s.EventManager.TriggerIncomingInstantMessage(im);
} }
} }
} }

View File

@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4) 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; return;
} }
@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 5) 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>"); m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
return; return;
} }
@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4) 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; return;
} }
@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("Link number", sop.LinkNum); cdl.AddRow("Link number", sop.LinkNum);
cdl.AddRow("Flags", sop.Flags); 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; object itemsOutput;
if (showFull) if (showFull)
{ {
@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
itemsOutput = sop.Inventory.Count; itemsOutput = sop.Inventory.Count;
} }
cdl.AddRow("Items", itemsOutput); cdl.AddRow("Items", itemsOutput);
return sb.Append(cdl.ToString()); return sb.Append(cdl.ToString());

View File

@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject
} }
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{ {
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
if (Position.Z < waterHeight) if (Position.Z < waterHeight)
{ {
_position.Z = waterHeight; _position.Z = waterHeight;

View File

@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private Quaternion m_referenceFrame = Quaternion.Identity; private Quaternion m_referenceFrame = Quaternion.Identity;
// Linear properties // 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_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_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_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 Vector3 m_linearFrictionTimescale = Vector3.Zero;
private float m_linearMotorDecayTimescale = 0; private float m_linearMotorDecayTimescale = 0;
private float m_linearMotorTimescale = 0; private float m_linearMotorTimescale = 0;
@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// private Vector3 m_linearMotorOffset = Vector3.Zero; // private Vector3 m_linearMotorOffset = Vector3.Zero;
//Angular properties //Angular properties
private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
// private int m_angularMotorApply = 0; // application frame counter // private int m_angularMotorApply = 0; // application frame counter
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 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. // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
//Attractor properties //Attractor properties
private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
private float m_verticalAttractionEfficiency = 1.0f; // damped private float m_verticalAttractionEfficiency = 1.0f; // damped
private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 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); m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
break; break;
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 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; break;
case Vehicle.ANGULAR_MOTOR_TIMESCALE: case Vehicle.ANGULAR_MOTOR_TIMESCALE:
m_angularMotorTimescale = Math.Max(pValue, 0.01f); m_angularMotorTimescale = Math.Max(pValue, 0.01f);
m_angularMotor.TimeScale = m_angularMotorTimescale;
break; break;
case Vehicle.BANKING_EFFICIENCY: case Vehicle.BANKING_EFFICIENCY:
m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 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); m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
break; break;
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 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; break;
case Vehicle.LINEAR_MOTOR_TIMESCALE: case Vehicle.LINEAR_MOTOR_TIMESCALE:
m_linearMotorTimescale = Math.Max(pValue, 0.01f); m_linearMotorTimescale = Math.Max(pValue, 0.01f);
m_linearMotor.TimeScale = m_linearMotorTimescale;
break; break;
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
break; break;
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
break; break;
// These are vector properties but the engine lets you use a single float value to // These are vector properties but the engine lets you use a single float value to
// set all of the components to the same value // set all of the components to the same value
case Vehicle.ANGULAR_FRICTION_TIMESCALE: case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break; break;
case Vehicle.ANGULAR_MOTOR_DIRECTION: case Vehicle.ANGULAR_MOTOR_DIRECTION:
m_angularMotorDirection = new Vector3(pValue, pValue, pValue); m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
// m_angularMotorApply = 100; m_angularMotor.SetTarget(m_angularMotorDirection);
break; break;
case Vehicle.LINEAR_FRICTION_TIMESCALE: case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break; break;
case Vehicle.LINEAR_MOTOR_DIRECTION: case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue, pValue, pValue); m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
m_linearMotor.SetTarget(m_linearMotorDirection);
break; break;
case Vehicle.LINEAR_MOTOR_OFFSET: case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue, pValue, pValue); m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
case Vehicle.ANGULAR_FRICTION_TIMESCALE: case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break; break;
case Vehicle.ANGULAR_MOTOR_DIRECTION: case Vehicle.ANGULAR_MOTOR_DIRECTION:
// Limit requested angular speed to 2 rps= 4 pi rads/sec // 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.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 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_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
// m_angularMotorApply = 100; m_angularMotor.SetTarget(m_angularMotorDirection);
break; break;
case Vehicle.LINEAR_FRICTION_TIMESCALE: case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break; break;
case Vehicle.LINEAR_MOTOR_DIRECTION: case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotor.SetTarget(m_linearMotorDirection);
break; break;
case Vehicle.LINEAR_MOTOR_OFFSET: case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_VhoverEfficiency = 0; m_VhoverEfficiency = 0;
m_VhoverTimescale = 0; m_VhoverTimescale = 0;
m_VehicleBuoyancy = 0; m_VehicleBuoyancy = 0;
m_linearDeflectionEfficiency = 1; m_linearDeflectionEfficiency = 1;
m_linearDeflectionTimescale = 1; m_linearDeflectionTimescale = 1;
@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_referenceFrame = Quaternion.Identity; m_referenceFrame = Quaternion.Identity;
m_flags = (VehicleFlag)0; m_flags = (VehicleFlag)0;
break; break;
case Vehicle.TYPE_SLED: case Vehicle.TYPE_SLED:
@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_bankingMix = 1; m_bankingMix = 1;
m_referenceFrame = Quaternion.Identity; m_referenceFrame = Quaternion.Identity;
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
m_flags &= | VehicleFlag.HOVER_TERRAIN_ONLY
~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | VehicleFlag.HOVER_GLOBAL_HEIGHT
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP);
break; break;
case Vehicle.TYPE_CAR: case Vehicle.TYPE_CAR:
m_linearMotorDirection = Vector3.Zero; m_linearMotorDirection = Vector3.Zero;
@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
| VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_UP_ONLY); | VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_WATER_ONLY); | VehicleFlag.HOVER_WATER_ONLY);
break; break;
case Vehicle.TYPE_AIRPLANE: case Vehicle.TYPE_AIRPLANE:
@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
| VehicleFlag.HOVER_GLOBAL_HEIGHT); | VehicleFlag.HOVER_GLOBAL_HEIGHT);
break; 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. // Some of the properties of this prim may have changed.
@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
if (IsActive) if (IsActive)
{ {
m_vehicleMass = Prim.Linkset.LinksetMass;
// Friction effects are handled by this vehicle code // Friction effects are handled by this vehicle code
BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); float friction = 0f;
BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 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; 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); MoveLinear(pTimestep);
// Commented out for debug
MoveAngular(pTimestep); MoveAngular(pTimestep);
// Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
// Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
LimitRotation(pTimestep); LimitRotation(pTimestep);
// remember the position so next step we can limit absolute movement effects // remember the position so next step we can limit absolute movement effects
m_lastPositionVector = Prim.ForcePosition; 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}", VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
}// end Step }
// Apply the effect of the linear motor. // Apply the effect of the linear motor.
// Also does hover and float. // Also does hover and float.
private void MoveLinear(float pTimestep) private void MoveLinear(float pTimestep)
{ {
// m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
// 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
// Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete // Rotate new object velocity from vehicle relative to world coordinates
Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; linearMotorContribution *= Prim.ForceOrientation;
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
// ==================================================================
// Gravity and Buoyancy // Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity. // There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 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 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); 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. // 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. // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
// if (rotatedSize.Z < terrainHeight) // if (rotatedSize.Z < terrainHeight)
if (pos.Z < terrainHeight) if (pos.Z < terrainHeight)
{ {
// TODO: correct position by applying force rather than forcing position.
pos.Z = terrainHeight + 2; pos.Z = terrainHeight + 2;
Prim.ForcePosition = pos; Prim.ForcePosition = pos;
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, 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_VhoverEfficiency: 0=bouncy, 1=totally damped
// m_VhoverTimescale: time to achieve height // m_VhoverTimescale: time to achieve height
if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 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 // We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 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) if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{ {
@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (pos.Z > m_VhoverTargetHeight) if (pos.Z > m_VhoverTargetHeight)
m_VhoverTargetHeight = pos.Z; m_VhoverTargetHeight = pos.Z;
} }
if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
{ {
if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 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? // RA: where does the 50 come from?
float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
// Replace Vertical speed with correction figure if significant // 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 //KF: m_VhoverEfficiency is not yet implemented
} }
else if (verticalError < -0.01) else if (verticalError < -0.01)
{ {
m_newVelocity.Z -= verticalCorrectionVelocity; ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
}
else
{
m_newVelocity.Z = 0f;
} }
} }
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; Vector3 posChange = pos - m_lastPositionVector;
if (m_BlockingEndPoint != Vector3.Zero) if (m_BlockingEndPoint != Vector3.Zero)
{ {
bool changed = false;
if (pos.X >= (m_BlockingEndPoint.X - (float)1)) if (pos.X >= (m_BlockingEndPoint.X - (float)1))
{ {
pos.X -= posChange.X + 1; pos.X -= posChange.X + 1;
@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Prim.LocalID, m_BlockingEndPoint, posChange, pos); Prim.LocalID, m_BlockingEndPoint, posChange, pos);
} }
} }
return changed;
}
#region downForce // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
Vector3 downForce = Vector3.Zero; // 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 ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
{ {
// If the vehicle is motoring into the sky, get it going back down. // 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; 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) * pTimestep);
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); // 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 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
// has a decay factor. This says this force should // has a decay factor. This says this force should
// be computed with a motor. // be computed with a motor.
VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", // TODO: add interaction with banking.
Prim.LocalID, distanceAboveGround, downForce); VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
Prim.LocalID, distanceAboveGround, ret);
} }
#endregion // downForce return ret;
}
// 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()
// =======================================================================
// ======================================================================= // =======================================================================
// Apply the effect of the angular motor. // Apply the effect of the angular motor.
private void MoveAngular(float pTimestep) private void MoveAngular(float pTimestep)
{ {
// m_angularMotorDirection // angular velocity requested by LSL motor // m_angularMotorDirection // angular velocity requested by LSL motor
// m_angularMotorApply // application frame counter
// m_angularMotorVelocity // current angular motor velocity (ramps up and down) // 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_angularMotorDecayTimescale // motor angular velocity decay rate
// m_angularFrictionTimescale // body angular velocity decay rate // m_angularFrictionTimescale // body angular velocity decay rate
// m_lastAngularVelocity // what was last applied to body // m_lastAngularVelocity // what was last applied to body
/*
if (m_angularMotorDirection.LengthSquared() > 0.0001) if (m_angularMotorDirection.LengthSquared() > 0.0001)
{ {
Vector3 origVel = m_angularMotorVelocity; Vector3 origVel = m_angularMotorVelocity;
@ -835,141 +867,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
m_angularMotorVelocity = Vector3.Zero; m_angularMotorVelocity = Vector3.Zero;
} }
*/
#region Vertical attactor Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
Vector3 vertattr = Vector3.Zero; // ==================================================================
Vector3 deflection = Vector3.Zero; // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
Vector3 banking = Vector3.Zero; // This flag prevents linear deflection parallel to world z-axis. This is useful
// for preventing ground vehicles with large linear deflection, like bumper cars,
// If vertical attaction timescale is reasonable and we applied an angular force last time... // from climbing their linear deflection into the sky.
if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) // 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; angularMotorContribution.X = 0f;
if (Prim.IsColliding) angularMotorContribution.Y = 0f;
VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
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;
} }
#endregion Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
#region Banking Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
if (m_bankingEfficiency != 0) Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
{
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); m_lastVertAttractor = verticalAttractionContribution;
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;
// Sum velocities // Sum velocities
m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; m_lastAngularVelocity = angularMotorContribution
+ verticalAttractionContribution
#region Linear Motor Offset + deflectionContribution
+ bankingContribution;
// ==================================================================
//Offset section //Offset section
if (m_linearMotorOffset != Vector3.Zero) 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 // The torque created is the linear velocity crossed with the offset
// NOTE: this computation does should be in the linear section // TODO: this computation should be in the linear section
// because there we know the impulse being applied. // because that is where we know the impulse being applied.
Vector3 torqueFromOffset = Vector3.Zero; Vector3 torqueFromOffset = Vector3.Zero;
// torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
if (float.IsNaN(torqueFromOffset.X)) if (float.IsNaN(torqueFromOffset.X))
@ -1000,20 +930,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 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)) if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{ {
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 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); VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
Prim.ZeroAngularMotion(true);
} }
else else
{ {
@ -1021,18 +944,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// The above calculates the absolute angular velocity needed. Angular velocity is massless. // 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 // Since we are stuffing the angular velocity directly into the object, the computed
// velocity needs to be scaled by the timestep. // 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; Prim.ForceRotationalVelocity = applyAngularForce;
// Decay the angular movement for next time VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; Prim.LocalID,
m_lastAngularVelocity *= Vector3.One - decayamount; angularMotorContribution, verticalAttractionContribution,
bankingContribution, deflectionContribution,
VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", applyAngularForce, m_lastAngularVelocity
Prim.LocalID, applyAngularForce, decayamount, 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) internal void LimitRotation(float timestep)
{ {
Quaternion rotq = Prim.ForceOrientation; Quaternion rotq = Prim.ForceOrientation;

View File

@ -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];
}
}
}

View File

@ -1,104 +1,169 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
using OpenMetaverse; using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public abstract class BSMotor public abstract class BSMotor
{ {
public virtual void Reset() { } // Timescales and other things can be turned off by setting them to 'infinite'.
public virtual void Zero() { } public const float Infinite = 10000f;
} public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
// Can all the incremental stepping be replaced with motor classes?
public class BSVMotor : BSMotor public BSMotor(string useName)
{ {
public Vector3 FrameOfReference { get; set; } UseName = useName;
public Vector3 Offset { get; set; } PhysicsScene = null;
}
public float TimeScale { get; set; } public virtual void Reset() { }
public float TargetValueDecayTimeScale { get; set; } public virtual void Zero() { }
public Vector3 CurrentValueReductionTimescale { get; set; }
public float Efficiency { get; set; } public string UseName { get; private set; }
// Used only for outputting debug information. Might not be set so check for null.
public Vector3 TargetValue { get; private set; } public BSScene PhysicsScene { get; set; }
public Vector3 CurrentValue { get; private set; } protected void MDetailLog(string msg, params Object[] parms)
{
if (PhysicsScene != null)
{
BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) if (PhysicsScene.VehicleLoggingEnabled)
{ {
TimeScale = timeScale; PhysicsScene.DetailLog(msg, parms);
TargetValueDecayTimeScale = decayTimeScale; }
CurrentValueReductionTimescale = frictionTimeScale; }
Efficiency = efficiency; }
} }
public void SetCurrent(Vector3 current) // Can all the incremental stepping be replaced with motor classes?
{ public class BSVMotor : BSMotor
CurrentValue = current; {
} public Vector3 FrameOfReference { get; set; }
public void SetTarget(Vector3 target) public Vector3 Offset { get; set; }
{
TargetValue = target; public float TimeScale { get; set; }
} public float TargetValueDecayTimeScale { get; set; }
public Vector3 Step(float timeStep) public Vector3 FrictionTimescale { get; set; }
{ public float Efficiency { get; set; }
if (CurrentValue.LengthSquared() > 0.001f)
{ public Vector3 TargetValue { get; private set; }
// Vector3 origDir = Target; // DEBUG public Vector3 CurrentValue { get; private set; }
// Vector3 origVel = CurrentValue; // DEBUG
public BSVMotor(string useName)
// Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete : base(useName)
Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; {
CurrentValue += addAmount; TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
Efficiency = 1f;
float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; FrictionTimescale = BSMotor.InfiniteVector;
TargetValue *= (1f - decayFactor); CurrentValue = TargetValue = Vector3.Zero;
}
Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
CurrentValue *= (Vector3.One - frictionFactor); : this(useName)
} {
else TimeScale = timeScale;
{ TargetValueDecayTimeScale = decayTimeScale;
// if what remains of direction is very small, zero it. FrictionTimescale = frictionTimeScale;
TargetValue = Vector3.Zero; Efficiency = efficiency;
CurrentValue = Vector3.Zero; CurrentValue = TargetValue = Vector3.Zero;
}
// VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); public void SetCurrent(Vector3 current)
} {
return CurrentValue; CurrentValue = current;
} }
} public void SetTarget(Vector3 target)
{
public class BSFMotor : BSMotor TargetValue = target;
{ }
public float TimeScale { get; set; } public Vector3 Step(float timeStep)
public float DecayTimeScale { get; set; } {
public float Friction { get; set; } Vector3 returnCurrent = Vector3.Zero;
public float Efficiency { get; set; } if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
{
public float Target { get; private set; } Vector3 origTarget = TargetValue; // DEBUG
public float CurrentValue { get; private set; } Vector3 origCurrVal = CurrentValue; // DEBUG
BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
{ Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
} CurrentValue += addAmount;
public void SetCurrent(float target)
{ returnCurrent = CurrentValue;
}
public void SetTarget(float target) // 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;
public float Step(float timeStep) if (TargetValueDecayTimeScale != BSMotor.Infinite)
{ {
return 0f; decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
} TargetValue *= (1f - decayFactor);
} }
public class BSPIDMotor : BSMotor
{ Vector3 frictionFactor = Vector3.Zero;
// TODO: write and use this one if (FrictionTimescale != BSMotor.InfiniteVector)
BSPIDMotor() {
{ // 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)
{
}
}
}

View File

@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
// Zero some other properties in the physics engine // Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{ {
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 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) 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 // TODO: a floating motor so object will bob in the water
if (Math.Abs(Position.Z - waterHeight) > 0.1f) if (Math.Abs(Position.Z - waterHeight) > 0.1f)
{ {
@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject
// TODO: check for out of bounds // TODO: check for out of bounds
// The above code computes a force to apply to correct any out-of-bounds problems. Apply same. // 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) if (ret)
{ {
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() // Apply upforce and overcome gravity.
{ AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
// Apply upforce and overcome gravity.
ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
});
} }
return ret; return ret;
} }
@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
public override void UpdateProperties(EntityProperties entprop) 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. // Updates only for individual prims and for the root object of a linkset.
if (Linkset.IsRoot(this)) 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 // Assign directly to the local variables so the normal set action does not happen
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _orientation = entprop.Rotation;

View File

@ -39,23 +39,10 @@ using log4net;
using OpenMetaverse; using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) // 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 // 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 // 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 // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
// Implement LockAngularMotion // 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? // Add PID movement operations. What does ScenePresence.MoveToTarget do?
// Check terrain size. 128 or 127? // Check terrain size. 128 or 127?
// Raycast // Raycast
@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public const uint GROUNDPLANE_ID = 1; public const uint GROUNDPLANE_ID = 1;
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 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 BSTerrainManager TerrainManager { get; private set; }
public ConfigurationParameters Params public ConfigurationParameters Params
@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir; private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix; private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes; private int m_physicsLoggingFileMinutes;
private bool m_physicsLoggingDoFlush;
// 'true' of the vehicle code is to log lots of details // 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; } public bool VehicleLoggingEnabled { get; private set; }
@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (m_physicsLoggingEnabled) if (m_physicsLoggingEnabled)
{ {
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
} }
else else
{ {
@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
// Very detailed logging for vehicle debugging // Very detailed logging for vehicle debugging
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
// Do any replacements in the parameters // Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 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 try
{ {
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 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); if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG // if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
} }
catch (Exception e) catch (Exception e)
{ {
@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
collidersCount = 0; 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(); SimulationNowTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim. // 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); ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear(); 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 any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0) 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. // 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. // 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). // Multiply by 55 to give a nominal frame rate of 55.
return numSubSteps * m_fixedTimeStep * 1000 * 55; return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
// return timeStep * 1000 * 55;
} }
// Something has collided // Something has collided
@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override void SetWaterLevel(float baseheight) public override void SetWaterLevel(float baseheight)
{ {
m_waterLevel = baseheight; SimpleWaterLevel = baseheight;
}
// Someday....
public float GetWaterLevelAtXYZ(Vector3 loc)
{
return m_waterLevel;
} }
public override void DeleteTerrain() public override void DeleteTerrain()
@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.PID_P = v; } ), (s,p,l,v) => { s.PID_P = v; } ),
new ParameterDefn("DefaultFriction", "Friction factor used on new objects", 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,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultFriction; }, (s) => { return s.m_params[0].defaultFriction; },
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), (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) => { return s.m_params[0].defaultRestitution; },
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", 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,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].collisionMargin; }, (s) => { return s.m_params[0].collisionMargin; },
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), (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) => { return s.m_params[0].terrainImplementation; },
(s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , 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,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainFriction; }, (s) => { return s.m_params[0].terrainFriction; },
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), (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,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainRestitution; }, (s) => { return s.m_params[0].terrainRestitution; },
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), (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.", new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.2f, 0.2f,
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarFriction; }, (s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), (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.", 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,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarStandingFriction; }, (s) => { return s.m_params[0].avatarStandingFriction; },
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), (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) => { return s.m_params[0].avatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), (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)", new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f, 0f,
@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{ {
PhysicsLogging.Write(msg, args); PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes. Gets all the messages written out. // 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. // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000"; public const string DetailLogZero = "0000000000";

View File

@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
{ {
m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
m_mapInfo.minCoords, m_mapInfo.maxCoords, 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 // Create the terrain shape from the mapInfo
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 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. // 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; float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
} }
return ret; return ret;
} }
// The passed position is relative to the base of the region.
public override float GetWaterLevelAtXYZ(Vector3 pos)
{
return PhysicsScene.SimpleWaterLevel;
}
} }
} }

View File

@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
ID = id; ID = id;
} }
public abstract void Dispose(); 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_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f; 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 // 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. // amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f; 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. // 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); 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 // The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape( 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); BSPhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, 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 // Release all the terrain we have allocated
public void ReleaseTerrain() 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. // The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) { public void SetTerrain(float[] heightMap) {
float[] localHeightMap = 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) if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
{ {
@ -211,6 +217,7 @@ public sealed class BSTerrainManager
// terrain shape is created and added to the body. // terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain. // 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.) // (The above does suggest that some simplification/refactoring is in order.)
// Called during taint-time.
private void UpdateTerrain(uint id, float[] heightMap, private void UpdateTerrain(uint id, float[] heightMap,
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{ {
@ -220,7 +227,7 @@ public sealed class BSTerrainManager
// Find high and low points of passed heightmap. // Find high and low points of passed heightmap.
// The min and max passed in is usually the area objects can be in (maximum // 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 // 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 minZ = float.MaxValue;
float maxZ = float.MinValue; float maxZ = float.MinValue;
foreach (float height in heightMap) foreach (float height in heightMap)
@ -238,15 +245,15 @@ public sealed class BSTerrainManager
Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
BSTerrainPhys terrainPhys; lock (m_terrains)
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{ {
// There is already a terrain in this spot. Free the old and build the new. BSTerrainPhys terrainPhys;
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
{ {
// 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 // Remove old terrain from the collection
m_terrains.Remove(terrainRegionBase); m_terrains.Remove(terrainRegionBase);
// Release any physical memory it may be using. // Release any physical memory it may be using.
@ -271,35 +278,24 @@ public sealed class BSTerrainManager
// I hate doing this, but just bail // I hate doing this, but just bail
return; return;
} }
}); }
} else
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()
{ {
DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", // We don't know about this terrain so either we are creating a new terrain or
BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); // 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); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrains.Add(terrainRegionBase, newTerrainPhys);
m_terrainModified = true; m_terrainModified = true;
}); }
} }
} }
@ -349,6 +345,7 @@ public sealed class BSTerrainManager
// with the same parameters as last time. // with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight; return lastHeight;
m_terrainModified = false;
lastHeightTX = tX; lastHeightTX = tX;
lastHeightTY = tY; lastHeightTY = tY;
@ -358,23 +355,50 @@ public sealed class BSTerrainManager
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
BSTerrainPhys physTerrain; lock (m_terrains)
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{ {
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); BSTerrainPhys physTerrain;
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); {
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; lastHeight = ret;
return 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. // Although no one seems to check this, I do support combining.
public bool SupportsCombining() public bool SupportsCombining()
{ {

View File

@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future. // Something is very messed up and a crash is in our future.
return; 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, m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
indicesCount, indices, verticesCount, vertices), indicesCount, indices, verticesCount, vertices),
BSPhysicsShapeType.SHAPE_MESH); BSPhysicsShapeType.SHAPE_MESH);
if (m_terrainShape.ptr == IntPtr.Zero) if (m_terrainShape.ptr == IntPtr.Zero)
{ {
@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Static objects are not very massive. // Static objects are not very massive.
BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 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); 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.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(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. // For the moment use the saved heightmap to get the terrain height.
// TODO: raycast downward to find the true terrain below the position. // TODO: raycast downward to find the true terrain below the position.
@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
return ret; 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(). // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
// Return 'true' if successfully created. // Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh( public static bool ConvertHeightmapToMesh(
@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Simple mesh creation which assumes magnification == 1. // Simple mesh creation which assumes magnification == 1.
// TODO: do a more general solution that scales, adds new vertices and smoothes the result. // 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 try
{ {
// One vertice per heightmap value plus the vertices off the top and bottom edge. // 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; float magY = (float)sizeY / extentY;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 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. // 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 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; 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 (yy == sizeY) offset -= sizeX;
if (xx == sizeX) offset -= 1; if (xx == sizeX) offset -= 1;
float height = heightMap[offset]; float height = heightMap[offset];
minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z; vertices[verticesCount + 2] = height + extentBase.Z;
@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
} }
} }
verticesCount = verticesCount / 3; verticesCount = verticesCount / 3;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
BSScene.DetailLogZero, verticesCount);
for (int yy = 0; yy < sizeY; yy++) for (int yy = 0; yy < sizeY; yy++)
{ {
for (int xx = 0; xx < sizeX; xx++) 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 // Each vertices is presumed to be the upper left corner of a box of two triangles
indices[indicesCount + 0] = offset; indices[indicesCount + 0] = offset;
indices[indicesCount + 1] = offset + 1; indices[indicesCount + 1] = offset + 1;
@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
indicesCount += 6; indicesCount += 6;
} }
} }
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
LogHeader, indicesCount); // DEBUG
ret = true; ret = true;
} }
catch (Exception e) catch (Exception e)

View File

@ -287,6 +287,8 @@ public struct ConfigurationParameters
public float terrainFriction; public float terrainFriction;
public float terrainHitFraction; public float terrainHitFraction;
public float terrainRestitution; public float terrainRestitution;
public float terrainCollisionMargin;
public float avatarFriction; public float avatarFriction;
public float avatarStandingFriction; public float avatarStandingFriction;
public float avatarDensity; public float avatarDensity;
@ -296,6 +298,8 @@ public struct ConfigurationParameters
public float avatarCapsuleHeight; public float avatarCapsuleHeight;
public float avatarContactProcessingThreshold; public float avatarContactProcessingThreshold;
public float vehicleAngularDamping;
public float maxPersistantManifoldPoolSize; public float maxPersistantManifoldPoolSize;
public float maxCollisionAlgorithmPoolSize; public float maxCollisionAlgorithmPoolSize;
public float shouldDisableContactPoolDynamicAllocation; public float shouldDisableContactPoolDynamicAllocation;
@ -353,7 +357,7 @@ public enum CollisionFlags : uint
CF_CHARACTER_OBJECT = 1 << 4, CF_CHARACTER_OBJECT = 1 << 4,
CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, 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_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
BS_FLOATS_ON_WATER = 1 << 11, BS_FLOATS_ON_WATER = 1 << 11,
BS_NONE = 0, BS_NONE = 0,
@ -481,6 +485,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData)
[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern bool IsNativeShape2(IntPtr shape); 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] [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);

View File

@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0) 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); // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
return false; return false;
} }

View File

@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
_pbs.SculptData = new byte[asset.Data.Length]; _pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(_pbs.SculptData, 0); asset.Data.CopyTo(_pbs.SculptData, 0);
// m_assetFailed = false; // 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; m_taintshape = true;
_parent_scene.AddPhysicsActorTaint(this); _parent_scene.AddPhysicsActorTaint(this);
} }

View File

@ -217,10 +217,10 @@
; to false if you have compatibility problems. ; to false if you have compatibility problems.
;CacheSculptMaps = true ;CacheSculptMaps = true
; Choose one of the physics engines below ; Choose one of the physics engines below.
; OpenDynamicsEngine is by some distance the most developed physics engine ; OpenDynamicsEngine is by some distance the most developed physics engine.
; basicphysics effectively does not model physics at all, making all objects phantom ; 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 = OpenDynamicsEngine
;physics = basicphysics ;physics = basicphysics
;physics = POS ;physics = POS
@ -904,15 +904,18 @@
[BulletSim] [BulletSim]
; World parameters ; World parameters
DefaultFriction = 0.50 DefaultFriction = 0.20
DefaultDensity = 10.000006836 DefaultDensity = 10.000006836
DefaultRestitution = 0.0 DefaultRestitution = 0.0
Gravity = -9.80665 Gravity = -9.80665
TerrainFriction = 0.50 TerrainFriction = 0.30
TerrainHitFriction = 0.8 TerrainHitFraction = 0.8
TerrainRestitution = 0 TerrainRestitution = 0
TerrainCollisionMargin = 0.04
AvatarFriction = 0.2 AvatarFriction = 0.2
AvatarStandingFriction = 0.99
AvatarRestitution = 0.0 AvatarRestitution = 0.0
AvatarDensity = 60.0 AvatarDensity = 60.0
AvatarCapsuleWidth = 0.6 AvatarCapsuleWidth = 0.6
@ -926,27 +929,15 @@
LinearDamping = 0.0 LinearDamping = 0.0
AngularDamping = 0.0 AngularDamping = 0.0
DeactivationTime = 0.2 DeactivationTime = 0.2
LinearSleepingThreshold = 0.8 CollisionMargin = 0.04
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
; Linkset constraint parameters ; Linkset constraint parameters
LinkImplementation = 1 ; 0=constraint, 1=compound
LinkConstraintUseFrameOffset = False LinkConstraintUseFrameOffset = False
LinkConstraintEnableTransMotor = True LinkConstraintEnableTransMotor = True
LinkConstraintTransMotorMaxVel = 5.0 LinkConstraintTransMotorMaxVel = 5.0
LinkConstraintTransMotorMaxForce = 0.1 LinkConstraintTransMotorMaxForce = 0.1
; Whether to mesh sculpties ; Whether to mesh sculpties
MeshSculptedPrim = true MeshSculptedPrim = true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.