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.
/// Requires NUnit 2.5 or better (to support the generics).
/// </summary>
/// <remarks>
/// FIXME: Should extend OpenSimTestCase but compile on mono 2.4.3 currently fails with
/// AssetTests`2 : System.MemberAccessException : Cannot create an instance of OpenSim.Data.Tests.AssetTests`2[TConn,TAssetData] because Type.ContainsGenericParameters is true.
/// and similar on EstateTests, InventoryTests and RegionTests.
/// Runs fine with mono 2.10.8.1, so easiest thing is to wait until min Mono version uplifts.
/// </remarks>
/// <typeparam name="TConn"></typeparam>
/// <typeparam name="TService"></typeparam>
public class BasicDataServiceTest<TConn, TService> : OpenSimTestCase
public class BasicDataServiceTest<TConn, TService>
where TConn : DbConnection, new()
where TService : class, new()
{

View File

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

View File

@ -189,20 +189,24 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
{
foreach (GridInstantMessage im in msglist)
{
// client.SendInstantMessage(im);
if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
// send it directly or else the item will be given twice
client.SendInstantMessage(im);
else
{
// Send through scene event manager so all modules get a chance
// to look at this message before it gets delivered.
//
// Needed for proper state management for stored group
// invitations
//
// Send through scene event manager so all modules get a chance
// to look at this message before it gets delivered.
//
// Needed for proper state management for stored group
// invitations
//
im.offline = 1;
im.offline = 1;
Scene s = FindScene(client.AgentId);
if (s != null)
s.EventManager.TriggerIncomingInstantMessage(im);
Scene s = FindScene(client.AgentId);
if (s != null)
s.EventManager.TriggerIncomingInstantMessage(im);
}
}
}
}

View File

@ -365,7 +365,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4)
{
m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
//m_console.OutputFormat("Usage: show part id [--full] <UUID-or-localID>");
m_console.OutputFormat("Usage: show part id <UUID-or-localID>");
return;
}
@ -405,6 +406,7 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 5)
{
//m_console.OutputFormat("Usage: show part pos <start-coord> to <end-coord>");
m_console.OutputFormat("Usage: show part pos [--full] <start-coord> to <end-coord>");
return;
}
@ -445,7 +447,8 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
if (mainParams.Count < 4)
{
m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
m_console.OutputFormat("Usage: show part name [--regex] <name>");
//m_console.OutputFormat("Usage: show part name [--full] [--regex] <name>");
return;
}
@ -577,6 +580,58 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
cdl.AddRow("Link number", sop.LinkNum);
cdl.AddRow("Flags", sop.Flags);
if (showFull)
{
PrimitiveBaseShape s = sop.Shape;
cdl.AddRow("FlexiDrag", s.FlexiDrag);
cdl.AddRow("FlexiEntry", s.FlexiEntry);
cdl.AddRow("FlexiForce", string.Format("<{0},{1},{2}>", s.FlexiForceX, s.FlexiForceY, s.FlexiForceZ));
cdl.AddRow("FlexiGravity", s.FlexiGravity);
cdl.AddRow("FlexiSoftness", s.FlexiSoftness);
cdl.AddRow("HollowShape", s.HollowShape);
cdl.AddRow(
"LightColor",
string.Format("<{0},{1},{2},{3}>", s.LightColorR, s.LightColorB, s.LightColorG, s.LightColorA));
cdl.AddRow("FlexiDrag", s.LightCutoff);
cdl.AddRow("FlexiDrag", s.LightEntry);
cdl.AddRow("FlexiDrag", s.LightFalloff);
cdl.AddRow("FlexiDrag", s.LightIntensity);
cdl.AddRow("FlexiDrag", s.LightRadius);
cdl.AddRow("Media", string.Format("{0} entries", s.Media != null ? s.Media.Count.ToString() : "n/a"));
cdl.AddRow("PathBegin", s.PathBegin);
cdl.AddRow("PathEnd", s.PathEnd);
cdl.AddRow("PathCurve", s.PathCurve);
cdl.AddRow("PathRadiusOffset", s.PathRadiusOffset);
cdl.AddRow("PathRevolutions", s.PathRevolutions);
cdl.AddRow("PathScale", string.Format("<{0},{1}>", s.PathScaleX, s.PathScaleY));
cdl.AddRow("PathSkew", string.Format("<{0},{1}>", s.PathShearX, s.PathShearY));
cdl.AddRow("FlexiDrag", s.PathSkew);
cdl.AddRow("PathTaper", string.Format("<{0},{1}>", s.PathTaperX, s.PathTaperY));
cdl.AddRow("PathTwist", s.PathTwist);
cdl.AddRow("PathTwistBegin", s.PathTwistBegin);
cdl.AddRow("PCode", s.PCode);
cdl.AddRow("ProfileBegin", s.ProfileBegin);
cdl.AddRow("ProfileEnd", s.ProfileEnd);
cdl.AddRow("ProfileHollow", s.ProfileHollow);
cdl.AddRow("ProfileShape", s.ProfileShape);
cdl.AddRow("ProjectionAmbiance", s.ProjectionAmbiance);
cdl.AddRow("ProjectionEntry", s.ProjectionEntry);
cdl.AddRow("ProjectionFocus", s.ProjectionFocus);
cdl.AddRow("ProjectionFOV", s.ProjectionFOV);
cdl.AddRow("ProjectionTextureUUID", s.ProjectionTextureUUID);
cdl.AddRow("Scale", s.Scale);
cdl.AddRow(
"SculptData",
string.Format("{0} bytes", s.SculptData != null ? s.SculptData.Length.ToString() : "n/a"));
cdl.AddRow("SculptEntry", s.SculptEntry);
cdl.AddRow("SculptTexture", s.SculptTexture);
cdl.AddRow("SculptType", s.SculptType);
cdl.AddRow("State", s.State);
// TODO, unpack and display texture entries
//cdl.AddRow("Textures", string.Format("{0} entries", s.Textures.
}
object itemsOutput;
if (showFull)
{
@ -588,7 +643,6 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands
itemsOutput = sop.Inventory.Count;
}
cdl.AddRow("Items", itemsOutput);
return sb.Append(cdl.ToString());

View File

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

View File

