BulletSim: Fix linkset crash. Caused by the different body and shape

pointers at runtime and at taint-time. Now passes the body into the
    taint.
Vehicles zero inertia when active to eliminate Bullet's contribution
    to vehicle motion.
connector_plugin
Robert Adams 2012-09-27 08:23:29 -07:00
parent 4589bc84a3
commit f82b903dee
9 changed files with 182 additions and 94 deletions

View File

@ -58,10 +58,22 @@ public class BS6DofConstraint : BSConstraint
m_world = world; m_world = world;
m_body1 = obj1; m_body1 = obj1;
m_body2 = obj2; m_body2 = obj2;
if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero)
{
world.scene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
"[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
world.scene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
"[BULLETSIM 6DOF CONSTRAINT]", world.worldID,
obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X"));
}
else
{
m_constraint = new BulletConstraint( m_constraint = new BulletConstraint(
BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr, BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
joinPoint, joinPoint,
useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
}
m_enabled = true; m_enabled = true;
} }

View File

@ -54,18 +54,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSDynamics public class BSDynamics
{ {
private int frcount = 0; // Used to limit dynamics debug output to private BSScene PhysicsScene { get; set; }
// every 100th frame // the prim this dynamic controller belongs to
private BSPrim Prim { get; set; }
private BSScene m_physicsScene;
private BSPrim m_prim; // the prim this dynamic controller belongs to
// Vehicle properties // Vehicle properties
private Vehicle m_type = Vehicle.TYPE_NONE; // If a 'VEHICLE', and what kind public Vehicle Type { get; set; }
public Vehicle Type
{
get { return m_type; }
}
// private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier // private Quaternion m_referenceFrame = Quaternion.Identity; // Axis modifier
private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings: private VehicleFlag m_flags = (VehicleFlag) 0; // Boolean settings:
// HOVER_TERRAIN_ONLY // HOVER_TERRAIN_ONLY
@ -126,14 +121,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin
public BSDynamics(BSScene myScene, BSPrim myPrim) public BSDynamics(BSScene myScene, BSPrim myPrim)
{ {
m_physicsScene = myScene; PhysicsScene = myScene;
m_prim = myPrim; Prim = myPrim;
m_type = Vehicle.TYPE_NONE; Type = Vehicle.TYPE_NONE;
}
// Return 'true' if this vehicle is doing vehicle things
public bool IsActive
{
get { return Type != Vehicle.TYPE_NONE; }
} }
internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
{ {
VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@ -232,7 +233,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
{ {
VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.ANGULAR_FRICTION_TIMESCALE: case Vehicle.ANGULAR_FRICTION_TIMESCALE:
@ -267,7 +268,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
{ {
VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue);
switch (pParam) switch (pParam)
{ {
case Vehicle.REFERENCE_FRAME: case Vehicle.REFERENCE_FRAME:
@ -281,7 +282,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessVehicleFlags(int pParam, bool remove) internal void ProcessVehicleFlags(int pParam, bool remove)
{ {
VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove);
VehicleFlag parm = (VehicleFlag)pParam; VehicleFlag parm = (VehicleFlag)pParam;
if (remove) if (remove)
{ {
@ -301,9 +302,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
internal void ProcessTypeChange(Vehicle pType) internal void ProcessTypeChange(Vehicle pType)
{ {
VDetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType);
// Set Defaults For Type // Set Defaults For Type
m_type = pType; Type = pType;
switch (pType) switch (pType)
{ {
case Vehicle.TYPE_NONE: case Vehicle.TYPE_NONE:
@ -465,26 +466,37 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
}//end SetDefaultsForType }//end SetDefaultsForType
// Some of the properties of this prim may have changed.
// Do any updating needed for a vehicle
public void Refresh()
{
if (Type == Vehicle.TYPE_NONE) return;
// Set the prim's inertia to zero. The vehicle code handles that and this
// removes the torque action introduced by Bullet.
Vector3 inertia = Vector3.Zero;
BulletSimAPI.SetMassProps2(Prim.BSBody.ptr, Prim.MassRaw, inertia);
BulletSimAPI.UpdateInertiaTensor2(Prim.BSBody.ptr);
}
// One step of the vehicle properties for the next 'pTimestep' seconds. // One step of the vehicle properties for the next 'pTimestep' seconds.
internal void Step(float pTimestep) internal void Step(float pTimestep)
{ {
if (m_type == Vehicle.TYPE_NONE) return; if (!IsActive) return;
frcount++; // used to limit debug comment output
if (frcount > 100)
frcount = 0;
MoveLinear(pTimestep); MoveLinear(pTimestep);
MoveAngular(pTimestep); MoveAngular(pTimestep);
LimitRotation(pTimestep); LimitRotation(pTimestep);
// remember the position so next step we can limit absolute movement effects // remember the position so next step we can limit absolute movement effects
m_lastPositionVector = m_prim.Position; m_lastPositionVector = Prim.Position;
VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); Prim.LocalID, Prim.Position, Prim.Force, Prim.Velocity, Prim.RotationalVelocity);
}// end Step }// end Step
// Apply the effect of the linear motor.
// Also does hover and float.
private void MoveLinear(float pTimestep) private void MoveLinear(float pTimestep)
{ {
// m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates // m_linearMotorDirection is the direction we are moving relative to the vehicle coordinates
@ -520,18 +532,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_linearMotorDirection *= keepfraction; m_linearMotorDirection *= keepfraction;
VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}", VDetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},notDecay={4},dir={5},vel={6}",
m_prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector); Prim.LocalID, origDir, origVel, addAmount, keepfraction, m_linearMotorDirection, m_lastLinearVelocityVector);
} }
else else
{ {
// if what remains of direction is very small, zero it. // if what remains of direction is very small, zero it.
m_linearMotorDirection = Vector3.Zero; m_linearMotorDirection = Vector3.Zero;
m_lastLinearVelocityVector = Vector3.Zero; m_lastLinearVelocityVector = Vector3.Zero;
VDetailLog("{0},MoveLinear,zeroed", m_prim.LocalID); VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID);
} }
// convert requested object velocity to object relative vector // convert requested object velocity to object relative vector
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
m_newVelocity = m_lastLinearVelocityVector * rotq; m_newVelocity = m_lastLinearVelocityVector * rotq;
// Add the various forces into m_dir which will be our new direction vector (velocity) // Add the various forces into m_dir which will be our new direction vector (velocity)
@ -539,7 +551,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// add Gravity and Buoyancy // add Gravity and Buoyancy
// There is some gravity, make a gravity force vector that is applied after object velocity. // There is some gravity, make a gravity force vector that is applied after object velocity.
// m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
Vector3 grav = m_prim.PhysicsScene.DefaultGravity * (m_prim.Mass * (1f - m_VehicleBuoyancy)); Vector3 grav = Prim.PhysicsScene.DefaultGravity * (Prim.Mass * (1f - m_VehicleBuoyancy));
/* /*
* RA: Not sure why one would do this * RA: Not sure why one would do this
@ -548,11 +560,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity
*/ */
Vector3 pos = m_prim.Position; Vector3 pos = Prim.Position;
// 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); // 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. // If below the terrain, move us above the ground a little.
float terrainHeight = m_prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
// Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset.
// Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. // Need to add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
// Vector3 rotatedSize = m_prim.Size * m_prim.Orientation; // Vector3 rotatedSize = m_prim.Size * m_prim.Orientation;
@ -560,8 +572,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
if (pos.Z < terrainHeight) if (pos.Z < terrainHeight)
{ {
pos.Z = terrainHeight + 2; pos.Z = terrainHeight + 2;
m_prim.Position = pos; Prim.Position = pos;
VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", m_prim.LocalID, terrainHeight, pos); VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos);
} }
// Check if hovering // Check if hovering
@ -570,7 +582,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// We should hover, get the target height // We should hover, get the target height
if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
{ {
m_VhoverTargetHeight = m_prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight;
} }
if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
{ {
@ -590,7 +602,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2)
{ {
m_prim.Position = pos; Prim.Position = pos;
} }
} }
else else
@ -608,7 +620,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
} }
VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight);
} }
Vector3 posChange = pos - m_lastPositionVector; Vector3 posChange = pos - m_lastPositionVector;
@ -642,9 +654,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
if (changed) if (changed)
{ {
m_prim.Position = pos; Prim.Position = pos;
VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
m_prim.LocalID, m_BlockingEndPoint, posChange, pos); Prim.LocalID, m_BlockingEndPoint, posChange, pos);
} }
} }
@ -664,7 +676,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
float postemp = (pos.Z - terrainHeight); float postemp = (pos.Z - terrainHeight);
if (postemp > 2.5f) if (postemp > 2.5f)
grav.Z = (float)(grav.Z * 1.037125); grav.Z = (float)(grav.Z * 1.037125);
VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav); VDetailLog("{0},MoveLinear,limitMotorUp,grav={1}", Prim.LocalID, grav);
} }
if ((m_flags & (VehicleFlag.NO_X)) != 0) if ((m_flags & (VehicleFlag.NO_X)) != 0)
m_newVelocity.X = 0; m_newVelocity.X = 0;
@ -674,7 +686,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_newVelocity.Z = 0; m_newVelocity.Z = 0;
// Apply velocity // Apply velocity
m_prim.Velocity = m_newVelocity; Prim.Velocity = m_newVelocity;
// apply gravity force // apply gravity force
// Why is this set here? The physics engine already does gravity. // Why is this set here? The physics engine already does gravity.
// m_prim.AddForce(grav, false); // m_prim.AddForce(grav, false);
@ -684,10 +696,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastLinearVelocityVector *= keepFraction; m_lastLinearVelocityVector *= keepFraction;
VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}", VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},grav={4},1Mdecay={5}",
m_prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction); Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, grav, keepFraction);
} // end MoveLinear() } // end MoveLinear()
// Apply the effect of the angular motor.
private void MoveAngular(float pTimestep) private void MoveAngular(float pTimestep)
{ {
// m_angularMotorDirection // angular velocity requested by LSL motor // m_angularMotorDirection // angular velocity requested by LSL motor
@ -699,7 +712,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// m_lastAngularVelocity // what was last applied to body // m_lastAngularVelocity // what was last applied to body
// Get what the body is doing, this includes 'external' influences // Get what the body is doing, this includes 'external' influences
Vector3 angularVelocity = m_prim.RotationalVelocity; Vector3 angularVelocity = Prim.RotationalVelocity;
if (m_angularMotorApply > 0) if (m_angularMotorApply > 0)
{ {
@ -716,7 +729,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep);
VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}", VDetailLog("{0},MoveAngular,angularMotorApply,apply={1},angTScale={2},timeStep={3},origvel={4},dir={5},vel={6}",
m_prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); Prim.LocalID, m_angularMotorApply, m_angularMotorTimescale, pTimestep, origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity);
// This is done so that if script request rate is less than phys frame rate the expected // This is done so that if script request rate is less than phys frame rate the expected
// velocity may still be acheived. // velocity may still be acheived.
@ -737,7 +750,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep); float VAservo = 0.2f / (m_verticalAttractionTimescale / pTimestep);
// get present body rotation // get present body rotation
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
// make a vector pointing up // make a vector pointing up
Vector3 verterr = Vector3.Zero; Vector3 verterr = Vector3.Zero;
verterr.Z = 1.0f; verterr.Z = 1.0f;
@ -767,7 +780,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
vertattr.Y += bounce * angularVelocity.Y; vertattr.Y += bounce * angularVelocity.Y;
VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", VDetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}",
m_prim.LocalID, verterr, bounce, vertattr); Prim.LocalID, verterr, bounce, vertattr);
} // else vertical attractor is off } // else vertical attractor is off
@ -784,13 +797,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
m_lastAngularVelocity.X = 0; m_lastAngularVelocity.X = 0;
m_lastAngularVelocity.Y = 0; m_lastAngularVelocity.Y = 0;
VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
} }
if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
{ {
m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero.
VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity);
} }
// apply friction // apply friction
@ -798,14 +811,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; m_lastAngularVelocity -= m_lastAngularVelocity * decayamount;
// Apply to the body // Apply to the body
m_prim.RotationalVelocity = m_lastAngularVelocity; Prim.RotationalVelocity = m_lastAngularVelocity;
VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); VDetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", Prim.LocalID, decayamount, m_lastAngularVelocity);
} //end MoveAngular } //end MoveAngular
internal void LimitRotation(float timestep) internal void LimitRotation(float timestep)
{ {
Quaternion rotq = m_prim.Orientation; Quaternion rotq = Prim.Orientation;
Quaternion m_rot = rotq; Quaternion m_rot = rotq;
bool changed = false; bool changed = false;
if (m_RollreferenceFrame != Quaternion.Identity) if (m_RollreferenceFrame != Quaternion.Identity)
@ -840,8 +853,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
} }
if (changed) if (changed)
{ {
m_prim.Orientation = m_rot; Prim.Orientation = m_rot;
VDetailLog("{0},LimitRotation,done,orig={1},new={2}", m_prim.LocalID, rotq, m_rot); VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
} }
} }
@ -849,8 +862,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void VDetailLog(string msg, params Object[] args) private void VDetailLog(string msg, params Object[] args)
{ {
if (m_prim.PhysicsScene.VehicleLoggingEnabled) if (Prim.PhysicsScene.VehicleLoggingEnabled)
m_prim.PhysicsScene.PhysicsLogging.Write(msg, args); Prim.PhysicsScene.PhysicsLogging.Write(msg, args);
} }
} }
} }

