Merge branch 'master' into careminster
commit
a126097d6b
|
@ -299,6 +299,13 @@ namespace OpenSim.Framework
|
|||
x;
|
||||
}
|
||||
|
||||
// Inclusive, within range test (true if equal to the endpoints)
|
||||
public static bool InRange<T>(T x, T min, T max)
|
||||
where T : IComparable<T>
|
||||
{
|
||||
return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
|
||||
}
|
||||
|
||||
public static uint GetNextXferID()
|
||||
{
|
||||
uint id = 0;
|
||||
|
|
|
@ -88,8 +88,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||
// replace with the default values.
|
||||
_size = size;
|
||||
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
|
||||
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
|
||||
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
|
||||
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
|
||||
|
||||
// A motor to control the acceleration and deceleration of the avatar movement.
|
||||
// _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
|
||||
|
@ -108,8 +108,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
_velocity = OMV.Vector3.Zero;
|
||||
_appliedVelocity = OMV.Vector3.Zero;
|
||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
_avatarDensity = PhysicsScene.Params.avatarDensity;
|
||||
_currentFriction = BSParam.AvatarStandingFriction;
|
||||
_avatarDensity = BSParam.AvatarDensity;
|
||||
|
||||
// The dimensions of the avatar capsule are kept in the scale.
|
||||
// Physics creates a unit capsule which is scaled by the physics engine.
|
||||
|
@ -134,6 +134,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// called when this character is being destroyed and the resources should be released
|
||||
public override void Destroy()
|
||||
{
|
||||
base.Destroy();
|
||||
|
||||
DetailLog("{0},BSCharacter.Destroy", LocalID);
|
||||
PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
|
||||
{
|
||||
|
@ -156,19 +158,20 @@ public sealed class BSCharacter : BSPhysObject
|
|||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
_velocityMotor.SetTarget(_velocity);
|
||||
_velocityMotor.Enabled = false;
|
||||
|
||||
// This will enable or disable the flying buoyancy of the avatar.
|
||||
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
|
||||
Flying = _flying;
|
||||
|
||||
BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution);
|
||||
BulletSimAPI.SetRestitution2(PhysBody.ptr, BSParam.AvatarRestitution);
|
||||
BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin);
|
||||
BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale);
|
||||
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
|
||||
if (BSParam.CcdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
|
||||
}
|
||||
|
||||
UpdatePhysicalMassProperties(RawMass);
|
||||
|
@ -208,8 +211,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
_size = value;
|
||||
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||
// replace with the default values.
|
||||
if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
|
||||
if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
|
||||
if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
|
||||
if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
|
||||
|
||||
ComputeAvatarScale(_size);
|
||||
ComputeAvatarVolumeAndMass();
|
||||
|
@ -433,13 +436,13 @@ public sealed class BSCharacter : BSPhysObject
|
|||
OMV.Vector3 targetVel = value;
|
||||
PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
|
||||
{
|
||||
float timeStep = 0.089f; // DEBUG DEBUG FIX FIX FIX
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetTarget(targetVel);
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
// Compute a velocity value and make sure it gets pushed into the avatar.
|
||||
// This makes sure the avatar will start from a stop.
|
||||
ForceVelocity = _velocityMotor.Step(timeStep);
|
||||
_velocityMotor.Enabled = true;
|
||||
|
||||
// Make sure a property update happens next step so the motor gets incorporated.
|
||||
BulletSimAPI.PushUpdate2(PhysBody.ptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -448,12 +451,15 @@ public sealed class BSCharacter : BSPhysObject
|
|||
get { return _velocity; }
|
||||
set {
|
||||
_velocity = value;
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
_velocityMotor.SetTarget(_velocity);
|
||||
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
|
||||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||
{
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
_velocityMotor.SetTarget(_velocity);
|
||||
// Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
|
||||
_velocityMotor.Enabled = false;
|
||||
|
||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
ForceVelocity = _velocity;
|
||||
});
|
||||
|
@ -464,27 +470,27 @@ public sealed class BSCharacter : BSPhysObject
|
|||
set {
|
||||
PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
|
||||
|
||||
_velocity = value;
|
||||
// Depending on whether the avatar is moving or not, change the friction
|
||||
// to keep the avatar from slipping around
|
||||
if (_velocity.Length() == 0)
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarStandingFriction)
|
||||
if (_currentFriction != BSParam.AvatarStandingFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarStandingFriction;
|
||||
_currentFriction = BSParam.AvatarStandingFriction;
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_currentFriction != PhysicsScene.Params.avatarFriction)
|
||||
if (_currentFriction != BSParam.AvatarFriction)
|
||||
{
|
||||
_currentFriction = PhysicsScene.Params.avatarFriction;
|
||||
_currentFriction = BSParam.AvatarFriction;
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
|
||||
}
|
||||
}
|
||||
_velocity = value;
|
||||
// Remember the set velocity so we can suppress the reduction by friction, ...
|
||||
_appliedVelocity = value;
|
||||
|
||||
|
@ -561,12 +567,6 @@ public sealed class BSCharacter : BSPhysObject
|
|||
set {
|
||||
_flying = value;
|
||||
|
||||
// Velocity movement is different when flying: flying velocity degrades over time.
|
||||
if (_flying)
|
||||
_velocityMotor.TargetValueDecayTimeScale = 1f;
|
||||
else
|
||||
_velocityMotor.TargetValueDecayTimeScale = BSMotor.Infinite;
|
||||
|
||||
// simulate flying by changing the effect of gravity
|
||||
Buoyancy = ComputeBuoyancyFromFlying(_flying);
|
||||
}
|
||||
|
@ -750,39 +750,42 @@ public sealed class BSCharacter : BSPhysObject
|
|||
_velocity = entprop.Velocity;
|
||||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
|
||||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||
PositionSanityCheck(true);
|
||||
|
||||
if (_velocityMotor.Enabled)
|
||||
{
|
||||
// TODO: Decide if the step parameters should be changed depending on the avatar's
|
||||
// state (flying, colliding, ...).
|
||||
|
||||
OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep);
|
||||
|
||||
// If falling, we keep the world's downward vector no matter what the other axis specify.
|
||||
if (!Flying && !IsColliding)
|
||||
{
|
||||
stepVelocity.Z = entprop.Velocity.Z;
|
||||
DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
|
||||
}
|
||||
|
||||
// If the user has said stop and we've stopped applying velocity correction,
|
||||
// the motor can be turned off. Set the velocity to zero so the zero motion is sent to the viewer.
|
||||
if (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero)
|
||||
{
|
||||
stepVelocity = OMV.Vector3.Zero;
|
||||
_velocityMotor.Enabled = false;
|
||||
DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor);
|
||||
}
|
||||
|
||||
_velocity = stepVelocity;
|
||||
entprop.Velocity = _velocity;
|
||||
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
|
||||
}
|
||||
|
||||
// remember the current and last set values
|
||||
LastEntityProperties = CurrentEntityProperties;
|
||||
CurrentEntityProperties = entprop;
|
||||
|
||||
// Avatars don't respond to world friction, etc. They only go the speed I tell them too.
|
||||
// Special kludge here for falling. Even though the target velocity might not have a
|
||||
// Z component, the avatar could be falling (walked off a ledge, stopped flying, ...)
|
||||
// and that velocity component must be retained.
|
||||
float timeStep = 0.089f; // DEBUG DEBUG FIX FIX FIX
|
||||
OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
|
||||
// Remove next line so avatars don't fly up forever. DEBUG DEBUG this is only temporary.
|
||||
// stepVelocity.Z += entprop.Velocity.Z;
|
||||
_velocity = stepVelocity;
|
||||
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
|
||||
/*
|
||||
OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
|
||||
OMV.Vector3 avVel = new OMV.Vector3(stepVelocity.X, stepVelocity.Y, entprop.Velocity.Z);
|
||||
_velocity = avVel;
|
||||
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
|
||||
|
||||
if (entprop.Velocity != LastEntityProperties.Velocity)
|
||||
{
|
||||
// Changes in the velocity are suppressed in avatars.
|
||||
// That's just the way they are defined.
|
||||
OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
|
||||
_velocity = avVel;
|
||||
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
|
||||
}
|
||||
*/
|
||||
|
||||
// Tell the linkset about value changes
|
||||
Linkset.UpdateProperties(this, true);
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ public abstract class BSConstraint : IDisposable
|
|||
// Setting an object's mass to zero (making it static like when it's selected)
|
||||
// automatically disables the constraints.
|
||||
// If the link is enabled, be sure to set the constraint itself to enabled.
|
||||
BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true));
|
||||
BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, BSParam.NumericBool(true));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -563,7 +563,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
// 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;
|
||||
float angularDamping = BSParam.VehicleAngularDamping;
|
||||
BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping);
|
||||
|
||||
// Vehicles report collision events so we know when it's on the ground
|
||||
|
@ -634,28 +634,33 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
m_knownHas = 0;
|
||||
m_knownChanged = 0;
|
||||
}
|
||||
// Push all the changed values back into the physics engine
|
||||
private void PushKnownChanged()
|
||||
{
|
||||
if (m_knownChanged != 0)
|
||||
{
|
||||
if ((m_knownChanged & m_knownChangedPosition) != 0)
|
||||
Prim.ForcePosition = VehiclePosition;
|
||||
Prim.ForcePosition = m_knownPosition;
|
||||
|
||||
if ((m_knownChanged & m_knownChangedOrientation) != 0)
|
||||
Prim.ForceOrientation = VehicleOrientation;
|
||||
Prim.ForceOrientation = m_knownOrientation;
|
||||
|
||||
if ((m_knownChanged & m_knownChangedVelocity) != 0)
|
||||
{
|
||||
Prim.ForceVelocity = VehicleVelocity;
|
||||
Prim.ForceVelocity = m_knownVelocity;
|
||||
BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity);
|
||||
}
|
||||
|
||||
if ((m_knownChanged & m_knownChangedForce) != 0)
|
||||
Prim.AddForce((Vector3)m_knownForce, false, true);
|
||||
|
||||
if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
|
||||
{
|
||||
Prim.ForceRotationalVelocity = VehicleRotationalVelocity;
|
||||
Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
|
||||
// Fake out Bullet by making it think the velocity is the same as last time.
|
||||
BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity);
|
||||
BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, m_knownRotationalVelocity);
|
||||
}
|
||||
|
||||
if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
|
||||
Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
|
||||
|
||||
|
@ -667,7 +672,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
}
|
||||
|
||||
// Since the computation of terrain height can be a little involved, this routine
|
||||
// is used ot fetch the height only once for each vehicle simulation step.
|
||||
// is used to fetch the height only once for each vehicle simulation step.
|
||||
private float GetTerrainHeight(Vector3 pos)
|
||||
{
|
||||
if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
|
||||
|
@ -699,12 +704,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
m_knownPosition = Prim.ForcePosition;
|
||||
m_knownHas |= m_knownChangedPosition;
|
||||
}
|
||||
return (Vector3)m_knownPosition;
|
||||
return m_knownPosition;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_knownPosition = value;
|
||||
m_knownChanged |= m_knownChangedPosition;
|
||||
m_knownHas |= m_knownChangedPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,12 +723,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
m_knownOrientation = Prim.ForceOrientation;
|
||||
m_knownHas |= m_knownChangedOrientation;
|
||||
}
|
||||
return (Quaternion)m_knownOrientation;
|
||||
return m_knownOrientation;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_knownOrientation = value;
|
||||
m_knownChanged |= m_knownChangedOrientation;
|
||||
m_knownHas |= m_knownChangedOrientation;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -741,13 +748,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
{
|
||||
m_knownVelocity = value;
|
||||
m_knownChanged |= m_knownChangedVelocity;
|
||||
m_knownHas |= m_knownChangedVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
private void VehicleAddForce(Vector3 aForce)
|
||||
{
|
||||
if ((m_knownHas & m_knownChangedForce) == 0)
|
||||
{
|
||||
m_knownForce = Vector3.Zero;
|
||||
}
|
||||
m_knownForce += aForce;
|
||||
m_knownChanged |= m_knownChangedForce;
|
||||
m_knownHas |= m_knownChangedForce;
|
||||
}
|
||||
|
||||
private Vector3 VehicleRotationalVelocity
|
||||
|
@ -765,12 +778,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
{
|
||||
m_knownRotationalVelocity = value;
|
||||
m_knownChanged |= m_knownChangedRotationalVelocity;
|
||||
m_knownHas |= m_knownChangedRotationalVelocity;
|
||||
}
|
||||
}
|
||||
private void VehicleAddAngularForce(Vector3 aForce)
|
||||
{
|
||||
if ((m_knownHas & m_knownChangedRotationalForce) == 0)
|
||||
{
|
||||
m_knownRotationalForce = Vector3.Zero;
|
||||
}
|
||||
m_knownRotationalForce += aForce;
|
||||
m_knownChanged |= m_knownChangedRotationalForce;
|
||||
m_knownHas |= m_knownChangedRotationalForce;
|
||||
}
|
||||
// Vehicle relative forward velocity
|
||||
private Vector3 VehicleForwardVelocity
|
||||
|
@ -782,7 +801,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
|
||||
m_knownHas |= m_knownChangedForwardVelocity;
|
||||
}
|
||||
return (Vector3)m_knownForwardVelocity;
|
||||
return m_knownForwardVelocity;
|
||||
}
|
||||
}
|
||||
private float VehicleForwardSpeed
|
||||
|
|
|
@ -56,7 +56,7 @@ public abstract class BSLinkset
|
|||
{
|
||||
BSLinkset ret = null;
|
||||
|
||||
switch ((int)physScene.Params.linksetImplementation)
|
||||
switch ((int)BSParam.LinksetImplementation)
|
||||
{
|
||||
case (int)LinksetImplementation.Constraint:
|
||||
ret = new BSLinksetConstraints(physScene, parent);
|
||||
|
|
|
@ -226,14 +226,14 @@ public sealed class BSLinksetConstraints : BSLinkset
|
|||
constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
|
||||
|
||||
// tweek the constraint to increase stability
|
||||
constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset));
|
||||
constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor),
|
||||
PhysicsScene.Params.linkConstraintTransMotorMaxVel,
|
||||
PhysicsScene.Params.linkConstraintTransMotorMaxForce);
|
||||
constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP);
|
||||
if (PhysicsScene.Params.linkConstraintSolverIterations != 0f)
|
||||
constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
|
||||
constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
|
||||
BSParam.LinkConstraintTransMotorMaxVel,
|
||||
BSParam.LinkConstraintTransMotorMaxForce);
|
||||
constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
|
||||
if (BSParam.LinkConstraintSolverIterations != 0f)
|
||||
{
|
||||
constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations);
|
||||
constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
|
||||
}
|
||||
return constrain;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ public abstract class BSMotor
|
|||
{
|
||||
UseName = useName;
|
||||
PhysicsScene = null;
|
||||
Enabled = true;
|
||||
}
|
||||
public virtual bool Enabled { get; set; }
|
||||
public virtual void Reset() { }
|
||||
public virtual void Zero() { }
|
||||
public virtual void GenerateTestOutput(float timeStep) { }
|
||||
|
@ -98,6 +100,12 @@ public class BSVMotor : BSMotor
|
|||
public virtual Vector3 CurrentValue { get; protected set; }
|
||||
public virtual Vector3 LastError { get; protected set; }
|
||||
|
||||
public virtual bool ErrorIsZero
|
||||
{ get {
|
||||
return (LastError == Vector3.Zero || LastError.LengthSquared() <= ErrorZeroThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
public BSVMotor(string useName)
|
||||
: base(useName)
|
||||
{
|
||||
|
@ -105,7 +113,7 @@ public class BSVMotor : BSMotor
|
|||
Efficiency = 1f;
|
||||
FrictionTimescale = BSMotor.InfiniteVector;
|
||||
CurrentValue = TargetValue = Vector3.Zero;
|
||||
ErrorZeroThreshold = 0.01f;
|
||||
ErrorZeroThreshold = 0.001f;
|
||||
}
|
||||
public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
|
||||
: this(useName)
|
||||
|
@ -133,6 +141,8 @@ public class BSVMotor : BSMotor
|
|||
// Compute the next step and return the new current value
|
||||
public virtual Vector3 Step(float timeStep)
|
||||
{
|
||||
if (!Enabled) return TargetValue;
|
||||
|
||||
Vector3 origTarget = TargetValue; // DEBUG
|
||||
Vector3 origCurrVal = CurrentValue; // DEBUG
|
||||
|
||||
|
@ -178,7 +188,7 @@ public class BSVMotor : BSMotor
|
|||
{
|
||||
// Difference between what we have and target is small. Motor is done.
|
||||
CurrentValue = TargetValue;
|
||||
MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={2}",
|
||||
MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
|
||||
BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
|
||||
}
|
||||
|
||||
|
@ -186,6 +196,8 @@ public class BSVMotor : BSMotor
|
|||
}
|
||||
public virtual Vector3 Step(float timeStep, Vector3 error)
|
||||
{
|
||||
if (!Enabled) return Vector3.Zero;
|
||||
|
||||
LastError = error;
|
||||
Vector3 returnCorrection = Vector3.Zero;
|
||||
if (!error.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
|
||||
|
@ -268,12 +280,14 @@ public class BSPIDVMotor : BSVMotor
|
|||
public Vector3 proportionFactor { get; set; }
|
||||
public Vector3 integralFactor { get; set; }
|
||||
public Vector3 derivFactor { get; set; }
|
||||
|
||||
// Arbritrary factor range.
|
||||
// EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
|
||||
public float EfficiencyHigh = 0.4f;
|
||||
public float EfficiencyLow = 4.0f;
|
||||
|
||||
Vector3 IntegralFactor { get; set; }
|
||||
// Running integration of the error
|
||||
Vector3 RunningIntegration { get; set; }
|
||||
|
||||
public BSPIDVMotor(string useName)
|
||||
: base(useName)
|
||||
|
@ -281,7 +295,7 @@ public class BSPIDVMotor : BSVMotor
|
|||
proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||
integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||
derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
|
||||
IntegralFactor = Vector3.Zero;
|
||||
RunningIntegration = Vector3.Zero;
|
||||
LastError = Vector3.Zero;
|
||||
}
|
||||
|
||||
|
@ -311,15 +325,21 @@ public class BSPIDVMotor : BSVMotor
|
|||
// Ignore Current and Target Values and just advance the PID computation on this error.
|
||||
public override Vector3 Step(float timeStep, Vector3 error)
|
||||
{
|
||||
if (!Enabled) return Vector3.Zero;
|
||||
|
||||
// Add up the error so we can integrate over the accumulated errors
|
||||
IntegralFactor += error * timeStep;
|
||||
RunningIntegration += error * timeStep;
|
||||
|
||||
// A simple derivitive is the rate of change from the last error.
|
||||
Vector3 derivFactor = (error - LastError) * timeStep;
|
||||
LastError = error;
|
||||
|
||||
// Correction = -(proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
|
||||
Vector3 ret = -(error * proportionFactor + IntegralFactor * integralFactor + derivFactor * derivFactor);
|
||||
Vector3 ret = -(
|
||||
error * proportionFactor
|
||||
+ RunningIntegration * integralFactor
|
||||
+ derivFactor * derivFactor
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,559 @@
|
|||
/*
|
||||
* 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 OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OpenMetaverse;
|
||||
using Nini.Config;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public static class BSParam
|
||||
{
|
||||
// Level of Detail values kept as float because that's what the Meshmerizer wants
|
||||
public static float MeshLOD { get; private set; }
|
||||
public static float MeshMegaPrimLOD { get; private set; }
|
||||
public static float MeshMegaPrimThreshold { get; private set; }
|
||||
public static float SculptLOD { get; private set; }
|
||||
|
||||
public static float MinimumObjectMass { get; private set; }
|
||||
public static float MaximumObjectMass { get; private set; }
|
||||
|
||||
public static float LinearDamping { get; private set; }
|
||||
public static float AngularDamping { get; private set; }
|
||||
public static float DeactivationTime { get; private set; }
|
||||
public static float LinearSleepingThreshold { get; private set; }
|
||||
public static float AngularSleepingThreshold { get; private set; }
|
||||
public static float CcdMotionThreshold { get; private set; }
|
||||
public static float CcdSweptSphereRadius { get; private set; }
|
||||
public static float ContactProcessingThreshold { get; private set; }
|
||||
|
||||
public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
|
||||
public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
|
||||
public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
|
||||
|
||||
public static float TerrainImplementation { get; private set; }
|
||||
public static float TerrainFriction { get; private set; }
|
||||
public static float TerrainHitFraction { get; private set; }
|
||||
public static float TerrainRestitution { get; private set; }
|
||||
public static float TerrainCollisionMargin { get; private set; }
|
||||
|
||||
// Avatar parameters
|
||||
public static float AvatarFriction { get; private set; }
|
||||
public static float AvatarStandingFriction { get; private set; }
|
||||
public static float AvatarDensity { get; private set; }
|
||||
public static float AvatarRestitution { get; private set; }
|
||||
public static float AvatarCapsuleWidth { get; private set; }
|
||||
public static float AvatarCapsuleDepth { get; private set; }
|
||||
public static float AvatarCapsuleHeight { get; private set; }
|
||||
public static float AvatarContactProcessingThreshold { get; private set; }
|
||||
|
||||
public static float VehicleAngularDamping { get; private set; }
|
||||
|
||||
public static float LinksetImplementation { get; private set; }
|
||||
public static float LinkConstraintUseFrameOffset { get; private set; }
|
||||
public static float LinkConstraintEnableTransMotor { get; private set; }
|
||||
public static float LinkConstraintTransMotorMaxVel { get; private set; }
|
||||
public static float LinkConstraintTransMotorMaxForce { get; private set; }
|
||||
public static float LinkConstraintERP { get; private set; }
|
||||
public static float LinkConstraintCFM { get; private set; }
|
||||
public static float LinkConstraintSolverIterations { get; private set; }
|
||||
|
||||
public static float PID_D { get; private set; } // derivative
|
||||
public static float PID_P { get; private set; } // proportional
|
||||
|
||||
public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
||||
public delegate float ParamGet(BSScene scene);
|
||||
public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
||||
public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
|
||||
|
||||
public struct ParameterDefn
|
||||
{
|
||||
public string name; // string name of the parameter
|
||||
public string desc; // a short description of what the parameter means
|
||||
public float defaultValue; // default value if not specified anywhere else
|
||||
public ParamUser userParam; // get the value from the configuration file
|
||||
public ParamGet getter; // return the current value stored for this parameter
|
||||
public ParamSet setter; // set the current value for this parameter
|
||||
public SetOnObject onObject; // set the value on an object in the physical domain
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = null;
|
||||
}
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = o;
|
||||
}
|
||||
}
|
||||
|
||||
// List of all of the externally visible parameters.
|
||||
// For each parameter, this table maps a text name to getter and setters.
|
||||
// To add a new externally referencable/settable parameter, add the paramter storage
|
||||
// location somewhere in the program and make an entry in this table with the
|
||||
// getters and setters.
|
||||
// It is easiest to find an existing definition and copy it.
|
||||
// Parameter values are floats. Booleans are converted to a floating value.
|
||||
//
|
||||
// A ParameterDefn() takes the following parameters:
|
||||
// -- the text name of the parameter. This is used for console input and ini file.
|
||||
// -- a short text description of the parameter. This shows up in the console listing.
|
||||
// -- a default value (float)
|
||||
// -- a delegate for fetching the parameter from the ini file.
|
||||
// Should handle fetching the right type from the ini file and converting it.
|
||||
// -- a delegate for getting the value as a float
|
||||
// -- a delegate for setting the value from a float
|
||||
// -- an optional delegate to update the value in the world. Most often used to
|
||||
// push the new value to an in-world object.
|
||||
//
|
||||
// The single letter parameters for the delegates are:
|
||||
// s = BSScene
|
||||
// o = BSPhysObject
|
||||
// p = string parameter name
|
||||
// l = localID of referenced object
|
||||
// v = value (float)
|
||||
// cf = parameter configuration class (for fetching values from ini file)
|
||||
private static ParameterDefn[] ParameterDefinitions =
|
||||
{
|
||||
new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
|
||||
(s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
|
||||
(s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
|
||||
new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
|
||||
(s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
|
||||
(s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
|
||||
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
|
||||
(s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
|
||||
(s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
|
||||
|
||||
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
|
||||
8f,
|
||||
(s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return MeshLOD; },
|
||||
(s,p,l,v) => { MeshLOD = v; } ),
|
||||
new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
|
||||
16f,
|
||||
(s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return MeshMegaPrimLOD; },
|
||||
(s,p,l,v) => { MeshMegaPrimLOD = v; } ),
|
||||
new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
|
||||
10f,
|
||||
(s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return MeshMegaPrimThreshold; },
|
||||
(s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
|
||||
new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
|
||||
32f,
|
||||
(s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return SculptLOD; },
|
||||
(s,p,l,v) => { SculptLOD = v; } ),
|
||||
|
||||
new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
|
||||
10f,
|
||||
(s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxSubSteps; },
|
||||
(s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
|
||||
new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
|
||||
1f / 60f,
|
||||
(s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)s.m_fixedTimeStep; },
|
||||
(s,p,l,v) => { s.m_fixedTimeStep = v; } ),
|
||||
new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
|
||||
2048f,
|
||||
(s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxCollisionsPerFrame; },
|
||||
(s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
|
||||
new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
|
||||
8000f,
|
||||
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxUpdatesPerFrame; },
|
||||
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
|
||||
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
|
||||
500f,
|
||||
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_taintsToProcessPerStep; },
|
||||
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
|
||||
new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
|
||||
0.0001f,
|
||||
(s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)MinimumObjectMass; },
|
||||
(s,p,l,v) => { MinimumObjectMass = v; } ),
|
||||
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
|
||||
10000.01f,
|
||||
(s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)MaximumObjectMass; },
|
||||
(s,p,l,v) => { MaximumObjectMass = v; } ),
|
||||
|
||||
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
|
||||
2200f,
|
||||
(s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)PID_D; },
|
||||
(s,p,l,v) => { PID_D = v; } ),
|
||||
new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
|
||||
900f,
|
||||
(s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)PID_P; },
|
||||
(s,p,l,v) => { PID_P = v; } ),
|
||||
|
||||
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].defaultFriction; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
|
||||
new ParameterDefn("DefaultDensity", "Density for new objects" ,
|
||||
10.000006836f, // Aluminum g/cm3
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].defaultDensity; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
|
||||
new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].defaultRestitution; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
|
||||
new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
|
||||
0.04f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].collisionMargin; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
|
||||
new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
|
||||
-9.80665f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].gravity; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
|
||||
|
||||
|
||||
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return LinearDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, AngularDamping); } ),
|
||||
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return AngularDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, LinearDamping, v); } ),
|
||||
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
|
||||
(s) => { return DeactivationTime; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||
0.8f,
|
||||
(s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return LinearSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||
1.0f,
|
||||
(s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return AngularSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
|
||||
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||
0f, // set to zero to disable
|
||||
(s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return CcdMotionThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||
(s) => { return CcdSweptSphereRadius; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||
0.1f,
|
||||
(s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return ContactProcessingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
|
||||
|
||||
new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
|
||||
(float)BSTerrainPhys.TerrainImplementation.Mesh,
|
||||
(s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
|
||||
(s) => { return TerrainImplementation; },
|
||||
(s,p,l,v) => { TerrainImplementation = v; } ),
|
||||
new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||
0.3f,
|
||||
(s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return TerrainFriction; },
|
||||
(s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
|
||||
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
|
||||
0.8f,
|
||||
(s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
|
||||
(s) => { return TerrainHitFraction; },
|
||||
(s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return TerrainRestitution; },
|
||||
(s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
|
||||
0.04f,
|
||||
(s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
|
||||
(s) => { return TerrainCollisionMargin; },
|
||||
(s,p,l,v) => { 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) => { AvatarFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarFriction; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
|
||||
10.0f,
|
||||
(s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarStandingFriction; },
|
||||
(s,p,l,v) => { AvatarStandingFriction = v; } ),
|
||||
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
|
||||
60f,
|
||||
(s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarDensity; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
|
||||
0f,
|
||||
(s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarRestitution; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
|
||||
0.6f,
|
||||
(s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarCapsuleWidth; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
|
||||
0.45f,
|
||||
(s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarCapsuleDepth; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
|
||||
1.5f,
|
||||
(s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarCapsuleHeight; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
|
||||
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return AvatarContactProcessingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
|
||||
|
||||
new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
|
||||
0.95f,
|
||||
(s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return VehicleAngularDamping; },
|
||||
(s,p,l,v) => { VehicleAngularDamping = v; } ),
|
||||
|
||||
new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
|
||||
new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
|
||||
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
|
||||
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
|
||||
new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
|
||||
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
|
||||
new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
|
||||
new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
|
||||
0f, // zero says use Bullet default
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
|
||||
(s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
|
||||
|
||||
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
||||
(float)BSLinkset.LinksetImplementation.Compound,
|
||||
(s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
|
||||
(s) => { return LinksetImplementation; },
|
||||
(s,p,l,v) => { LinksetImplementation = v; } ),
|
||||
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return LinkConstraintUseFrameOffset; },
|
||||
(s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
|
||||
new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
|
||||
(s) => { return LinkConstraintEnableTransMotor; },
|
||||
(s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
|
||||
new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
|
||||
5.0f,
|
||||
(s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
|
||||
(s) => { return LinkConstraintTransMotorMaxVel; },
|
||||
(s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
|
||||
new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
|
||||
(s) => { return LinkConstraintTransMotorMaxForce; },
|
||||
(s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
|
||||
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
|
||||
(s) => { return LinkConstraintCFM; },
|
||||
(s,p,l,v) => { LinkConstraintCFM = v; } ),
|
||||
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
|
||||
(s) => { return LinkConstraintERP; },
|
||||
(s,p,l,v) => { LinkConstraintERP = v; } ),
|
||||
new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
|
||||
40,
|
||||
(s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
|
||||
(s) => { return LinkConstraintSolverIterations; },
|
||||
(s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
|
||||
|
||||
new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.UnmanagedParams[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.UnmanagedParams[0].physicsLoggingFrames; },
|
||||
(s,p,l,v) => { s.UnmanagedParams[0].physicsLoggingFrames = (int)v; } ),
|
||||
};
|
||||
|
||||
// Convert a boolean to our numeric true and false values
|
||||
public static float NumericBool(bool b)
|
||||
{
|
||||
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
|
||||
}
|
||||
|
||||
// Convert numeric true and false values to a boolean
|
||||
public static bool BoolNumeric(float b)
|
||||
{
|
||||
return (b == ConfigurationParameters.numericTrue ? true : false);
|
||||
}
|
||||
|
||||
// Search through the parameter definitions and return the matching
|
||||
// ParameterDefn structure.
|
||||
// Case does not matter as names are compared after converting to lower case.
|
||||
// Returns 'false' if the parameter is not found.
|
||||
internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
|
||||
{
|
||||
bool ret = false;
|
||||
ParameterDefn foundDefn = new ParameterDefn();
|
||||
string pName = paramName.ToLower();
|
||||
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
if (pName == parm.name.ToLower())
|
||||
{
|
||||
foundDefn = parm;
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
defn = foundDefn;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Pass through the settable parameters and set the default values
|
||||
internal static void SetParameterDefaultValues(BSScene physicsScene)
|
||||
{
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Get user set values out of the ini file.
|
||||
internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
|
||||
{
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
|
||||
|
||||
// This creates an array in the correct format for returning the list of
|
||||
// parameters. This is used by the 'list' option of the 'physics' command.
|
||||
internal static void BuildParameterTable()
|
||||
{
|
||||
if (SettableParameters.Length < ParameterDefinitions.Length)
|
||||
{
|
||||
List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
|
||||
for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
|
||||
{
|
||||
ParameterDefn pd = ParameterDefinitions[ii];
|
||||
entries.Add(new PhysParameterEntry(pd.name, pd.desc));
|
||||
}
|
||||
|
||||
// make the list in alphabetical order for estetic reasons
|
||||
entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
|
||||
{
|
||||
return ppe1.name.CompareTo(ppe2.name);
|
||||
});
|
||||
|
||||
SettableParameters = entries.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
|
||||
* The last two (and certainly the last one) should be referenced only in taint-time.
|
||||
*/
|
||||
|
||||
/*
|
||||
* As of 20121221, the following are the call sequences (going down) for different script physical functions:
|
||||
* llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
|
||||
* SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
|
||||
* SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
|
||||
* PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
|
||||
* BS.ApplyCentralForce BS.ApplyTorque
|
||||
*/
|
||||
|
||||
public abstract class BSPhysObject : PhysicsActor
|
||||
{
|
||||
protected BSPhysObject()
|
||||
|
@ -69,6 +79,12 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
CollidingGroundStep = 0;
|
||||
}
|
||||
|
||||
// Tell the object to clean up.
|
||||
public virtual void Destroy()
|
||||
{
|
||||
UnRegisterAllPreStepActions();
|
||||
}
|
||||
|
||||
public BSScene PhysicsScene { get; protected set; }
|
||||
// public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
|
||||
public string PhysObjectName { get; protected set; }
|
||||
|
@ -130,9 +146,6 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Update the physical location and motion of the object. Called with data from Bullet.
|
||||
public abstract void UpdateProperties(EntityProperties entprop);
|
||||
|
||||
// Tell the object to clean up.
|
||||
public abstract void Destroy();
|
||||
|
||||
public abstract OMV.Vector3 RawPosition { get; set; }
|
||||
public abstract OMV.Vector3 ForcePosition { get; set; }
|
||||
|
||||
|
@ -140,7 +153,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
public abstract OMV.Quaternion ForceOrientation { get; set; }
|
||||
|
||||
// The system is telling us the velocity it wants to move at.
|
||||
protected OMV.Vector3 m_targetVelocity;
|
||||
// protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
|
||||
public override OMV.Vector3 TargetVelocity
|
||||
{
|
||||
get { return m_targetVelocity; }
|
||||
|
@ -280,11 +293,53 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
|
||||
#endregion // Collisions
|
||||
|
||||
#region Per Simulation Step actions
|
||||
// There are some actions that must be performed for a physical object before each simulation step.
|
||||
// These actions are optional so, rather than scanning all the physical objects and asking them
|
||||
// if they have anything to do, a physical object registers for an event call before the step is performed.
|
||||
// This bookkeeping makes it easy to add, remove and clean up after all these registrations.
|
||||
private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
|
||||
protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
RegisteredActions[identifier] = actn;
|
||||
PhysicsScene.BeforeStep += actn;
|
||||
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
|
||||
}
|
||||
|
||||
// Unregister a pre step action. Safe to call if the action has not been registered.
|
||||
protected void UnRegisterPreStepAction(string op, uint id)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
bool removed = false;
|
||||
if (RegisteredActions.ContainsKey(identifier))
|
||||
{
|
||||
PhysicsScene.BeforeStep -= RegisteredActions[identifier];
|
||||
RegisteredActions.Remove(identifier);
|
||||
removed = true;
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
|
||||
}
|
||||
|
||||
protected void UnRegisterAllPreStepActions()
|
||||
{
|
||||
foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
|
||||
{
|
||||
PhysicsScene.BeforeStep -= kvp.Value;
|
||||
}
|
||||
RegisteredActions.Clear();
|
||||
DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
|
||||
}
|
||||
|
||||
|
||||
#endregion // Per Simulation Step actions
|
||||
|
||||
// High performance detailed logging routine used by the physical objects.
|
||||
protected void DetailLog(string msg, params Object[] args)
|
||||
{
|
||||
if (PhysicsScene.PhysicsLogging.Enabled)
|
||||
PhysicsScene.DetailLog(msg, args);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
public override void Destroy()
|
||||
{
|
||||
// m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
|
||||
base.Destroy();
|
||||
|
||||
// Undo any links between me and any other object
|
||||
BSPhysObject parentBefore = Linkset.LinksetRoot;
|
||||
|
@ -434,12 +435,26 @@ public sealed class BSPrim : BSPhysObject
|
|||
get { return _force; }
|
||||
set {
|
||||
_force = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
|
||||
if (_force != OMV.Vector3.Zero)
|
||||
{
|
||||
// DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force);
|
||||
});
|
||||
// If the force is non-zero, it must be reapplied each tick because
|
||||
// Bullet clears the forces applied last frame.
|
||||
RegisterPreStepAction("BSPrim.setForce", LocalID,
|
||||
delegate(float timeStep)
|
||||
{
|
||||
DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,15 +465,18 @@ public sealed class BSPrim : BSPhysObject
|
|||
set {
|
||||
Vehicle type = (Vehicle)value;
|
||||
|
||||
// Tell the scene about the vehicle so it will get processing each frame.
|
||||
PhysicsScene.VehicleInSceneTypeChanged(this, type);
|
||||
|
||||
PhysicsScene.TaintedObject("setVehicleType", delegate()
|
||||
{
|
||||
// Done at taint time so we're sure the physics engine is not using the variables
|
||||
// Vehicle code changes the parameters for this vehicle type.
|
||||
_vehicle.ProcessTypeChange(type);
|
||||
ActivateIfPhysical(false);
|
||||
|
||||
// If an active vehicle, register the vehicle code to be called before each step
|
||||
if (_vehicle.Type == Vehicle.TYPE_NONE)
|
||||
UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
|
||||
else
|
||||
RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -494,23 +512,6 @@ public sealed class BSPrim : BSPhysObject
|
|||
});
|
||||
}
|
||||
|
||||
// Called each simulation step to advance vehicle characteristics.
|
||||
// Called from Scene when doing simulation step so we're in taint processing time.
|
||||
public override void StepVehicle(float timeStep)
|
||||
{
|
||||
if (IsPhysical && _vehicle.IsActive)
|
||||
{
|
||||
_vehicle.Step(timeStep);
|
||||
/* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
|
||||
PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
|
||||
{
|
||||
// This resets the interpolation values and recomputes the tensor variables
|
||||
BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
|
||||
});
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
|
||||
public override void SetVolumeDetect(int param) {
|
||||
bool newValue = (param != 0);
|
||||
|
@ -543,14 +544,32 @@ public sealed class BSPrim : BSPhysObject
|
|||
|
||||
_velocity = value;
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 Torque {
|
||||
get { return _torque; }
|
||||
set {
|
||||
_torque = value;
|
||||
AddAngularForce(_torque, false, false);
|
||||
if (_torque != OMV.Vector3.Zero)
|
||||
{
|
||||
// If the torque is non-zero, it must be reapplied each tick because
|
||||
// Bullet clears the forces applied last frame.
|
||||
RegisterPreStepAction("BSPrim.setTorque", LocalID,
|
||||
delegate(float timeStep)
|
||||
{
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
AddAngularForce(_torque, false, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
|
||||
}
|
||||
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
|
||||
}
|
||||
}
|
||||
|
@ -720,10 +739,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
// Mass is zero which disables a bunch of physics stuff in Bullet
|
||||
UpdatePhysicalMassProperties(0f);
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
if (BSParam.CcdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
|
||||
}
|
||||
|
||||
// The activation state is 'disabled' so Bullet will not try to act on it.
|
||||
|
@ -761,17 +780,17 @@ public sealed class BSPrim : BSPhysObject
|
|||
UpdatePhysicalMassProperties(RawMass);
|
||||
|
||||
// Set collision detection parameters
|
||||
if (PhysicsScene.Params.ccdMotionThreshold > 0f)
|
||||
if (BSParam.CcdMotionThreshold > 0f)
|
||||
{
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
|
||||
BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
|
||||
BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
|
||||
}
|
||||
|
||||
// Various values for simulation limits
|
||||
BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
|
||||
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime);
|
||||
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
|
||||
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
|
||||
BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping);
|
||||
BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime);
|
||||
BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
|
||||
BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
|
||||
|
||||
// This collides like an object.
|
||||
PhysBody.collisionType = CollisionType.Dynamic;
|
||||
|
@ -819,7 +838,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
// Called in taint-time!!
|
||||
private void ActivateIfPhysical(bool forceIt)
|
||||
{
|
||||
if (IsPhysical)
|
||||
if (IsPhysical && PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
|
||||
}
|
||||
|
||||
|
@ -893,8 +912,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
|
||||
{
|
||||
DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
|
||||
ForceRotationalVelocity = _rotationalVelocity;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -904,7 +922,11 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
set {
|
||||
_rotationalVelocity = value;
|
||||
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override bool Kinematic {
|
||||
|
@ -933,6 +955,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
{
|
||||
float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
|
||||
BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -969,56 +992,35 @@ public sealed class BSPrim : BSPhysObject
|
|||
public override float APIDStrength { set { return; } }
|
||||
public override float APIDDamping { set { return; } }
|
||||
|
||||
private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
|
||||
public override void AddForce(OMV.Vector3 force, bool pushforce) {
|
||||
AddForce(force, pushforce, false);
|
||||
}
|
||||
// Applying a force just adds this to the total force on the object.
|
||||
// This added force will only last the next simulation tick.
|
||||
public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||
// for an object, doesn't matter if force is a pushforce or not
|
||||
if (force.IsFinite())
|
||||
{
|
||||
// _force += force;
|
||||
lock (m_accumulatedForces)
|
||||
m_accumulatedForces.Add(new OMV.Vector3(force));
|
||||
OMV.Vector3 addForce = force;
|
||||
DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
|
||||
{
|
||||
// Bullet adds this central force to the total force for this tick
|
||||
DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
|
||||
return;
|
||||
}
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
|
||||
{
|
||||
OMV.Vector3 fSum = OMV.Vector3.Zero;
|
||||
lock (m_accumulatedForces)
|
||||
{
|
||||
// Sum the accumulated additional forces for one big force to apply once.
|
||||
foreach (OMV.Vector3 v in m_accumulatedForces)
|
||||
{
|
||||
fSum += v;
|
||||
}
|
||||
m_accumulatedForces.Clear();
|
||||
}
|
||||
DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
|
||||
if (fSum != OMV.Vector3.Zero)
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
|
||||
});
|
||||
}
|
||||
|
||||
// An impulse force is scaled by the mass of the object.
|
||||
public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
|
||||
{
|
||||
OMV.Vector3 applyImpulse = impulse;
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
|
||||
{
|
||||
DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
|
||||
});
|
||||
}
|
||||
|
||||
private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
||||
AddAngularForce(force, pushforce, false);
|
||||
}
|
||||
|
@ -1026,36 +1028,23 @@ public sealed class BSPrim : BSPhysObject
|
|||
{
|
||||
if (force.IsFinite())
|
||||
{
|
||||
// _force += force;
|
||||
lock (m_accumulatedAngularForces)
|
||||
m_accumulatedAngularForces.Add(new OMV.Vector3(force));
|
||||
OMV.Vector3 angForce = force;
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
|
||||
{
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
|
||||
return;
|
||||
}
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
|
||||
{
|
||||
OMV.Vector3 fSum = OMV.Vector3.Zero;
|
||||
lock (m_accumulatedAngularForces)
|
||||
{
|
||||
// Sum the accumulated additional forces for one big force to apply once.
|
||||
foreach (OMV.Vector3 v in m_accumulatedAngularForces)
|
||||
{
|
||||
fSum += v;
|
||||
}
|
||||
m_accumulatedAngularForces.Clear();
|
||||
}
|
||||
DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
|
||||
if (fSum != OMV.Vector3.Zero)
|
||||
{
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
|
||||
_torque = fSum;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// A torque impulse.
|
||||
// ApplyTorqueImpulse adds torque directly to the angularVelocity.
|
||||
// AddAngularForce accumulates the force and applied it to the angular velocity all at once.
|
||||
|
@ -1066,7 +1055,10 @@ public sealed class BSPrim : BSPhysObject
|
|||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
|
||||
{
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1361,11 +1353,7 @@ public sealed class BSPrim : BSPhysObject
|
|||
}
|
||||
*/
|
||||
|
||||
if (returnMass <= 0)
|
||||
returnMass = 0.0001f;
|
||||
|
||||
if (returnMass > PhysicsScene.MaximumObjectMass)
|
||||
returnMass = PhysicsScene.MaximumObjectMass;
|
||||
returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
|
||||
|
||||
return returnMass;
|
||||
}// end CalculateMass
|
||||
|
|
|
@ -69,20 +69,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
// every tick so OpenSim will update its animation.
|
||||
private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
|
||||
|
||||
// List of all the objects that have vehicle properties and should be called
|
||||
// to update each physics step.
|
||||
private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
|
||||
|
||||
// let my minuions use my logger
|
||||
public ILog Logger { get { return m_log; } }
|
||||
|
||||
public IMesher mesher;
|
||||
// Level of Detail values kept as float because that's what the Meshmerizer wants
|
||||
public float MeshLOD { get; private set; }
|
||||
public float MeshMegaPrimLOD { get; private set; }
|
||||
public float MeshMegaPrimThreshold { get; private set; }
|
||||
public float SculptLOD { get; private set; }
|
||||
|
||||
public uint WorldID { get; private set; }
|
||||
public BulletSim World { get; private set; }
|
||||
|
||||
|
@ -90,24 +80,18 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public BSConstraintCollection Constraints { get; private set; }
|
||||
|
||||
// Simulation parameters
|
||||
private int m_maxSubSteps;
|
||||
private float m_fixedTimeStep;
|
||||
private long m_simulationStep = 0;
|
||||
internal int m_maxSubSteps;
|
||||
internal float m_fixedTimeStep;
|
||||
internal long m_simulationStep = 0;
|
||||
public long SimulationStep { get { return m_simulationStep; } }
|
||||
private int m_taintsToProcessPerStep;
|
||||
|
||||
// Avatar parameters
|
||||
public float ParamAvatarFriction { get; private set; }
|
||||
public float ParamAvatarStandingFriction { get; private set; }
|
||||
public float ParamAvatarDensity { get; private set; }
|
||||
public float ParamAvatarRestitution { get; private set; }
|
||||
public float ParamAvatarCapsuleWidth { get; private set; }
|
||||
public float ParamAvatarCapsuleDepth { get; private set; }
|
||||
public float ParamAvatarCapsuleHeight { get; private set; }
|
||||
public float ParamAvatarContactProcessingThreshold { get; private set; }
|
||||
internal int m_taintsToProcessPerStep;
|
||||
internal float LastTimeStep { get; private set; }
|
||||
|
||||
// Physical objects can register for prestep or poststep events
|
||||
public delegate void PreStepAction(float timeStep);
|
||||
public delegate void PostStepAction(float timeStep);
|
||||
public event PreStepAction BeforeStep;
|
||||
public event PreStepAction AfterStep;
|
||||
|
||||
// A value of the time now so all the collision and update routines do not have to get their own
|
||||
// Set to 'now' just before all the prims and actors are called for collisions and updates
|
||||
|
@ -121,20 +105,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public bool InTaintTime { get; private set; }
|
||||
|
||||
// Pinned memory used to pass step information between managed and unmanaged
|
||||
private int m_maxCollisionsPerFrame;
|
||||
private CollisionDesc[] m_collisionArray;
|
||||
private GCHandle m_collisionArrayPinnedHandle;
|
||||
internal int m_maxCollisionsPerFrame;
|
||||
internal CollisionDesc[] m_collisionArray;
|
||||
internal GCHandle m_collisionArrayPinnedHandle;
|
||||
|
||||
private int m_maxUpdatesPerFrame;
|
||||
private EntityProperties[] m_updateArray;
|
||||
private GCHandle m_updateArrayPinnedHandle;
|
||||
|
||||
public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
|
||||
public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
|
||||
public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
|
||||
|
||||
public float PID_D { get; private set; } // derivative
|
||||
public float PID_P { get; private set; } // proportional
|
||||
internal int m_maxUpdatesPerFrame;
|
||||
internal EntityProperties[] m_updateArray;
|
||||
internal GCHandle m_updateArrayPinnedHandle;
|
||||
|
||||
public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
|
||||
public const uint GROUNDPLANE_ID = 1;
|
||||
|
@ -145,7 +122,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
|
||||
public ConfigurationParameters Params
|
||||
{
|
||||
get { return m_params[0]; }
|
||||
get { return UnmanagedParams[0]; }
|
||||
}
|
||||
public Vector3 DefaultGravity
|
||||
{
|
||||
|
@ -157,8 +134,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
get { return Params.gravity; }
|
||||
}
|
||||
|
||||
public float MaximumObjectMass { get; private set; }
|
||||
|
||||
// When functions in the unmanaged code must be called, it is only
|
||||
// done at a known time just before the simulation step. The taint
|
||||
// system saves all these function calls and executes them in
|
||||
|
@ -181,7 +156,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
|
||||
// A pointer to an instance if this structure is passed to the C++ code
|
||||
// Used to pass basic configuration values to the unmanaged code.
|
||||
ConfigurationParameters[] m_params;
|
||||
internal ConfigurationParameters[] UnmanagedParams;
|
||||
GCHandle m_paramsHandle;
|
||||
|
||||
// Handle to the callback used by the unmanaged code to call into the managed code.
|
||||
|
@ -218,8 +193,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
Shapes = new BSShapeCollection(this);
|
||||
|
||||
// Allocate pinned memory to pass parameters.
|
||||
m_params = new ConfigurationParameters[1];
|
||||
m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
|
||||
UnmanagedParams = new ConfigurationParameters[1];
|
||||
m_paramsHandle = GCHandle.Alloc(UnmanagedParams, GCHandleType.Pinned);
|
||||
|
||||
// Set default values for physics parameters plus any overrides from the ini file
|
||||
GetInitialParameterValues(config);
|
||||
|
@ -277,7 +252,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
TerrainManager = new BSTerrainManager(this);
|
||||
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
||||
|
||||
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation);
|
||||
m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
|
||||
|
||||
InTaintTime = false;
|
||||
m_initialized = true;
|
||||
|
@ -288,9 +263,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
private void GetInitialParameterValues(IConfigSource config)
|
||||
{
|
||||
ConfigurationParameters parms = new ConfigurationParameters();
|
||||
m_params[0] = parms;
|
||||
UnmanagedParams[0] = parms;
|
||||
|
||||
SetParameterDefaultValues();
|
||||
BSParam.SetParameterDefaultValues(this);
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
|
@ -298,7 +273,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
IConfig pConfig = config.Configs["BulletSim"];
|
||||
if (pConfig != null)
|
||||
{
|
||||
SetParameterConfigurationValues(pConfig);
|
||||
BSParam.SetParameterConfigurationValues(this, pConfig);
|
||||
|
||||
// Very detailed logging for physics debugging
|
||||
m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
|
||||
|
@ -492,6 +467,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
// Simulate one timestep
|
||||
public override float Simulate(float timeStep)
|
||||
{
|
||||
// prevent simulation until we've been initialized
|
||||
if (!m_initialized) return 5.0f;
|
||||
|
||||
LastTimeStep = timeStep;
|
||||
|
||||
int updatedEntityCount = 0;
|
||||
IntPtr updatedEntitiesPtr;
|
||||
int collidersCount = 0;
|
||||
|
@ -500,26 +480,27 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
int beforeTime = 0;
|
||||
int simTime = 0;
|
||||
|
||||
// prevent simulation until we've been initialized
|
||||
if (!m_initialized) return 5.0f;
|
||||
|
||||
// update the prim states while we know the physics engine is not busy
|
||||
int numTaints = _taintOperations.Count;
|
||||
|
||||
InTaintTime = true; // Only used for debugging so locking is not necessary.
|
||||
|
||||
ProcessTaints();
|
||||
|
||||
// Some of the prims operate with special vehicle properties
|
||||
DoPreStepActions(timeStep);
|
||||
// Some of the physical objects requre individual, pre-step calls
|
||||
TriggerPreStepEvent(timeStep);
|
||||
|
||||
// the prestep actions might have added taints
|
||||
ProcessTaints();
|
||||
|
||||
InTaintTime = false; // Only used for debugging so locking is not necessary.
|
||||
|
||||
// step the physical world one interval
|
||||
m_simulationStep++;
|
||||
int numSubSteps = 0;
|
||||
|
||||
try
|
||||
{
|
||||
if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
|
||||
if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount();
|
||||
|
||||
numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep,
|
||||
|
@ -529,7 +510,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
|
||||
DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
|
||||
updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
|
||||
if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -608,7 +588,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
ProcessPostStepTaints();
|
||||
TriggerPostStepEvent(timeStep);
|
||||
|
||||
// The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
|
||||
// Only enable this in a limited test world with few objects.
|
||||
|
@ -700,6 +680,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public override bool IsThreaded { get { return false; } }
|
||||
|
||||
#region Taints
|
||||
// The simulation execution order is:
|
||||
// Simulate()
|
||||
// DoOneTimeTaints
|
||||
// TriggerPreStepEvent
|
||||
// DoOneTimeTaints
|
||||
// Step()
|
||||
// ProcessAndForwardCollisions
|
||||
// ProcessAndForwardPropertyUpdates
|
||||
// TriggerPostStepEvent
|
||||
|
||||
// Calls to the PhysicsActors can't directly call into the physics engine
|
||||
// because it might be busy. We delay changes to a known time.
|
||||
|
@ -726,58 +715,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
TaintedObject(ident, callback);
|
||||
}
|
||||
|
||||
private void TriggerPreStepEvent(float timeStep)
|
||||
{
|
||||
PreStepAction actions = BeforeStep;
|
||||
if (actions != null)
|
||||
actions(timeStep);
|
||||
|
||||
}
|
||||
|
||||
private void TriggerPostStepEvent(float timeStep)
|
||||
{
|
||||
PreStepAction actions = AfterStep;
|
||||
if (actions != null)
|
||||
actions(timeStep);
|
||||
|
||||
}
|
||||
|
||||
// When someone tries to change a property on a BSPrim or BSCharacter, the object queues
|
||||
// a callback into itself to do the actual property change. That callback is called
|
||||
// here just before the physics engine is called to step the simulation.
|
||||
public void ProcessTaints()
|
||||
{
|
||||
InTaintTime = true; // Only used for debugging so locking is not necessary.
|
||||
ProcessRegularTaints();
|
||||
ProcessPostTaintTaints();
|
||||
InTaintTime = false;
|
||||
}
|
||||
|
||||
private void ProcessRegularTaints()
|
||||
{
|
||||
if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
|
||||
{
|
||||
/*
|
||||
// Code to limit the number of taints processed per step. Meant to limit step time.
|
||||
// Unsure if a good idea as code assumes that taints are done before the step.
|
||||
int taintCount = m_taintsToProcessPerStep;
|
||||
TaintCallbackEntry oneCallback = new TaintCallbackEntry();
|
||||
while (_taintOperations.Count > 0 && taintCount-- > 0)
|
||||
{
|
||||
bool gotOne = false;
|
||||
lock (_taintLock)
|
||||
{
|
||||
if (_taintOperations.Count > 0)
|
||||
{
|
||||
oneCallback = _taintOperations[0];
|
||||
_taintOperations.RemoveAt(0);
|
||||
gotOne = true;
|
||||
}
|
||||
}
|
||||
if (gotOne)
|
||||
{
|
||||
try
|
||||
{
|
||||
DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
|
||||
oneCallback.callback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
|
||||
m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_taintOperations.Count > 0)
|
||||
{
|
||||
DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
|
||||
}
|
||||
*/
|
||||
|
||||
// swizzle a new list into the list location so we can process what's there
|
||||
List<TaintCallbackEntry> oldList;
|
||||
lock (_taintLock)
|
||||
|
@ -816,6 +782,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
return;
|
||||
}
|
||||
|
||||
// Taints that happen after the normal taint processing but before the simulation step.
|
||||
private void ProcessPostTaintTaints()
|
||||
{
|
||||
if (_postTaintOperations.Count > 0)
|
||||
|
@ -843,45 +810,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
}
|
||||
}
|
||||
|
||||
public void PostStepTaintObject(String ident, TaintCallback callback)
|
||||
{
|
||||
if (!m_initialized) return;
|
||||
|
||||
lock (_taintLock)
|
||||
{
|
||||
_postStepOperations.Add(new TaintCallbackEntry(ident, callback));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
private void ProcessPostStepTaints()
|
||||
{
|
||||
if (_postStepOperations.Count > 0)
|
||||
{
|
||||
List<TaintCallbackEntry> oldList;
|
||||
lock (_taintLock)
|
||||
{
|
||||
oldList = _postStepOperations;
|
||||
_postStepOperations = new List<TaintCallbackEntry>();
|
||||
}
|
||||
|
||||
foreach (TaintCallbackEntry tcbe in oldList)
|
||||
{
|
||||
try
|
||||
{
|
||||
DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
|
||||
tcbe.callback();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
|
||||
}
|
||||
}
|
||||
oldList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Only used for debugging. Does not change state of anything so locking is not necessary.
|
||||
public bool AssertInTaintTime(string whereFrom)
|
||||
{
|
||||
|
@ -889,540 +817,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
{
|
||||
DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
|
||||
m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
|
||||
Util.PrintCallStack(); // Prints the stack into the DEBUG log file.
|
||||
Util.PrintCallStack(DetailLog);
|
||||
}
|
||||
return InTaintTime;
|
||||
}
|
||||
|
||||
#endregion // Taints
|
||||
|
||||
#region Vehicles
|
||||
|
||||
public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
|
||||
{
|
||||
RemoveVehiclePrim(vehic);
|
||||
if (newType != Vehicle.TYPE_NONE)
|
||||
{
|
||||
// make it so the scene will call us each tick to do vehicle things
|
||||
AddVehiclePrim(vehic);
|
||||
}
|
||||
}
|
||||
|
||||
// Make so the scene will call this prim for vehicle actions each tick.
|
||||
// Safe to call if prim is already in the vehicle list.
|
||||
public void AddVehiclePrim(BSPrim vehicle)
|
||||
{
|
||||
lock (m_vehicles)
|
||||
{
|
||||
if (!m_vehicles.Contains(vehicle))
|
||||
{
|
||||
m_vehicles.Add(vehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove a prim from our list of vehicles.
|
||||
// Safe to call if the prim is not in the vehicle list.
|
||||
public void RemoveVehiclePrim(BSPrim vehicle)
|
||||
{
|
||||
lock (m_vehicles)
|
||||
{
|
||||
if (m_vehicles.Contains(vehicle))
|
||||
{
|
||||
m_vehicles.Remove(vehicle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DoPreStepActions(float timeStep)
|
||||
{
|
||||
ProcessVehicles(timeStep);
|
||||
|
||||
PreStepAction actions = BeforeStep;
|
||||
if (actions != null)
|
||||
actions(timeStep);
|
||||
|
||||
}
|
||||
|
||||
// Some prims have extra vehicle actions
|
||||
// Called at taint time!
|
||||
private void ProcessVehicles(float timeStep)
|
||||
{
|
||||
foreach (BSPhysObject pobj in m_vehicles)
|
||||
{
|
||||
pobj.StepVehicle(timeStep);
|
||||
}
|
||||
}
|
||||
#endregion Vehicles
|
||||
|
||||
#region INI and command line parameter processing
|
||||
|
||||
delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
|
||||
delegate float ParamGet(BSScene scene);
|
||||
delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
|
||||
delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
|
||||
|
||||
private struct ParameterDefn
|
||||
{
|
||||
public string name; // string name of the parameter
|
||||
public string desc; // a short description of what the parameter means
|
||||
public float defaultValue; // default value if not specified anywhere else
|
||||
public ParamUser userParam; // get the value from the configuration file
|
||||
public ParamGet getter; // return the current value stored for this parameter
|
||||
public ParamSet setter; // set the current value for this parameter
|
||||
public SetOnObject onObject; // set the value on an object in the physical domain
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = null;
|
||||
}
|
||||
public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
|
||||
{
|
||||
name = n;
|
||||
desc = d;
|
||||
defaultValue = v;
|
||||
userParam = u;
|
||||
getter = g;
|
||||
setter = s;
|
||||
onObject = o;
|
||||
}
|
||||
}
|
||||
|
||||
// List of all of the externally visible parameters.
|
||||
// For each parameter, this table maps a text name to getter and setters.
|
||||
// To add a new externally referencable/settable parameter, add the paramter storage
|
||||
// location somewhere in the program and make an entry in this table with the
|
||||
// getters and setters.
|
||||
// It is easiest to find an existing definition and copy it.
|
||||
// Parameter values are floats. Booleans are converted to a floating value.
|
||||
//
|
||||
// A ParameterDefn() takes the following parameters:
|
||||
// -- the text name of the parameter. This is used for console input and ini file.
|
||||
// -- a short text description of the parameter. This shows up in the console listing.
|
||||
// -- a delegate for fetching the parameter from the ini file.
|
||||
// Should handle fetching the right type from the ini file and converting it.
|
||||
// -- a delegate for getting the value as a float
|
||||
// -- a delegate for setting the value from a float
|
||||
// -- an optional delegate to update the value in the world. Most often used to
|
||||
// push the new value to an in-world object.
|
||||
//
|
||||
// The single letter parameters for the delegates are:
|
||||
// s = BSScene
|
||||
// o = BSPhysObject
|
||||
// p = string parameter name
|
||||
// l = localID of referenced object
|
||||
// v = float value
|
||||
// cf = parameter configuration class (for fetching values from ini file)
|
||||
private ParameterDefn[] ParameterDefinitions =
|
||||
{
|
||||
new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
|
||||
(s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
|
||||
(s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
|
||||
new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
|
||||
(s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
|
||||
(s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
|
||||
new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
|
||||
(s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
|
||||
(s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
|
||||
|
||||
new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
|
||||
8f,
|
||||
(s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return s.MeshLOD; },
|
||||
(s,p,l,v) => { s.MeshLOD = v; } ),
|
||||
new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
|
||||
16f,
|
||||
(s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return s.MeshMegaPrimLOD; },
|
||||
(s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
|
||||
new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
|
||||
10f,
|
||||
(s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return s.MeshMegaPrimThreshold; },
|
||||
(s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
|
||||
new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
|
||||
32f,
|
||||
(s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
|
||||
(s) => { return s.SculptLOD; },
|
||||
(s,p,l,v) => { s.SculptLOD = v; } ),
|
||||
|
||||
new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
|
||||
10f,
|
||||
(s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxSubSteps; },
|
||||
(s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
|
||||
new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
|
||||
1f / 60f,
|
||||
(s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)s.m_fixedTimeStep; },
|
||||
(s,p,l,v) => { s.m_fixedTimeStep = v; } ),
|
||||
new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
|
||||
2048f,
|
||||
(s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxCollisionsPerFrame; },
|
||||
(s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
|
||||
new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
|
||||
8000f,
|
||||
(s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_maxUpdatesPerFrame; },
|
||||
(s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
|
||||
new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
|
||||
500f,
|
||||
(s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_taintsToProcessPerStep; },
|
||||
(s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
|
||||
new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
|
||||
10000.01f,
|
||||
(s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)s.MaximumObjectMass; },
|
||||
(s,p,l,v) => { s.MaximumObjectMass = v; } ),
|
||||
|
||||
new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
|
||||
2200f,
|
||||
(s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)s.PID_D; },
|
||||
(s,p,l,v) => { s.PID_D = v; } ),
|
||||
new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
|
||||
900f,
|
||||
(s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
|
||||
(s) => { return (float)s.PID_P; },
|
||||
(s,p,l,v) => { s.PID_P = v; } ),
|
||||
|
||||
new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
|
||||
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; } ),
|
||||
new ParameterDefn("DefaultDensity", "Density for new objects" ,
|
||||
10.000006836f, // Aluminum g/cm3
|
||||
(s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].defaultDensity; },
|
||||
(s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
|
||||
new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
|
||||
(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!)",
|
||||
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; } ),
|
||||
new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
|
||||
-9.80665f,
|
||||
(s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].gravity; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
|
||||
|
||||
|
||||
new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
|
||||
new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularDamping; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
|
||||
new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
|
||||
0.2f,
|
||||
(s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].deactivationTime; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linearSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
|
||||
new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
|
||||
1.0f,
|
||||
(s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].angularSleepingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
|
||||
new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
|
||||
0f, // set to zero to disable
|
||||
(s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdMotionThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].ccdSweptSphereRadius; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
|
||||
new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].contactProcessingThreshold; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
|
||||
(s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
|
||||
|
||||
new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
|
||||
(float)BSTerrainPhys.TerrainImplementation.Mesh,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
|
||||
(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.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 */} ),
|
||||
new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
|
||||
0.8f,
|
||||
(s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].terrainHitFraction; },
|
||||
(s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
|
||||
new ParameterDefn("TerrainRestitution", "Bouncyness" ,
|
||||
0f,
|
||||
(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.",
|
||||
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; } ),
|
||||
new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
|
||||
60f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarDensity; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
|
||||
new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarRestitution; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
|
||||
0.6f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarCapsuleWidth; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
|
||||
0.45f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarCapsuleDepth; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
|
||||
new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
|
||||
1.5f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].avatarCapsuleHeight; },
|
||||
(s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
|
||||
new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
|
||||
(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,
|
||||
(s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
|
||||
(s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
|
||||
new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
|
||||
(s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
|
||||
new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
|
||||
(s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
|
||||
new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
|
||||
(s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
|
||||
new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
|
||||
(s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
|
||||
new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].shouldSplitSimulationIslands; },
|
||||
(s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
|
||||
new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].shouldEnableFrictionCaching; },
|
||||
(s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
|
||||
new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
|
||||
0f, // zero says use Bullet default
|
||||
(s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].numberOfSolverIterations; },
|
||||
(s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
|
||||
|
||||
new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
|
||||
(float)BSLinkset.LinksetImplementation.Compound,
|
||||
(s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
|
||||
(s) => { return s.m_params[0].linksetImplementation; },
|
||||
(s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
|
||||
new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
|
||||
ConfigurationParameters.numericFalse,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
|
||||
new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
|
||||
ConfigurationParameters.numericTrue,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
|
||||
(s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
|
||||
new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
|
||||
5.0f,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
|
||||
new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
|
||||
new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linkConstraintCFM; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
|
||||
new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
|
||||
0.1f,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linkConstraintERP; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
|
||||
new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
|
||||
40,
|
||||
(s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
|
||||
(s) => { return s.m_params[0].linkConstraintSolverIterations; },
|
||||
(s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
|
||||
|
||||
new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
|
||||
0f,
|
||||
(s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
|
||||
(s) => { return (float)s.m_params[0].physicsLoggingFrames; },
|
||||
(s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
|
||||
};
|
||||
|
||||
// Convert a boolean to our numeric true and false values
|
||||
public float NumericBool(bool b)
|
||||
{
|
||||
return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
|
||||
}
|
||||
|
||||
// Convert numeric true and false values to a boolean
|
||||
public bool BoolNumeric(float b)
|
||||
{
|
||||
return (b == ConfigurationParameters.numericTrue ? true : false);
|
||||
}
|
||||
|
||||
// Search through the parameter definitions and return the matching
|
||||
// ParameterDefn structure.
|
||||
// Case does not matter as names are compared after converting to lower case.
|
||||
// Returns 'false' if the parameter is not found.
|
||||
private bool TryGetParameter(string paramName, out ParameterDefn defn)
|
||||
{
|
||||
bool ret = false;
|
||||
ParameterDefn foundDefn = new ParameterDefn();
|
||||
string pName = paramName.ToLower();
|
||||
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
if (pName == parm.name.ToLower())
|
||||
{
|
||||
foundDefn = parm;
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
defn = foundDefn;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Pass through the settable parameters and set the default values
|
||||
private void SetParameterDefaultValues()
|
||||
{
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Get user set values out of the ini file.
|
||||
private void SetParameterConfigurationValues(IConfig cfg)
|
||||
{
|
||||
foreach (ParameterDefn parm in ParameterDefinitions)
|
||||
{
|
||||
parm.userParam(this, cfg, parm.name, parm.defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
|
||||
|
||||
// This creates an array in the correct format for returning the list of
|
||||
// parameters. This is used by the 'list' option of the 'physics' command.
|
||||
private void BuildParameterTable()
|
||||
{
|
||||
if (SettableParameters.Length < ParameterDefinitions.Length)
|
||||
{
|
||||
List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
|
||||
for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
|
||||
{
|
||||
ParameterDefn pd = ParameterDefinitions[ii];
|
||||
entries.Add(new PhysParameterEntry(pd.name, pd.desc));
|
||||
}
|
||||
|
||||
// make the list in alphabetical order for estetic reasons
|
||||
entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
|
||||
{
|
||||
return ppe1.name.CompareTo(ppe2.name);
|
||||
});
|
||||
|
||||
SettableParameters = entries.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region IPhysicsParameters
|
||||
// Get the list of parameters this physics engine supports
|
||||
public PhysParameterEntry[] GetParameterList()
|
||||
{
|
||||
BuildParameterTable();
|
||||
return SettableParameters;
|
||||
BSParam.BuildParameterTable();
|
||||
return BSParam.SettableParameters;
|
||||
}
|
||||
|
||||
// Set parameter on a specific or all instances.
|
||||
|
@ -1434,8 +843,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
public bool SetPhysicsParameter(string parm, float val, uint localID)
|
||||
{
|
||||
bool ret = false;
|
||||
ParameterDefn theParam;
|
||||
if (TryGetParameter(parm, out theParam))
|
||||
BSParam.ParameterDefn theParam;
|
||||
if (BSParam.TryGetParameter(parm, out theParam))
|
||||
{
|
||||
theParam.setter(this, parm, localID, val);
|
||||
ret = true;
|
||||
|
@ -1447,19 +856,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
// If the local ID is APPLY_TO_NONE, just change the default value
|
||||
// If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
|
||||
// If the localID is a specific object, apply the parameter change to only that object
|
||||
private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val)
|
||||
internal delegate void AssignVal(float x);
|
||||
internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
|
||||
{
|
||||
List<uint> objectIDs = new List<uint>();
|
||||
switch (localID)
|
||||
{
|
||||
case PhysParameterEntry.APPLY_TO_NONE:
|
||||
defaultLoc = val; // setting only the default value
|
||||
setDefault(val); // setting only the default value
|
||||
// This will cause a call into the physical world if some operation is specified (SetOnObject).
|
||||
objectIDs.Add(TERRAIN_ID);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
case PhysParameterEntry.APPLY_TO_ALL:
|
||||
defaultLoc = val; // setting ALL also sets the default value
|
||||
setDefault(val); // setting ALL also sets the default value
|
||||
lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
|
||||
TaintedUpdateParameter(parm, objectIDs, val);
|
||||
break;
|
||||
|
@ -1478,8 +888,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
List<uint> xlIDs = lIDs;
|
||||
string xparm = parm;
|
||||
TaintedObject("BSScene.UpdateParameterSet", delegate() {
|
||||
ParameterDefn thisParam;
|
||||
if (TryGetParameter(xparm, out thisParam))
|
||||
BSParam.ParameterDefn thisParam;
|
||||
if (BSParam.TryGetParameter(xparm, out thisParam))
|
||||
{
|
||||
if (thisParam.onObject != null)
|
||||
{
|
||||
|
@ -1500,8 +910,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
{
|
||||
float val = 0f;
|
||||
bool ret = false;
|
||||
ParameterDefn theParam;
|
||||
if (TryGetParameter(parm, out theParam))
|
||||
BSParam.ParameterDefn theParam;
|
||||
if (BSParam.TryGetParameter(parm, out theParam))
|
||||
{
|
||||
val = theParam.getter(this);
|
||||
ret = true;
|
||||
|
@ -1514,16 +924,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
|||
|
||||
#endregion Runtime settable parameters
|
||||
|
||||
// Debugging routine for dumping detailed physical information for vehicle prims
|
||||
private void DumpVehicles()
|
||||
{
|
||||
foreach (BSPrim prim in m_vehicles)
|
||||
{
|
||||
BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
|
||||
BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Invoke the detailed logger and output something if it's enabled.
|
||||
public void DetailLog(string msg, params Object[] args)
|
||||
{
|
||||
|
|
|
@ -456,7 +456,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
if (!haveShape
|
||||
&& pbs != null
|
||||
&& nativeShapePossible
|
||||
&& ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim)
|
||||
&& ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
|
||||
|| (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
|
||||
&& pbs.ProfileHollow == 0
|
||||
&& pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
|
||||
|
@ -520,7 +520,7 @@ public sealed class BSShapeCollection : IDisposable
|
|||
bool ret = false;
|
||||
// Note that if it's a native shape, the check for physical/non-physical is not
|
||||
// made. Native shapes work in either case.
|
||||
if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects)
|
||||
if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
|
||||
{
|
||||
// Update prim.BSShape to reference a hull of this shape.
|
||||
ret = GetReferenceToHull(prim,shapeCallback);
|
||||
|
@ -836,14 +836,14 @@ public sealed class BSShapeCollection : IDisposable
|
|||
private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
|
||||
{
|
||||
// level of detail based on size and type of the object
|
||||
float lod = PhysicsScene.MeshLOD;
|
||||
float lod = BSParam.MeshLOD;
|
||||
if (pbs.SculptEntry)
|
||||
lod = PhysicsScene.SculptLOD;
|
||||
lod = BSParam.SculptLOD;
|
||||
|
||||
// Mega prims usually get more detail because one can interact with shape approximations at this size.
|
||||
float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
|
||||
if (maxAxis > PhysicsScene.MeshMegaPrimThreshold)
|
||||
lod = PhysicsScene.MeshMegaPrimLOD;
|
||||
if (maxAxis > BSParam.MeshMegaPrimThreshold)
|
||||
lod = BSParam.MeshMegaPrimLOD;
|
||||
|
||||
retLod = lod;
|
||||
return pbs.GetMeshKey(size, lod);
|
||||
|
|
|
@ -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, PhysicsScene.Params.terrainCollisionMargin);
|
||||
m_mapInfo.heightMap, BSParam.TerrainCollisionMargin);
|
||||
|
||||
// Create the terrain shape from the mapInfo
|
||||
m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr),
|
||||
|
@ -110,9 +110,9 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
|||
m_mapInfo.ID, centerPos, Quaternion.Identity));
|
||||
|
||||
// Set current terrain attributes
|
||||
BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
||||
BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
||||
BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
||||
BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainFriction);
|
||||
BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, BSParam.TerrainHitFraction);
|
||||
BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, BSParam.TerrainRestitution);
|
||||
BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
||||
|
||||
// Return the new terrain to the world of physical objects
|
||||
|
|
|
@ -135,7 +135,7 @@ public sealed class BSTerrainManager : IDisposable
|
|||
// 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,
|
||||
PhysicsScene.Params.terrainCollisionMargin),
|
||||
BSParam.TerrainCollisionMargin),
|
||||
BSPhysicsShapeType.SHAPE_GROUNDPLANE);
|
||||
m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID,
|
||||
BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID,
|
||||
|
@ -309,9 +309,9 @@ public sealed class BSTerrainManager : IDisposable
|
|||
{
|
||||
PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
|
||||
LogHeader, PhysicsScene.RegionName, terrainRegionBase,
|
||||
(BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation);
|
||||
(BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
|
||||
BSTerrainPhys newTerrainPhys = null;
|
||||
switch ((int)PhysicsScene.Params.terrainImplementation)
|
||||
switch ((int)BSParam.TerrainImplementation)
|
||||
{
|
||||
case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
|
||||
newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
|
||||
|
@ -324,8 +324,8 @@ public sealed class BSTerrainManager : IDisposable
|
|||
default:
|
||||
PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
|
||||
LogHeader,
|
||||
(int)PhysicsScene.Params.terrainImplementation,
|
||||
PhysicsScene.Params.terrainImplementation,
|
||||
(int)BSParam.TerrainImplementation,
|
||||
BSParam.TerrainImplementation,
|
||||
PhysicsScene.RegionName, terrainRegionBase);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -116,9 +116,9 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
|||
}
|
||||
|
||||
// Set current terrain attributes
|
||||
BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction);
|
||||
BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
|
||||
BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution);
|
||||
BulletSimAPI.SetFriction2(m_terrainBody.ptr, BSParam.TerrainFriction);
|
||||
BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, BSParam.TerrainHitFraction);
|
||||
BulletSimAPI.SetRestitution2(m_terrainBody.ptr, BSParam.TerrainRestitution);
|
||||
BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
|
||||
|
||||
// Static objects are not very massive.
|
||||
|
|
|
@ -141,6 +141,8 @@ public struct EntityProperties
|
|||
}
|
||||
|
||||
// Format of this structure must match the definition in the C++ code
|
||||
// NOTE: adding the X causes compile breaks if used. These are unused symbols
|
||||
// that can be removed from both here and the unmanaged definition of this structure.
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct ConfigurationParameters
|
||||
{
|
||||
|
@ -150,31 +152,31 @@ public struct ConfigurationParameters
|
|||
public float collisionMargin;
|
||||
public float gravity;
|
||||
|
||||
public float linearDamping;
|
||||
public float angularDamping;
|
||||
public float deactivationTime;
|
||||
public float linearSleepingThreshold;
|
||||
public float angularSleepingThreshold;
|
||||
public float ccdMotionThreshold;
|
||||
public float ccdSweptSphereRadius;
|
||||
public float contactProcessingThreshold;
|
||||
public float XlinearDamping;
|
||||
public float XangularDamping;
|
||||
public float XdeactivationTime;
|
||||
public float XlinearSleepingThreshold;
|
||||
public float XangularSleepingThreshold;
|
||||
public float XccdMotionThreshold;
|
||||
public float XccdSweptSphereRadius;
|
||||
public float XcontactProcessingThreshold;
|
||||
|
||||
public float terrainImplementation;
|
||||
public float terrainFriction;
|
||||
public float terrainHitFraction;
|
||||
public float terrainRestitution;
|
||||
public float terrainCollisionMargin;
|
||||
public float XterrainImplementation;
|
||||
public float XterrainFriction;
|
||||
public float XterrainHitFraction;
|
||||
public float XterrainRestitution;
|
||||
public float XterrainCollisionMargin;
|
||||
|
||||
public float avatarFriction;
|
||||
public float avatarStandingFriction;
|
||||
public float avatarDensity;
|
||||
public float avatarRestitution;
|
||||
public float avatarCapsuleWidth;
|
||||
public float avatarCapsuleDepth;
|
||||
public float avatarCapsuleHeight;
|
||||
public float avatarContactProcessingThreshold;
|
||||
public float XavatarFriction;
|
||||
public float XavatarStandingFriction;
|
||||
public float XavatarDensity;
|
||||
public float XavatarRestitution;
|
||||
public float XavatarCapsuleWidth;
|
||||
public float XavatarCapsuleDepth;
|
||||
public float XavatarCapsuleHeight;
|
||||
public float XavatarContactProcessingThreshold;
|
||||
|
||||
public float vehicleAngularDamping;
|
||||
public float XvehicleAngularDamping;
|
||||
|
||||
public float maxPersistantManifoldPoolSize;
|
||||
public float maxCollisionAlgorithmPoolSize;
|
||||
|
@ -185,14 +187,14 @@ public struct ConfigurationParameters
|
|||
public float shouldEnableFrictionCaching;
|
||||
public float numberOfSolverIterations;
|
||||
|
||||
public float linksetImplementation;
|
||||
public float linkConstraintUseFrameOffset;
|
||||
public float linkConstraintEnableTransMotor;
|
||||
public float linkConstraintTransMotorMaxVel;
|
||||
public float linkConstraintTransMotorMaxForce;
|
||||
public float linkConstraintERP;
|
||||
public float linkConstraintCFM;
|
||||
public float linkConstraintSolverIterations;
|
||||
public float XlinksetImplementation;
|
||||
public float XlinkConstraintUseFrameOffset;
|
||||
public float XlinkConstraintEnableTransMotor;
|
||||
public float XlinkConstraintTransMotorMaxVel;
|
||||
public float XlinkConstraintTransMotorMaxForce;
|
||||
public float XlinkConstraintERP;
|
||||
public float XlinkConstraintCFM;
|
||||
public float XlinkConstraintSolverIterations;
|
||||
|
||||
public float physicsLoggingFrames;
|
||||
|
||||
|
|
|
@ -112,6 +112,9 @@ Test avatar walking up stairs. How does compare with SL.
|
|||
Debounce avatar contact so legs don't keep folding up when standing.
|
||||
Implement LSL physics controls. Like STATUS_ROTATE_X.
|
||||
Add border extensions to terrain to help region crossings and objects leaving region.
|
||||
Use a different capsule shape for avatar when sitting
|
||||
LL uses a pyrimidal shape scaled by the avatar's bounding box
|
||||
http://wiki.secondlife.com/wiki/File:Avmeshforms.png
|
||||
|
||||
Performance test with lots of avatars. Can BulletSim support a thousand?
|
||||
Optimize collisions in C++: only send up to the object subscribed to collisions.
|
||||
|
|
Loading…
Reference in New Issue