@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private Quaternion m_referenceFrame = Quaternion.Identity;
// Linear properties
private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
private Vector3 m_linearFrictionTimescale = Vector3.Zero;
private float m_linearMotorDecayTimescale = 0;
private float m_linearMotorTimescale = 0;
@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// private Vector3 m_linearMotorOffset = Vector3.Zero;
//Angular properties
private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
// private int m_angularMotorApply = 0; // application frame counter
private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
@ -124,6 +125,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
//Attractor properties
private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
private float m_verticalAttractionEfficiency = 1.0f; // damped
private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor.
@ -152,10 +154,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
break;
case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f);
m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
break;
case Vehicle.ANGULAR_MOTOR_TIMESCALE:
m_angularMotorTimescale = Math.Max(pValue, 0.01f);
m_angularMotor.TimeScale = m_angularMotorTimescale;
break;
case Vehicle.BANKING_EFFICIENCY:
m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f));
@ -185,33 +189,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
break;
case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f);
m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120));
m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
break;
case Vehicle.LINEAR_MOTOR_TIMESCALE:
m_linearMotorTimescale = Math.Max(pValue, 0.01f);
m_linearMotor.TimeScale = m_linearMotorTimescale;
break;
case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f));
m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
break;
case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
break;
// These are vector properties but the engine lets you use a single float value to
// set all of the components to the same value
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
// m_angularMotorApply = 100;
m_angularMotor.SetTarget(m_angularMotorDirection);
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
m_linearMotor.SetTarget(m_linearMotorDirection);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@ -227,6 +238,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
case Vehicle.ANGULAR_FRICTION_TIMESCALE:
m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
break;
case Vehicle.ANGULAR_MOTOR_DIRECTION:
// Limit requested angular speed to 2 rps= 4 pi rads/sec
@ -234,14 +246,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f));
pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f));
m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
// m_angularMotorApply = 100;
m_angularMotor.SetTarget(m_angularMotorDirection);
break;
case Vehicle.LINEAR_FRICTION_TIMESCALE:
m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
break;
case Vehicle.LINEAR_MOTOR_DIRECTION:
m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
m_linearMotor.SetTarget(m_linearMotorDirection);
break;
case Vehicle.LINEAR_MOTOR_OFFSET:
m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@ -303,7 +317,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_VhoverEfficiency = 0;
m_VhoverTimescale = 0;
m_VehicleBuoyancy = 0;
m_linearDeflectionEfficiency = 1;
m_linearDeflectionTimescale = 1;
@ -319,6 +333,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_referenceFrame = Quaternion.Identity;
m_flags = (VehicleFlag)0;
break;
case Vehicle.TYPE_SLED:
@ -351,10 +366,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_bankingMix = 1;
m_referenceFrame = Quaternion.Identity;
m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP);
m_flags &=
~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY |
VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY);
m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
| VehicleFlag.HOVER_TERRAIN_ONLY
| VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP);
break;
case Vehicle.TYPE_CAR:
m_linearMotorDirection = Vector3.Zero;
@ -427,9 +445,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_flags &= ~(VehicleFlag.HOVER_TERRAIN_ONLY
| VehicleFlag.HOVER_GLOBAL_HEIGHT
| VehicleFlag.LIMIT_ROLL_ONLY
| VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_UP_ONLY);
m_flags |= (VehicleFlag.NO_DEFLECTION_UP
| VehicleFlag.LIMIT_MOTOR_UP
| VehicleFlag.HOVER_WATER_ONLY);
break;
case Vehicle.TYPE_AIRPLANE:
@ -510,6 +528,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
| VehicleFlag.HOVER_GLOBAL_HEIGHT);
break;
}
// Update any physical parameters based on this type.
Refresh();
m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
m_linearMotorDecayTimescale, m_linearFrictionTimescale,
1f);
m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
m_angularMotorDecayTimescale, m_angularFrictionTimescale,
1f);
m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
BSMotor.Infinite, BSMotor.InfiniteVector,
m_verticalAttractionEfficiency);
// Z goes away and we keep X and Y
m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
// m_bankingMotor = new BSVMotor("BankingMotor", ...);
}
// Some of the properties of this prim may have changed.
@ -518,13 +558,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
if (IsActive)
{
m_vehicleMass = Prim.Linkset.LinksetMass;
// Friction effects are handled by this vehicle code
BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f);
BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
float friction = 0f;
BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction);
// BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f);
// Moderate angular movement introduced by Bullet.
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
// Maybe compute linear and angular factor and damping from params.
float angularDamping = PhysicsScene.Params.vehicleAngularDamping;
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID);
// DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet
// Vector3 localInertia = new Vector3(1f, 1f, 1f);
Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass);
BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia);
VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}",
Prim.LocalID, friction, localInertia, angularDamping);
}
}
@ -551,111 +603,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
if (!IsActive) return;
// DEBUG
// Because Bullet does apply forces to the vehicle, our last computed
// linear and angular velocities are not what is happening now.
// Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
// m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
// m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
// m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
// END DEBUG
m_vehicleMass = Prim.Linkset.LinksetMass;
MoveLinear(pTimestep);
// Commented out for debug
MoveAngular(pTimestep);
// Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
// Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
LimitRotation(pTimestep);
// remember the position so next step we can limit absolute movement effects
m_lastPositionVector = Prim.ForcePosition;
VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG
Prim.LocalID,
BulletSimAPI.GetFriction2(Prim.PhysBody.ptr),
BulletSimAPI.GetGravity2(Prim.PhysBody.ptr),
Prim.Inertia,
m_vehicleMass
);
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity);
}// end Step
}
// Apply the effect of the linear motor.
// Also does hover and float.
private void MoveLinear(float pTimestep)
{
// m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates
// m_lastLinearVelocityVector is the current speed we are moving in that direction
if (m_linearMotorDirection.LengthSquared() > 0.001f)
{
Vector3 origDir = m_linearMotorDirection; // DEBUG
Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
// DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
// Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete
Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep;
m_lastLinearVelocityVector += addAmount;
float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep;
m_linearMotorDirection *= (1f - decayFactor);
// Rotate new object velocity from vehicle relative to world coordinates
m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
// Apply friction for next time
Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}",
Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor,
m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity);
}
else
{
// if what remains of direction is very small, zero it.
m_linearMotorDirection = Vector3.Zero;
m_lastLinearVelocityVector = Vector3.Zero;
m_newVelocity = Vector3.Zero;
VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
}
// m_newVelocity is velocity computed from linear motor in world coordinates
// Rotate new object velocity from vehicle relative to world coordinates
linearMotorContribution *= Prim.ForceOrientation;
// ==================================================================
// Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy);
/*
* RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ...
// Preserve the current Z velocity
Vector3 vel_now = m_prim.Velocity;
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
*/
Vector3 pos = Prim.ForcePosition;
// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
// If below the terrain, move us above the ground a little.
float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep, ref pos, terrainHeight);
Vector3 hoverContribution = ComputeLinearHover(pTimestep, ref pos, terrainHeight);
ComputeLinearBlockingEndPoint(pTimestep, ref pos);
Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep, pos, terrainHeight);
// ==================================================================
Vector3 newVelocity = linearMotorContribution
+ terrainHeightContribution
+ hoverContribution
+ limitMotorUpContribution;
// If not changing some axis, reduce out velocity
if ((m_flags & (VehicleFlag.NO_X)) != 0)
newVelocity.X = 0;
if ((m_flags & (VehicleFlag.NO_Y)) != 0)
newVelocity.Y = 0;
if ((m_flags & (VehicleFlag.NO_Z)) != 0)
newVelocity.Z = 0;
// ==================================================================
// Clamp REALLY high or low velocities
float newVelocityLengthSq = newVelocity.LengthSquared();
if (newVelocityLengthSq > 1e6f)
{
newVelocity /= newVelocity.Length();
newVelocity *= 1000f;
}
else if (newVelocityLengthSq < 1e-6f)
newVelocity = Vector3.Zero;
// ==================================================================
// Stuff new linear velocity into the vehicle
Prim.ForceVelocity = newVelocity;
// Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
// Other linear forces are applied as forces.
Vector3 totalDownForce = grav * m_vehicleMass;
if (totalDownForce != Vector3.Zero)
{
Prim.AddForce(totalDownForce, false);
}
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector,
newVelocity, Prim.Velocity, totalDownForce);
} // end MoveLinear()
public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep, ref Vector3 pos, float terrainHeight)
{
Vector3 ret = Vector3.Zero;
// If below the terrain, move us above the ground a little.
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
// TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
// if (rotatedSize.Z < terrainHeight)
if (pos.Z < terrainHeight)
{
// TODO: correct position by applying force rather than forcing position.
pos.Z = terrainHeight + 2;
Prim.ForcePosition = pos;
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
}
return ret;
}
public Vector3 ComputeLinearHover(float pTimestep, ref Vector3 pos, float terrainHeight)
{
Vector3 ret = Vector3.Zero;
// Check if hovering
// m_VhoverEfficiency: 0=bouncy, 1=totally damped
// m_VhoverTimescale: time to achieve height
if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@ -663,7 +713,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{
m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
m_VhoverTargetHeight = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
}
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{
@ -680,6 +730,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (pos.Z > m_VhoverTargetHeight)
m_VhoverTargetHeight = pos.Z;
}
if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
{
if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f)
@ -694,28 +745,31 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// RA: where does the 50 come from?
float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale);
// Replace Vertical speed with correction figure if significant
if (Math.Abs(verticalError) > 0.01f)
if (verticalError > 0.01f)
{
m_newVelocity.Z += verticalCorrectionVelocity;
ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
//KF: m_VhoverEfficiency is not yet implemented
}
else if (verticalError < -0.01)
{
m_newVelocity.Z -= verticalCorrectionVelocity;
}
else
{
m_newVelocity.Z = 0f;
ret = new Vector3(0f, 0f, -verticalCorrectionVelocity);
}
}
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}",
Prim.LocalID, pos, ret, m_VhoverHeight, m_VhoverTargetHeight);
}
return ret;
}
public bool ComputeLinearBlockingEndPoint(float pTimestep, ref Vector3 pos)
{
bool changed = false;
Vector3 posChange = pos - m_lastPositionVector;
if (m_BlockingEndPoint != Vector3.Zero)
{
bool changed = false;
if (pos.X >= (m_BlockingEndPoint.X - (float)1))
{
pos.X -= posChange.X + 1;
@ -748,75 +802,53 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Prim.LocalID, m_BlockingEndPoint, posChange, pos);
}
}
return changed;
}
#region downForce
Vector3 downForce = Vector3.Zero;
// From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
// Prevent ground vehicles from motoring into the sky.This flag has a subtle effect when
// used with conjunction with banking: the strength of the banking will decay when the
// vehicle no longer experiences collisions. The decay timescale is the same as
// VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
// when they are in mid jump.
// TODO: this code is wrong. Also, what should it do for boats?
public Vector3 ComputeLinearMotorUp(float pTimestep, Vector3 pos, float terrainHeight)
{
Vector3 ret = Vector3.Zero;
if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
{
// If the vehicle is motoring into the sky, get it going back down.
// Is this an angular force or both linear and angular??
float distanceAboveGround = pos.Z - terrainHeight;
if (distanceAboveGround > 2f)
if (distanceAboveGround > 1f)
{
// downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
// downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
downForce = new Vector3(0, 0, -distanceAboveGround);
ret = new Vector3(0, 0, -distanceAboveGround);
}
// TODO: this calculation is all wrong. From the description at
// TODO: this calculation is wrong. From the description at
// (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
// has a decay factor. This says this force should
// be computed with a motor.
VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
Prim.LocalID, distanceAboveGround, downForce);
// TODO: add interaction with banking.
VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}",
Prim.LocalID, distanceAboveGround, ret);
}
#endregion // downForce
// If not changing some axis, reduce out velocity
if ((m_flags & (VehicleFlag.NO_X)) != 0)
m_newVelocity.X = 0;
if ((m_flags & (VehicleFlag.NO_Y)) != 0)
m_newVelocity.Y = 0;
if ((m_flags & (VehicleFlag.NO_Z)) != 0)
m_newVelocity.Z = 0;
// Clamp REALLY high or low velocities
if (m_newVelocity.LengthSquared() > 1e6f)
{
m_newVelocity /= m_newVelocity.Length();
m_newVelocity *= 1000f;
}
else if (m_newVelocity.LengthSquared() < 1e-6f)
m_newVelocity = Vector3.Zero;
// Stuff new linear velocity into the vehicle
Prim.ForceVelocity = m_newVelocity;
// Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
Vector3 totalDownForce = downForce + grav;
if (totalDownForce != Vector3.Zero)
{
Prim.AddForce(totalDownForce * m_vehicleMass, false);
// Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
}
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}",
Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce);
} // end MoveLinear()
return ret;
}
// =======================================================================
// =======================================================================
// Apply the effect of the angular motor.
private void MoveAngular(float pTimestep)
{
// m_angularMotorDirection // angular velocity requested by LSL motor
// m_angularMotorApply // application frame counter
// m_angularMotorVelocity // current angular motor velocity (ramps up and down)
// m_angularMotorTimescale // motor angular velocity ramp up rate
// m_angularMotorTimescale // motor angular velocity ramp up time
// m_angularMotorDecayTimescale // motor angular velocity decay rate
// m_angularFrictionTimescale // body angular velocity decay rate
// m_lastAngularVelocity // what was last applied to body
/*
if (m_angularMotorDirection.LengthSquared() > 0.0001)
{
Vector3 origVel = m_angularMotorVelocity;
@ -835,141 +867,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
m_angularMotorVelocity = Vector3.Zero;
}
*/
#region Vertical attactor
Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
Vector3 vertattr = Vector3.Zero;
Vector3 deflection = Vector3.Zero;
Vector3 banking = Vector3.Zero;
// If vertical attaction timescale is reasonable and we applied an angular force last time...
if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
// ==================================================================
// From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
// This flag prevents linear deflection parallel to world z-axis. This is useful
// for preventing ground vehicles with large linear deflection, like bumper cars,
// from climbing their linear deflection into the sky.
// That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
if (Prim.IsColliding)
VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
// Create a vector of the vehicle "up" in world coordinates
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
// verticalError.X and .Y are the World error amounts. They are 0 when there is no
// error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
// side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
// and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
// modulated to prevent a stable inverted body.
// Error is 0 (no error) to +/- 2 (max error)
if (verticalError.Z < 0.0f)
{
verticalError.X = 2.0f - verticalError.X;
verticalError.Y = 2.0f - verticalError.Y;
}
// scale it by VAservo (timestep and timescale)
verticalError = verticalError * VAservo;
// As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
// then .X increases, so change Body angular velocity X based on Y, and Y based on X.
// Z is not changed.
vertattr.X = verticalError.Y;
vertattr.Y = - verticalError.X;
vertattr.Z = 0f;
// scaling appears better usingsquare-law
Vector3 angularVelocity = Prim.ForceRotationalVelocity;
float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
vertattr.X += bounce * angularVelocity.X;
vertattr.Y += bounce * angularVelocity.Y;
VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}",
Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
}
#endregion // Vertical attactor
#region Deflection
if (m_angularDeflectionEfficiency != 0)
{
// Compute a scaled vector that points in the preferred axis (X direction)
Vector3 scaledDefaultDirection =
new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
// Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
// Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
// Scale by efficiency and timescale
deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
Prim.LocalID, preferredAxisOfMotion, deflection);
// This deflection computation is not correct.
deflection = Vector3.Zero;
angularMotorContribution.X = 0f;
angularMotorContribution.Y = 0f;
VDetailLog("{0},MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
}
#endregion
Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(pTimestep);
#region Banking
Vector3 deflectionContribution = ComputeAngularDeflection(pTimestep);
if (m_bankingEfficiency != 0)
{
Vector3 dir = Vector3.One * Prim.ForceOrientation;
float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1);
//Changes which way it banks in and out of turns
Vector3 bankingContribution = ComputeAngularBanking(pTimestep);
//Use the square of the efficiency, as it looks much more how SL banking works
float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
if (m_bankingEfficiency < 0)
effSquared *= -1; //Keep the negative!
float mix = Math.Abs(m_bankingMix);
if (m_angularMotorVelocity.X == 0)
{
/*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
{
Vector3 axisAngle;
float angle;
parent.Orientation.GetAxisAngle(out axisAngle, out angle);
Vector3 rotatedVel = parent.Velocity * parent.Orientation;
if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
else
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
}*/
}
else
banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
//If they are colliding, we probably shouldn't shove the prim around... probably
{
float angVelZ = m_angularMotorVelocity.X*-1;
/*if(angVelZ > mix)
angVelZ = mix;
else if(angVelZ < -mix)
angVelZ = -mix;*/
//This controls how fast and how far the banking occurs
Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
if (bankingRot.X > 3)
bankingRot.X = 3;
else if (bankingRot.X < -3)
bankingRot.X = -3;
bankingRot *= Prim.ForceOrientation;
banking += bankingRot;
}
m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
}
#endregion
m_lastVertAttractor = vertattr;
// ==================================================================
m_lastVertAttractor = verticalAttractionContribution;
// Sum velocities
m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
#region Linear Motor Offset
m_lastAngularVelocity = angularMotorContribution
+ verticalAttractionContribution
+ deflectionContribution
+ bankingContribution;
// ==================================================================
//Offset section
if (m_linearMotorOffset != Vector3.Zero)
{
@ -985,8 +915,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
//
// The torque created is the linear velocity crossed with the offset
// NOTE: this computation does should be in the linear section
// because there we know the impulse being applied.
// TODO: this computation should be in the linear section
// because that is where we know the impulse being applied.
Vector3 torqueFromOffset = Vector3.Zero;
// torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
if (float.IsNaN(torqueFromOffset.X))
@ -1000,20 +930,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
}
#endregion
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
m_lastAngularVelocity.X = 0;
m_lastAngularVelocity.Y = 0;
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
}
// ==================================================================
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
Prim.ZeroAngularMotion(true);
// TODO: zeroing is good but it also sets values in unmanaged code. Remove the stores when idle.
VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
Prim.ZeroAngularMotion(true);
}
else
{
@ -1021,18 +944,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// The above calculates the absolute angular velocity needed. Angular velocity is massless.
// Since we are stuffing the angular velocity directly into the object, the computed
// velocity needs to be scaled by the timestep.
Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity);
// Also remove any motion that is on the object so added motion is only from vehicle.
Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep)
- Prim.ForceRotationalVelocity);
// Unscale the force by the angular factor so it overwhelmes the Bullet additions.
Prim.ForceRotationalVelocity = applyAngularForce;
// Decay the angular movement for next time
Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep;
m_lastAngularVelocity *= Vector3.One - decayamount;
VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}",
Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity);
VDetailLog("{0},MoveAngular,done,angMotor={1},vertAttr={2},bank={3},deflect={4},newAngForce={5},lastAngular={6}",
Prim.LocalID,
angularMotorContribution, verticalAttractionContribution,
bankingContribution, deflectionContribution,
applyAngularForce, m_lastAngularVelocity
);
}
} //end MoveAngular
}
public Vector3 ComputeAngularVerticalAttraction(float pTimestep)
{
Vector3 ret = Vector3.Zero;
// If vertical attaction timescale is reasonable and we applied an angular force last time...
if (m_verticalAttractionTimescale < 500)
{
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
verticalError.Normalize();
m_verticalAttractionMotor.SetCurrent(verticalError);
m_verticalAttractionMotor.SetTarget(Vector3.UnitZ);
ret = m_verticalAttractionMotor.Step(pTimestep);
/*
// Take a vector pointing up and convert it from world to vehicle relative coords.
Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
verticalError.Normalize();
// If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
// is now leaning to one side (rotated around the X axis) and the Y value will
// go from zero (nearly straight up) to one (completely to the side) or leaning
// front-to-back (rotated around the Y axis) and the value of X will be between
// zero and one.
// The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
// If verticalError.Z is negative, the vehicle is upside down. Add additional push.
if (verticalError.Z < 0f)
{
verticalError.X = 2f - verticalError.X;
verticalError.Y = 2f - verticalError.Y;
}
// Y error means needed rotation around X axis and visa versa.
verticalAttractionContribution.X = verticalError.Y;
verticalAttractionContribution.Y = - verticalError.X;
verticalAttractionContribution.Z = 0f;
// scale by the time scale and timestep
Vector3 unscaledContrib = verticalAttractionContribution;
verticalAttractionContribution /= m_verticalAttractionTimescale;
verticalAttractionContribution *= pTimestep;
// apply efficiency
Vector3 preEfficiencyContrib = verticalAttractionContribution;
float efficencySquared = m_verticalAttractionEfficiency * m_verticalAttractionEfficiency;
verticalAttractionContribution *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
VDetailLog("{0},MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},preEff={3},eff={4},effSq={5},vertAttr={6}",
Prim.LocalID, verticalError, unscaledContrib, preEfficiencyContrib,
m_verticalAttractionEfficiency, efficencySquared,
verticalAttractionContribution);
*/
}
return ret;
}
public Vector3 ComputeAngularDeflection(float pTimestep)
{
Vector3 ret = Vector3.Zero;
if (m_angularDeflectionEfficiency != 0)
{
// Compute a scaled vector that points in the preferred axis (X direction)
Vector3 scaledDefaultDirection =
new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
// Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
// Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
// Scale by efficiency and timescale
ret = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", Prim.LocalID, preferredAxisOfMotion, ret);
// This deflection computation is not correct.
ret = Vector3.Zero;
}
return ret;
}
public Vector3 ComputeAngularBanking(float pTimestep)
{
Vector3 ret = Vector3.Zero;
if (m_bankingEfficiency != 0)
{
Vector3 dir = Vector3.One * Prim.ForceOrientation;
float mult = (m_bankingMix * m_bankingMix) * -1 * (m_bankingMix < 0 ? -1 : 1);
//Changes which way it banks in and out of turns
//Use the square of the efficiency, as it looks much more how SL banking works
float effSquared = (m_bankingEfficiency * m_bankingEfficiency);
if (m_bankingEfficiency < 0)
effSquared *= -1; //Keep the negative!
float mix = Math.Abs(m_bankingMix);
if (m_angularMotorVelocity.X == 0)
{
// The vehicle is stopped
/*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
{
Vector3 axisAngle;
float angle;
parent.Orientation.GetAxisAngle(out axisAngle, out angle);
Vector3 rotatedVel = parent.Velocity * parent.Orientation;
if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
else
m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
}*/
}
else
{
ret.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4;
}
//If they are colliding, we probably shouldn't shove the prim around... probably
if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
{
float angVelZ = m_angularMotorVelocity.X * -1;
/*if(angVelZ > mix)
angVelZ = mix;
else if(angVelZ < -mix)
angVelZ = -mix;*/
//This controls how fast and how far the banking occurs
Vector3 bankingRot = new Vector3(angVelZ * (effSquared * mult), 0, 0);
if (bankingRot.X > 3)
bankingRot.X = 3;
else if (bankingRot.X < -3)
bankingRot.X = -3;
bankingRot *= Prim.ForceOrientation;
ret += bankingRot;
}
m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}",
Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, ret);
}
return ret;
}
// This is from previous instantiations of XXXDynamics.cs.
// Applies roll reference frame.
// TODO: is this the right way to separate the code to do this operation?
// Should this be in MoveAngular()?
internal void LimitRotation(float timestep)
{
Quaternion rotq = Prim.ForceOrientation;

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.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public abstract class BSMotor
{
public virtual void Reset() { }
public virtual void Zero() { }
}
// Can all the incremental stepping be replaced with motor classes?
public class BSVMotor : BSMotor
{
public Vector3 FrameOfReference { get; set; }
public Vector3 Offset { get; set; }
public float TimeScale { get; set; }
public float TargetValueDecayTimeScale { get; set; }
public Vector3 CurrentValueReductionTimescale { get; set; }
public float Efficiency { get; set; }
public Vector3 TargetValue { get; private set; }
public Vector3 CurrentValue { get; private set; }
BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
{
TimeScale = timeScale;
TargetValueDecayTimeScale = decayTimeScale;
CurrentValueReductionTimescale = frictionTimeScale;
Efficiency = efficiency;
}
public void SetCurrent(Vector3 current)
{
CurrentValue = current;
}
public void SetTarget(Vector3 target)
{
TargetValue = target;
}
public Vector3 Step(float timeStep)
{
if (CurrentValue.LengthSquared() > 0.001f)
{
// Vector3 origDir = Target; // DEBUG
// Vector3 origVel = CurrentValue; // DEBUG
// Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete
Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep;
CurrentValue += addAmount;
float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
TargetValue *= (1f - decayFactor);
Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep;
CurrentValue *= (Vector3.One - frictionFactor);
}
else
{
// if what remains of direction is very small, zero it.
TargetValue = Vector3.Zero;
CurrentValue = Vector3.Zero;
// VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
}
return CurrentValue;
}
}
public class BSFMotor : BSMotor
{
public float TimeScale { get; set; }
public float DecayTimeScale { get; set; }
public float Friction { get; set; }
public float Efficiency { get; set; }
public float Target { get; private set; }
public float CurrentValue { get; private set; }
BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency)
{
}
public void SetCurrent(float target)
{
}
public void SetTarget(float target)
{
}
public float Step(float timeStep)
{
return 0f;
}
}
public class BSPIDMotor : BSMotor
{
// TODO: write and use this one
BSPIDMotor()
{
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public abstract class BSMotor
{
// Timescales and other things can be turned off by setting them to 'infinite'.
public const float Infinite = 10000f;
public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
public BSMotor(string useName)
{
UseName = useName;
PhysicsScene = null;
}
public virtual void Reset() { }
public virtual void Zero() { }
public string UseName { get; private set; }
// Used only for outputting debug information. Might not be set so check for null.
public BSScene PhysicsScene { get; set; }
protected void MDetailLog(string msg, params Object[] parms)
{
if (PhysicsScene != null)
{
if (PhysicsScene.VehicleLoggingEnabled)
{
PhysicsScene.DetailLog(msg, parms);
}
}
}
}
// Can all the incremental stepping be replaced with motor classes?
public class BSVMotor : BSMotor
{
public Vector3 FrameOfReference { get; set; }
public Vector3 Offset { get; set; }
public float TimeScale { get; set; }
public float TargetValueDecayTimeScale { get; set; }
public Vector3 FrictionTimescale { get; set; }
public float Efficiency { get; set; }
public Vector3 TargetValue { get; private set; }
public Vector3 CurrentValue { get; private set; }
public BSVMotor(string useName)
: base(useName)
{
TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
Efficiency = 1f;
FrictionTimescale = BSMotor.InfiniteVector;
CurrentValue = TargetValue = Vector3.Zero;
}
public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
: this(useName)
{
TimeScale = timeScale;
TargetValueDecayTimeScale = decayTimeScale;
FrictionTimescale = frictionTimeScale;
Efficiency = efficiency;
CurrentValue = TargetValue = Vector3.Zero;
}
public void SetCurrent(Vector3 current)
{
CurrentValue = current;
}
public void SetTarget(Vector3 target)
{
TargetValue = target;
}
public Vector3 Step(float timeStep)
{
Vector3 returnCurrent = Vector3.Zero;
if (!CurrentValue.ApproxEquals(TargetValue, 0.01f))
{
Vector3 origTarget = TargetValue; // DEBUG
Vector3 origCurrVal = CurrentValue; // DEBUG
// Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete
Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep;
CurrentValue += addAmount;
returnCurrent = CurrentValue;
// The desired value reduces to zero which also reduces the difference with current.
// If the decay time is infinite, don't decay at all.
float decayFactor = 0f;
if (TargetValueDecayTimeScale != BSMotor.Infinite)
{
decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
TargetValue *= (1f - decayFactor);
}
Vector3 frictionFactor = Vector3.Zero;
if (FrictionTimescale != BSMotor.InfiniteVector)
{
// frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep;
frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep;
frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep;
CurrentValue *= (Vector3.One - frictionFactor);
}
MDetailLog("{0},BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}",
BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
timeStep, TimeScale, addAmount,
TargetValueDecayTimeScale, decayFactor,
FrictionTimescale, frictionFactor);
MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}",
BSScene.DetailLogZero, UseName, CurrentValue, TargetValue,
addAmount, decayFactor, frictionFactor, returnCurrent);
}
else
{
// Difference between what we have and target is small. Motor is done.
CurrentValue = Vector3.Zero;
TargetValue = Vector3.Zero;
MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}",
BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent);
}
return returnCurrent;
}
public override string ToString()
{
return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>",
UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale);
}
}
public class BSFMotor : BSMotor
{
public float TimeScale { get; set; }
public float DecayTimeScale { get; set; }
public float Friction { get; set; }
public float Efficiency { get; set; }
public float Target { get; private set; }
public float CurrentValue { get; private set; }
public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
: base(useName)
{
}
public void SetCurrent(float target)
{
}
public void SetTarget(float target)
{
}
public float Step(float timeStep)
{
return 0f;
}
}
public class BSPIDMotor : BSMotor
{
// TODO: write and use this one
public BSPIDMotor(string useName)
: base(useName)
{
}
}
}