View File

@ -92,6 +92,8 @@ public class BSLinkset
{ {
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
// Don't add the root to its own linkset
if (!IsRoot(child))
AddChildToLinkset(child); AddChildToLinkset(child);
} }
return this; return this;
@ -105,6 +107,17 @@ public class BSLinkset
lock (m_linksetActivityLock) lock (m_linksetActivityLock)
{ {
if (IsRoot(child)) if (IsRoot(child))
{
// Cannot remove the root from a linkset.
return this;
}
RemoveChildFromLinkset(child);
/* Alternate implementation that destroys the linkset of the root is removed.
* This fails because items are added and removed from linksets to build shapes.
* Code left for reference.
if (IsRoot(child))
{ {
// if root of linkset, take the linkset apart // if root of linkset, take the linkset apart
while (m_children.Count > 0) while (m_children.Count > 0)
@ -120,6 +133,7 @@ public class BSLinkset
// Just removing a child from an existing linkset // Just removing a child from an existing linkset
RemoveChildFromLinkset(child); RemoveChildFromLinkset(child);
} }
*/
} }
// The child is down to a linkset of just itself // The child is down to a linkset of just itself
@ -308,12 +322,16 @@ public class BSLinkset
{ {
m_children.Add(child); m_children.Add(child);
BSPhysObject rootx = LinksetRoot; // capture the root as of now BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BulletBody rootBodyx = LinksetRoot.BSBody;
BSPhysObject childx = child; BSPhysObject childx = child;
BulletBody childBodyx = child.BSBody;
PhysicsScene.TaintedObject("AddChildToLinkset", delegate() PhysicsScene.TaintedObject("AddChildToLinkset", delegate()
{ {
DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); DetailLog("{0},AddChildToLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicallyLinkAChildToRoot(rootx, childx); // build the physical binding between me and the child // build the physical binding between me and the child
PhysicallyLinkAChildToRoot(rootx, rootBodyx, childx, childBodyx);
}); });
} }
return; return;
@ -323,7 +341,7 @@ public class BSLinkset
// This is not being called by the child so we have to make sure the child doesn't think // This is not being called by the child so we have to make sure the child doesn't think
// it's still connected to the linkset. // it's still connected to the linkset.
// Normal OpenSimulator operation will never do this because other SceneObjectPart information // Normal OpenSimulator operation will never do this because other SceneObjectPart information
// has to be updated also (like pointer to prim's parent). // also has to be updated (like pointer to prim's parent).
private void RemoveChildFromOtherLinkset(BSPhysObject pchild) private void RemoveChildFromOtherLinkset(BSPhysObject pchild)
{ {
pchild.Linkset = new BSLinkset(PhysicsScene, pchild); pchild.Linkset = new BSLinkset(PhysicsScene, pchild);
@ -336,13 +354,15 @@ public class BSLinkset
{ {
if (m_children.Remove(child)) if (m_children.Remove(child))
{ {
BSPhysObject rootx = LinksetRoot; // capture the root as of now BSPhysObject rootx = LinksetRoot; // capture the root and body as of now
BulletBody rootBodyx = LinksetRoot.BSBody;
BSPhysObject childx = child; BSPhysObject childx = child;
BulletBody childBodyx = child.BSBody;
PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate() PhysicsScene.TaintedObject("RemoveChildFromLinkset", delegate()
{ {
DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID); DetailLog("{0},RemoveChildFromLinkset,taint,child={1}", LinksetRoot.LocalID, child.LocalID);
PhysicallyUnlinkAChildFromRoot(rootx, childx); PhysicallyUnlinkAChildFromRoot(rootx, rootBodyx, childx, childBodyx);
RecomputeLinksetConstraintVariables(); RecomputeLinksetConstraintVariables();
}); });
@ -357,7 +377,8 @@ public class BSLinkset
// Create a constraint between me (root of linkset) and the passed prim (the child). // Create a constraint between me (root of linkset) and the passed prim (the child).
// Called at taint time! // Called at taint time!
private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BSPhysObject childPrim) private void PhysicallyLinkAChildToRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
{ {
// Zero motion for children so they don't interpolate // Zero motion for children so they don't interpolate
childPrim.ZeroMotion(); childPrim.ZeroMotion();
@ -371,16 +392,32 @@ public class BSLinkset
// create a constraint that allows no freedom of movement between the two objects // create a constraint that allows no freedom of movement between the two objects
// http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},child={2},rLoc={3},cLoc={4},midLoc={5}", DetailLog("{0},PhysicallyLinkAChildToRoot,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID, rootPrim.Position, childPrim.Position, midPoint); rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"),
rootPrim.Position, childPrim.Position, midPoint);
// There is great subtlty in these paramters. Notice the check for a ptr of zero.
// We pass the BulletBody structure into the taint in order to capture the pointer
// of the body at the time of constraint creation. This doesn't work for the very first
// construction because there is no body yet. The body
// is constructed later at taint time. Thus we use the body address at time of the
// taint creation but, if it is zero, use what's in the prim at the moment.
// There is a possible race condition since shape can change without a taint call
// (like changing to a mesh that is already constructed). The fix for that would be
// to only change BSShape at taint time thus syncronizing these operations at
// the cost of efficiency and lag.
BS6DofConstraint constrain = new BS6DofConstraint( BS6DofConstraint constrain = new BS6DofConstraint(
PhysicsScene.World, rootPrim.BSBody, childPrim.BSBody, PhysicsScene.World,
rootBody.ptr == IntPtr.Zero ? rootPrim.BSBody : rootBody,
childBody.ptr == IntPtr.Zero ? childPrim.BSBody : childBody,
midPoint, midPoint,
true, true,
true true
); );
/* NOTE: below is an attempt to build constraint with full frame computation, etc. /* NOTE: below is an attempt to build constraint with full frame computation, etc.
* Using the midpoint is easier since it lets the Bullet code use the transforms * Using the midpoint is easier since it lets the Bullet code manipulate the transforms
* of the objects. * of the objects.
* Code left as a warning to future programmers. * Code left as a warning to future programmers.
// ================================================================================== // ==================================================================================
@ -433,19 +470,26 @@ public class BSLinkset
} }
// Remove linkage between myself and a particular child // Remove linkage between myself and a particular child
// The root and child bodies are passed in because we need to remove the constraint between
// the bodies that were at unlink time.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BSPhysObject childPrim) private void PhysicallyUnlinkAChildFromRoot(BSPhysObject rootPrim, BulletBody rootBody,
BSPhysObject childPrim, BulletBody childBody)
{ {
DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, childPrim.LocalID); DetailLog("{0},PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
rootPrim.LocalID,
rootPrim.LocalID, rootBody.ptr.ToString("X"),
childPrim.LocalID, childBody.ptr.ToString("X"));
// Find the constraint for this link and get rid of it from the overall collection and from my list // Find the constraint for this link and get rid of it from the overall collection and from my list
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody, childPrim.BSBody); PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootBody, childBody);
// Make the child refresh its location // Make the child refresh its location
BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr); BulletSimAPI.PushUpdate2(childPrim.BSBody.ptr);
} }
// Remove linkage between myself and any possible children I might have /*
// Remove linkage between myself and any possible children I might have.
// Called at taint time! // Called at taint time!
private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim) private void PhysicallyUnlinkAllChildrenFromRoot(BSPhysObject rootPrim)
{ {
@ -453,6 +497,7 @@ public class BSLinkset
PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody); PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.BSBody);
} }
*/
// Invoke the detailed logger and output something if it's enabled. // Invoke the detailed logger and output something if it's enabled.
private void DetailLog(string msg, params Object[] args) private void DetailLog(string msg, params Object[] args)

View File

@ -135,8 +135,11 @@ public abstract class BSPhysObject : PhysicsActor
// collision event to make collision_end work. // collision event to make collision_end work.
// Called at taint time from within the Step() function thus no locking problems // Called at taint time from within the Step() function thus no locking problems
// with CollisionCollection and ObjectsWithNoMoreCollisions. // with CollisionCollection and ObjectsWithNoMoreCollisions.
public virtual void SendCollisions() // Return 'true' if there were some actual collisions passed up
public virtual bool SendCollisions()
{ {
bool ret = true;
// throttle the collisions to the number of milliseconds specified in the subscription // throttle the collisions to the number of milliseconds specified in the subscription
int nowTime = PhysicsScene.SimulationNowTime; int nowTime = PhysicsScene.SimulationNowTime;
if (nowTime >= NextCollisionOkTime) if (nowTime >= NextCollisionOkTime)
@ -148,7 +151,7 @@ public abstract class BSPhysObject : PhysicsActor
if (CollisionCollection.Count == 0) if (CollisionCollection.Count == 0)
{ {
// If I have no collisions this time, remove me from the list of objects with collisions. // If I have no collisions this time, remove me from the list of objects with collisions.
PhysicsScene.ObjectsWithNoMoreCollisions.Add(this); ret = false;
} }
// DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
@ -158,6 +161,7 @@ public abstract class BSPhysObject : PhysicsActor
// Make sure we don't have a handle to that one and that a new one is used for next time. // Make sure we don't have a handle to that one and that a new one is used for next time.
CollisionCollection = new CollisionEventUpdate(); CollisionCollection = new CollisionEventUpdate();
} }
return ret;
} }
// Subscribe for collision events. // Subscribe for collision events.

View File

@ -507,6 +507,9 @@ public sealed class BSPrim : BSPhysObject
// Set up the object physicalness (does gravity and collisions move this object) // Set up the object physicalness (does gravity and collisions move this object)
MakeDynamic(IsStatic); MakeDynamic(IsStatic);
// Do any vehicle stuff
_vehicle.Refresh();
// Arrange for collision events if the simulator wants them // Arrange for collision events if the simulator wants them
EnableCollisions(SubscribedEvents()); EnableCollisions(SubscribedEvents());
@ -556,9 +559,8 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
// There can be special things needed for implementing linksets // There can be special things needed for implementing linksets
Linkset.MakeStatic(this); Linkset.MakeStatic(this);
// The activation state is 'sleeping' so Bullet will not try to act on it // The activation state is 'disabled' so Bullet will not try to act on it
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
// BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask; BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
@ -577,7 +579,8 @@ public sealed class BSPrim : BSPhysObject
// A dynamic object has mass // A dynamic object has mass
IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr); IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Linkset.LinksetMass); OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
// OMV.Vector3 inertia = OMV.Vector3.Zero;
BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia); BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr); BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
@ -587,10 +590,12 @@ public sealed class BSPrim : BSPhysObject
BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold); BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
// There can be special things needed for implementing linksets // There can be special things needed for implementing linksets.
Linkset.MakeDynamic(this); Linkset.MakeDynamic(this);
// Force activation of the object so Bullet will act on it. // Force activation of the object so Bullet will act on it.
// Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
BulletSimAPI.Activate2(BSBody.ptr, true); BulletSimAPI.Activate2(BSBody.ptr, true);
BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter; BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
@ -1457,10 +1462,17 @@ public sealed class BSPrim : BSPhysObject
ShapeData shapeData; ShapeData shapeData;
FillShapeInfo(out shapeData); FillShapeInfo(out shapeData);
// Undo me from any possible linkset so, if body is rebuilt, the link will get restored.
// NOTE that the new linkset is not set. This saves the handle to the linkset
// so we can add ourselves back when shape mangling is complete.
Linkset.RemoveMeFromLinkset(this);
// Create the correct physical representation for this type of object. // Create the correct physical representation for this type of object.
// Updates BSBody and BSShape with the new information. // Updates BSBody and BSShape with the new information.
PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs); PhysicsScene.Shapes.GetBodyAndShape(forceRebuild, PhysicsScene.World, this, shapeData, _pbs);
Linkset = Linkset.AddMeToLinkset(this);
// Make sure the properties are set on the new object // Make sure the properties are set on the new object
UpdatePhysicalParameters(); UpdatePhysicalParameters();
#else #else

