Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

TeleportWork
Diva Canto 2013-07-30 17:27:32 -07:00
commit 590a8b0315
10 changed files with 225 additions and 92 deletions

View File

@ -27,6 +27,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring
/// </summary> /// </summary>
public class SimExtraStatsCollector : BaseStatsCollector public class SimExtraStatsCollector : BaseStatsCollector
{ {
private long abnormalClientThreadTerminations;
// private long assetsInCache; // private long assetsInCache;
// private long texturesInCache; // private long texturesInCache;
// private long assetCacheMemoryUsage; // private long assetCacheMemoryUsage;
@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring
private volatile float activeScripts; private volatile float activeScripts;
private volatile float scriptLinesPerSecond; private volatile float scriptLinesPerSecond;
/// <summary>
/// Number of times that a client thread terminated because of an exception
/// </summary>
public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } }
// /// <summary> // /// <summary>
// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
// /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these
@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring
private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
= new Dictionary<UUID, PacketQueueStatsCollector>(); = new Dictionary<UUID, PacketQueueStatsCollector>();
public void AddAbnormalClientThreadTermination()
{
abnormalClientThreadTerminations++;
}
// public void AddAsset(AssetBase asset) // public void AddAsset(AssetBase asset)
// { // {
// assetsInCache++; // assetsInCache++;
@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("CONNECTION STATISTICS"); sb.Append("CONNECTION STATISTICS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append(
string.Format( List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
"Abnormal client thread terminations: {0}" + Environment.NewLine,
abnormalClientThreadTerminations)); sb.AppendFormat(
"Client logouts due to no data receive timeout: {0}\n\n",
stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
// sb.Append(Environment.NewLine); // sb.Append(Environment.NewLine);
// sb.Append("INVENTORY STATISTICS"); // sb.Append("INVENTORY STATISTICS");
@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine,
// InventoryServiceRetrievalFailures)); // InventoryServiceRetrievalFailures));
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("FRAME STATISTICS"); sb.Append("SAMPLE FRAME STATISTICS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);
sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
sb.Append(Environment.NewLine); sb.Append(Environment.NewLine);

View File

@ -271,7 +271,7 @@ namespace OpenSim.Framework.Monitoring
// Stat name is not unique across category/container/shortname key. // Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests // XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM. // in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container)) if (TryGetStatParents(stat, out category, out container))
return false; return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
@ -307,7 +307,7 @@ namespace OpenSim.Framework.Monitoring
lock (RegisteredStats) lock (RegisteredStats)
{ {
if (!TryGetStat(stat, out category, out container)) if (!TryGetStatParents(stat, out category, out container))
return false; return false;
newContainer = new SortedDictionary<string, Stat>(container); newContainer = new SortedDictionary<string, Stat>(container);
@ -323,12 +323,67 @@ namespace OpenSim.Framework.Monitoring
} }
} }
public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats) public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
{ {
return RegisteredStats.TryGetValue(category, out stats); stat = null;
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!TryGetStatsForCategory(category, out categoryStats))
return false;
SortedDictionary<string, Stat> containerStats;
if (!categoryStats.TryGetValue(container, out containerStats))
return false;
return containerStats.TryGetValue(statShortName, out stat);
}
} }
public static bool TryGetStat( public static bool TryGetStatsForCategory(
string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
{
lock (RegisteredStats)
return RegisteredStats.TryGetValue(category, out stats);
}
/// <summary>
/// Get the same stat for each container in a given category.
/// </summary>
/// <returns>
/// The stats if there were any to fetch. Otherwise null.
/// </returns>
/// <param name='category'></param>
/// <param name='statShortName'></param>
public static List<Stat> GetStatsFromEachContainer(string category, string statShortName)
{
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!RegisteredStats.TryGetValue(category, out categoryStats))
return null;
List<Stat> stats = null;
foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values)
{
if (containerStats.ContainsKey(statShortName))
{
if (stats == null)
stats = new List<Stat>();
stats.Add(containerStats[statShortName]);
}
}
return stats;
}
}
public static bool TryGetStatParents(
Stat stat, Stat stat,
out SortedDictionary<string, SortedDictionary<string, Stat>> category, out SortedDictionary<string, SortedDictionary<string, Stat>> category,
out SortedDictionary<string, Stat> container) out SortedDictionary<string, Stat> container)