View File

@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject
// Zero some other properties in the physics engine
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
{
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero);
// DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
});
}
@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
{
float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
// TODO: a floating motor so object will bob in the water
if (Math.Abs(Position.Z - waterHeight) > 0.1f)
{
@ -342,13 +343,12 @@ public sealed class BSPrim : BSPhysObject
// TODO: check for out of bounds
// The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
// TODO: This should be intergrated with a geneal physics action mechanism.
// TODO: This should be moderated with PID'ness.
if (ret)
{
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate()
{
// Apply upforce and overcome gravity.
ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity;
});
// Apply upforce and overcome gravity.
AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime);
}
return ret;
}
@ -1381,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject
public override void UpdateProperties(EntityProperties entprop)
{
/*
UpdatedProperties changed = 0;
// assign to the local variables so the normal set action does not happen
// if (_position != entprop.Position)
if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
{
_position = entprop.Position;
changed |= UpdatedProperties.Position;
}
// if (_orientation != entprop.Rotation)
if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
{
_orientation = entprop.Rotation;
changed |= UpdatedProperties.Rotation;
}
// if (_velocity != entprop.Velocity)
if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
{
_velocity = entprop.Velocity;
changed |= UpdatedProperties.Velocity;
}
// if (_acceleration != entprop.Acceleration)
if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
{
_acceleration = entprop.Acceleration;
changed |= UpdatedProperties.Acceleration;
}
// if (_rotationalVelocity != entprop.RotationalVelocity)
if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
{
_rotationalVelocity = entprop.RotationalVelocity;
changed |= UpdatedProperties.RotationalVel;
}
if (changed != 0)
{
// Only update the position of single objects and linkset roots
if (Linkset.IsRoot(this))
{
base.RequestPhysicsterseUpdate();
}
}
*/
// Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
// Updates only for individual prims and for the root object of a linkset.
if (Linkset.IsRoot(this))
{
// A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
// TODO: handle physics introduced by Bullet with computed vehicle physics.
if (_vehicle.IsActive)
{
entprop.RotationalVelocity = OMV.Vector3.Zero;
}
// Assign directly to the local variables so the normal set action does not happen
_position = entprop.Position;
_orientation = entprop.Rotation;

View File

@ -39,23 +39,10 @@ using log4net;
using OpenMetaverse;
// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
// Test sculpties (verified that they don't work)
// Compute physics FPS reasonably
// Based on material, set density and friction
// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
// At the moment, physical and phantom causes object to drop through the terrain
// Physical phantom objects and related typing (collision options )
// Check out llVolumeDetect. Must do something for that.
// Use collision masks for collision with terrain and phantom objects
// More efficient memory usage when passing hull information from BSPrim to BulletSim
// Should prim.link() and prim.delink() membership checking happen at taint time?
// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
// Implement LockAngularMotion
// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
// Add PID movement operations. What does ScenePresence.MoveToTarget do?
// Check terrain size. 128 or 127?
// Raycast
@ -140,7 +127,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public const uint GROUNDPLANE_ID = 1;
public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
private float m_waterLevel;
public float SimpleWaterLevel { get; set; }
public BSTerrainManager TerrainManager { get; private set; }
public ConfigurationParameters Params
@ -195,6 +182,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
private string m_physicsLoggingDir;
private string m_physicsLoggingPrefix;
private int m_physicsLoggingFileMinutes;
private bool m_physicsLoggingDoFlush;
// 'true' of the vehicle code is to log lots of details
public bool VehicleLoggingEnabled { get; private set; }
@ -234,6 +222,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (m_physicsLoggingEnabled)
{
PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
}
else
{
@ -302,12 +291,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
// Very detailed logging for vehicle debugging
VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
// Do any replacements in the parameters
m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
}
// The material characteristics.
BSMaterials.InitializeFromDefaults(Params);
if (pConfig != null)
{
BSMaterials.InitializefromParameters(pConfig);
}
}
}
@ -499,7 +496,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
try
{
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
// if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
@ -508,7 +505,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime);
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}",
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount);
if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
// if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG
}
catch (Exception e)
{
@ -520,9 +517,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
collidersCount = 0;
}
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in
// Don't have to use the pointers passed back since we know it is the same pinned memory we passed in.
// Get a value for 'now' so all the collision and update routines don't have to get their own
// Get a value for 'now' so all the collision and update routines don't have to get their own.
SimulationNowTime = Util.EnvironmentTickCount();
// If there were collisions, process them by sending the event to the prim.
@ -568,6 +565,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
ObjectsWithCollisions.Remove(po);
ObjectsWithNoMoreCollisions.Clear();
}
// Done with collisions.
// If any of the objects had updated properties, tell the object it has been changed by the physics engine
if (updatedEntityCount > 0)
@ -591,9 +589,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
// The physics engine returns the number of milliseconds it simulated this call.
// These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
// We multiply by 55 to give a recognizable running rate (55 or less).
return numSubSteps * m_fixedTimeStep * 1000 * 55;
// return timeStep * 1000 * 55;
// Multiply by 55 to give a nominal frame rate of 55.
return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f;
}
// Something has collided
@ -639,12 +636,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
public override void SetWaterLevel(float baseheight)
{
m_waterLevel = baseheight;
}
// Someday....
public float GetWaterLevelAtXYZ(Vector3 loc)
{
return m_waterLevel;
SimpleWaterLevel = baseheight;
}
public override void DeleteTerrain()
@ -1069,7 +1061,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s,p,l,v) => { s.PID_P = v; } ),
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
0.5f,
0.2f,
(s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].defaultFriction; },
(s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
@ -1084,7 +1076,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].defaultRestitution; },
(s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
0f,
0.04f,
(s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].collisionMargin; },
(s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
@ -1151,7 +1143,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].terrainImplementation; },
(s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
0.5f,
0.3f,
(s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainFriction; },
(s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
@ -1165,13 +1157,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainRestitution; },
(s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
0.04f,
(s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].terrainCollisionMargin; },
(s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
0.2f,
(s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarFriction; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
10f,
10.0f,
(s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].avatarStandingFriction; },
(s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
@ -1206,6 +1204,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
(s) => { return s.m_params[0].avatarContactProcessingThreshold; },
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
0.95f,
(s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); },
(s) => { return s.m_params[0].vehicleAngularDamping; },
(s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ),
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
0f,
@ -1487,7 +1490,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
{
PhysicsLogging.Write(msg, args);
// Add the Flush() if debugging crashes. Gets all the messages written out.
// PhysicsLogging.Flush();
if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
}
// Used to fill in the LocalID when there isn't one. It's the correct number of characters.
public const string DetailLogZero = "0000000000";

View File

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

View File

@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable
ID = id;
}
public abstract void Dispose();
public abstract float GetHeightAtXYZ(Vector3 pos);
public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
public abstract float GetWaterLevelAtXYZ(Vector3 pos);
}
// ==========================================================================================
@ -75,13 +76,12 @@ public sealed class BSTerrainManager
public const float HEIGHT_INITIALIZATION = 24.987f;
public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
public const float HEIGHT_GETHEIGHT_RET = 24.765f;
public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
// If the min and max height are equal, we reduce the min by this
// amount to make sure that a bounding box is built for the terrain.
public const float HEIGHT_EQUAL_FUDGE = 0.2f;
public const float TERRAIN_COLLISION_MARGIN = 0.0f;
// Until the whole simulator is changed to pass us the region size, we rely on constants.
public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
@ -129,7 +129,8 @@ public sealed class BSTerrainManager
{
// The ground plane is here to catch things that are trying to drop to negative infinity
BulletShape groundPlaneShape = new BulletShape(
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN),
BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f,
PhysicsScene.Params.terrainCollisionMargin),
BSPhysicsShapeType.SHAPE_GROUNDPLANE);
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
@ -165,17 +166,22 @@ public sealed class BSTerrainManager
// Release all the terrain we have allocated
public void ReleaseTerrain()
{
foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
lock (m_terrains)
{
kvp.Value.Dispose();
foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
{
kvp.Value.Dispose();
}
m_terrains.Clear();
}
m_terrains.Clear();
}
// The simulator wants to set a new heightmap for the terrain.
public void SetTerrain(float[] heightMap) {
float[] localHeightMap = heightMap;
PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate()
// If there are multiple requests for changes to the same terrain between ticks,
// only do that last one.
PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
{
if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
{
@ -211,6 +217,7 @@ public sealed class BSTerrainManager
// terrain shape is created and added to the body.
// This call is most often used to update the heightMap and parameters of the terrain.
// (The above does suggest that some simplification/refactoring is in order.)
// Called during taint-time.
private void UpdateTerrain(uint id, float[] heightMap,
Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
{
@ -220,7 +227,7 @@ public sealed class BSTerrainManager
// Find high and low points of passed heightmap.
// The min and max passed in is usually the area objects can be in (maximum
// object height, for instance). The terrain wants the bounding box for the
// terrain so we replace passed min and max Z with the actual terrain min/max Z.
// terrain so replace passed min and max Z with the actual terrain min/max Z.
float minZ = float.MaxValue;
float maxZ = float.MinValue;
foreach (float height in heightMap)
@ -238,15 +245,15 @@ public sealed class BSTerrainManager
Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
BSTerrainPhys terrainPhys;
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
lock (m_terrains)
{
// There is already a terrain in this spot. Free the old and build the new.
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
BSTerrainPhys terrainPhys;
if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
{
// There is already a terrain in this spot. Free the old and build the new.
DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
// Remove old terrain from the collection
m_terrains.Remove(terrainRegionBase);
// Release any physical memory it may be using.
@ -271,35 +278,24 @@ public sealed class BSTerrainManager
// I hate doing this, but just bail
return;
}
});
}
else
{
// We don't know about this terrain so either we are creating a new terrain or
// our mega-prim child is giving us a new terrain to add to the phys world
// if this is a child terrain, calculate a unique terrain id
uint newTerrainID = id;
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount;
float[] heightMapX = heightMap;
Vector3 minCoordsX = minCoords;
Vector3 maxCoordsX = maxCoords;
DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
// Code that must happen at taint-time
PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate()
}
else
{
DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
// We don't know about this terrain so either we are creating a new terrain or
// our mega-prim child is giving us a new terrain to add to the phys world
// if this is a child terrain, calculate a unique terrain id
uint newTerrainID = id;
if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
newTerrainID = ++m_terrainCount;
DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
m_terrains.Add(terrainRegionBase, newTerrainPhys);
m_terrainModified = true;
});
}
}
}
@ -349,6 +345,7 @@ public sealed class BSTerrainManager
// with the same parameters as last time.
if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY)
return lastHeight;
m_terrainModified = false;
lastHeightTX = tX;
lastHeightTY = tY;
@ -358,23 +355,50 @@ public sealed class BSTerrainManager
int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
BSTerrainPhys physTerrain;
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
lock (m_terrains)
{
ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ);
DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
BSTerrainPhys physTerrain;
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{
ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ);
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
m_terrainModified = false;
lastHeight = ret;
return ret;
}
public float GetWaterLevelAtXYZ(Vector3 pos)
{
float ret = WATER_HEIGHT_GETHEIGHT_RET;
float tX = pos.X;
float tY = pos.Y;
Vector3 terrainBaseXYZ = Vector3.Zero;
terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
lock (m_terrains)
{
BSTerrainPhys physTerrain;
if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain))
{
ret = physTerrain.GetWaterLevelAtXYZ(pos);
}
else
{
PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
LogHeader, PhysicsScene.RegionName, tX, tY);
}
}
return ret;
}
// Although no one seems to check this, I do support combining.
public bool SupportsCombining()
{

View File

@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Something is very messed up and a crash is in our future.
return;
}
PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
ID, indicesCount, indices.Length, verticesCount, vertices.Length);
m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr,
indicesCount, indices, verticesCount, vertices),
indicesCount, indices, verticesCount, vertices),
BSPhysicsShapeType.SHAPE_MESH);
if (m_terrainShape.ptr == IntPtr.Zero)
{
@ -122,10 +124,10 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Static objects are not very massive.
BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero);
// Return the new terrain to the world of physical objects
// Put the new terrain to the world of physical objects
BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr);
// redo its bounding box now that it is in the world
// Redo its bounding box now that it is in the world
BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr);
BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr,
@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
}
public override float GetHeightAtXYZ(Vector3 pos)
public override float GetTerrainHeightAtXYZ(Vector3 pos)
{
// For the moment use the saved heightmap to get the terrain height.
// TODO: raycast downward to find the true terrain below the position.
@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
return ret;
}
// The passed position is relative to the base of the region.
public override float GetWaterLevelAtXYZ(Vector3 pos)
{
return PhysicsScene.SimpleWaterLevel;
}
// Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
// Return 'true' if successfully created.
public static bool ConvertHeightmapToMesh(
@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
// Simple mesh creation which assumes magnification == 1.
// TODO: do a more general solution that scales, adds new vertices and smoothes the result.
// Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
// from zero to <= sizeX). The triangle indices are then generated as two triangles
// per heightmap point. There are sizeX by sizeY of these squares. The extra row and
// column of vertices are used to complete the triangles of the last row and column
// of the heightmap.
try
{
// One vertice per heightmap value plus the vertices off the top and bottom edge.
@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
float magY = (float)sizeY / extentY;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region.
for (int yy = 0; yy <= sizeY; yy++)
{
for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times
for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
{
int offset = yy * sizeX + xx;
// Extend the height from the height from the last row or column
// Extend the height with the height from the last row or column
if (yy == sizeY) offset -= sizeX;
if (xx == sizeX) offset -= 1;
float height = heightMap[offset];
minHeight = Math.Min(minHeight, height);
vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
vertices[verticesCount + 2] = height + extentBase.Z;
@ -217,14 +232,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
}
verticesCount = verticesCount / 3;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
BSScene.DetailLogZero, verticesCount);
for (int yy = 0; yy < sizeY; yy++)
{
for (int xx = 0; xx < sizeX; xx++)
{
int offset = yy * sizeX + xx;
int offset = yy * (sizeX + 1) + xx;
// Each vertices is presumed to be the upper left corner of a box of two triangles
indices[indicesCount + 0] = offset;
indices[indicesCount + 1] = offset + 1;
@ -235,8 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
indicesCount += 6;
}
}
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG
LogHeader, indicesCount); // DEBUG
ret = true;
}
catch (Exception e)

