aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs826
1 files changed, 555 insertions, 271 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index 13c2539..c16b7d3 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -35,17 +35,19 @@ using System.Collections.Generic;
35using System.Reflection; 35using System.Reflection;
36using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
37using OpenMetaverse; 37using OpenMetaverse;
38using OpenSim.Framework;
38using OpenSim.Region.Physics.Manager; 39using OpenSim.Region.Physics.Manager;
39 40
40namespace OpenSim.Region.Physics.BulletSPlugin 41namespace OpenSim.Region.Physics.BulletSPlugin
41{ 42{
42 public sealed class BSDynamics 43 public sealed class BSDynamics : BSActor
43 { 44 {
44 private static string LogHeader = "[BULLETSIM VEHICLE]"; 45 private static string LogHeader = "[BULLETSIM VEHICLE]";
45 46
46 private BSScene PhysicsScene { get; set; }
47 // the prim this dynamic controller belongs to 47 // the prim this dynamic controller belongs to
48 private BSPrim Prim { get; set; } 48 private BSPrim ControllingPrim { get; set; }
49
50 private bool m_haveRegisteredForSceneEvents;
49 51
50 // mass of the vehicle fetched each time we're calles 52 // mass of the vehicle fetched each time we're calles
51 private float m_vehicleMass; 53 private float m_vehicleMass;
@@ -108,10 +110,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
108 private float m_VhoverEfficiency = 0f; 110 private float m_VhoverEfficiency = 0f;
109 private float m_VhoverTimescale = 0f; 111 private float m_VhoverTimescale = 0f;
110 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height 112 private float m_VhoverTargetHeight = -1.0f; // if <0 then no hover, else its the current target height
111 private float m_VehicleBuoyancy = 0f; //KF: m_VehicleBuoyancy is set by VEHICLE_BUOYANCY for a vehicle. 113 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity)
112 // Modifies gravity. Slider between -1 (double-gravity) and 1 (full anti-gravity) 114 private float m_VehicleBuoyancy = 0f;
113 // KF: So far I have found no good method to combine a script-requested .Z velocity and gravity. 115 private Vector3 m_VehicleGravity = Vector3.Zero; // Gravity computed when buoyancy set
114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
115 116
116 //Attractor properties 117 //Attractor properties
117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); 118 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
@@ -124,22 +125,51 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 static readonly float PIOverFour = ((float)Math.PI) / 4f; 125 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f; 126 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
126 127
127 public BSDynamics(BSScene myScene, BSPrim myPrim) 128 // For debugging, flags to turn on and off individual corrections.
129 public bool enableAngularVerticalAttraction;
130 public bool enableAngularDeflection;
131 public bool enableAngularBanking;
132
133 public BSDynamics(BSScene myScene, BSPrim myPrim, string actorName)
134 : base(myScene, myPrim, actorName)
128 { 135 {
129 PhysicsScene = myScene; 136 ControllingPrim = myPrim;
130 Prim = myPrim;
131 Type = Vehicle.TYPE_NONE; 137 Type = Vehicle.TYPE_NONE;
138 m_haveRegisteredForSceneEvents = false;
139 SetupVehicleDebugging();
140 }
141
142 // Stopgap debugging enablement. Allows source level debugging but still checking
143 // in changes by making enablement of debugging flags from INI file.
144 public void SetupVehicleDebugging()
145 {
146 enableAngularVerticalAttraction = true;
147 enableAngularDeflection = false;
148 enableAngularBanking = true;
149 if (BSParam.VehicleDebuggingEnable)
150 {
151 enableAngularVerticalAttraction = true;
152 enableAngularDeflection = false;
153 enableAngularBanking = false;
154 }
132 } 155 }
133 156
134 // Return 'true' if this vehicle is doing vehicle things 157 // Return 'true' if this vehicle is doing vehicle things
135 public bool IsActive 158 public bool IsActive
136 { 159 {
137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } 160 get { return (Type != Vehicle.TYPE_NONE && ControllingPrim.IsPhysicallyActive); }
161 }
162
163 // Return 'true' if this a vehicle that should be sitting on the ground
164 public bool IsGroundVehicle
165 {
166 get { return (Type == Vehicle.TYPE_CAR || Type == Vehicle.TYPE_SLED); }
138 } 167 }
139 168
140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 169 #region Vehicle parameter setting
170 public void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
141 { 171 {
142 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 172 VDetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
143 switch (pParam) 173 switch (pParam)
144 { 174 {
145 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: 175 case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY:
@@ -167,6 +197,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 break; 197 break;
168 case Vehicle.BUOYANCY: 198 case Vehicle.BUOYANCY:
169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); 199 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
200 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
170 break; 201 break;
171 case Vehicle.HOVER_EFFICIENCY: 202 case Vehicle.HOVER_EFFICIENCY:
172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); 203 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
@@ -204,15 +235,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
204 // set all of the components to the same value 235 // set all of the components to the same value
205 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 236 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 237 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
208 break; 238 break;
209 case Vehicle.ANGULAR_MOTOR_DIRECTION: 239 case Vehicle.ANGULAR_MOTOR_DIRECTION:
210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 240 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
241 m_angularMotor.Zero();
211 m_angularMotor.SetTarget(m_angularMotorDirection); 242 m_angularMotor.SetTarget(m_angularMotorDirection);
212 break; 243 break;
213 case Vehicle.LINEAR_FRICTION_TIMESCALE: 244 case Vehicle.LINEAR_FRICTION_TIMESCALE:
214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 245 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
216 break; 246 break;
217 case Vehicle.LINEAR_MOTOR_DIRECTION: 247 case Vehicle.LINEAR_MOTOR_DIRECTION:
218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 248 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
@@ -228,12 +258,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
228 258
229 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) 259 internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue)
230 { 260 {
231 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 261 VDetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
232 switch (pParam) 262 switch (pParam)
233 { 263 {
234 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 264 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 265 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
237 break; 266 break;
238 case Vehicle.ANGULAR_MOTOR_DIRECTION: 267 case Vehicle.ANGULAR_MOTOR_DIRECTION:
239 // Limit requested angular speed to 2 rps= 4 pi rads/sec 268 // Limit requested angular speed to 2 rps= 4 pi rads/sec
@@ -241,11 +270,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); 270 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); 271 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 272 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
273 m_angularMotor.Zero();
244 m_angularMotor.SetTarget(m_angularMotorDirection); 274 m_angularMotor.SetTarget(m_angularMotorDirection);
245 break; 275 break;
246 case Vehicle.LINEAR_FRICTION_TIMESCALE: 276 case Vehicle.LINEAR_FRICTION_TIMESCALE:
247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 277 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
249 break; 278 break;
250 case Vehicle.LINEAR_MOTOR_DIRECTION: 279 case Vehicle.LINEAR_MOTOR_DIRECTION:
251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 280 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -263,7 +292,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
263 292
264 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) 293 internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue)
265 { 294 {
266 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", Prim.LocalID, pParam, pValue); 295 VDetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", ControllingPrim.LocalID, pParam, pValue);
267 switch (pParam) 296 switch (pParam)
268 { 297 {
269 case Vehicle.REFERENCE_FRAME: 298 case Vehicle.REFERENCE_FRAME:
@@ -277,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
277 306
278 internal void ProcessVehicleFlags(int pParam, bool remove) 307 internal void ProcessVehicleFlags(int pParam, bool remove)
279 { 308 {
280 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", Prim.LocalID, pParam, remove); 309 VDetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", ControllingPrim.LocalID, pParam, remove);
281 VehicleFlag parm = (VehicleFlag)pParam; 310 VehicleFlag parm = (VehicleFlag)pParam;
282 if (pParam == -1) 311 if (pParam == -1)
283 m_flags = (VehicleFlag)0; 312 m_flags = (VehicleFlag)0;
@@ -290,9 +319,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
290 } 319 }
291 } 320 }
292 321
293 internal void ProcessTypeChange(Vehicle pType) 322 public void ProcessTypeChange(Vehicle pType)
294 { 323 {
295 VDetailLog("{0},ProcessTypeChange,type={1}", Prim.LocalID, pType); 324 VDetailLog("{0},ProcessTypeChange,type={1}", ControllingPrim.LocalID, pType);
296 // Set Defaults For Type 325 // Set Defaults For Type
297 Type = pType; 326 Type = pType;
298 switch (pType) 327 switch (pType)
@@ -526,81 +555,136 @@ namespace OpenSim.Region.Physics.BulletSPlugin
526 break; 555 break;
527 } 556 }
528 557
529 // Update any physical parameters based on this type. 558 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, m_linearMotorDecayTimescale, 1f);
530 Refresh(); 559 m_linearMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536 560
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, 561 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, m_angularMotorDecayTimescale, 1f);
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale, 562 m_angularMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541 563
564 /* Not implemented
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, 565 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector, 566 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency); 567 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y 568 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) 569 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
570 */
571
572 if (this.Type == Vehicle.TYPE_NONE)
573 {
574 UnregisterForSceneEvents();
575 }
576 else
577 {
578 RegisterForSceneEvents();
579 }
580
581 // Update any physical parameters based on this type.
582 Refresh();
583 }
584 #endregion // Vehicle parameter setting
585
586 // BSActor.Refresh()
587 public override void Refresh()
588 {
589 // If asking for a refresh, reset the physical parameters before the next simulation step.
590 // Called whether active or not since the active state may be updated before the next step.
591 m_physicsScene.PostTaintObject("BSDynamics.Refresh", ControllingPrim.LocalID, delegate()
592 {
593 SetPhysicalParameters();
594 });
548 } 595 }
549 596
550 // Some of the properties of this prim may have changed. 597 // Some of the properties of this prim may have changed.
551 // Do any updating needed for a vehicle 598 // Do any updating needed for a vehicle
552 public void Refresh() 599 private void SetPhysicalParameters()
553 { 600 {
554 if (IsActive) 601 if (IsActive)
555 { 602 {
556 // Remember the mass so we don't have to fetch it every step 603 // Remember the mass so we don't have to fetch it every step
557 m_vehicleMass = Prim.Linkset.LinksetMass; 604 m_vehicleMass = ControllingPrim.TotalMass;
558 605
559 // Friction affects are handled by this vehicle code 606 // Friction affects are handled by this vehicle code
560 float friction = 0f; 607 m_physicsScene.PE.SetFriction(ControllingPrim.PhysBody, BSParam.VehicleFriction);
561 PhysicsScene.PE.SetFriction(Prim.PhysBody, friction); 608 m_physicsScene.PE.SetRestitution(ControllingPrim.PhysBody, BSParam.VehicleRestitution);
562 609
563 // Moderate angular movement introduced by Bullet. 610 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. 611 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params. 612 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping; 613 m_physicsScene.PE.SetAngularDamping(ControllingPrim.PhysBody, BSParam.VehicleAngularDamping);
567 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping); 614 m_physicsScene.PE.SetLinearFactor(ControllingPrim.PhysBody, BSParam.VehicleLinearFactor);
615 m_physicsScene.PE.SetAngularFactorV(ControllingPrim.PhysBody, BSParam.VehicleAngularFactor);
568 616
569 // Vehicles report collision events so we know when it's on the ground 617 // Vehicles report collision events so we know when it's on the ground
570 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 618 m_physicsScene.PE.AddToCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
619
620 ControllingPrim.Inertia = m_physicsScene.PE.CalculateLocalInertia(ControllingPrim.PhysShape.physShapeInfo, m_vehicleMass);
621 m_physicsScene.PE.SetMassProps(ControllingPrim.PhysBody, m_vehicleMass, ControllingPrim.Inertia);
622 m_physicsScene.PE.UpdateInertiaTensor(ControllingPrim.PhysBody);
623
624 // Set the gravity for the vehicle depending on the buoyancy
625 // TODO: what should be done if prim and vehicle buoyancy differ?
626 m_VehicleGravity = ControllingPrim.ComputeGravity(m_VehicleBuoyancy);
627 // The actual vehicle gravity is set to zero in Bullet so we can do all the application of same.
628 m_physicsScene.PE.SetGravity(ControllingPrim.PhysBody, Vector3.Zero);
629
630 VDetailLog("{0},BSDynamics.SetPhysicalParameters,mass={1},inert={2},vehGrav={3},aDamp={4},frict={5},rest={6},lFact={7},aFact={8}",
631 ControllingPrim.LocalID, m_vehicleMass, ControllingPrim.Inertia, m_VehicleGravity,
632 BSParam.VehicleAngularDamping, BSParam.VehicleFriction, BSParam.VehicleRestitution,
633 BSParam.VehicleLinearFactor, BSParam.VehicleAngularFactor
634 );
635 }
636 else
637 {
638 if (ControllingPrim.PhysBody.HasPhysicalBody)
639 m_physicsScene.PE.RemoveFromCollisionFlags(ControllingPrim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
640 }
641 }
571 642
572 Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass); 643 // BSActor.RemoveBodyDependencies
573 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia); 644 public override void RemoveDependencies()
574 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody); 645 {
646 Refresh();
647 }
575 648
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy); 649 // BSActor.Release()
577 PhysicsScene.PE.SetGravity(Prim.PhysBody, grav); 650 public override void Dispose()
651 {
652 UnregisterForSceneEvents();
653 Type = Vehicle.TYPE_NONE;
654 Enabled = false;
655 return;
656 }
578 657
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", 658 private void RegisterForSceneEvents()
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); 659 {
581 } 660 if (!m_haveRegisteredForSceneEvents)
582 else
583 { 661 {
584 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS); 662 m_physicsScene.BeforeStep += this.Step;
663 m_physicsScene.AfterStep += this.PostStep;
664 ControllingPrim.OnPreUpdateProperty += this.PreUpdateProperty;
665 m_haveRegisteredForSceneEvents = true;
585 } 666 }
586 } 667 }
587 668
588 public bool RemoveBodyDependencies(BSPhysObject prim) 669 private void UnregisterForSceneEvents()
589 { 670 {
590 // If active, we need to add our properties back when the body is rebuilt. 671 if (m_haveRegisteredForSceneEvents)
591 return IsActive; 672 {
673 m_physicsScene.BeforeStep -= this.Step;
674 m_physicsScene.AfterStep -= this.PostStep;
675 ControllingPrim.OnPreUpdateProperty -= this.PreUpdateProperty;
676 m_haveRegisteredForSceneEvents = false;
677 }
592 } 678 }
593 679
594 public void RestoreBodyDependencies(BSPhysObject prim) 680 private void PreUpdateProperty(ref EntityProperties entprop)
595 { 681 {
596 if (Prim.LocalID != prim.LocalID) 682 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
683 // TODO: handle physics introduced by Bullet with computed vehicle physics.
684 if (IsActive)
597 { 685 {
598 // The call should be on us by our prim. Error if not. 686 entprop.RotationalVelocity = Vector3.Zero;
599 PhysicsScene.Logger.ErrorFormat("{0} RestoreBodyDependencies: called by not my prim. passedLocalID={1}, vehiclePrimLocalID={2}",
600 LogHeader, prim.LocalID, Prim.LocalID);
601 return;
602 } 687 }
603 Refresh();
604 } 688 }
605 689
606 #region Known vehicle value functions 690 #region Known vehicle value functions
@@ -617,70 +701,87 @@ namespace OpenSim.Region.Physics.BulletSPlugin
617 private Vector3 m_knownPosition; 701 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity; 702 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce; 703 private Vector3 m_knownForce;
704 private Vector3 m_knownForceImpulse;
620 private Quaternion m_knownOrientation; 705 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity; 706 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce; 707 private Vector3 m_knownRotationalForce;
708 private Vector3 m_knownRotationalImpulse;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed 709 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
624 710
625 private const int m_knownChangedPosition = 1 << 0; 711 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1; 712 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2; 713 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3; 714 private const int m_knownChangedForceImpulse = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4; 715 private const int m_knownChangedOrientation = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5; 716 private const int m_knownChangedRotationalVelocity = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6; 717 private const int m_knownChangedRotationalForce = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7; 718 private const int m_knownChangedRotationalImpulse = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8; 719 private const int m_knownChangedTerrainHeight = 1 << 8;
634 720 private const int m_knownChangedWaterLevel = 1 << 9;
635 private void ForgetKnownVehicleProperties() 721 private const int m_knownChangedForwardVelocity = 1 <<10;
722
723 public void ForgetKnownVehicleProperties()
636 { 724 {
637 m_knownHas = 0; 725 m_knownHas = 0;
638 m_knownChanged = 0; 726 m_knownChanged = 0;
639 } 727 }
640 // Push all the changed values back into the physics engine 728 // Push all the changed values back into the physics engine
641 private void PushKnownChanged() 729 public void PushKnownChanged()
642 { 730 {
643 if (m_knownChanged != 0) 731 if (m_knownChanged != 0)
644 { 732 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0) 733 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition; 734 ControllingPrim.ForcePosition = m_knownPosition;
647 735
648 if ((m_knownChanged & m_knownChangedOrientation) != 0) 736 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation; 737 ControllingPrim.ForceOrientation = m_knownOrientation;
650 738
651 if ((m_knownChanged & m_knownChangedVelocity) != 0) 739 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 { 740 {
653 Prim.ForceVelocity = m_knownVelocity; 741 ControllingPrim.ForceVelocity = m_knownVelocity;
654 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity); 742 // Fake out Bullet by making it think the velocity is the same as last time.
743 // Bullet does a bunch of smoothing for changing parameters.
744 // Since the vehicle is demanding this setting, we override Bullet's smoothing
745 // by telling Bullet the value was the same last time.
746 // PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, m_knownVelocity);
655 } 747 }
656 748
657 if ((m_knownChanged & m_knownChangedForce) != 0) 749 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true); 750 ControllingPrim.AddForce((Vector3)m_knownForce, false /*pushForce*/, true /*inTaintTime*/);
751
752 if ((m_knownChanged & m_knownChangedForceImpulse) != 0)
753 ControllingPrim.AddForceImpulse((Vector3)m_knownForceImpulse, false /*pushforce*/, true /*inTaintTime*/);
659 754
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) 755 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 { 756 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity; 757 ControllingPrim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time. 758 // PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
664 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
665 } 759 }
666 760
761 if ((m_knownChanged & m_knownChangedRotationalImpulse) != 0)
762 ControllingPrim.ApplyTorqueImpulse((Vector3)m_knownRotationalImpulse, true /*inTaintTime*/);
763
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0) 764 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); 765 {
766 ControllingPrim.AddAngularForce((Vector3)m_knownRotationalForce, false /*pushForce*/, true /*inTaintTime*/);
767 }
669 768
670 // If we set one of the values (ie, the physics engine didn't do it) we must force 769 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator. 770 // an UpdateProperties event to send the changes up to the simulator.
672 PhysicsScene.PE.PushUpdate(Prim.PhysBody); 771 m_physicsScene.PE.PushUpdate(ControllingPrim.PhysBody);
673 } 772 }
674 m_knownChanged = 0; 773 m_knownChanged = 0;
675 } 774 }
676 775
677 // Since the computation of terrain height can be a little involved, this routine 776 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step. 777 // is used to fetch the height only once for each vehicle simulation step.
778 Vector3 lastRememberedHeightPos;
679 private float GetTerrainHeight(Vector3 pos) 779 private float GetTerrainHeight(Vector3 pos)
680 { 780 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0) 781 if ((m_knownHas & m_knownChangedTerrainHeight) == 0 || pos != lastRememberedHeightPos)
682 { 782 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 783 lastRememberedHeightPos = pos;
784 m_knownTerrainHeight = ControllingPrim.PhysScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight; 785 m_knownHas |= m_knownChangedTerrainHeight;
685 } 786 }
686 return m_knownTerrainHeight; 787 return m_knownTerrainHeight;
@@ -692,7 +793,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
692 { 793 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0) 794 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
694 { 795 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); 796 m_knownWaterLevel = ControllingPrim.PhysScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel; 797 m_knownHas |= m_knownChangedWaterLevel;
697 } 798 }
698 return (float)m_knownWaterLevel; 799 return (float)m_knownWaterLevel;
@@ -704,7 +805,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
704 { 805 {
705 if ((m_knownHas & m_knownChangedPosition) == 0) 806 if ((m_knownHas & m_knownChangedPosition) == 0)
706 { 807 {
707 m_knownPosition = Prim.ForcePosition; 808 m_knownPosition = ControllingPrim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition; 809 m_knownHas |= m_knownChangedPosition;
709 } 810 }
710 return m_knownPosition; 811 return m_knownPosition;
@@ -723,7 +824,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
723 { 824 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0) 825 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 { 826 {
726 m_knownOrientation = Prim.ForceOrientation; 827 m_knownOrientation = ControllingPrim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation; 828 m_knownHas |= m_knownChangedOrientation;
728 } 829 }
729 return m_knownOrientation; 830 return m_knownOrientation;
@@ -742,10 +843,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
742 { 843 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0) 844 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 { 845 {
745 m_knownVelocity = Prim.ForceVelocity; 846 m_knownVelocity = ControllingPrim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity; 847 m_knownHas |= m_knownChangedVelocity;
747 } 848 }
748 return (Vector3)m_knownVelocity; 849 return m_knownVelocity;
749 } 850 }
750 set 851 set
751 { 852 {
@@ -755,15 +856,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
755 } 856 }
756 } 857 }
757 858
758 private void VehicleAddForce(Vector3 aForce) 859 private void VehicleAddForce(Vector3 pForce)
759 { 860 {
760 if ((m_knownHas & m_knownChangedForce) == 0) 861 if ((m_knownHas & m_knownChangedForce) == 0)
761 { 862 {
762 m_knownForce = Vector3.Zero; 863 m_knownForce = Vector3.Zero;
864 m_knownHas |= m_knownChangedForce;
763 } 865 }
764 m_knownForce += aForce; 866 m_knownForce += pForce;
765 m_knownChanged |= m_knownChangedForce; 867 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce; 868 }
869
870 private void VehicleAddForceImpulse(Vector3 pImpulse)
871 {
872 if ((m_knownHas & m_knownChangedForceImpulse) == 0)
873 {
874 m_knownForceImpulse = Vector3.Zero;
875 m_knownHas |= m_knownChangedForceImpulse;
876 }
877 m_knownForceImpulse += pImpulse;
878 m_knownChanged |= m_knownChangedForceImpulse;
767 } 879 }
768 880
769 private Vector3 VehicleRotationalVelocity 881 private Vector3 VehicleRotationalVelocity
@@ -772,7 +884,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
772 { 884 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0) 885 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 { 886 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity; 887 m_knownRotationalVelocity = ControllingPrim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity; 888 m_knownHas |= m_knownChangedRotationalVelocity;
777 } 889 }
778 return (Vector3)m_knownRotationalVelocity; 890 return (Vector3)m_knownRotationalVelocity;
@@ -794,6 +906,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin
794 m_knownChanged |= m_knownChangedRotationalForce; 906 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce; 907 m_knownHas |= m_knownChangedRotationalForce;
796 } 908 }
909 private void VehicleAddRotationalImpulse(Vector3 pImpulse)
910 {
911 if ((m_knownHas & m_knownChangedRotationalImpulse) == 0)
912 {
913 m_knownRotationalImpulse = Vector3.Zero;
914 m_knownHas |= m_knownChangedRotationalImpulse;
915 }
916 m_knownRotationalImpulse += pImpulse;
917 m_knownChanged |= m_knownChangedRotationalImpulse;
918 }
919
797 // Vehicle relative forward velocity 920 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity 921 private Vector3 VehicleForwardVelocity
799 { 922 {
@@ -822,9 +945,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin
822 { 945 {
823 if (!IsActive) return; 946 if (!IsActive) return;
824 947
825 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
826 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
827
828 ForgetKnownVehicleProperties(); 948 ForgetKnownVehicleProperties();
829 949
830 MoveLinear(pTimestep); 950 MoveLinear(pTimestep);
@@ -839,106 +959,116 @@ namespace OpenSim.Region.Physics.BulletSPlugin
839 // for the physics engine to note the changes so an UpdateProperties event will happen. 959 // for the physics engine to note the changes so an UpdateProperties event will happen.
840 PushKnownChanged(); 960 PushKnownChanged();
841 961
842 if (PhysicsScene.VehiclePhysicalLoggingEnabled) 962 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
843 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody); 963 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
844 964
845 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 965 VDetailLog("{0},BSDynamics.Step,done,pos={1}, force={2},velocity={3},angvel={4}",
846 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); 966 ControllingPrim.LocalID, VehiclePosition, m_knownForce, VehicleVelocity, VehicleRotationalVelocity);
847 } 967 }
848 968
849 // Apply the effect of the linear motor and other linear motions (like hover and float). 969 // Called after the simulation step
850 private void MoveLinear(float pTimestep) 970 internal void PostStep(float pTimestep)
851 { 971 {
852 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); 972 if (!IsActive) return;
853 973
854 // The movement computed in the linear motor is relative to the vehicle 974 if (m_physicsScene.VehiclePhysicalLoggingEnabled)
855 // coordinates. Rotate the movement to world coordinates. 975 m_physicsScene.PE.DumpRigidBody(m_physicsScene.World, ControllingPrim.PhysBody);
856 linearMotorContribution *= VehicleOrientation; 976 }
857 977
858 // ================================================================== 978 // Apply the effect of the linear motor and other linear motions (like hover and float).
859 // Buoyancy: force to overcome gravity. 979 private void MoveLinear(float pTimestep)
860 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 980 {
861 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. 981 ComputeLinearVelocity(pTimestep);
862 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
863 982
864 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); 983 ComputeLinearTerrainHeightCorrection(pTimestep);
865 984
866 Vector3 hoverContribution = ComputeLinearHover(pTimestep); 985 ComputeLinearHover(pTimestep);
867 986
868 ComputeLinearBlockingEndPoint(pTimestep); 987 ComputeLinearBlockingEndPoint(pTimestep);
869 988
870 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); 989 ComputeLinearMotorUp(pTimestep);
871 990
872 // ================================================================== 991 ApplyGravity(pTimestep);
873 Vector3 newVelocity = linearMotorContribution
874 + terrainHeightContribution
875 + hoverContribution
876 + limitMotorUpContribution;
877
878 Vector3 newForce = buoyancyContribution;
879 992
880 // If not changing some axis, reduce out velocity 993 // If not changing some axis, reduce out velocity
881 if ((m_flags & (VehicleFlag.NO_X)) != 0) 994 if ((m_flags & (VehicleFlag.NO_X | VehicleFlag.NO_Y | VehicleFlag.NO_Z)) != 0)
882 newVelocity.X = 0; 995 {
883 if ((m_flags & (VehicleFlag.NO_Y)) != 0) 996 Vector3 vel = VehicleVelocity;
884 newVelocity.Y = 0; 997 if ((m_flags & (VehicleFlag.NO_X)) != 0)
885 if ((m_flags & (VehicleFlag.NO_Z)) != 0) 998 vel.X = 0;
886 newVelocity.Z = 0; 999 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
1000 vel.Y = 0;
1001 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
1002 vel.Z = 0;
1003 VehicleVelocity = vel;
1004 }
887 1005
888 // ================================================================== 1006 // ==================================================================
889 // Clamp high or low velocities 1007 // Clamp high or low velocities
890 float newVelocityLengthSq = newVelocity.LengthSquared(); 1008 float newVelocityLengthSq = VehicleVelocity.LengthSquared();
891 if (newVelocityLengthSq > 1000f) 1009 if (newVelocityLengthSq > BSParam.VehicleMaxLinearVelocitySquared)
892 { 1010 {
893 newVelocity /= newVelocity.Length(); 1011 Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
894 newVelocity *= 1000f; 1012 VehicleVelocity /= VehicleVelocity.Length();
1013 VehicleVelocity *= BSParam.VehicleMaxLinearVelocity;
1014 VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
1015 ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
895 } 1016 }
896 else if (newVelocityLengthSq < 0.001f) 1017 else if (newVelocityLengthSq < 0.001f)
897 newVelocity = Vector3.Zero; 1018 VehicleVelocity = Vector3.Zero;
898 1019
899 // ================================================================== 1020 VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.IsColliding, VehicleVelocity );
900 // Stuff new linear velocity into the vehicle. 1021
901 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. 1022 } // end MoveLinear()
902 VehicleVelocity = newVelocity; 1023
1024 public void ComputeLinearVelocity(float pTimestep)
1025 {
1026 // Step the motor from the current value. Get the correction needed this step.
1027 Vector3 origVelW = VehicleVelocity; // DEBUG
1028 Vector3 currentVelV = VehicleVelocity * Quaternion.Inverse(VehicleOrientation);
1029 Vector3 linearMotorCorrectionV = m_linearMotor.Step(pTimestep, currentVelV);
1030
1031 // Friction reduces vehicle motion
1032 Vector3 frictionFactorW = ComputeFrictionFactor(m_linearFrictionTimescale, pTimestep);
1033 linearMotorCorrectionV -= (currentVelV * frictionFactorW);
903 1034
904 // Other linear forces are applied as forces. 1035 // Motor is vehicle coordinates. Rotate it to world coordinates
905 Vector3 totalDownForce = newForce * m_vehicleMass; 1036 Vector3 linearMotorVelocityW = linearMotorCorrectionV * VehicleOrientation;
906 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) 1037
1038 // If we're a ground vehicle, don't add any upward Z movement
1039 if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0)
907 { 1040 {
908 VehicleAddForce(totalDownForce); 1041 if (linearMotorVelocityW.Z > 0f)
1042 linearMotorVelocityW.Z = 0f;
909 } 1043 }
910 1044
911 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", 1045 // Add this correction to the velocity to make it faster/slower.
912 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); 1046 VehicleVelocity += linearMotorVelocityW;
913 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
914 Prim.LocalID,
915 linearMotorContribution, terrainHeightContribution, hoverContribution,
916 limitMotorUpContribution, buoyancyContribution
917 );
918 1047
919 } // end MoveLinear()
920 1048
921 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) 1049
1050 VDetailLog("{0}, MoveLinear,velocity,origVelW={1},velV={2},correctV={3},correctW={4},newVelW={5},fricFact={6}",
1051 ControllingPrim.LocalID, origVelW, currentVelV, linearMotorCorrectionV,
1052 linearMotorVelocityW, VehicleVelocity, frictionFactorW);
1053 }
1054
1055 public void ComputeLinearTerrainHeightCorrection(float pTimestep)
922 { 1056 {
923 Vector3 ret = Vector3.Zero;
924 // If below the terrain, move us above the ground a little. 1057 // If below the terrain, move us above the ground a little.
925 // TODO: Consider taking the rotated size of the object or possibly casting a ray. 1058 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
926 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) 1059 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
927 { 1060 {
928 // TODO: correct position by applying force rather than forcing position. 1061 // Force position because applying force won't get the vehicle through the terrain
929 Vector3 newPosition = VehiclePosition; 1062 Vector3 newPosition = VehiclePosition;
930 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; 1063 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
931 VehiclePosition = newPosition; 1064 VehiclePosition = newPosition;
932 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", 1065 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
933 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); 1066 ControllingPrim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
934 } 1067 }
935 return ret;
936 } 1068 }
937 1069
938 public Vector3 ComputeLinearHover(float pTimestep) 1070 public void ComputeLinearHover(float pTimestep)
939 { 1071 {
940 Vector3 ret = Vector3.Zero;
941
942 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 1072 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
943 // m_VhoverTimescale: time to achieve height 1073 // m_VhoverTimescale: time to achieve height
944 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 1074 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -963,7 +1093,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
963 if (VehiclePosition.Z > m_VhoverTargetHeight) 1093 if (VehiclePosition.Z > m_VhoverTargetHeight)
964 m_VhoverTargetHeight = VehiclePosition.Z; 1094 m_VhoverTargetHeight = VehiclePosition.Z;
965 } 1095 }
966 1096
967 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 1097 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
968 { 1098 {
969 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) 1099 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
@@ -971,26 +1101,42 @@ namespace OpenSim.Region.Physics.BulletSPlugin
971 Vector3 pos = VehiclePosition; 1101 Vector3 pos = VehiclePosition;
972 pos.Z = m_VhoverTargetHeight; 1102 pos.Z = m_VhoverTargetHeight;
973 VehiclePosition = pos; 1103 VehiclePosition = pos;
1104
1105 VDetailLog("{0}, MoveLinear,hover,pos={1},lockHoverHeight", ControllingPrim.LocalID, pos);
974 } 1106 }
975 } 1107 }
976 else 1108 else
977 { 1109 {
978 // Error is positive if below the target and negative if above. 1110 // Error is positive if below the target and negative if above.
979 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; 1111 Vector3 hpos = VehiclePosition;
1112 float verticalError = m_VhoverTargetHeight - hpos.Z;
1113 float verticalCorrection = verticalError / m_VhoverTimescale;
1114 verticalCorrection *= m_VhoverEfficiency;
1115
1116 hpos.Z += verticalCorrection;
1117 VehiclePosition = hpos;
1118
1119 // Since we are hovering, we need to do the opposite of falling -- get rid of world Z
1120 Vector3 vel = VehicleVelocity;
1121 vel.Z = 0f;
1122 VehicleVelocity = vel;
1123
1124 /*
980 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; 1125 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
1126 Vector3 verticalCorrection = new Vector3(0f, 0f, verticalCorrectionVelocity);
1127 verticalCorrection *= m_vehicleMass;
981 1128
982 // TODO: implement m_VhoverEfficiency correctly 1129 // TODO: implement m_VhoverEfficiency correctly
983 if (Math.Abs(verticalError) > m_VhoverEfficiency) 1130 VehicleAddForceImpulse(verticalCorrection);
984 { 1131 */
985 ret = new Vector3(0f, 0f, verticalCorrectionVelocity); 1132
986 } 1133 VDetailLog("{0}, MoveLinear,hover,pos={1},eff={2},hoverTS={3},height={4},target={5},err={6},corr={7}",
1134 ControllingPrim.LocalID, VehiclePosition, m_VhoverEfficiency,
1135 m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight,
1136 verticalError, verticalCorrection);
987 } 1137 }
988 1138
989 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
990 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
991 } 1139 }
992
993 return ret;
994 } 1140 }
995 1141
996 public bool ComputeLinearBlockingEndPoint(float pTimestep) 1142 public bool ComputeLinearBlockingEndPoint(float pTimestep)
@@ -1030,7 +1176,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1030 { 1176 {
1031 VehiclePosition = pos; 1177 VehiclePosition = pos;
1032 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1178 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
1033 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1179 ControllingPrim.LocalID, m_BlockingEndPoint, posChange, pos);
1034 } 1180 }
1035 } 1181 }
1036 return changed; 1182 return changed;
@@ -1041,34 +1187,75 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1041 // used with conjunction with banking: the strength of the banking will decay when the 1187 // used with conjunction with banking: the strength of the banking will decay when the
1042 // vehicle no longer experiences collisions. The decay timescale is the same as 1188 // vehicle no longer experiences collisions. The decay timescale is the same as
1043 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering 1189 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1044 // when they are in mid jump. 1190 // when they are in mid jump.
1045 // TODO: this code is wrong. Also, what should it do for boats (height from water)? 1191 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1046 // This is just using the ground and a general collision check. Should really be using 1192 // This is just using the ground and a general collision check. Should really be using
1047 // a downward raycast to find what is below. 1193 // a downward raycast to find what is below.
1048 public Vector3 ComputeLinearMotorUp(float pTimestep) 1194 public void ComputeLinearMotorUp(float pTimestep)
1049 { 1195 {
1050 Vector3 ret = Vector3.Zero;
1051 float distanceAboveGround = 0f;
1052
1053 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1196 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
1054 { 1197 {
1198 // This code tries to decide if the object is not on the ground and then pushing down
1199 /*
1055 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); 1200 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
1056 distanceAboveGround = VehiclePosition.Z - targetHeight; 1201 distanceAboveGround = VehiclePosition.Z - targetHeight;
1057 // Not colliding if the vehicle is off the ground 1202 // Not colliding if the vehicle is off the ground
1058 if (!Prim.IsColliding) 1203 if (!Prim.IsColliding)
1059 { 1204 {
1060 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1205 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
1061 ret = new Vector3(0, 0, -distanceAboveGround); 1206 VehicleVelocity += new Vector3(0, 0, -distanceAboveGround);
1062 } 1207 }
1063 // TODO: this calculation is wrong. From the description at 1208 // TODO: this calculation is wrong. From the description at
1064 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1209 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
1065 // has a decay factor. This says this force should 1210 // has a decay factor. This says this force should
1066 // be computed with a motor. 1211 // be computed with a motor.
1067 // TODO: add interaction with banking. 1212 // TODO: add interaction with banking.
1068 } 1213 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1069 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
1070 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); 1214 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
1071 return ret; 1215 */
1216
1217 // Another approach is to measure if we're going up. If going up and not colliding,
1218 // the vehicle is in the air. Fix that by pushing down.
1219 if (!ControllingPrim.IsColliding && VehicleVelocity.Z > 0.1)
1220 {
1221 // Get rid of any of the velocity vector that is pushing us up.
1222 float upVelocity = VehicleVelocity.Z;
1223 VehicleVelocity += new Vector3(0, 0, -upVelocity);
1224
1225 /*
1226 // If we're pointed up into the air, we should nose down
1227 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1228 // The rotation around the Y axis is pitch up or down
1229 if (pointingDirection.Y > 0.01f)
1230 {
1231 float angularCorrectionForce = -(float)Math.Asin(pointingDirection.Y);
1232 Vector3 angularCorrectionVector = new Vector3(0f, angularCorrectionForce, 0f);
1233 // Rotate into world coordinates and apply to vehicle
1234 angularCorrectionVector *= VehicleOrientation;
1235 VehicleAddAngularForce(angularCorrectionVector);
1236 VDetailLog("{0}, MoveLinear,limitMotorUp,newVel={1},pntDir={2},corrFrc={3},aCorr={4}",
1237 Prim.LocalID, VehicleVelocity, pointingDirection, angularCorrectionForce, angularCorrectionVector);
1238 }
1239 */
1240 VDetailLog("{0}, MoveLinear,limitMotorUp,collide={1},upVel={2},newVel={3}",
1241 ControllingPrim.LocalID, ControllingPrim.IsColliding, upVelocity, VehicleVelocity);
1242 }
1243 }
1244 }
1245
1246 private void ApplyGravity(float pTimeStep)
1247 {
1248 Vector3 appliedGravity = m_VehicleGravity * m_vehicleMass;
1249
1250 // Hack to reduce downward force if the vehicle is probably sitting on the ground
1251 if (ControllingPrim.IsColliding && IsGroundVehicle)
1252 appliedGravity *= BSParam.VehicleGroundGravityFudge;
1253
1254 VehicleAddForce(appliedGravity);
1255
1256 VDetailLog("{0}, MoveLinear,applyGravity,vehGrav={1},collid={2},fudge={3},mass={4},appliedForce={3}",
1257 ControllingPrim.LocalID, m_VehicleGravity,
1258 ControllingPrim.IsColliding, BSParam.VehicleGroundGravityFudge, m_vehicleMass, appliedGravity);
1072 } 1259 }
1073 1260
1074 // ======================================================================= 1261 // =======================================================================
@@ -1079,55 +1266,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1079 // set directly on the vehicle. 1266 // set directly on the vehicle.
1080 private void MoveAngular(float pTimestep) 1267 private void MoveAngular(float pTimestep)
1081 { 1268 {
1082 // The user wants this many radians per second angular change? 1269 ComputeAngularTurning(pTimestep);
1083 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
1084 1270
1085 // ================================================================== 1271 ComputeAngularVerticalAttraction();
1086 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1087 // This flag prevents linear deflection parallel to world z-axis. This is useful
1088 // for preventing ground vehicles with large linear deflection, like bumper cars,
1089 // from climbing their linear deflection into the sky.
1090 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1091 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1092 {
1093 angularMotorContribution.X = 0f;
1094 angularMotorContribution.Y = 0f;
1095 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
1096 }
1097
1098 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
1099 1272
1100 Vector3 deflectionContribution = ComputeAngularDeflection(); 1273 ComputeAngularDeflection();
1101 1274
1102 Vector3 bankingContribution = ComputeAngularBanking(); 1275 ComputeAngularBanking();
1103 1276
1104 // ================================================================== 1277 // ==================================================================
1105 m_lastVertAttractor = verticalAttractionContribution; 1278 if (VehicleRotationalVelocity.ApproxEquals(Vector3.Zero, 0.0001f))
1106
1107 m_lastAngularVelocity = angularMotorContribution
1108 + verticalAttractionContribution
1109 + deflectionContribution
1110 + bankingContribution;
1111
1112 // ==================================================================
1113 // Apply the correction velocity.
1114 // TODO: Should this be applied as an angular force (torque)?
1115 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
1116 { 1279 {
1117 VehicleRotationalVelocity = m_lastAngularVelocity; 1280 // The vehicle is not adding anything angular wise.
1118 1281 VehicleRotationalVelocity = Vector3.Zero;
1119 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", 1282 VDetailLog("{0}, MoveAngular,done,zero", ControllingPrim.LocalID);
1120 Prim.LocalID,
1121 angularMotorContribution, verticalAttractionContribution,
1122 bankingContribution, deflectionContribution,
1123 m_lastAngularVelocity
1124 );
1125 } 1283 }
1126 else 1284 else
1127 { 1285 {
1128 // The vehicle is not adding anything angular wise. 1286 VDetailLog("{0}, MoveAngular,done,nonZero,angVel={1}", ControllingPrim.LocalID, VehicleRotationalVelocity);
1129 VehicleRotationalVelocity = Vector3.Zero;
1130 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
1131 } 1287 }
1132 1288
1133 // ================================================================== 1289 // ==================================================================
@@ -1158,10 +1314,42 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1158 torqueFromOffset.Z = 0; 1314 torqueFromOffset.Z = 0;
1159 1315
1160 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); 1316 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1161 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1317 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", ControllingPrim.LocalID, torqueFromOffset);
1162 } 1318 }
1163 1319
1164 } 1320 }
1321
1322 private void ComputeAngularTurning(float pTimestep)
1323 {
1324 // The user wants this many radians per second angular change?
1325 Vector3 currentAngularV = VehicleRotationalVelocity * Quaternion.Inverse(VehicleOrientation);
1326 Vector3 angularMotorContributionV = m_angularMotor.Step(pTimestep, currentAngularV);
1327
1328 // ==================================================================
1329 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
1330 // This flag prevents linear deflection parallel to world z-axis. This is useful
1331 // for preventing ground vehicles with large linear deflection, like bumper cars,
1332 // from climbing their linear deflection into the sky.
1333 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
1334 // TODO: This is here because this is where ODE put it but documentation says it
1335 // is a linear effect. Where should this check go?
1336 //if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
1337 // {
1338 // angularMotorContributionV.X = 0f;
1339 // angularMotorContributionV.Y = 0f;
1340 // }
1341
1342 // Reduce any velocity by friction.
1343 Vector3 frictionFactorW = ComputeFrictionFactor(m_angularFrictionTimescale, pTimestep);
1344 angularMotorContributionV -= (currentAngularV * frictionFactorW);
1345
1346 VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
1347
1348
1349
1350 VDetailLog("{0}, MoveAngular,angularTurning,angContribV={1}", ControllingPrim.LocalID, angularMotorContributionV);
1351 }
1352
1165 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1353 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1166 // Some vehicles, like boats, should always keep their up-side up. This can be done by 1354 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1167 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to 1355 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
@@ -1170,15 +1358,84 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1170 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An 1358 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1171 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an 1359 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1172 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. 1360 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1173 public Vector3 ComputeAngularVerticalAttraction() 1361 public void ComputeAngularVerticalAttraction()
1174 { 1362 {
1175 Vector3 ret = Vector3.Zero;
1176 1363
1177 // If vertical attaction timescale is reasonable 1364 // If vertical attaction timescale is reasonable
1178 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) 1365 if (enableAngularVerticalAttraction && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1179 { 1366 {
1367 //Another formula to try got from :
1368 //http://answers.unity3d.com/questions/10425/how-to-stabilize-angular-motion-alignment-of-hover.html
1369
1370 Vector3 VehicleUpAxis = Vector3.UnitZ * VehicleOrientation;
1371
1372 // Flipping what was originally a timescale into a speed variable and then multiplying it by 2
1373 // since only computing half the distance between the angles.
1374 float VerticalAttractionSpeed = (1 / m_verticalAttractionTimescale) * 2.0f;
1375
1376 // Make a prediction of where the up axis will be when this is applied rather then where it is now as
1377 // this makes for a smoother adjustment and less fighting between the various forces.
1378 Vector3 predictedUp = VehicleUpAxis * Quaternion.CreateFromAxisAngle(VehicleRotationalVelocity, 0f);
1379
1380 // This is only half the distance to the target so it will take 2 seconds to complete the turn.
1381 Vector3 torqueVector = Vector3.Cross(predictedUp, Vector3.UnitZ);
1382
1383 // Scale vector by our timescale since it is an acceleration it is r/s^2 or radians a timescale squared
1384 Vector3 vertContributionV = torqueVector * VerticalAttractionSpeed * VerticalAttractionSpeed;
1385
1386 VehicleRotationalVelocity += vertContributionV;
1387
1388 VDetailLog("{0}, MoveAngular,verticalAttraction,UpAxis={1},PredictedUp={2},torqueVector={3},contrib={4}",
1389 ControllingPrim.LocalID,
1390 VehicleUpAxis,
1391 predictedUp,
1392 torqueVector,
1393 vertContributionV);
1394 //=====================================================================
1395 /*
1396 // Possible solution derived from a discussion at:
1397 // http://stackoverflow.com/questions/14939657/computing-vector-from-quaternion-works-computing-quaternion-from-vector-does-no
1398
1399 // Create a rotation that is only the vehicle's rotation around Z
1400 Vector3 currentEuler = Vector3.Zero;
1401 VehicleOrientation.GetEulerAngles(out currentEuler.X, out currentEuler.Y, out currentEuler.Z);
1402 Quaternion justZOrientation = Quaternion.CreateFromAxisAngle(Vector3.UnitZ, currentEuler.Z);
1403
1404 // Create the axis that is perpendicular to the up vector and the rotated up vector.
1405 Vector3 differenceAxis = Vector3.Cross(Vector3.UnitZ * justZOrientation, Vector3.UnitZ * VehicleOrientation);
1406 // Compute the angle between those to vectors.
1407 double differenceAngle = Math.Acos((double)Vector3.Dot(Vector3.UnitZ, Vector3.Normalize(Vector3.UnitZ * VehicleOrientation)));
1408 // 'differenceAngle' is the angle to rotate and 'differenceAxis' is the plane to rotate in to get the vehicle vertical
1409
1410 // Reduce the change by the time period it is to change in. Timestep is handled when velocity is applied.
1411 // TODO: add 'efficiency'.
1412 differenceAngle /= m_verticalAttractionTimescale;
1413
1414 // Create the quaterian representing the correction angle
1415 Quaternion correctionRotation = Quaternion.CreateFromAxisAngle(differenceAxis, (float)differenceAngle);
1416
1417 // Turn that quaternion into Euler values to make it into velocities to apply.
1418 Vector3 vertContributionV = Vector3.Zero;
1419 correctionRotation.GetEulerAngles(out vertContributionV.X, out vertContributionV.Y, out vertContributionV.Z);
1420 vertContributionV *= -1f;
1421
1422 VehicleRotationalVelocity += vertContributionV;
1423
1424 VDetailLog("{0}, MoveAngular,verticalAttraction,diffAxis={1},diffAng={2},corrRot={3},contrib={4}",
1425 ControllingPrim.LocalID,
1426 differenceAxis,
1427 differenceAngle,
1428 correctionRotation,
1429 vertContributionV);
1430 */
1431
1432 // ===================================================================
1433 /*
1434 Vector3 vertContributionV = Vector3.Zero;
1435 Vector3 origRotVelW = VehicleRotationalVelocity; // DEBUG DEBUG
1436
1180 // Take a vector pointing up and convert it from world to vehicle relative coords. 1437 // Take a vector pointing up and convert it from world to vehicle relative coords.
1181 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; 1438 Vector3 verticalError = Vector3.Normalize(Vector3.UnitZ * VehicleOrientation);
1182 1439
1183 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) 1440 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1184 // is now: 1441 // is now:
@@ -1190,49 +1447,57 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1190 1447
1191 // Y error means needed rotation around X axis and visa versa. 1448 // Y error means needed rotation around X axis and visa versa.
1192 // Since the error goes from zero to one, the asin is the corresponding angle. 1449 // Since the error goes from zero to one, the asin is the corresponding angle.
1193 ret.X = (float)Math.Asin(verticalError.Y); 1450 vertContributionV.X = (float)Math.Asin(verticalError.Y);
1194 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.) 1451 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1195 ret.Y = -(float)Math.Asin(verticalError.X); 1452 vertContributionV.Y = -(float)Math.Asin(verticalError.X);
1196 1453
1197 // If verticalError.Z is negative, the vehicle is upside down. Add additional push. 1454 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1198 if (verticalError.Z < 0f) 1455 if (verticalError.Z < 0f)
1199 { 1456 {
1200 ret.X += PIOverFour; 1457 vertContributionV.X += Math.Sign(vertContributionV.X) * PIOverFour;
1201 ret.Y += PIOverFour; 1458 // vertContribution.Y -= PIOverFour;
1202 } 1459 }
1203 1460
1204 // 'ret' is now the necessary velocity to correct tilt in one second. 1461 // 'vertContrbution' is now the necessary angular correction to correct tilt in one second.
1205 // Correction happens over a number of seconds. 1462 // Correction happens over a number of seconds.
1206 Vector3 unscaledContrib = ret; 1463 Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
1207 ret /= m_verticalAttractionTimescale; 1464
1465 // The correction happens over the user's time period
1466 vertContributionV /= m_verticalAttractionTimescale;
1208 1467
1209 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}", 1468 // Rotate the vehicle rotation to the world coordinates.
1210 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret); 1469 VehicleRotationalVelocity += (vertContributionV * VehicleOrientation);
1470
1471 VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
1472 Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
1473 m_verticalAttractionEfficiency, m_verticalAttractionTimescale, vertContributionV);
1474 */
1211 } 1475 }
1212 return ret;
1213 } 1476 }
1214 1477
1215 // Return the angular correction to correct the direction the vehicle is pointing to be 1478 // Angular correction to correct the direction the vehicle is pointing to be
1216 // the direction is should want to be pointing. 1479 // the direction is should want to be pointing.
1217 // The vehicle is moving in some direction and correct its orientation to it is pointing 1480 // The vehicle is moving in some direction and correct its orientation to it is pointing
1218 // in that direction. 1481 // in that direction.
1219 // TODO: implement reference frame. 1482 // TODO: implement reference frame.
1220 public Vector3 ComputeAngularDeflection() 1483 public void ComputeAngularDeflection()
1221 { 1484 {
1222 Vector3 ret = Vector3.Zero;
1223 return ret; // DEBUG DEBUG DEBUG
1224 // Disable angular deflection for the moment.
1225 // Since angularMotorUp and angularDeflection are computed independently, they will calculate 1485 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1226 // approximately the same X or Y correction. When added together (when contributions are combined) 1486 // approximately the same X or Y correction. When added together (when contributions are combined)
1227 // this creates an over-correction and then wabbling as the target is overshot. 1487 // this creates an over-correction and then wabbling as the target is overshot.
1228 // TODO: rethink how the different correction computations inter-relate. 1488 // TODO: rethink how the different correction computations inter-relate.
1229 1489
1230 if (m_angularDeflectionEfficiency != 0) 1490 if (enableAngularDeflection && m_angularDeflectionEfficiency != 0 && VehicleForwardSpeed > 0.2)
1231 { 1491 {
1492 Vector3 deflectContributionV = Vector3.Zero;
1493
1232 // The direction the vehicle is moving 1494 // The direction the vehicle is moving
1233 Vector3 movingDirection = VehicleVelocity; 1495 Vector3 movingDirection = VehicleVelocity;
1234 movingDirection.Normalize(); 1496 movingDirection.Normalize();
1235 1497
1498 // If the vehicle is going backward, it is still pointing forward
1499 movingDirection *= Math.Sign(VehicleForwardSpeed);
1500
1236 // The direction the vehicle is pointing 1501 // The direction the vehicle is pointing
1237 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; 1502 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1238 pointingDirection.Normalize(); 1503 pointingDirection.Normalize();
@@ -1241,6 +1506,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1241 Vector3 deflectionError = movingDirection - pointingDirection; 1506 Vector3 deflectionError = movingDirection - pointingDirection;
1242 1507
1243 // Don't try to correct very large errors (not our job) 1508 // Don't try to correct very large errors (not our job)
1509 // if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = PIOverTwo * Math.Sign(deflectionError.X);
1510 // if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = PIOverTwo * Math.Sign(deflectionError.Y);
1511 // if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = PIOverTwo * Math.Sign(deflectionError.Z);
1244 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f; 1512 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1245 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f; 1513 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1246 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f; 1514 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
@@ -1248,18 +1516,19 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1248 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError); 1516 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1249 1517
1250 // Scale the correction by recovery timescale and efficiency 1518 // Scale the correction by recovery timescale and efficiency
1251 ret = (-deflectionError) * m_angularDeflectionEfficiency; 1519 deflectContributionV = (-deflectionError) * m_angularDeflectionEfficiency;
1252 ret /= m_angularDeflectionTimescale; 1520 deflectContributionV /= m_angularDeflectionTimescale;
1521
1522 VehicleRotationalVelocity += deflectContributionV * VehicleOrientation;
1253 1523
1254 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", 1524 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1255 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); 1525 ControllingPrim.LocalID, movingDirection, pointingDirection, deflectionError, deflectContributionV);
1256 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}", 1526 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1257 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale); 1527 ControllingPrim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1258 } 1528 }
1259 return ret;
1260 } 1529 }
1261 1530
1262 // Return an angular change to rotate the vehicle around the Z axis when the vehicle 1531 // Angular change to rotate the vehicle around the Z axis when the vehicle
1263 // is tipped around the X axis. 1532 // is tipped around the X axis.
1264 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: 1533 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1265 // The vertical attractor feature must be enabled in order for the banking behavior to 1534 // The vertical attractor feature must be enabled in order for the banking behavior to
@@ -1267,13 +1536,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1267 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude 1536 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1268 // of the yaw effect will be proportional to the 1537 // of the yaw effect will be proportional to the
1269 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's 1538 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1270 // velocity along its preferred axis of motion. 1539 // velocity along its preferred axis of motion.
1271 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any 1540 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1272 // positive rotation (by the right-hand rule) about the roll-axis will effect a 1541 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1273 // (negative) torque around the yaw-axis, making it turn to the right--that is the 1542 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1274 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. 1543 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1275 // Negating the banking coefficient will make it so that the vehicle leans to the 1544 // Negating the banking coefficient will make it so that the vehicle leans to the
1276 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). 1545 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1277 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making 1546 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1278 // banking vehicles do what you want rather than what the laws of physics allow. 1547 // banking vehicles do what you want rather than what the laws of physics allow.
1279 // For example, consider a real motorcycle...it must be moving forward in order for 1548 // For example, consider a real motorcycle...it must be moving forward in order for
@@ -1285,46 +1554,44 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1285 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the 1554 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1286 // banking effect depends only on the vehicle's rotation about its roll-axis compared 1555 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1287 // to "dynamic" where the banking is also proportional to its velocity along its 1556 // to "dynamic" where the banking is also proportional to its velocity along its
1288 // roll-axis. Finding the best value of the "mixture" will probably require trial and error. 1557 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1289 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the 1558 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1290 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to 1559 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1291 // bank quickly then give it a banking timescale of about a second or less, otherwise you can 1560 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1292 // make a sluggish vehicle by giving it a timescale of several seconds. 1561 // make a sluggish vehicle by giving it a timescale of several seconds.
1293 public Vector3 ComputeAngularBanking() 1562 public void ComputeAngularBanking()
1294 { 1563 {
1295 Vector3 ret = Vector3.Zero; 1564 if (enableAngularBanking && m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1296
1297 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1298 { 1565 {
1299 // This works by rotating a unit vector to the orientation of the vehicle. The 1566 Vector3 bankingContributionV = Vector3.Zero;
1300 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt 1567
1301 // up to one for full over). 1568 // Rotate a UnitZ vector (pointing up) to how the vehicle is oriented.
1569 // As the vehicle rolls to the right or left, the Y value will increase from
1570 // zero (straight up) to 1 or -1 (full tilt right or left)
1302 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; 1571 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1303 1572
1304 // Figure out the yaw value for this much roll. 1573 // Figure out the yaw value for this much roll.
1305 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; 1574 float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
1306 // Keep the sign
1307 if (rollComponents.Y < 0f)
1308 turnComponent = -turnComponent;
1309
1310 // TODO: there must be a better computation of the banking force.
1311 float bankingTurnForce = turnComponent;
1312
1313 // actual error = static turn error + dynamic turn error 1575 // actual error = static turn error + dynamic turn error
1314 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; 1576 float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
1577
1315 // TODO: the banking effect should not go to infinity but what to limit it to? 1578 // TODO: the banking effect should not go to infinity but what to limit it to?
1316 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); 1579 // And what should happen when this is being added to a user defined yaw that is already PI*4?
1580 mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
1317 1581
1318 // Build the force vector to change rotation from what it is to what it should be 1582 // Build the force vector to change rotation from what it is to what it should be
1319 ret.Z = -mixedBankingError; 1583 bankingContributionV.Z = -mixedYawAngle;
1584
1585 // Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
1586 bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
1320 1587
1321 // Don't do it all at once. 1588 //VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
1322 ret /= m_bankingTimescale; 1589 VehicleRotationalVelocity += bankingContributionV;
1323 1590
1324 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", 1591
1325 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); 1592 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
1593 ControllingPrim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
1326 } 1594 }
1327 return ret;
1328 } 1595 }
1329 1596
1330 // This is from previous instantiations of XXXDynamics.cs. 1597 // This is from previous instantiations of XXXDynamics.cs.
@@ -1362,11 +1629,28 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1362 if (rotq != m_rot) 1629 if (rotq != m_rot)
1363 { 1630 {
1364 VehicleOrientation = m_rot; 1631 VehicleOrientation = m_rot;
1365 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1632 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", ControllingPrim.LocalID, rotq, m_rot);
1366 } 1633 }
1367 1634
1368 } 1635 }
1369 1636
1637 // Given a friction vector (reduction in seconds) and a timestep, return the factor to reduce
1638 // some value by to apply this friction.
1639 private Vector3 ComputeFrictionFactor(Vector3 friction, float pTimestep)
1640 {
1641 Vector3 frictionFactor = Vector3.Zero;
1642 if (friction != BSMotor.InfiniteVector)
1643 {
1644 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
1645 // Individual friction components can be 'infinite' so compute each separately.
1646 frictionFactor.X = (friction.X == BSMotor.Infinite) ? 0f : (1f / friction.X);
1647 frictionFactor.Y = (friction.Y == BSMotor.Infinite) ? 0f : (1f / friction.Y);
1648 frictionFactor.Z = (friction.Z == BSMotor.Infinite) ? 0f : (1f / friction.Z);
1649 frictionFactor *= pTimestep;
1650 }
1651 return frictionFactor;
1652 }
1653
1370 private float ClampInRange(float low, float val, float high) 1654 private float ClampInRange(float low, float val, float high)
1371 { 1655 {
1372 return Math.Max(low, Math.Min(val, high)); 1656 return Math.Max(low, Math.Min(val, high));
@@ -1376,8 +1660,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1376 // Invoke the detailed logger and output something if it's enabled. 1660 // Invoke the detailed logger and output something if it's enabled.
1377 private void VDetailLog(string msg, params Object[] args) 1661 private void VDetailLog(string msg, params Object[] args)
1378 { 1662 {
1379 if (Prim.PhysicsScene.VehicleLoggingEnabled) 1663 if (ControllingPrim.PhysScene.VehicleLoggingEnabled)
1380 Prim.PhysicsScene.DetailLog(msg, args); 1664 ControllingPrim.PhysScene.DetailLog(msg, args);
1381 } 1665 }
1382 } 1666 }
1383} 1667}