View File

@ -67,11 +67,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
m_udpServer.AddScene(scene); m_udpServer.AddScene(scene);
StatsManager.RegisterStat(
new Stat(
"ClientLogoutsDueToNoReceives",
"Number of times a client has been logged out because no packets were received before the timeout.",
"",
"",
"clientstack",
scene.Name,
StatType.Pull,
MeasuresOfInterest.None,
stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
StatVerbosity.Debug));
StatsManager.RegisterStat( StatsManager.RegisterStat(
new Stat( new Stat(
"IncomingUDPReceivesCount", "IncomingUDPReceivesCount",
"Number of UDP receives performed", "Number of UDP receives performed",
"Number of UDP receives performed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -84,7 +97,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
new Stat( new Stat(
"IncomingPacketsProcessedCount", "IncomingPacketsProcessedCount",
"Number of inbound LL protocol packets processed", "Number of inbound LL protocol packets processed",
"Number of inbound LL protocol packets processed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -97,7 +110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
new Stat( new Stat(
"OutgoingUDPSendsCount", "OutgoingUDPSendsCount",
"Number of UDP sends performed", "Number of UDP sends performed",
"Number of UDP sends performed", "",
"", "",
"clientstack", "clientstack",
scene.Name, scene.Name,
@ -149,6 +162,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
public const int MTU = 1400; public const int MTU = 1400;
/// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
public int ClientLogoutsDueToNoReceives { get; private set; }
/// <summary> /// <summary>
/// Default packet debug level given to new clients /// Default packet debug level given to new clients
/// </summary> /// </summary>
@ -1046,7 +1062,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Fire this out on a different thread so that we don't hold up outgoing packet processing for // Fire this out on a different thread so that we don't hold up outgoing packet processing for
// everybody else if this is being called due to an ack timeout. // everybody else if this is being called due to an ack timeout.
// This is the same as processing as the async process of a logout request. // This is the same as processing as the async process of a logout request.
Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); Util.FireAndForget(o => DeactivateClientDueToTimeout(client, timeoutTicks));
return; return;
} }
@ -1770,18 +1786,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// regular client pings. /// regular client pings.
/// </remarks> /// </remarks>
/// <param name='client'></param> /// <param name='client'></param>
private void DeactivateClientDueToTimeout(LLClientView client) /// <param name='timeoutTicks'></param>
private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
{ {
lock (client.CloseSyncLock) lock (client.CloseSyncLock)
{ {
m_log.WarnFormat( ClientLogoutsDueToNoReceives++;
"[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); m_log.WarnFormat(
"[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, m_scene.Name);
if (!client.SceneAgent.IsChildAgent) if (!client.SceneAgent.IsChildAgent)
client.Kick("Simulator logged you out due to connection timeout"); client.Kick("Simulator logged you out due to connection timeout.");
client.CloseWithoutChecks(); client.CloseWithoutChecks();
} }

View File

@ -31,10 +31,10 @@ using System.Reflection;
using System.Text; using System.Text;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.CoreModules;
using OpenSim.Region.Framework; using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.CoreModules;
using Mono.Addins; using Mono.Addins;
using Nini.Config; using Nini.Config;
@ -49,6 +49,10 @@ public class ExtendedPhysics : INonSharedRegionModule
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[EXTENDED PHYSICS]"; private static string LogHeader = "[EXTENDED PHYSICS]";
// Since BulletSim is a plugin, this these values aren't defined easily in one place.
// This table must coorespond to an identical table in BSScene.
public const string PhysFunctSetLinksetType = "BulletSim.SetLinksetType";
private IConfig Configuration { get; set; } private IConfig Configuration { get; set; }
private bool Enabled { get; set; } private bool Enabled { get; set; }
private Scene BaseScene { get; set; } private Scene BaseScene { get; set; }
@ -143,13 +147,6 @@ public class ExtendedPhysics : INonSharedRegionModule
[ScriptConstant] [ScriptConstant]
public static int PHYS_CENTER_OF_MASS = 1 << 0; public static int PHYS_CENTER_OF_MASS = 1 << 0;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_CONSTRAINT = 1;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_COMPOUND = 2;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_MANUAL = 3;
[ScriptInvocation] [ScriptInvocation]
public string physGetEngineType(UUID hostID, UUID scriptID) public string physGetEngineType(UUID hostID, UUID scriptID)
{ {
@ -163,9 +160,50 @@ public class ExtendedPhysics : INonSharedRegionModule
return ret; return ret;
} }
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_CONSTRAINT = 0;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_COMPOUND = 1;
[ScriptConstant]
public static int PHYS_LINKSET_TYPE_MANUAL = 2;
[ScriptInvocation] [ScriptInvocation]
public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType) public void physSetLinksetType(UUID hostID, UUID scriptID, int linksetType)
{ {
if (!Enabled) return;
// The part that is requesting the change.
SceneObjectPart requestingPart = BaseScene.GetSceneObjectPart(hostID);
if (requestingPart != null)
{
// The change is always made to the root of a linkset.
SceneObjectGroup containingGroup = requestingPart.ParentGroup;
SceneObjectPart rootPart = containingGroup.RootPart;
if (rootPart != null)
{
Physics.Manager.PhysicsActor rootPhysActor = rootPart.PhysActor;
if (rootPhysActor != null)
{
rootPhysActor.Extension(PhysFunctSetLinksetType, linksetType);
}
else
{
m_log.WarnFormat("{0} physSetLinksetType: root part does not have a physics actor. rootName={1}, hostID={2}",
LogHeader, rootPart.Name, hostID);
}
}
else
{
m_log.WarnFormat("{0} physSetLinksetType: root part does not exist. RequestingPartName={1}, hostID={2}",
LogHeader, requestingPart.Name, hostID);
}
}
else
{
m_log.WarnFormat("{0} physSetLinsetType: cannot find script object in scene. hostID={1}", LogHeader, hostID);
}
} }
} }
} }

View File

@ -75,7 +75,7 @@ public sealed class BSCharacter : BSPhysObject
RawVelocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
Friction = BSParam.AvatarStandingFriction; Friction = BSParam.AvatarStandingFriction;
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; Density = BSParam.AvatarDensity;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero, // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values. // replace with the default values.

View File

@ -589,10 +589,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_vehicleMass = ControllingPrim.TotalMass; m_vehicleMass = ControllingPrim.TotalMass;
// Friction affects are handled by this vehicle code // Friction affects are handled by this vehicle code
m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction); // m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution); // m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
// ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction); ControllingPrim.Linkset.SetPhysicalFriction(BSParam.VehicleFriction);
// ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution); ControllingPrim.Linkset.SetPhysicalRestitution(BSParam.VehicleRestitution);
// Moderate angular movement introduced by Bullet. // Moderate angular movement introduced by Bullet.
// TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
@ -602,21 +602,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor); m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
// Vehicles report collision events so we know when it's on the ground // Vehicles report collision events so we know when it's on the ground
m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); // m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
// ControllingPrim.Linkset.SetPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS); ControllingPrim.Linkset.AddToPhysicalCollisionFlags(CollisionFlags.BS_VEHICLE_COLLISIONS);
Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass); // Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor; // ControllingPrim.Inertia = inertia * BSParam.VehicleInertiaFactor;
m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia); // m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody); // m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
// ControllingPrim.Linkset.ComputeLocalInertia(BSParam.VehicleInertiaFactor); ControllingPrim.Linkset.ComputeAndSetLocalInertia(BSParam.VehicleInertiaFactor, m_vehicleMass);
// Set the gravity for the vehicle depending on the buoyancy // Set the gravity for the vehicle depending on the buoyancy
// TODO: what should be done if prim and vehicle buoyancy differ? // TODO: what should be done if prim and vehicle buoyancy differ?
m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy); m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
// The actual vehicle gravity is set to zero in Bullet so we can do all the application of same. // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero); // m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
// ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero); ControllingPrim.Linkset.SetPhysicalGravity(Vector3.Zero);
VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}", VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity, ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
@ -1121,7 +1121,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
m_VhoverTargetHeight = m_VhoverHeight; m_VhoverTargetHeight = m_VhoverHeight;
} }
if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
{ {
// If body is already heigher, use its height as target height // If body is already heigher, use its height as target height
@ -1170,7 +1169,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
verticalError, verticalCorrection); verticalError, verticalCorrection);
} }
} }
} }
@ -1357,6 +1355,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
private void ComputeAngularTurning(float pTimestep) private void ComputeAngularTurning(float pTimestep)
{ {
// The user wants this many radians per second angular change? // The user wants this many radians per second angular change?
Vector3 origVehicleRotationalVelocity = VehicleRotationalVelocity; // DEBUG DEBUG
Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation); Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV); Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
@ -1369,20 +1368,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// TODO: This is here because this is where ODE put it but documentation says it // TODO: This is here because this is where ODE put it but documentation says it
// is a linear effect. Where should this check go? // is a linear effect. Where should this check go?
//if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
// { // {
// angularMotorContributionV.X = 0f; // angularMotorContributionV.X = 0f;
// angularMotorContributionV.Y = 0f; // angularMotorContributionV.Y = 0f;
// } // }
// Reduce any velocity by friction. // Reduce any velocity by friction.
Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep); Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
angularMotorContributionV -= (currentAngularV * frictionFactorW); angularMotorContributionV -= (currentAngularV * frictionFactorW);
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation; Vector3 angularMotorContributionW = angularMotorContributionV * VehicleOrientation;
VehicleRotationalVelocity += angularMotorContributionW;
VDetailLog("{0}, MoveAngular,angularTurning,curAngVelV={1},origVehRotVel={2},vehRotVel={3},frictFact={4}, angContribV={5},angContribW={6}",
ControllingPrim.LocalID, currentAngularV, origVehicleRotationalVelocity, VehicleRotationalVelocity, frictionFactorW, angularMotorContributionV, angularMotorContributionW);
VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV);
} }
// From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
@ -1409,7 +1408,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Flipping what was originally a timescale into a speed variable and then multiplying it by 2 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
// since only computing half the distance between the angles. // since only computing half the distance between the angles.
float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f; float verticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
// Make a prediction of where the up axis will be when this is applied rather then where it is now as // Make a prediction of where the up axis will be when this is applied rather then where it is now as
// this makes for a smoother adjustment and less fighting between the various forces. // this makes for a smoother adjustment and less fighting between the various forces.
@ -1419,12 +1418,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ); Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
// Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed; Vector3 vertContributionV = torqueVector * verticalAttractionSpeed * verticalAttractionSpeed;
VehicleRotationalVelocity += vertContributionV; VehicleRotationalVelocity += vertContributionV;
VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},PredictedUp={2},torqueVector={3},contrib={4}", VDetailLog("{0}, MoveAngular,verticalAttraction,vertAttrSpeed={1},upAxis={2},PredictedUp={3},torqueVector={4},contrib={5}",
ControllingPrim.LocalID, ControllingPrim.LocalID,
verticalAttractionSpeed,
vehicleUpAxis, vehicleUpAxis,
predictedUp, predictedUp,
torqueVector, torqueVector,
@ -1437,37 +1437,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
// Create a rotation that is only the vehicle's rotation around Z // Create a rotation that is only the vehicle's rotation around Z
Vector3 currentEuler = Vector3.Zero; Vector3 currentEulerW = Vector3.Zero;
VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z); VehicleOrientation.GetEulerAngles(out currentEulerW.X, out currentEulerW.Y, out currentEulerW.Z);
Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z); Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEulerW.Z);
// Create the axis that is perpendicular to the up vector and the rotated up vector. // Create the axis that is perpendicular to the up vector and the rotated up vector.
Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation); Vector3 differenceAxisW = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
// Compute the angle between those to vectors. // Compute the angle between those to vectors.
double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation))); double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
// 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
// Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied. // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
// TODO: add 'efficiency'. // TODO: add 'efficiency'.
differenceAngle /= m_verticalAttractionTimescale; // differenceAngle /= m_verticalAttractionTimescale;
// Create the quaterian representing the correction angle // Create the quaterian representing the correction angle
Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle); Quaternion correctionRotationW = Quaternion.CreateFromAxisAngle(differenceAxisW, (float)differenceAngle);
// Turn that quaternion into Euler values to make it into velocities to apply. // Turn that quaternion into Euler values to make it into velocities to apply.
Vector3 vertContributionV = Vector3.Zero; Vector3 vertContributionW = Vector3.Zero;
correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z); correctionRotationW.GetEulerAngles(out vertContributionW.X, out vertContributionW.Y, out vertContributionW.Z);
vertContributionV *= -1f; vertContributionW *= -1f;
vertContributionW /= m_verticalAttractionTimescale;
VehicleRotationalVelocity += vertContributionV; VehicleRotationalVelocity += vertContributionW;
VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}", VDetailLog("{0}, MoveAngular,verticalAttraction,upAxis={1},diffAxis={2},diffAng={3},corrRot={4},contrib={5}",
ControllingPrim.LocalID, ControllingPrim.LocalID,
vehicleUpAxis, vehicleUpAxis,
differenceAxis, differenceAxisW,
differenceAngle, differenceAngle,
correctionRotation, correctionRotationW,
vertContributionV); vertContributionW);
break; break;
} }
case 2: case 2:

View File

@ -309,16 +309,18 @@ public abstract class BSLinkset
} }
); );
} }
public virtual void ComputeLocalInertia(OMV.Vector3 inertiaFactor) public virtual void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
{ {
ForEachMember((member) => ForEachMember((member) =>
{ {
if (member.PhysBody.HasPhysicalBody) if (member.PhysBody.HasPhysicalBody)
{ {
OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, member.Mass); OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(member.PhysShape.physShapeInfo, linksetMass);
member.Inertia = inertia * inertiaFactor; member.Inertia = inertia * inertiaFactor;
m_physicsScene.PE.SetMassProps(member.PhysBody, member.Mass, member.Inertia); m_physicsScene.PE.SetMassProps(member.PhysBody, linksetMass, member.Inertia);
m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody); m_physicsScene.PE.UpdateInertiaTensor(member.PhysBody);
DetailLog("{0},BSLinkset.ComputeAndSetLocalInertia,m.mass={1}, inertia={2}", member.LocalID, linksetMass, member.Inertia);
} }
return false; // 'false' says to continue looping return false; // 'false' says to continue looping
} }
@ -334,6 +336,16 @@ public abstract class BSLinkset
} }
); );
} }
public virtual void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
{
ForEachMember((member) =>
{
if (member.PhysBody.HasPhysicalBody)
m_physicsScene.PE.AddToCollisionFlags(member.PhysBody, collFlags);
return false; // 'false' says to continue looping
}
);
}
public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) public virtual void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
{ {
ForEachMember((member) => ForEachMember((member) =>

View File

@ -61,11 +61,11 @@ public sealed class BSLinksetCompound : BSLinkset
if (LinksetRoot.PhysBody.HasPhysicalBody) if (LinksetRoot.PhysBody.HasPhysicalBody)
m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity); m_physicsScene.PE.SetGravity(LinksetRoot.PhysBody, gravity);
} }
public override void ComputeLocalInertia(OMV.Vector3 inertiaFactor) public override void ComputeAndSetLocalInertia(OMV.Vector3 inertiaFactor, float linksetMass)
{ {
OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, LinksetRoot.Mass); OMV.Vector3 inertia = m_physicsScene.PE.CalculateLocalInertia(LinksetRoot.PhysShape.physShapeInfo, linksetMass);
LinksetRoot.Inertia = inertia * inertiaFactor; LinksetRoot.Inertia = inertia * inertiaFactor;
m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, LinksetRoot.Mass, LinksetRoot.Inertia); m_physicsScene.PE.SetMassProps(LinksetRoot.PhysBody, linksetMass, LinksetRoot.Inertia);
m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody); m_physicsScene.PE.UpdateInertiaTensor(LinksetRoot.PhysBody);
} }
public override void SetPhysicalCollisionFlags(CollisionFlags collFlags) public override void SetPhysicalCollisionFlags(CollisionFlags collFlags)
@ -73,6 +73,11 @@ public sealed class BSLinksetCompound : BSLinkset
if (LinksetRoot.PhysBody.HasPhysicalBody) if (LinksetRoot.PhysBody.HasPhysicalBody)
m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags); m_physicsScene.PE.SetCollisionFlags(LinksetRoot.PhysBody, collFlags);
} }
public override void AddToPhysicalCollisionFlags(CollisionFlags collFlags)
{
if (LinksetRoot.PhysBody.HasPhysicalBody)
m_physicsScene.PE.AddToCollisionFlags(LinksetRoot.PhysBody, collFlags);
}
public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags) public override void RemoveFromPhysicalCollisionFlags(CollisionFlags collFlags)
{ {
if (LinksetRoot.PhysBody.HasPhysicalBody) if (LinksetRoot.PhysBody.HasPhysicalBody)

View File

@ -463,7 +463,7 @@ public static class BSParam
// Density is passed around as 100kg/m3. This scales that to 1kg/m3. // Density is passed around as 100kg/m3. This scales that to 1kg/m3.
// Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well // Reduce by power of 100 because Bullet doesn't seem to handle objects with large mass very well
new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)", new ParameterDefn<float>("DensityScaleFactor", "Conversion for simulator/viewer density (100kg/m3) to physical density (1kg/m3)",
0.0001f ), 0.01f ),
new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing", new ParameterDefn<float>("PID_D", "Derivitive factor for motion smoothing",
2200f ), 2200f ),
@ -474,8 +474,9 @@ public static class BSParam
0.2f, 0.2f,
(s) => { return DefaultFriction; }, (s) => { return DefaultFriction; },
(s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ), (s,v) => { DefaultFriction = v; s.UnmanagedParams[0].defaultFriction = v; } ),
// For historical reasons, the viewer and simulator multiply the density by 100
new ParameterDefn<float>("DefaultDensity", "Density for new objects" , new ParameterDefn<float>("DefaultDensity", "Density for new objects" ,
10.000006836f, // Aluminum g/cm3 1000.0006836f, // Aluminum g/cm3 * 100
(s) => { return DefaultDensity; }, (s) => { return DefaultDensity; },
(s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ), (s,v) => { DefaultDensity = v; s.UnmanagedParams[0].defaultDensity = v; } ),
new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" , new ParameterDefn<float>("DefaultRestitution", "Bouncyness of an object" ,
@ -555,8 +556,9 @@ public static class BSParam
0.95f ), 0.95f ),
new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run", new ParameterDefn<float>("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
1.3f ), 1.3f ),
new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation.", // For historical reasons, density is reported * 100
3.5f) , new ParameterDefn<float>("AvatarDensity", "Density of an avatar. Changed on avatar recreation. Scaled times 100.",
3500f) , // 3.5 * 100
new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.", new ParameterDefn<float>("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
0f ), 0f ),
new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule", new ParameterDefn<float>("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
@ -608,9 +610,8 @@ public static class BSParam
0.0f ), 0.0f ),
new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)", new ParameterDefn<float>("VehicleRestitution", "Bouncyness factor for vehicles (0.0 - 1.0)",
0.0f ), 0.0f ),
// Turn off fudge with DensityScaleFactor = 0.0001. Value used to be 0.2f;
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)", new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
1.0f ), 0.2f ),
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.", new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
60.0f ), 60.0f ),
new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect", new ParameterDefn<bool>("VehicleEnableLinearDeflection", "Turn on/off vehicle linear deflection effect",

View File

@ -187,10 +187,23 @@ public abstract class BSPhysObject : PhysicsActor
MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
Friction = matAttrib.friction; Friction = matAttrib.friction;
Restitution = matAttrib.restitution; Restitution = matAttrib.restitution;
Density = matAttrib.density / BSParam.DensityScaleFactor; Density = matAttrib.density;
// DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density); // DetailLog("{0},{1}.SetMaterial,Mat={2},frict={3},rest={4},den={5}", LocalID, TypeName, Material, Friction, Restitution, Density);
} }
public override float Density
{
get
{
return base.Density;
}
set
{
DetailLog("{0},BSPhysObject.Density,set,den={1}", LocalID, value);
base.Density = value;
}
}
// Stop all physical motion. // Stop all physical motion.
public abstract void ZeroMotion(bool inTaintTime); public abstract void ZeroMotion(bool inTaintTime);
public abstract void ZeroAngularMotion(bool inTaintTime); public abstract void ZeroAngularMotion(bool inTaintTime);