View File

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

View File

@ -321,6 +321,9 @@ namespace OpenSim.Region.Physics.Meshing
if (primShape.SculptData.Length <= 0)
{
// XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this
// method twice - once before it has loaded sculpt data from the asset service and once afterwards.
// The first time will always call with unloaded SculptData if this needs to be uploaded.
// m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName);
return false;
}

View File

@ -3367,6 +3367,11 @@ Console.WriteLine(" JointCreateFixed");
_pbs.SculptData = new byte[asset.Data.Length];
asset.Data.CopyTo(_pbs.SculptData, 0);
// m_assetFailed = false;
// m_log.DebugFormat(
// "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}",
// _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name);
m_taintshape = true;
_parent_scene.AddPhysicsActorTaint(this);
}

View File

@ -217,10 +217,10 @@
; to false if you have compatibility problems.
;CacheSculptMaps = true
; Choose one of the physics engines below
; OpenDynamicsEngine is by some distance the most developed physics engine
; basicphysics effectively does not model physics at all, making all objects phantom
; Choose one of the physics engines below.
; OpenDynamicsEngine is by some distance the most developed physics engine.
; BulletSim is a high performance, up-and-coming physics engine.
; basicphysics effectively does not model physics at all, making all objects phantom.
physics = OpenDynamicsEngine
;physics = basicphysics
;physics = POS
@ -904,15 +904,18 @@
[BulletSim]
; World parameters
DefaultFriction = 0.50
DefaultFriction = 0.20
DefaultDensity = 10.000006836
DefaultRestitution = 0.0
Gravity = -9.80665
TerrainFriction = 0.50
TerrainHitFriction = 0.8
TerrainFriction = 0.30
TerrainHitFraction = 0.8
TerrainRestitution = 0
TerrainCollisionMargin = 0.04
AvatarFriction = 0.2
AvatarStandingFriction = 0.99
AvatarRestitution = 0.0
AvatarDensity = 60.0
AvatarCapsuleWidth = 0.6
@ -926,27 +929,15 @@
LinearDamping = 0.0
AngularDamping = 0.0
DeactivationTime = 0.2
LinearSleepingThreshold = 0.8
AngularSleepingThreshold = 1.0
CcdMotionThreshold = 0.0
CcdSweptSphereRadius = 0.0
ContactProcessingThreshold = 0.1
; If setting a pool size, also disable dynamic allocation (default pool size is 4096 with dynamic alloc)
MaxPersistantManifoldPoolSize = 0
ShouldDisableContactPoolDynamicAllocation = False
ShouldForceUpdateAllAabbs = False
ShouldRandomizeSolverOrder = True
ShouldSplitSimulationIslands = True
ShouldEnableFrictionCaching = False
NumberOfSolverIterations = 0
CollisionMargin = 0.04
; Linkset constraint parameters
LinkImplementation = 1 ; 0=constraint, 1=compound
LinkConstraintUseFrameOffset = False
LinkConstraintEnableTransMotor = True
LinkConstraintTransMotorMaxVel = 5.0
LinkConstraintTransMotorMaxForce = 0.1
; Whether to mesh sculpties
MeshSculptedPrim = true

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.