diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039705..95a41347be 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs @@ -80,10 +80,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin private Quaternion m_referenceFrame = Quaternion.Identity; // Linear properties + private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL - private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body private Vector3 m_linearFrictionTimescale = Vector3.Zero; private float m_linearMotorDecayTimescale = 0; private float m_linearMotorTimescale = 0; @@ -93,6 +93,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin // private Vector3 m_linearMotorOffset = Vector3.Zero; //Angular properties + private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor // private int m_angularMotorApply = 0; // application frame counter private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity @@ -152,10 +153,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: - m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); + m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); + m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; break; case Vehicle.ANGULAR_MOTOR_TIMESCALE: m_angularMotorTimescale = Math.Max(pValue, 0.01f); + m_angularMotor.TimeScale = m_angularMotorTimescale; break; case Vehicle.BANKING_EFFICIENCY: m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); @@ -185,10 +188,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); break; case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: - m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); + m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); + m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; break; case Vehicle.LINEAR_MOTOR_TIMESCALE: m_linearMotorTimescale = Math.Max(pValue, 0.01f); + m_linearMotor.TimeScale = m_linearMotorTimescale; break; case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); @@ -201,17 +206,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin // set all of the components to the same value case Vehicle.ANGULAR_FRICTION_TIMESCALE: m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); + m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; break; case Vehicle.ANGULAR_MOTOR_DIRECTION: m_angularMotorDirection = new Vector3(pValue, pValue, pValue); - // m_angularMotorApply = 100; + m_angularMotor.SetTarget(m_angularMotorDirection); break; case Vehicle.LINEAR_FRICTION_TIMESCALE: m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); + m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; break; case Vehicle.LINEAR_MOTOR_DIRECTION: m_linearMotorDirection = new Vector3(pValue, pValue, pValue); m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); + m_linearMotor.SetTarget(m_linearMotorDirection); break; case Vehicle.LINEAR_MOTOR_OFFSET: m_linearMotorOffset = new Vector3(pValue, pValue, pValue); @@ -227,6 +235,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin { case Vehicle.ANGULAR_FRICTION_TIMESCALE: m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; break; case Vehicle.ANGULAR_MOTOR_DIRECTION: // Limit requested angular speed to 2 rps= 4 pi rads/sec @@ -234,14 +243,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); - // m_angularMotorApply = 100; + m_angularMotor.SetTarget(m_angularMotorDirection); break; case Vehicle.LINEAR_FRICTION_TIMESCALE: m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; break; case Vehicle.LINEAR_MOTOR_DIRECTION: m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); + m_linearMotor.SetTarget(m_linearMotorDirection); break; case Vehicle.LINEAR_MOTOR_OFFSET: m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); @@ -319,6 +330,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_referenceFrame = Quaternion.Identity; m_flags = (VehicleFlag)0; + break; case Vehicle.TYPE_SLED: @@ -351,10 +363,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_bankingMix = 1; m_referenceFrame = Quaternion.Identity; - m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); - m_flags &= - ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | - VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); + m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY + | VehicleFlag.HOVER_TERRAIN_ONLY + | VehicleFlag.HOVER_GLOBAL_HEIGHT + | VehicleFlag.HOVER_UP_ONLY); + m_flags |= (VehicleFlag.NO_DEFLECTION_UP + | VehicleFlag.LIMIT_ROLL_ONLY + | VehicleFlag.LIMIT_MOTOR_UP); break; case Vehicle.TYPE_CAR: m_linearMotorDirection = Vector3.Zero; @@ -510,6 +525,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin | VehicleFlag.HOVER_GLOBAL_HEIGHT); break; } + + // Update any physical parameters based on this type. + Refresh(); + + m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, + m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f); + m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, + m_angularMotorDecayTimescale, m_angularFrictionTimescale, 1f); + m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) + + // m_bankingMotor = new BSVMotor("BankingMotor", ...); } // Some of the properties of this prim may have changed. @@ -518,13 +545,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (IsActive) { + m_vehicleMass = Prim.Linkset.LinksetMass; + // Friction effects are handled by this vehicle code - BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); - BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); + float friction = 0f; + BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); - // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); + // Moderate angular movement introduced by Bullet. + // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. + // Maybe compute linear and angular factor and damping from params. + float angularDamping = PhysicsScene.Params.vehicleAngularDamping; + BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); - VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); + // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet + // Vector3 localInertia = new Vector3(1f, 1f, 1f); + Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); + BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); + + VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", + Prim.LocalID, friction, localInertia, angularDamping); } } @@ -551,97 +590,38 @@ namespace OpenSim.Region.Physics.BulletSPlugin { if (!IsActive) return; - // DEBUG - // Because Bullet does apply forces to the vehicle, our last computed - // linear and angular velocities are not what is happening now. - // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; - // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; - // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time - // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: - // END DEBUG - - m_vehicleMass = Prim.Linkset.LinksetMass; - MoveLinear(pTimestep); - // Commented out for debug MoveAngular(pTimestep); - // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG - // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG LimitRotation(pTimestep); // remember the position so next step we can limit absolute movement effects m_lastPositionVector = Prim.ForcePosition; - VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG - Prim.LocalID, - BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), - BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), - Prim.Inertia, - m_vehicleMass - ); VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); - }// end Step + } // Apply the effect of the linear motor. // Also does hover and float. private void MoveLinear(float pTimestep) { - // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates - // m_lastLinearVelocityVector is the current speed we are moving in that direction - if (m_linearMotorDirection.LengthSquared() > 0.001f) - { - Vector3 origDir = m_linearMotorDirection; // DEBUG - Vector3 origVel = m_lastLinearVelocityVector; // DEBUG - // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison - Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG + Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); - // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete - Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; - m_lastLinearVelocityVector += addAmount; - - float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; - m_linearMotorDirection *= (1f - decayFactor); - - // Rotate new object velocity from vehicle relative to world coordinates - m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; - - // Apply friction for next time - Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; - m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); - - VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", - Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, - m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); - } - else - { - // if what remains of direction is very small, zero it. - m_linearMotorDirection = Vector3.Zero; - m_lastLinearVelocityVector = Vector3.Zero; - m_newVelocity = Vector3.Zero; - - VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); - } - - // m_newVelocity is velocity computed from linear motor in world coordinates + // Rotate new object velocity from vehicle relative to world coordinates + linearMotorContribution *= Prim.ForceOrientation; + // ================================================================== // Gravity and Buoyancy // There is some gravity, make a gravity force vector that is applied after object velocity. // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); - /* - * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... - // Preserve the current Z velocity - Vector3 vel_now = m_prim.Velocity; - m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity - */ - + // Current vehicle position Vector3 pos = Prim.ForcePosition; -// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); + // ================================================================== + Vector3 terrainHeightContribution = Vector3.Zero; // If below the terrain, move us above the ground a little. float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. @@ -650,11 +630,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin // if (rotatedSize.Z < terrainHeight) if (pos.Z < terrainHeight) { + // TODO: correct position by applying force rather than forcing position. pos.Z = terrainHeight + 2; Prim.ForcePosition = pos; VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); } + // ================================================================== + Vector3 hoverContribution = Vector3.Zero; // Check if hovering // m_VhoverEfficiency: 0=bouncy, 1=totally damped // m_VhoverTimescale: time to achieve height @@ -694,24 +677,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin // RA: where does the 50 come from? float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); // Replace Vertical speed with correction figure if significant - if (Math.Abs(verticalError) > 0.01f) + if (verticalError > 0.01f) { - m_newVelocity.Z += verticalCorrectionVelocity; + hoverContribution = new Vector3(0f, 0f, verticalCorrectionVelocity); //KF: m_VhoverEfficiency is not yet implemented } else if (verticalError < -0.01) { - m_newVelocity.Z -= verticalCorrectionVelocity; - } - else - { - m_newVelocity.Z = 0f; + hoverContribution = new Vector3(0f, 0f, -verticalCorrectionVelocity); } } - VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); + VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", + Prim.LocalID, pos, hoverContribution, m_VhoverHeight, m_VhoverTargetHeight); } + // ================================================================== Vector3 posChange = pos - m_lastPositionVector; if (m_BlockingEndPoint != Vector3.Zero) { @@ -749,70 +730,77 @@ namespace OpenSim.Region.Physics.BulletSPlugin } } - #region downForce - Vector3 downForce = Vector3.Zero; - + // ================================================================== + Vector3 limitMotorUpContribution = Vector3.Zero; if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) { // If the vehicle is motoring into the sky, get it going back down. - // Is this an angular force or both linear and angular?? float distanceAboveGround = pos.Z - terrainHeight; - if (distanceAboveGround > 2f) + if (distanceAboveGround > 1f) { // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); - downForce = new Vector3(0, 0, -distanceAboveGround); + limitMotorUpContribution = new Vector3(0, 0, -distanceAboveGround); } // TODO: this calculation is all wrong. From the description at // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce // has a decay factor. This says this force should // be computed with a motor. VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", - Prim.LocalID, distanceAboveGround, downForce); + Prim.LocalID, distanceAboveGround, limitMotorUpContribution); } - #endregion // downForce + + // ================================================================== + Vector3 newVelocity = linearMotorContribution + + terrainHeightContribution + + hoverContribution + + limitMotorUpContribution; // If not changing some axis, reduce out velocity if ((m_flags & (VehicleFlag.NO_X)) != 0) - m_newVelocity.X = 0; + newVelocity.X = 0; if ((m_flags & (VehicleFlag.NO_Y)) != 0) - m_newVelocity.Y = 0; + newVelocity.Y = 0; if ((m_flags & (VehicleFlag.NO_Z)) != 0) - m_newVelocity.Z = 0; + newVelocity.Z = 0; + // ================================================================== // Clamp REALLY high or low velocities - if (m_newVelocity.LengthSquared() > 1e6f) + float newVelocityLengthSq = newVelocity.LengthSquared(); + if (newVelocityLengthSq > 1e6f) { - m_newVelocity /= m_newVelocity.Length(); - m_newVelocity *= 1000f; + newVelocity /= newVelocity.Length(); + newVelocity *= 1000f; } - else if (m_newVelocity.LengthSquared() < 1e-6f) - m_newVelocity = Vector3.Zero; + else if (newVelocityLengthSq < 1e-6f) + newVelocity = Vector3.Zero; + // ================================================================== // Stuff new linear velocity into the vehicle - Prim.ForceVelocity = m_newVelocity; + Prim.ForceVelocity = newVelocity; // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG - Vector3 totalDownForce = downForce + grav; + // Other linear forces are applied as forces. + Vector3 totalDownForce = grav * m_vehicleMass; if (totalDownForce != Vector3.Zero) { - Prim.AddForce(totalDownForce * m_vehicleMass, false); - // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); + Prim.AddForce(totalDownForce, false); } VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", - Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); + Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, + newVelocity, Prim.Velocity, totalDownForce); } // end MoveLinear() + // ======================================================================= // ======================================================================= // Apply the effect of the angular motor. private void MoveAngular(float pTimestep) { // m_angularMotorDirection // angular velocity requested by LSL motor - // m_angularMotorApply // application frame counter // m_angularMotorVelocity // current angular motor velocity (ramps up and down) - // m_angularMotorTimescale // motor angular velocity ramp up rate + // m_angularMotorTimescale // motor angular velocity ramp up time // m_angularMotorDecayTimescale // motor angular velocity decay rate // m_angularFrictionTimescale // body angular velocity decay rate // m_lastAngularVelocity // what was last applied to body @@ -836,18 +824,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin m_angularMotorVelocity = Vector3.Zero; } - #region Vertical attactor - - Vector3 vertattr = Vector3.Zero; - Vector3 deflection = Vector3.Zero; - Vector3 banking = Vector3.Zero; + Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); + // ================================================================== + Vector3 verticalAttractionContribution = Vector3.Zero; // If vertical attaction timescale is reasonable and we applied an angular force last time... if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) { float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; if (Prim.IsColliding) - VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); + VAservo = pTimestep * 0.05f / m_verticalAttractionTimescale; VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); @@ -871,24 +857,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y // then .X increases, so change Body angular velocity X based on Y, and Y based on X. // Z is not changed. - vertattr.X = verticalError.Y; - vertattr.Y = - verticalError.X; - vertattr.Z = 0f; + verticalAttractionContribution.X = verticalError.Y; + verticalAttractionContribution.Y = - verticalError.X; + verticalAttractionContribution.Z = 0f; // scaling appears better usingsquare-law Vector3 angularVelocity = Prim.ForceRotationalVelocity; float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); - vertattr.X += bounce * angularVelocity.X; - vertattr.Y += bounce * angularVelocity.Y; + verticalAttractionContribution.X += bounce * angularVelocity.X; + verticalAttractionContribution.Y += bounce * angularVelocity.Y; VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", - Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); + Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, verticalAttractionContribution); } - #endregion // Vertical attactor - - #region Deflection + // ================================================================== + Vector3 deflectionContribution = Vector3.Zero; if (m_angularDeflectionEfficiency != 0) { // Compute a scaled vector that points in the preferred axis (X direction) @@ -899,18 +884,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); // Scale by efficiency and timescale - deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; + deflectionContribution = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", - Prim.LocalID, preferredAxisOfMotion, deflection); + Prim.LocalID, preferredAxisOfMotion, deflectionContribution); // This deflection computation is not correct. - deflection = Vector3.Zero; + deflectionContribution = Vector3.Zero; } - #endregion - - #region Banking - + // ================================================================== + Vector3 bankingContribution = Vector3.Zero; if (m_bankingEfficiency != 0) { Vector3 dir = Vector3.One * Prim.ForceOrientation; @@ -925,6 +908,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin float mix = Math.Abs(m_bankingMix); if (m_angularMotorVelocity.X == 0) { + // The vehicle is stopped /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) { Vector3 axisAngle; @@ -938,9 +922,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin }*/ } else - banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; + { + bankingContribution.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4; + } + + //If they are colliding, we probably shouldn't shove the prim around... probably if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) - //If they are colliding, we probably shouldn't shove the prim around... probably { float angVelZ = m_angularMotorVelocity.X*-1; /*if(angVelZ > mix) @@ -954,22 +941,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin else if (bankingRot.X < -3) bankingRot.X = -3; bankingRot *= Prim.ForceOrientation; - banking += bankingRot; + bankingContribution += bankingRot; } m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; - VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", - Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); + VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}", + Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, bankingContribution); } - #endregion - - m_lastVertAttractor = vertattr; + // ================================================================== + m_lastVertAttractor = verticalAttractionContribution; // Sum velocities - m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; - - #region Linear Motor Offset + m_lastAngularVelocity = angularMotorContribution + + verticalAttractionContribution + + bankingContribution + + deflectionContribution; + // ================================================================== //Offset section if (m_linearMotorOffset != Vector3.Zero) { @@ -985,8 +973,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin // // The torque created is the linear velocity crossed with the offset - // NOTE: this computation does should be in the linear section - // because there we know the impulse being applied. + // TODO: this computation should be in the linear section + // because that is where we know the impulse being applied. Vector3 torqueFromOffset = Vector3.Zero; // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); if (float.IsNaN(torqueFromOffset.X)) @@ -1000,8 +988,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); } - #endregion - + // ================================================================== + // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) { m_lastAngularVelocity.X = 0; @@ -1009,6 +997,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); } + // ================================================================== if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) { m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. @@ -1021,18 +1010,20 @@ namespace OpenSim.Region.Physics.BulletSPlugin // The above calculates the absolute angular velocity needed. Angular velocity is massless. // Since we are stuffing the angular velocity directly into the object, the computed // velocity needs to be scaled by the timestep. - Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); + // Also remove any motion that is on the object so added motion is only from vehicle. + Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) + - Prim.ForceRotationalVelocity); Prim.ForceRotationalVelocity = applyAngularForce; - // Decay the angular movement for next time - Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; - m_lastAngularVelocity *= Vector3.One - decayamount; - - VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", - Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); + VDetailLog("{0},MoveAngular,done,newRotVel={1},lastAngular={2}", + Prim.LocalID, applyAngularForce, m_lastAngularVelocity); } - } //end MoveAngular + } + // This is from previous instantiations of XXXDynamics.cs. + // Applies roll reference frame. + // TODO: is this the right way to separate the code to do this operation? + // Should this be in MoveAngular()? internal void LimitRotation(float timestep) { Quaternion rotq = Prim.ForceOrientation; diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000000..663b6f44b7 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs @@ -0,0 +1,191 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyrightD + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections.Generic; +using System.Text; +using System.Reflection; +using Nini.Config; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ + +public struct MaterialAttributes +{ + // Material type values that correspond with definitions for LSL + public enum Material : int + { + Stone = 0, + Metal, + Glass, + Wood, + Flesh, + Plastic, + Rubber, + Light, + // Hereafter are BulletSim additions + Avatar, + NumberOfTypes // the count of types in the enum. + } + // Names must be in the order of the above enum. + public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", + "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; + public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", + "ccdMotionThreshold", "ccdSweptSphereRadius" }; + + public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS) + { + type = t; + density = d; + friction = f; + restitution = r; + ccdMotionThreshold = ccdM; + ccdSweptSphereRadius = ccdS; + } + public string type; + public float density; + public float friction; + public float restitution; + public float ccdMotionThreshold; + public float ccdSweptSphereRadius; +} + +public static class BSMaterials +{ + public static MaterialAttributes[] Attributes; + + static BSMaterials() + { + // Attribute sets for both the non-physical and physical instances of materials. + Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; + } + + // This is where all the default material attributes are defined. + public static void InitializeFromDefaults(ConfigurationParameters parms) + { + // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", + // "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; + float dFriction = parms.defaultFriction; + float dRestitution = parms.defaultRestitution; + float dDensity = parms.defaultDensity; + float dCcdM = parms.ccdMotionThreshold; + float dCcdS = parms.ccdSweptSphereRadius; + Attributes[(int)MaterialAttributes.Material.Stone] = + new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Metal] = + new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Glass] = + new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Wood] = + new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Flesh] = + new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Plastic] = + new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Rubber] = + new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Light] = + new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Avatar] = + new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + + Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = + new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); + } + + // Under the [BulletSim] section, one can change the individual material + // attribute values. The format of the configuration parameter is: + // ["Physical"] = floatValue + // For instance: + // [BulletSim] + // StoneFriction = 0.2 + // FleshRestitutionPhysical = 0.8 + // Materials can have different parameters for their static and + // physical instantiations. When setting the non-physical value, + // both values are changed. Setting the physical value only changes + // the physical value. + public static void InitializefromParameters(IConfig pConfig) + { + int matType = 0; + foreach (string matName in MaterialAttributes.MaterialNames) + { + foreach (string attribName in MaterialAttributes.MaterialAttribs) + { + string paramName = matName + attribName; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue(matType, attribName, paramValue); + // set the physical value also + SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } + paramName += "Physical"; + if (pConfig.Contains(paramName)) + { + float paramValue = pConfig.GetFloat(paramName); + SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); + } + } + matType++; + } + } + + private static void SetAttributeValue(int matType, string attribName, float val) + { + MaterialAttributes thisAttrib = Attributes[matType]; + FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); + if (fieldInfo != null) + { + fieldInfo.SetValue(thisAttrib, val); + Attributes[matType] = thisAttrib; + } + } + + public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) + { + int ind = (int)type; + if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; + return Attributes[ind]; + } + +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c452b..480da2c9ee 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs @@ -1,104 +1,152 @@ -using System; -using System.Collections.Generic; -using System.Text; -using OpenMetaverse; - -namespace OpenSim.Region.Physics.BulletSPlugin -{ -public abstract class BSMotor -{ - public virtual void Reset() { } - public virtual void Zero() { } -} -// Can all the incremental stepping be replaced with motor classes? -public class BSVMotor : BSMotor -{ - public Vector3 FrameOfReference { get; set; } - public Vector3 Offset { get; set; } - - public float TimeScale { get; set; } - public float TargetValueDecayTimeScale { get; set; } - public Vector3 CurrentValueReductionTimescale { get; set; } - public float Efficiency { get; set; } - - public Vector3 TargetValue { get; private set; } - public Vector3 CurrentValue { get; private set; } - - - - BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) - { - TimeScale = timeScale; - TargetValueDecayTimeScale = decayTimeScale; - CurrentValueReductionTimescale = frictionTimeScale; - Efficiency = efficiency; - } - public void SetCurrent(Vector3 current) - { - CurrentValue = current; - } - public void SetTarget(Vector3 target) - { - TargetValue = target; - } - public Vector3 Step(float timeStep) - { - if (CurrentValue.LengthSquared() > 0.001f) - { - // Vector3 origDir = Target; // DEBUG - // Vector3 origVel = CurrentValue; // DEBUG - - // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete - Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; - CurrentValue += addAmount; - - float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; - TargetValue *= (1f - decayFactor); - - Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; - CurrentValue *= (Vector3.One - frictionFactor); - } - else - { - // if what remains of direction is very small, zero it. - TargetValue = Vector3.Zero; - CurrentValue = Vector3.Zero; - - // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); - } - return CurrentValue; - } -} - -public class BSFMotor : BSMotor -{ - public float TimeScale { get; set; } - public float DecayTimeScale { get; set; } - public float Friction { get; set; } - public float Efficiency { get; set; } - - public float Target { get; private set; } - public float CurrentValue { get; private set; } - - BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) - { - } - public void SetCurrent(float target) - { - } - public void SetTarget(float target) - { - } - public float Step(float timeStep) - { - return 0f; - } -} -public class BSPIDMotor : BSMotor -{ - // TODO: write and use this one - BSPIDMotor() - { - } -} -} +using System; +using System.Collections.Generic; +using System.Text; +using OpenMetaverse; + +namespace OpenSim.Region.Physics.BulletSPlugin +{ +public abstract class BSMotor +{ + public BSMotor(string useName) + { + UseName = useName; + PhysicsScene = null; + } + public virtual void Reset() { } + public virtual void Zero() { } + + public string UseName { get; private set; } + // Used only for outputting debug information. Might not be set so check for null. + public BSScene PhysicsScene { get; set; } + protected void MDetailLog(string msg, params Object[] parms) + { + if (PhysicsScene != null) + { + if (PhysicsScene.VehicleLoggingEnabled) + { + PhysicsScene.DetailLog(msg, parms); + } + } + } +} +// Can all the incremental stepping be replaced with motor classes? +public class BSVMotor : BSMotor +{ + public Vector3 FrameOfReference { get; set; } + public Vector3 Offset { get; set; } + + public float TimeScale { get; set; } + public float TargetValueDecayTimeScale { get; set; } + public Vector3 FrictionTimescale { get; set; } + public float Efficiency { get; set; } + + public Vector3 TargetValue { get; private set; } + public Vector3 CurrentValue { get; private set; } + + public BSVMotor(string useName) + : base(useName) + { + TimeScale = TargetValueDecayTimeScale = Efficiency = 1f; + FrictionTimescale = Vector3.Zero; + CurrentValue = TargetValue = Vector3.Zero; + } + public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) + : this(useName) + { + TimeScale = timeScale; + TargetValueDecayTimeScale = decayTimeScale; + FrictionTimescale = frictionTimeScale; + Efficiency = efficiency; + CurrentValue = TargetValue = Vector3.Zero; + } + public void SetCurrent(Vector3 current) + { + CurrentValue = current; + } + public void SetTarget(Vector3 target) + { + TargetValue = target; + } + public Vector3 Step(float timeStep) + { + Vector3 returnCurrent = Vector3.Zero; + if (!CurrentValue.ApproxEquals(TargetValue, 0.01f)) + { + Vector3 origTarget = TargetValue; // DEBUG + Vector3 origCurrVal = CurrentValue; // DEBUG + + // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete + Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; + CurrentValue += addAmount; + returnCurrent = CurrentValue; + + // The desired value reduces to zero when also reduces the difference with current. + float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; + TargetValue *= (1f - decayFactor); + + Vector3 frictionFactor = Vector3.Zero; + frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; + CurrentValue *= (Vector3.One - frictionFactor); + + MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", + BSScene.DetailLogZero, UseName, origTarget, origCurrVal, + timeStep, TimeScale, addAmount, + TargetValueDecayTimeScale, decayFactor, + FrictionTimescale, frictionFactor); + MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", + BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, + addAmount, decayFactor, frictionFactor, returnCurrent); + } + else + { + // Difference between what we have and target is small. Motor is done. + CurrentValue = Vector3.Zero; + TargetValue = Vector3.Zero; + + MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", + BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); + + } + return returnCurrent; + } + public override string ToString() + { + return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", + UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); + } +} + +public class BSFMotor : BSMotor +{ + public float TimeScale { get; set; } + public float DecayTimeScale { get; set; } + public float Friction { get; set; } + public float Efficiency { get; set; } + + public float Target { get; private set; } + public float CurrentValue { get; private set; } + + public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) + : base(useName) + { + } + public void SetCurrent(float target) + { + } + public void SetTarget(float target) + { + } + public float Step(float timeStep) + { + return 0f; + } +} +public class BSPIDMotor : BSMotor +{ + // TODO: write and use this one + public BSPIDMotor(string useName) + : base(useName) + { + } +} +} diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa2580b..caa6c4696f 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs @@ -342,13 +342,12 @@ public sealed class BSPrim : BSPhysObject // TODO: check for out of bounds // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. + // TODO: This should be intergrated with a geneal physics action mechanism. + // TODO: This should be moderated with PID'ness. if (ret) { - PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() - { - // Apply upforce and overcome gravity. - ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; - }); + // Apply upforce and overcome gravity. + AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); } return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1f2a..805e670c1b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs @@ -39,23 +39,10 @@ using log4net; using OpenMetaverse; // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) -// Test sculpties (verified that they don't work) -// Compute physics FPS reasonably // Based on material, set density and friction -// Don't use constraints in linksets of non-physical objects. Means having to move children manually. -// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? -// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) -// At the moment, physical and phantom causes object to drop through the terrain -// Physical phantom objects and related typing (collision options ) -// Check out llVolumeDetect. Must do something for that. -// Use collision masks for collision with terrain and phantom objects // More efficient memory usage when passing hull information from BSPrim to BulletSim -// Should prim.link() and prim.delink() membership checking happen at taint time? -// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect // Implement LockAngularMotion -// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) -// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. // Add PID movement operations. What does ScenePresence.MoveToTarget do? // Check terrain size. 128 or 127? // Raycast @@ -234,6 +221,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters if (m_physicsLoggingEnabled) { PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); + PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. } else { @@ -308,6 +296,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters // Do any replacements in the parameters m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); } + + // The material characteristics. + BSMaterials.InitializeFromDefaults(Params); + if (pConfig != null) + { + BSMaterials.InitializefromParameters(pConfig); + } } } @@ -1069,7 +1064,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters (s,p,l,v) => { s.PID_P = v; } ), new ParameterDefn("DefaultFriction", "Friction factor used on new objects", - 0.5f, + 0.2f, (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].defaultFriction; }, (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), @@ -1084,7 +1079,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters (s) => { return s.m_params[0].defaultRestitution; }, (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", - 0f, + 0.04f, (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].collisionMargin; }, (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), @@ -1151,7 +1146,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters (s) => { return s.m_params[0].terrainImplementation; }, (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , - 0.5f, + 0.3f, (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].terrainFriction; }, (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), @@ -1165,13 +1160,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].terrainRestitution; }, (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), + new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , + 0.04f, + (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, + (s) => { return s.m_params[0].terrainCollisionMargin; }, + (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ), + new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", 0.2f, (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].avatarFriction; }, (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", - 10f, + 0.99f, (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, (s) => { return s.m_params[0].avatarStandingFriction; }, (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), @@ -1206,6 +1207,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), + new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", + 0.95f, + (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, + (s) => { return s.m_params[0].vehicleAngularDamping; }, + (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", 0f, diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756cba9..1450f66491 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs @@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys { m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, m_mapInfo.minCoords, m_mapInfo.maxCoords, - m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); + m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); // Create the terrain shape from the mapInfo m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd33aa..cd623f1398 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs @@ -80,8 +80,6 @@ public sealed class BSTerrainManager // amount to make sure that a bounding box is built for the terrain. public const float HEIGHT_EQUAL_FUDGE = 0.2f; - public const float TERRAIN_COLLISION_MARGIN = 0.0f; - // Until the whole simulator is changed to pass us the region size, we rely on constants. public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); @@ -129,7 +127,8 @@ public sealed class BSTerrainManager { // The ground plane is here to catch things that are trying to drop to negative infinity BulletShape groundPlaneShape = new BulletShape( - BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), + BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, + PhysicsScene.Params.terrainCollisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE); m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, @@ -165,17 +164,22 @@ public sealed class BSTerrainManager // Release all the terrain we have allocated public void ReleaseTerrain() { - foreach (KeyValuePair kvp in m_terrains) + lock (m_terrains) { - kvp.Value.Dispose(); + foreach (KeyValuePair kvp in m_terrains) + { + kvp.Value.Dispose(); + } + m_terrains.Clear(); } - m_terrains.Clear(); } // The simulator wants to set a new heightmap for the terrain. public void SetTerrain(float[] heightMap) { float[] localHeightMap = heightMap; - PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() + // If there are multiple requests for changes to the same terrain between ticks, + // only do that last one. + PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() { if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) { @@ -211,6 +215,7 @@ public sealed class BSTerrainManager // terrain shape is created and added to the body. // This call is most often used to update the heightMap and parameters of the terrain. // (The above does suggest that some simplification/refactoring is in order.) + // Called during taint-time. private void UpdateTerrain(uint id, float[] heightMap, Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) { @@ -220,7 +225,7 @@ public sealed class BSTerrainManager // Find high and low points of passed heightmap. // The min and max passed in is usually the area objects can be in (maximum // object height, for instance). The terrain wants the bounding box for the - // terrain so we replace passed min and max Z with the actual terrain min/max Z. + // terrain so replace passed min and max Z with the actual terrain min/max Z. float minZ = float.MaxValue; float maxZ = float.MinValue; foreach (float height in heightMap) @@ -238,15 +243,15 @@ public sealed class BSTerrainManager Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); - BSTerrainPhys terrainPhys; - if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) + lock (m_terrains) { - // There is already a terrain in this spot. Free the old and build the new. - DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", - BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); - - PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() + BSTerrainPhys terrainPhys; + if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) { + // There is already a terrain in this spot. Free the old and build the new. + DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", + BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); + // Remove old terrain from the collection m_terrains.Remove(terrainRegionBase); // Release any physical memory it may be using. @@ -271,35 +276,24 @@ public sealed class BSTerrainManager // I hate doing this, but just bail return; } - }); - } - else - { - // We don't know about this terrain so either we are creating a new terrain or - // our mega-prim child is giving us a new terrain to add to the phys world - - // if this is a child terrain, calculate a unique terrain id - uint newTerrainID = id; - if (newTerrainID >= BSScene.CHILDTERRAIN_ID) - newTerrainID = ++m_terrainCount; - - float[] heightMapX = heightMap; - Vector3 minCoordsX = minCoords; - Vector3 maxCoordsX = maxCoords; - - DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", - BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); - - // Code that must happen at taint-time - PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() + } + else { - DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", - BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); + // We don't know about this terrain so either we are creating a new terrain or + // our mega-prim child is giving us a new terrain to add to the phys world + + // if this is a child terrain, calculate a unique terrain id + uint newTerrainID = id; + if (newTerrainID >= BSScene.CHILDTERRAIN_ID) + newTerrainID = ++m_terrainCount; + + DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", + BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); m_terrains.Add(terrainRegionBase, newTerrainPhys); m_terrainModified = true; - }); + } } } @@ -349,6 +343,7 @@ public sealed class BSTerrainManager // with the same parameters as last time. if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) return lastHeight; + m_terrainModified = false; lastHeightTX = tX; lastHeightTY = tY; @@ -358,19 +353,19 @@ public sealed class BSTerrainManager int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); - BSTerrainPhys physTerrain; - if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) + lock (m_terrains) { - ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); - DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", - BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); + BSTerrainPhys physTerrain; + if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) + { + ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); + } + else + { + PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", + LogHeader, PhysicsScene.RegionName, tX, tY); + } } - else - { - PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", - LogHeader, PhysicsScene.RegionName, tX, tY); - } - m_terrainModified = false; lastHeight = ret; return ret; } diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150931..d7afdeb038 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs @@ -217,8 +217,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys } } verticesCount = verticesCount / 3; - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", - BSScene.DetailLogZero, verticesCount); for (int yy = 0; yy < sizeY; yy++) { @@ -235,8 +233,6 @@ public sealed class BSTerrainMesh : BSTerrainPhys indicesCount += 6; } } - physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG - LogHeader, indicesCount); // DEBUG ret = true; } catch (Exception e) diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index e60a7604a8..12baee9ff5 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs @@ -287,6 +287,8 @@ public struct ConfigurationParameters public float terrainFriction; public float terrainHitFraction; public float terrainRestitution; + public float terrainCollisionMargin; + public float avatarFriction; public float avatarStandingFriction; public float avatarDensity; @@ -296,6 +298,8 @@ public struct ConfigurationParameters public float avatarCapsuleHeight; public float avatarContactProcessingThreshold; + public float vehicleAngularDamping; + public float maxPersistantManifoldPoolSize; public float maxCollisionAlgorithmPoolSize; public float shouldDisableContactPoolDynamicAllocation; @@ -481,6 +485,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern bool IsNativeShape2(IntPtr shape); +[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] +public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); + [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini index 8a451ecdad..e9bdabc7fe 100644 --- a/bin/OpenSimDefaults.ini +++ b/bin/OpenSimDefaults.ini @@ -221,10 +221,10 @@ ; to false if you have compatibility problems. ;CacheSculptMaps = true - ; Choose one of the physics engines below - ; OpenDynamicsEngine is by some distance the most developed physics engine - ; basicphysics effectively does not model physics at all, making all objects phantom - + ; Choose one of the physics engines below. + ; OpenDynamicsEngine is by some distance the most developed physics engine. + ; BulletSim is a high performance, up-and-coming physics engine. + ; basicphysics effectively does not model physics at all, making all objects phantom. physics = OpenDynamicsEngine ;physics = basicphysics ;physics = POS @@ -908,15 +908,18 @@ [BulletSim] ; World parameters - DefaultFriction = 0.50 + DefaultFriction = 0.20 DefaultDensity = 10.000006836 DefaultRestitution = 0.0 Gravity = -9.80665 - TerrainFriction = 0.50 - TerrainHitFriction = 0.8 + TerrainFriction = 0.30 + TerrainHitFraction = 0.8 TerrainRestitution = 0 + TerrainCollisionMargin = 0.04 + AvatarFriction = 0.2 + AvatarStandingFriction = 0.99 AvatarRestitution = 0.0 AvatarDensity = 60.0 AvatarCapsuleWidth = 0.6 @@ -930,27 +933,15 @@ LinearDamping = 0.0 AngularDamping = 0.0 DeactivationTime = 0.2 - LinearSleepingThreshold = 0.8 - AngularSleepingThreshold = 1.0 - CcdMotionThreshold = 0.0 - CcdSweptSphereRadius = 0.0 - ContactProcessingThreshold = 0.1 - ; If setting a pool size, also disable dynamic allocation (default pool size is 4096 with dynamic alloc) - MaxPersistantManifoldPoolSize = 0 - ShouldDisableContactPoolDynamicAllocation = False - ShouldForceUpdateAllAabbs = False - ShouldRandomizeSolverOrder = True - ShouldSplitSimulationIslands = True - ShouldEnableFrictionCaching = False - NumberOfSolverIterations = 0 + CollisionMargin = 0.04 ; Linkset constraint parameters + LinkImplementation = 1 ; 0=constraint, 1=compound LinkConstraintUseFrameOffset = False LinkConstraintEnableTransMotor = True LinkConstraintTransMotorMaxVel = 5.0 LinkConstraintTransMotorMaxForce = 0.1 - ; Whether to mesh sculpties MeshSculptedPrim = true diff --git a/bin/lib32/BulletSim.dll b/bin/lib32/BulletSim.dll index 2ae1c75e3d..38b11cd9f1 100755 Binary files a/bin/lib32/BulletSim.dll and b/bin/lib32/BulletSim.dll differ diff --git a/bin/lib32/libBulletSim.so b/bin/lib32/libBulletSim.so index d4852a55bd..f59ec978fc 100755 Binary files a/bin/lib32/libBulletSim.so and b/bin/lib32/libBulletSim.so differ diff --git a/bin/lib64/BulletSim.dll b/bin/lib64/BulletSim.dll index 77cf7e3f28..1861d6d21b 100755 Binary files a/bin/lib64/BulletSim.dll and b/bin/lib64/BulletSim.dll differ diff --git a/bin/lib64/libBulletSim.so b/bin/lib64/libBulletSim.so index 4ec62b2a66..e9b8845729 100755 Binary files a/bin/lib64/libBulletSim.so and b/bin/lib64/libBulletSim.so differ