View File

@ -544,12 +544,15 @@ public class BSScene : PhysicsScene, IPhysicsParameters
// The above SendCollision's batch up the collisions on the objects. // The above SendCollision's batch up the collisions on the objects.
// Now push the collisions into the simulator. // Now push the collisions into the simulator.
// If the object is done colliding, it will add itself to the ObjectsWithNoMoreCollisions list.
if (ObjectsWithCollisions.Count > 0) if (ObjectsWithCollisions.Count > 0)
{ {
foreach (BSPhysObject bsp in ObjectsWithCollisions) foreach (BSPhysObject bsp in ObjectsWithCollisions)
if (!m_avatars.Contains(bsp)) // don't call avatars twice if (!m_avatars.Contains(bsp)) // don't call avatars twice
bsp.SendCollisions(); if (!bsp.SendCollisions())
{
// If the object is done colliding, see that it's removed from the colliding list
ObjectsWithNoMoreCollisions.Add(bsp);
}
} }
// Objects that are done colliding are removed from the ObjectsWithCollisions list. // Objects that are done colliding are removed from the ObjectsWithCollisions list.

View File

@ -498,7 +498,8 @@ public class BSShapeCollection : IDisposable
ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod); ulong newHullKey = ComputeShapeKey(shapeData, pbs, out lod);
// if the hull hasn't changed, don't rebuild it // if the hull hasn't changed, don't rebuild it
if (newHullKey == prim.BSShape.shapeKey) return false; if (newHullKey == prim.BSShape.shapeKey && prim.BSShape.type == ShapeData.PhysicsShapeType.SHAPE_HULL)
return false;
DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}", DetailLog("{0},BSShapeCollection.CreateGeomHull,create,oldKey={1},newKey={2}",
prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X")); prim.LocalID, prim.BSShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
@ -508,11 +509,8 @@ public class BSShapeCollection : IDisposable
newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod); newShape = CreatePhysicalHull(prim.PhysObjectName, newHullKey, pbs, shapeData.Size, lod);
if (!ReferenceShape(newShape)) ReferenceShape(newShape);
{
PhysicsScene.Logger.ErrorFormat("{0} Created new hull shape but one already exists: id={1}, key={2}, refCnt={3}",
LogHeader, shapeData.ID, newHullKey.ToString("X"), Hulls[newHullKey].referenceCount);
}
// hulls are already scaled by the meshmerizer // hulls are already scaled by the meshmerizer
prim.Scale = new OMV.Vector3(1f, 1f, 1f); prim.Scale = new OMV.Vector3(1f, 1f, 1f);
prim.BSShape = newShape; prim.BSShape = newShape;

View File

@ -334,7 +334,8 @@ public class BSTerrainManager
(uint)CollisionFilterGroups.TerrainMask); (uint)CollisionFilterGroups.TerrainMask);
// Make sure the new shape is processed. // Make sure the new shape is processed.
BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true); // BulletSimAPI.Activate2(mapInfo.terrainBody.ptr, true);
BulletSimAPI.ForceActivationState2(mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION);
m_terrainModified = true; m_terrainModified = true;
}; };

View File

@ -369,16 +369,16 @@ public enum CollisionFilterGroups : uint
BSolidFilter = 1 << 13, BSolidFilter = 1 << 13,
// The collsion filters and masked are defined in one place -- don't want them scattered // The collsion filters and masked are defined in one place -- don't want them scattered
AvatarFilter = BDefaultFilter | BCharacterFilter | BSolidFilter, AvatarFilter = BCharacterFilter,
AvatarMask = BAllFilter, AvatarMask = BAllFilter,
ObjectFilter = BDefaultFilter | BSolidFilter, ObjectFilter = BSolidFilter,
ObjectMask = BAllFilter, ObjectMask = BAllFilter,
StaticObjectFilter = BDefaultFilter | BStaticFilter | BSolidFilter, StaticObjectFilter = BStaticFilter,
StaticObjectMask = BAllFilter, StaticObjectMask = BAllFilter,
VolumeDetectFilter = BSensorTrigger, VolumeDetectFilter = BSensorTrigger,
VolumeDetectMask = ~BSensorTrigger, VolumeDetectMask = ~BSensorTrigger,
TerrainFilter = BTerrainFilter, TerrainFilter = BTerrainFilter,
TerrainMask = BAllFilter, TerrainMask = BAllFilter & ~BStaticFilter,
GroundPlaneFilter = BAllFilter, GroundPlaneFilter = BAllFilter,
GroundPlaneMask = BAllFilter GroundPlaneMask = BAllFilter