diff options
author | BlueWall | 2012-12-07 15:36:43 -0500 |
---|---|---|
committer | BlueWall | 2012-12-07 15:36:43 -0500 |
commit | 0b455d2882a51ce0841d003f12d4c35ad9edb753 (patch) | |
tree | c48c95f48786f8fe435fc5c90477ac3b7c9eaf6c /OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |
parent | Merge branch 'master' into connector_plugin (diff) | |
parent | Merge branch 'master' of ssh://opensimulator.org/var/git/opensim (diff) | |
download | opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.zip opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.gz opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.bz2 opensim-SC_OLD-0b455d2882a51ce0841d003f12d4c35ad9edb753.tar.xz |
Merge branch 'master' into connector_plugin
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 863 |
1 files changed, 554 insertions, 309 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index 95a4134..fa3110c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -24,30 +24,17 @@ | |||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | 27 | * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial | |
28 | /* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to | 28 | * are Copyright (c) 2009 Linden Research, Inc and are used under their license |
29 | * call the BulletSim system. | 29 | * of Creative Commons Attribution-Share Alike 3.0 |
30 | */ | 30 | * (http://creativecommons.org/licenses/by-sa/3.0/). |
31 | /* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces | ||
32 | * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised: | ||
33 | * ODEPrim.cs contains methods dealing with Prim editing, Prim | ||
34 | * characteristics and Kinetic motion. | ||
35 | * ODEDynamics.cs contains methods dealing with Prim Physical motion | ||
36 | * (dynamics) and the associated settings. Old Linear and angular | ||
37 | * motors for dynamic motion have been replace with MoveLinear() | ||
38 | * and MoveAngular(); 'Physical' is used only to switch ODE dynamic | ||
39 | * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to | ||
40 | * switch between 'VEHICLE' parameter use and general dynamics | ||
41 | * settings use. | ||
42 | */ | 31 | */ |
43 | 32 | ||
44 | using System; | 33 | using System; |
45 | using System.Collections.Generic; | 34 | using System.Collections.Generic; |
46 | using System.Reflection; | 35 | using System.Reflection; |
47 | using System.Runtime.InteropServices; | 36 | using System.Runtime.InteropServices; |
48 | using log4net; | ||
49 | using OpenMetaverse; | 37 | using OpenMetaverse; |
50 | using OpenSim.Framework; | ||
51 | using OpenSim.Region.Physics.Manager; | 38 | using OpenSim.Region.Physics.Manager; |
52 | 39 | ||
53 | namespace OpenSim.Region.Physics.BulletSPlugin | 40 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -100,7 +87,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
100 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 87 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
101 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 88 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
102 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 89 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
103 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 90 | private Vector3 m_lastAngularCorrection = Vector3.Zero; |
104 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body | 91 | private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body |
105 | 92 | ||
106 | //Deflection properties | 93 | //Deflection properties |
@@ -125,8 +112,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
125 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. | 112 | // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. |
126 | 113 | ||
127 | //Attractor properties | 114 | //Attractor properties |
128 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 115 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
129 | private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. | 116 | private float m_verticalAttractionEfficiency = 1.0f; // damped |
117 | private float m_verticalAttractionCutoff = 500f; // per the documentation | ||
118 | // Timescale > cutoff means no vert attractor. | ||
119 | private float m_verticalAttractionTimescale = 510f; | ||
130 | 120 | ||
131 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 121 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
132 | { | 122 | { |
@@ -153,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
153 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 143 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
154 | break; | 144 | break; |
155 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 145 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
156 | m_angularMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); | 146 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
157 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | 147 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; |
158 | break; | 148 | break; |
159 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 149 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
@@ -161,7 +151,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
161 | m_angularMotor.TimeScale = m_angularMotorTimescale; | 151 | m_angularMotor.TimeScale = m_angularMotorTimescale; |
162 | break; | 152 | break; |
163 | case Vehicle.BANKING_EFFICIENCY: | 153 | case Vehicle.BANKING_EFFICIENCY: |
164 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 154 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
165 | break; | 155 | break; |
166 | case Vehicle.BANKING_MIX: | 156 | case Vehicle.BANKING_MIX: |
167 | m_bankingMix = Math.Max(pValue, 0.01f); | 157 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -170,10 +160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
170 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 160 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
171 | break; | 161 | break; |
172 | case Vehicle.BUOYANCY: | 162 | case Vehicle.BUOYANCY: |
173 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 163 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
174 | break; | 164 | break; |
175 | case Vehicle.HOVER_EFFICIENCY: | 165 | case Vehicle.HOVER_EFFICIENCY: |
176 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 166 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
177 | break; | 167 | break; |
178 | case Vehicle.HOVER_HEIGHT: | 168 | case Vehicle.HOVER_HEIGHT: |
179 | m_VhoverHeight = pValue; | 169 | m_VhoverHeight = pValue; |
@@ -188,7 +178,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
188 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 178 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
189 | break; | 179 | break; |
190 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 180 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
191 | m_linearMotorDecayTimescale = Math.Max(0.01f, Math.Min(pValue,120)); | 181 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
192 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | 182 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; |
193 | break; | 183 | break; |
194 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 184 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
@@ -196,10 +186,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
196 | m_linearMotor.TimeScale = m_linearMotorTimescale; | 186 | m_linearMotor.TimeScale = m_linearMotorTimescale; |
197 | break; | 187 | break; |
198 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 188 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
199 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 189 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
190 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
200 | break; | 191 | break; |
201 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 192 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
202 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 193 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
194 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
203 | break; | 195 | break; |
204 | 196 | ||
205 | // These are vector properties but the engine lets you use a single float value to | 197 | // These are vector properties but the engine lets you use a single float value to |
@@ -239,9 +231,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
239 | break; | 231 | break; |
240 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 232 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
241 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 233 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
242 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 234 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
243 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 235 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
244 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 236 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
245 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 237 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
246 | m_angularMotor.SetTarget(m_angularMotorDirection); | 238 | m_angularMotor.SetTarget(m_angularMotorDirection); |
247 | break; | 239 | break; |
@@ -314,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
314 | m_VhoverEfficiency = 0; | 306 | m_VhoverEfficiency = 0; |
315 | m_VhoverTimescale = 0; | 307 | m_VhoverTimescale = 0; |
316 | m_VehicleBuoyancy = 0; | 308 | m_VehicleBuoyancy = 0; |
317 | 309 | ||
318 | m_linearDeflectionEfficiency = 1; | 310 | m_linearDeflectionEfficiency = 1; |
319 | m_linearDeflectionTimescale = 1; | 311 | m_linearDeflectionTimescale = 1; |
320 | 312 | ||
@@ -363,13 +355,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
363 | m_bankingMix = 1; | 355 | m_bankingMix = 1; |
364 | 356 | ||
365 | m_referenceFrame = Quaternion.Identity; | 357 | m_referenceFrame = Quaternion.Identity; |
366 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY | 358 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
367 | | VehicleFlag.HOVER_TERRAIN_ONLY | 359 | | VehicleFlag.HOVER_TERRAIN_ONLY |
368 | | VehicleFlag.HOVER_GLOBAL_HEIGHT | 360 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
369 | | VehicleFlag.HOVER_UP_ONLY); | 361 | | VehicleFlag.HOVER_UP_ONLY); |
370 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | 362 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP |
371 | | VehicleFlag.LIMIT_ROLL_ONLY | 363 | | VehicleFlag.LIMIT_ROLL_ONLY |
372 | | VehicleFlag.LIMIT_MOTOR_UP); | 364 | | VehicleFlag.LIMIT_MOTOR_UP); |
365 | |||
373 | break; | 366 | break; |
374 | case Vehicle.TYPE_CAR: | 367 | case Vehicle.TYPE_CAR: |
375 | m_linearMotorDirection = Vector3.Zero; | 368 | m_linearMotorDirection = Vector3.Zero; |
@@ -513,6 +506,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
513 | m_bankingEfficiency = 0; | 506 | m_bankingEfficiency = 0; |
514 | m_bankingMix = 0.7f; | 507 | m_bankingMix = 0.7f; |
515 | m_bankingTimescale = 5; | 508 | m_bankingTimescale = 5; |
509 | |||
516 | m_referenceFrame = Quaternion.Identity; | 510 | m_referenceFrame = Quaternion.Identity; |
517 | 511 | ||
518 | m_referenceFrame = Quaternion.Identity; | 512 | m_referenceFrame = Quaternion.Identity; |
@@ -530,13 +524,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
530 | Refresh(); | 524 | Refresh(); |
531 | 525 | ||
532 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | 526 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, |
533 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, 1f); | 527 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, |
528 | 1f); | ||
534 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | 529 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
530 | |||
535 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | 531 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, |
536 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, 1f); | 532 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, |
533 | 1f); | ||
537 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | 534 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) |
538 | 535 | ||
539 | // m_bankingMotor = new BSVMotor("BankingMotor", ...); | 536 | m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale, |
537 | BSMotor.Infinite, BSMotor.InfiniteVector, | ||
538 | m_verticalAttractionEfficiency); | ||
539 | // Z goes away and we keep X and Y | ||
540 | m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f); | ||
541 | m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
540 | } | 542 | } |
541 | 543 | ||
542 | // Some of the properties of this prim may have changed. | 544 | // Some of the properties of this prim may have changed. |
@@ -545,9 +547,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
545 | { | 547 | { |
546 | if (IsActive) | 548 | if (IsActive) |
547 | { | 549 | { |
550 | // Remember the mass so we don't have to fetch it every step | ||
548 | m_vehicleMass = Prim.Linkset.LinksetMass; | 551 | m_vehicleMass = Prim.Linkset.LinksetMass; |
549 | 552 | ||
550 | // Friction effects are handled by this vehicle code | 553 | // Friction affects are handled by this vehicle code |
551 | float friction = 0f; | 554 | float friction = 0f; |
552 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | 555 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); |
553 | 556 | ||
@@ -557,14 +560,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
557 | float angularDamping = PhysicsScene.Params.vehicleAngularDamping; | 560 | float angularDamping = PhysicsScene.Params.vehicleAngularDamping; |
558 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | 561 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); |
559 | 562 | ||
563 | // Vehicles report collision events so we know when it's on the ground | ||
564 | BulletSimAPI.AddToCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
565 | |||
560 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet | 566 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet |
561 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | 567 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); |
562 | Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | 568 | // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); |
569 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); | ||
563 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | 570 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); |
571 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | ||
564 | 572 | ||
565 | VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", | 573 | VDetailLog("{0},BSDynamics.Refresh,frict={1},inert={2},aDamp={3}", |
566 | Prim.LocalID, friction, localInertia, angularDamping); | 574 | Prim.LocalID, friction, localInertia, angularDamping); |
567 | } | 575 | } |
576 | else | ||
577 | { | ||
578 | BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
579 | } | ||
568 | } | 580 | } |
569 | 581 | ||
570 | public bool RemoveBodyDependencies(BSPhysObject prim) | 582 | public bool RemoveBodyDependencies(BSPhysObject prim) |
@@ -585,60 +597,288 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
585 | Refresh(); | 597 | Refresh(); |
586 | } | 598 | } |
587 | 599 | ||
600 | #region Known vehicle value functions | ||
601 | // Vehicle physical parameters that we buffer from constant getting and setting. | ||
602 | // The "m_known*" variables are initialized to 'null', fetched only if referenced | ||
603 | // and stored back into the physics engine only if updated. | ||
604 | // This does two things: 1) saves continuious calls into unmanaged code, and | ||
605 | // 2) signals when a physics property update must happen back to the simulator | ||
606 | // to update values modified for the vehicle. | ||
607 | private int m_knownChanged; | ||
608 | private float? m_knownTerrainHeight; | ||
609 | private float? m_knownWaterLevel; | ||
610 | private Vector3? m_knownPosition; | ||
611 | private Vector3? m_knownVelocity; | ||
612 | private Vector3 m_knownForce; | ||
613 | private Quaternion? m_knownOrientation; | ||
614 | private Vector3? m_knownRotationalVelocity; | ||
615 | private Vector3 m_knownRotationalForce; | ||
616 | private float? m_knownForwardSpeed; | ||
617 | |||
618 | private const int m_knownChangedPosition = 1 << 0; | ||
619 | private const int m_knownChangedVelocity = 1 << 1; | ||
620 | private const int m_knownChangedForce = 1 << 2; | ||
621 | private const int m_knownChangedOrientation = 1 << 3; | ||
622 | private const int m_knownChangedRotationalVelocity = 1 << 4; | ||
623 | private const int m_knownChangedRotationalForce = 1 << 5; | ||
624 | |||
625 | private void ForgetKnownVehicleProperties() | ||
626 | { | ||
627 | m_knownTerrainHeight = null; | ||
628 | m_knownWaterLevel = null; | ||
629 | m_knownPosition = null; | ||
630 | m_knownVelocity = null; | ||
631 | m_knownForce = Vector3.Zero; | ||
632 | m_knownOrientation = null; | ||
633 | m_knownRotationalVelocity = null; | ||
634 | m_knownRotationalForce = Vector3.Zero; | ||
635 | m_knownForwardSpeed = null; | ||
636 | m_knownChanged = 0; | ||
637 | } | ||
638 | private void PushKnownChanged() | ||
639 | { | ||
640 | if (m_knownChanged != 0) | ||
641 | { | ||
642 | if ((m_knownChanged & m_knownChangedPosition) != 0) | ||
643 | Prim.ForcePosition = VehiclePosition; | ||
644 | if ((m_knownChanged & m_knownChangedOrientation) != 0) | ||
645 | Prim.ForceOrientation = VehicleOrientation; | ||
646 | if ((m_knownChanged & m_knownChangedVelocity) != 0) | ||
647 | { | ||
648 | Prim.ForceVelocity = VehicleVelocity; | ||
649 | BulletSimAPI.SetInterpolationLinearVelocity2(Prim.PhysBody.ptr, VehicleVelocity); | ||
650 | } | ||
651 | if ((m_knownChanged & m_knownChangedForce) != 0) | ||
652 | Prim.AddForce((Vector3)m_knownForce, false, true); | ||
653 | |||
654 | if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0) | ||
655 | { | ||
656 | Prim.ForceRotationalVelocity = VehicleRotationalVelocity; | ||
657 | // Fake out Bullet by making it think the velocity is the same as last time. | ||
658 | BulletSimAPI.SetInterpolationAngularVelocity2(Prim.PhysBody.ptr, VehicleRotationalVelocity); | ||
659 | } | ||
660 | if ((m_knownChanged & m_knownChangedRotationalForce) != 0) | ||
661 | Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true); | ||
662 | |||
663 | // If we set one of the values (ie, the physics engine didn't do it) we must force | ||
664 | // an UpdateProperties event to send the changes up to the simulator. | ||
665 | BulletSimAPI.PushUpdate2(Prim.PhysBody.ptr); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | // Since the computation of terrain height can be a little involved, this routine | ||
670 | // is used ot fetch the height only once for each vehicle simulation step. | ||
671 | private float GetTerrainHeight(Vector3 pos) | ||
672 | { | ||
673 | if (m_knownTerrainHeight == null) | ||
674 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
675 | return (float)m_knownTerrainHeight; | ||
676 | } | ||
677 | |||
678 | // Since the computation of water level can be a little involved, this routine | ||
679 | // is used ot fetch the level only once for each vehicle simulation step. | ||
680 | private float GetWaterLevel(Vector3 pos) | ||
681 | { | ||
682 | if (m_knownWaterLevel == null) | ||
683 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
684 | return (float)m_knownWaterLevel; | ||
685 | } | ||
686 | |||
687 | private Vector3 VehiclePosition | ||
688 | { | ||
689 | get | ||
690 | { | ||
691 | if (m_knownPosition == null) | ||
692 | m_knownPosition = Prim.ForcePosition; | ||
693 | return (Vector3)m_knownPosition; | ||
694 | } | ||
695 | set | ||
696 | { | ||
697 | m_knownPosition = value; | ||
698 | m_knownChanged |= m_knownChangedPosition; | ||
699 | } | ||
700 | } | ||
701 | |||
702 | private Quaternion VehicleOrientation | ||
703 | { | ||
704 | get | ||
705 | { | ||
706 | if (m_knownOrientation == null) | ||
707 | m_knownOrientation = Prim.ForceOrientation; | ||
708 | return (Quaternion)m_knownOrientation; | ||
709 | } | ||
710 | set | ||
711 | { | ||
712 | m_knownOrientation = value; | ||
713 | m_knownChanged |= m_knownChangedOrientation; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | private Vector3 VehicleVelocity | ||
718 | { | ||
719 | get | ||
720 | { | ||
721 | if (m_knownVelocity == null) | ||
722 | m_knownVelocity = Prim.ForceVelocity; | ||
723 | return (Vector3)m_knownVelocity; | ||
724 | } | ||
725 | set | ||
726 | { | ||
727 | m_knownVelocity = value; | ||
728 | m_knownChanged |= m_knownChangedVelocity; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | private void VehicleAddForce(Vector3 aForce) | ||
733 | { | ||
734 | m_knownForce += aForce; | ||
735 | m_knownChanged |= m_knownChangedForce; | ||
736 | } | ||
737 | |||
738 | private Vector3 VehicleRotationalVelocity | ||
739 | { | ||
740 | get | ||
741 | { | ||
742 | if (m_knownRotationalVelocity == null) | ||
743 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
744 | return (Vector3)m_knownRotationalVelocity; | ||
745 | } | ||
746 | set | ||
747 | { | ||
748 | m_knownRotationalVelocity = value; | ||
749 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
750 | } | ||
751 | } | ||
752 | private void VehicleAddAngularForce(Vector3 aForce) | ||
753 | { | ||
754 | m_knownRotationalForce += aForce; | ||
755 | m_knownChanged |= m_knownChangedRotationalForce; | ||
756 | } | ||
757 | private float VehicleForwardSpeed | ||
758 | { | ||
759 | get | ||
760 | { | ||
761 | if (m_knownForwardSpeed == null) | ||
762 | m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X; | ||
763 | return (float)m_knownForwardSpeed; | ||
764 | } | ||
765 | } | ||
766 | |||
767 | #endregion // Known vehicle value functions | ||
768 | |||
588 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 769 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
589 | internal void Step(float pTimestep) | 770 | internal void Step(float pTimestep) |
590 | { | 771 | { |
591 | if (!IsActive) return; | 772 | if (!IsActive) return; |
592 | 773 | ||
774 | ForgetKnownVehicleProperties(); | ||
775 | |||
593 | MoveLinear(pTimestep); | 776 | MoveLinear(pTimestep); |
594 | MoveAngular(pTimestep); | 777 | MoveAngular(pTimestep); |
595 | 778 | ||
596 | LimitRotation(pTimestep); | 779 | LimitRotation(pTimestep); |
597 | 780 | ||
598 | // remember the position so next step we can limit absolute movement effects | 781 | // remember the position so next step we can limit absolute movement effects |
599 | m_lastPositionVector = Prim.ForcePosition; | 782 | m_lastPositionVector = VehiclePosition; |
783 | |||
784 | // If we forced the changing of some vehicle parameters, update the values and | ||
785 | // for the physics engine to note the changes so an UpdateProperties event will happen. | ||
786 | PushKnownChanged(); | ||
600 | 787 | ||
601 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 788 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
602 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 789 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); |
603 | } | 790 | } |
604 | 791 | ||
605 | // Apply the effect of the linear motor. | 792 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
606 | // Also does hover and float. | ||
607 | private void MoveLinear(float pTimestep) | 793 | private void MoveLinear(float pTimestep) |
608 | { | 794 | { |
609 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); | 795 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
610 | 796 | ||
611 | // Rotate new object velocity from vehicle relative to world coordinates | 797 | // The movement computed in the linear motor is relative to the vehicle |
612 | linearMotorContribution *= Prim.ForceOrientation; | 798 | // coordinates. Rotate the movement to world coordinates. |
799 | linearMotorContribution *= VehicleOrientation; | ||
613 | 800 | ||
614 | // ================================================================== | 801 | // ================================================================== |
615 | // Gravity and Buoyancy | 802 | // Buoyancy: force to overcome gravity. |
616 | // There is some gravity, make a gravity force vector that is applied after object velocity. | ||
617 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 803 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
618 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 804 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. |
805 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
806 | |||
807 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); | ||
808 | |||
809 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); | ||
810 | |||
811 | ComputeLinearBlockingEndPoint(pTimestep); | ||
812 | |||
813 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); | ||
814 | |||
815 | // ================================================================== | ||
816 | Vector3 newVelocity = linearMotorContribution | ||
817 | + terrainHeightContribution | ||
818 | + hoverContribution | ||
819 | + limitMotorUpContribution; | ||
820 | |||
821 | // If not changing some axis, reduce out velocity | ||
822 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
823 | newVelocity.X = 0; | ||
824 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
825 | newVelocity.Y = 0; | ||
826 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
827 | newVelocity.Z = 0; | ||
619 | 828 | ||
620 | // Current vehicle position | 829 | // ================================================================== |
621 | Vector3 pos = Prim.ForcePosition; | 830 | // Clamp high or low velocities |
831 | float newVelocityLengthSq = newVelocity.LengthSquared(); | ||
832 | // if (newVelocityLengthSq > 1e6f) | ||
833 | if (newVelocityLengthSq > 1000f) | ||
834 | { | ||
835 | newVelocity /= newVelocity.Length(); | ||
836 | newVelocity *= 1000f; | ||
837 | } | ||
838 | // else if (newVelocityLengthSq < 1e-6f) | ||
839 | else if (newVelocityLengthSq < 0.001f) | ||
840 | newVelocity = Vector3.Zero; | ||
622 | 841 | ||
623 | // ================================================================== | 842 | // ================================================================== |
624 | Vector3 terrainHeightContribution = Vector3.Zero; | 843 | // Stuff new linear velocity into the vehicle. |
844 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | ||
845 | VehicleVelocity = newVelocity; | ||
846 | |||
847 | // Other linear forces are applied as forces. | ||
848 | Vector3 totalDownForce = buoyancyContribution * m_vehicleMass; | ||
849 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) | ||
850 | { | ||
851 | VehicleAddForce(totalDownForce); | ||
852 | } | ||
853 | |||
854 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", | ||
855 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); | ||
856 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", | ||
857 | Prim.LocalID, | ||
858 | linearMotorContribution, terrainHeightContribution, hoverContribution, | ||
859 | limitMotorUpContribution, buoyancyContribution | ||
860 | ); | ||
861 | |||
862 | } // end MoveLinear() | ||
863 | |||
864 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
865 | { | ||
866 | Vector3 ret = Vector3.Zero; | ||
625 | // If below the terrain, move us above the ground a little. | 867 | // If below the terrain, move us above the ground a little. |
626 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 868 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
627 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 869 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
628 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
629 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
630 | // if (rotatedSize.Z < terrainHeight) | ||
631 | if (pos.Z < terrainHeight) | ||
632 | { | 870 | { |
633 | // TODO: correct position by applying force rather than forcing position. | 871 | // TODO: correct position by applying force rather than forcing position. |
634 | pos.Z = terrainHeight + 2; | 872 | VehiclePosition += new Vector3(0f, 0f, GetTerrainHeight(VehiclePosition) + 2f); |
635 | Prim.ForcePosition = pos; | 873 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); |
636 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | ||
637 | } | 874 | } |
875 | return ret; | ||
876 | } | ||
877 | |||
878 | public Vector3 ComputeLinearHover(float pTimestep) | ||
879 | { | ||
880 | Vector3 ret = Vector3.Zero; | ||
638 | 881 | ||
639 | // ================================================================== | ||
640 | Vector3 hoverContribution = Vector3.Zero; | ||
641 | // Check if hovering | ||
642 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 882 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
643 | // m_VhoverTimescale: time to achieve height | 883 | // m_VhoverTimescale: time to achieve height |
644 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 884 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -646,11 +886,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
646 | // We should hover, get the target height | 886 | // We should hover, get the target height |
647 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 887 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
648 | { | 888 | { |
649 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 889 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
650 | } | 890 | } |
651 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 891 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
652 | { | 892 | { |
653 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 893 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
654 | } | 894 | } |
655 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 895 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
656 | { | 896 | { |
@@ -660,43 +900,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
660 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 900 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
661 | { | 901 | { |
662 | // If body is already heigher, use its height as target height | 902 | // If body is already heigher, use its height as target height |
663 | if (pos.Z > m_VhoverTargetHeight) | 903 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
664 | m_VhoverTargetHeight = pos.Z; | 904 | m_VhoverTargetHeight = VehiclePosition.Z; |
665 | } | 905 | } |
906 | |||
666 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 907 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
667 | { | 908 | { |
668 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 909 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
669 | { | 910 | { |
911 | Vector3 pos = VehiclePosition; | ||
670 | pos.Z = m_VhoverTargetHeight; | 912 | pos.Z = m_VhoverTargetHeight; |
671 | Prim.ForcePosition = pos; | 913 | VehiclePosition = pos; |
672 | } | 914 | } |
673 | } | 915 | } |
674 | else | 916 | else |
675 | { | 917 | { |
676 | float verticalError = pos.Z - m_VhoverTargetHeight; | 918 | // Error is positive if below the target and negative if above. |
677 | // RA: where does the 50 come from? | 919 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; |
678 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 920 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
679 | // Replace Vertical speed with correction figure if significant | 921 | |
680 | if (verticalError > 0.01f) | 922 | // TODO: implement m_VhoverEfficiency correctly |
681 | { | 923 | if (Math.Abs(verticalError) > m_VhoverEfficiency) |
682 | hoverContribution = new Vector3(0f, 0f, verticalCorrectionVelocity); | ||
683 | //KF: m_VhoverEfficiency is not yet implemented | ||
684 | } | ||
685 | else if (verticalError < -0.01) | ||
686 | { | 924 | { |
687 | hoverContribution = new Vector3(0f, 0f, -verticalCorrectionVelocity); | 925 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
688 | } | 926 | } |
689 | } | 927 | } |
690 | 928 | ||
691 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", | 929 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", |
692 | Prim.LocalID, pos, hoverContribution, m_VhoverHeight, m_VhoverTargetHeight); | 930 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); |
693 | } | 931 | } |
694 | 932 | ||
695 | // ================================================================== | 933 | return ret; |
934 | } | ||
935 | |||
936 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
937 | { | ||
938 | bool changed = false; | ||
939 | |||
940 | Vector3 pos = VehiclePosition; | ||
696 | Vector3 posChange = pos - m_lastPositionVector; | 941 | Vector3 posChange = pos - m_lastPositionVector; |
697 | if (m_BlockingEndPoint != Vector3.Zero) | 942 | if (m_BlockingEndPoint != Vector3.Zero) |
698 | { | 943 | { |
699 | bool changed = false; | ||
700 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 944 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
701 | { | 945 | { |
702 | pos.X -= posChange.X + 1; | 946 | pos.X -= posChange.X + 1; |
@@ -724,240 +968,111 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
724 | } | 968 | } |
725 | if (changed) | 969 | if (changed) |
726 | { | 970 | { |
727 | Prim.ForcePosition = pos; | 971 | VehiclePosition = pos; |
728 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 972 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
729 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 973 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
730 | } | 974 | } |
731 | } | 975 | } |
976 | return changed; | ||
977 | } | ||
978 | |||
979 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : | ||
980 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when | ||
981 | // used with conjunction with banking: the strength of the banking will decay when the | ||
982 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
983 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
984 | // when they are in mid jump. | ||
985 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
986 | // This is just using the ground and a general collision check. Should really be using | ||
987 | // a downward raycast to find what is below. | ||
988 | public Vector3 ComputeLinearMotorUp(float pTimestep) | ||
989 | { | ||
990 | Vector3 ret = Vector3.Zero; | ||
732 | 991 | ||
733 | // ================================================================== | ||
734 | Vector3 limitMotorUpContribution = Vector3.Zero; | ||
735 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 992 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
736 | { | 993 | { |
737 | // If the vehicle is motoring into the sky, get it going back down. | 994 | // If the vehicle is motoring into the sky, get it going back down. |
738 | float distanceAboveGround = pos.Z - terrainHeight; | 995 | float distanceAboveGround = VehiclePosition.Z - GetTerrainHeight(VehiclePosition); |
739 | if (distanceAboveGround > 1f) | 996 | // Not colliding if the vehicle is off the ground |
997 | if (!Prim.IsColliding) | ||
740 | { | 998 | { |
741 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | 999 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); |
742 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1000 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
743 | limitMotorUpContribution = new Vector3(0, 0, -distanceAboveGround); | 1001 | ret = new Vector3(0, 0, -distanceAboveGround); |
744 | } | 1002 | } |
745 | // TODO: this calculation is all wrong. From the description at | 1003 | // TODO: this calculation is wrong. From the description at |
746 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1004 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
747 | // has a decay factor. This says this force should | 1005 | // has a decay factor. This says this force should |
748 | // be computed with a motor. | 1006 | // be computed with a motor. |
749 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 1007 | // TODO: add interaction with banking. |
750 | Prim.LocalID, distanceAboveGround, limitMotorUpContribution); | 1008 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},downForce={2}", |
751 | } | 1009 | Prim.LocalID, distanceAboveGround, ret); |
752 | |||
753 | // ================================================================== | ||
754 | Vector3 newVelocity = linearMotorContribution | ||
755 | + terrainHeightContribution | ||
756 | + hoverContribution | ||
757 | + limitMotorUpContribution; | ||
758 | |||
759 | // If not changing some axis, reduce out velocity | ||
760 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
761 | newVelocity.X = 0; | ||
762 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
763 | newVelocity.Y = 0; | ||
764 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
765 | newVelocity.Z = 0; | ||
766 | |||
767 | // ================================================================== | ||
768 | // Clamp REALLY high or low velocities | ||
769 | float newVelocityLengthSq = newVelocity.LengthSquared(); | ||
770 | if (newVelocityLengthSq > 1e6f) | ||
771 | { | ||
772 | newVelocity /= newVelocity.Length(); | ||
773 | newVelocity *= 1000f; | ||
774 | } | ||
775 | else if (newVelocityLengthSq < 1e-6f) | ||
776 | newVelocity = Vector3.Zero; | ||
777 | |||
778 | // ================================================================== | ||
779 | // Stuff new linear velocity into the vehicle | ||
780 | Prim.ForceVelocity = newVelocity; | ||
781 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
782 | |||
783 | // Other linear forces are applied as forces. | ||
784 | Vector3 totalDownForce = grav * m_vehicleMass; | ||
785 | if (totalDownForce != Vector3.Zero) | ||
786 | { | ||
787 | Prim.AddForce(totalDownForce, false); | ||
788 | } | 1010 | } |
789 | 1011 | return ret; | |
790 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | 1012 | } |
791 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, | ||
792 | newVelocity, Prim.Velocity, totalDownForce); | ||
793 | |||
794 | } // end MoveLinear() | ||
795 | 1013 | ||
796 | // ======================================================================= | 1014 | // ======================================================================= |
797 | // ======================================================================= | 1015 | // ======================================================================= |
798 | // Apply the effect of the angular motor. | 1016 | // Apply the effect of the angular motor. |
1017 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1018 | // All the contributions are added together and the resulting velocity is | ||
1019 | // set directly on the vehicle. | ||
799 | private void MoveAngular(float pTimestep) | 1020 | private void MoveAngular(float pTimestep) |
800 | { | 1021 | { |
801 | // m_angularMotorDirection // angular velocity requested by LSL motor | 1022 | // The user wants how many radians per second angular change? |
802 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | ||
803 | // m_angularMotorTimescale // motor angular velocity ramp up time | ||
804 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | ||
805 | // m_angularFrictionTimescale // body angular velocity decay rate | ||
806 | // m_lastAngularVelocity // what was last applied to body | ||
807 | |||
808 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | ||
809 | { | ||
810 | Vector3 origVel = m_angularMotorVelocity; | ||
811 | Vector3 origDir = m_angularMotorDirection; | ||
812 | |||
813 | // new velocity += error / ( time to get there / step interval) | ||
814 | // requested direction - current vehicle direction | ||
815 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
816 | // decay requested direction | ||
817 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
818 | |||
819 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | ||
820 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
821 | } | ||
822 | else | ||
823 | { | ||
824 | m_angularMotorVelocity = Vector3.Zero; | ||
825 | } | ||
826 | |||
827 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); | 1023 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
828 | 1024 | ||
829 | // ================================================================== | 1025 | // ================================================================== |
830 | Vector3 verticalAttractionContribution = Vector3.Zero; | 1026 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
831 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | 1027 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
832 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | 1028 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
1029 | // from climbing their linear deflection into the sky. | ||
1030 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | ||
1031 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | ||
833 | { | 1032 | { |
834 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | 1033 | angularMotorContribution.X = 0f; |
835 | if (Prim.IsColliding) | 1034 | angularMotorContribution.Y = 0f; |
836 | VAservo = pTimestep * 0.05f / m_verticalAttractionTimescale; | 1035 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); |
837 | 1036 | } | |
838 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
839 | |||
840 | // Create a vector of the vehicle "up" in world coordinates | ||
841 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
842 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | ||
843 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | ||
844 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | ||
845 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
846 | // modulated to prevent a stable inverted body. | ||
847 | |||
848 | // Error is 0 (no error) to +/- 2 (max error) | ||
849 | if (verticalError.Z < 0.0f) | ||
850 | { | ||
851 | verticalError.X = 2.0f - verticalError.X; | ||
852 | verticalError.Y = 2.0f - verticalError.Y; | ||
853 | } | ||
854 | // scale it by VAservo (timestep and timescale) | ||
855 | verticalError = verticalError * VAservo; | ||
856 | 1037 | ||
857 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | 1038 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); |
858 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | ||
859 | // Z is not changed. | ||
860 | verticalAttractionContribution.X = verticalError.Y; | ||
861 | verticalAttractionContribution.Y = - verticalError.X; | ||
862 | verticalAttractionContribution.Z = 0f; | ||
863 | 1039 | ||
864 | // scaling appears better usingsquare-law | 1040 | Vector3 deflectionContribution = ComputeAngularDeflection(); |
865 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
866 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
867 | verticalAttractionContribution.X += bounce * angularVelocity.X; | ||
868 | verticalAttractionContribution.Y += bounce * angularVelocity.Y; | ||
869 | 1041 | ||
870 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | 1042 | Vector3 bankingContribution = ComputeAngularBanking(); |
871 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, verticalAttractionContribution); | ||
872 | 1043 | ||
873 | } | 1044 | // ================================================================== |
1045 | m_lastVertAttractor = verticalAttractionContribution; | ||
1046 | |||
1047 | // Sum corrections | ||
1048 | m_lastAngularCorrection = angularMotorContribution | ||
1049 | + verticalAttractionContribution | ||
1050 | + deflectionContribution | ||
1051 | + bankingContribution; | ||
874 | 1052 | ||
875 | // ================================================================== | 1053 | // ================================================================== |
876 | Vector3 deflectionContribution = Vector3.Zero; | 1054 | // Apply the correction velocity. |
877 | if (m_angularDeflectionEfficiency != 0) | 1055 | // TODO: Should this be applied as an angular force (torque)? |
1056 | if (!m_lastAngularCorrection.ApproxEquals(Vector3.Zero, 0.01f)) | ||
878 | { | 1057 | { |
879 | // Compute a scaled vector that points in the preferred axis (X direction) | 1058 | Vector3 scaledCorrection = m_lastAngularCorrection * pTimestep; |
880 | Vector3 scaledDefaultDirection = | 1059 | VehicleRotationalVelocity = scaledCorrection; |
881 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | 1060 | |
882 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | 1061 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5},scaledCorr={6}", |
883 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | 1062 | Prim.LocalID, |
884 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | 1063 | angularMotorContribution, verticalAttractionContribution, |
885 | 1064 | bankingContribution, deflectionContribution, | |
886 | // Scale by efficiency and timescale | 1065 | m_lastAngularCorrection, scaledCorrection |
887 | deflectionContribution = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | 1066 | ); |
888 | |||
889 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
890 | Prim.LocalID, preferredAxisOfMotion, deflectionContribution); | ||
891 | // This deflection computation is not correct. | ||
892 | deflectionContribution = Vector3.Zero; | ||
893 | } | 1067 | } |
894 | 1068 | else | |
895 | // ================================================================== | ||
896 | Vector3 bankingContribution = Vector3.Zero; | ||
897 | if (m_bankingEfficiency != 0) | ||
898 | { | 1069 | { |
899 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1070 | // The vehicle is not adding anything angular wise. |
900 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | 1071 | VehicleRotationalVelocity = Vector3.Zero; |
901 | //Changes which way it banks in and out of turns | 1072 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); |
902 | |||
903 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
904 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
905 | if (m_bankingEfficiency < 0) | ||
906 | effSquared *= -1; //Keep the negative! | ||
907 | |||
908 | float mix = Math.Abs(m_bankingMix); | ||
909 | if (m_angularMotorVelocity.X == 0) | ||
910 | { | ||
911 | // The vehicle is stopped | ||
912 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
913 | { | ||
914 | Vector3 axisAngle; | ||
915 | float angle; | ||
916 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
917 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
918 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
919 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
920 | else | ||
921 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
922 | }*/ | ||
923 | } | ||
924 | else | ||
925 | { | ||
926 | bankingContribution.Z += (effSquared * (mult * mix)) * (m_angularMotorVelocity.X) * 4; | ||
927 | } | ||
928 | |||
929 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
930 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
931 | { | ||
932 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
933 | /*if(angVelZ > mix) | ||
934 | angVelZ = mix; | ||
935 | else if(angVelZ < -mix) | ||
936 | angVelZ = -mix;*/ | ||
937 | //This controls how fast and how far the banking occurs | ||
938 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
939 | if (bankingRot.X > 3) | ||
940 | bankingRot.X = 3; | ||
941 | else if (bankingRot.X < -3) | ||
942 | bankingRot.X = -3; | ||
943 | bankingRot *= Prim.ForceOrientation; | ||
944 | bankingContribution += bankingRot; | ||
945 | } | ||
946 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
947 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},effSq={3},mult={4},mix={5},banking={6}", | ||
948 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, effSquared, mult, mix, bankingContribution); | ||
949 | } | 1073 | } |
950 | 1074 | ||
951 | // ================================================================== | 1075 | // ================================================================== |
952 | m_lastVertAttractor = verticalAttractionContribution; | ||
953 | |||
954 | // Sum velocities | ||
955 | m_lastAngularVelocity = angularMotorContribution | ||
956 | + verticalAttractionContribution | ||
957 | + bankingContribution | ||
958 | + deflectionContribution; | ||
959 | |||
960 | // ================================================================== | ||
961 | //Offset section | 1076 | //Offset section |
962 | if (m_linearMotorOffset != Vector3.Zero) | 1077 | if (m_linearMotorOffset != Vector3.Zero) |
963 | { | 1078 | { |
@@ -983,41 +1098,166 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
983 | torqueFromOffset.Y = 0; | 1098 | torqueFromOffset.Y = 0; |
984 | if (float.IsNaN(torqueFromOffset.Z)) | 1099 | if (float.IsNaN(torqueFromOffset.Z)) |
985 | torqueFromOffset.Z = 0; | 1100 | torqueFromOffset.Z = 0; |
986 | torqueFromOffset *= m_vehicleMass; | 1101 | |
987 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1102 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
988 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1103 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
989 | } | 1104 | } |
990 | 1105 | ||
991 | // ================================================================== | 1106 | } |
992 | // NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement | 1107 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: |
993 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1108 | // Some vehicles, like boats, should always keep their up-side up. This can be done by |
1109 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1110 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1111 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1112 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1113 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1114 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1115 | public Vector3 ComputeAngularVerticalAttraction() | ||
1116 | { | ||
1117 | Vector3 ret = Vector3.Zero; | ||
1118 | |||
1119 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | ||
1120 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
994 | { | 1121 | { |
995 | m_lastAngularVelocity.X = 0; | 1122 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
996 | m_lastAngularVelocity.Y = 0; | 1123 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; |
997 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1124 | verticalError.Normalize(); |
1125 | |||
1126 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1127 | // is now leaning to one side (rotated around the X axis) and the Y value will | ||
1128 | // go from zero (nearly straight up) to one (completely to the side) or leaning | ||
1129 | // front-to-back (rotated around the Y axis) and the value of X will be between | ||
1130 | // zero and one. | ||
1131 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1132 | |||
1133 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1134 | if (verticalError.Z < 0f) | ||
1135 | { | ||
1136 | verticalError.X = 2f - verticalError.X; | ||
1137 | verticalError.Y = 2f - verticalError.Y; | ||
1138 | } | ||
1139 | |||
1140 | // Y error means needed rotation around X axis and visa versa. | ||
1141 | ret.X = verticalError.Y; | ||
1142 | ret.Y = - verticalError.X; | ||
1143 | ret.Z = 0f; | ||
1144 | |||
1145 | // Scale the correction force by how far we're off from vertical. | ||
1146 | // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over. | ||
1147 | float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f); | ||
1148 | float vertForce = 1f / clampedSqrZError; | ||
1149 | |||
1150 | ret *= vertForce; | ||
1151 | |||
1152 | // Correction happens over a number of seconds. | ||
1153 | Vector3 unscaledContrib = ret; | ||
1154 | ret /= m_verticalAttractionTimescale; | ||
1155 | |||
1156 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}", | ||
1157 | Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret); | ||
998 | } | 1158 | } |
1159 | return ret; | ||
1160 | } | ||
999 | 1161 | ||
1000 | // ================================================================== | 1162 | // Return the angular correction to correct the direction the vehicle is pointing to be |
1001 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 1163 | // the direction is should want to be pointing. |
1164 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1165 | // in that direction. | ||
1166 | // TODO: implement reference frame. | ||
1167 | public Vector3 ComputeAngularDeflection() | ||
1168 | { | ||
1169 | Vector3 ret = Vector3.Zero; | ||
1170 | return ret; // DEBUG DEBUG DEBUG debug one force at a time | ||
1171 | |||
1172 | if (m_angularDeflectionEfficiency != 0) | ||
1002 | { | 1173 | { |
1003 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 1174 | // The direction the vehicle is moving |
1004 | Prim.ZeroAngularMotion(true); | 1175 | Vector3 movingDirection = VehicleVelocity; |
1005 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1176 | movingDirection.Normalize(); |
1177 | |||
1178 | // The direction the vehicle is pointing | ||
1179 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1180 | pointingDirection.Normalize(); | ||
1181 | |||
1182 | // The difference between what is and what should be | ||
1183 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1184 | |||
1185 | // Scale the correction by recovery timescale and efficiency | ||
1186 | ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency; | ||
1187 | ret /= m_angularDeflectionTimescale; | ||
1188 | |||
1189 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1190 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | ||
1006 | } | 1191 | } |
1007 | else | 1192 | return ret; |
1193 | } | ||
1194 | |||
1195 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | ||
1196 | // is tipped around the X axis. | ||
1197 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1198 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1199 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1200 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1201 | // of the yaw effect will be proportional to the | ||
1202 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1203 | // velocity along its preferred axis of motion. | ||
1204 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1205 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1206 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1207 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1208 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1209 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1210 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1211 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1212 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1213 | // it to turn while banking, however video-game motorcycles are often configured | ||
1214 | // to turn in place when at a dead stop--because they are often easier to control | ||
1215 | // that way using the limited interface of the keyboard or game controller. The | ||
1216 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1217 | // banking by functioning as a slider between a banking that is correspondingly | ||
1218 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1219 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1220 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1221 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1222 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1223 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1224 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1225 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1226 | public Vector3 ComputeAngularBanking() | ||
1227 | { | ||
1228 | Vector3 ret = Vector3.Zero; | ||
1229 | |||
1230 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1008 | { | 1231 | { |
1009 | // Apply to the body. | 1232 | // This works by rotating a unit vector to the orientation of the vehicle. The |
1010 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | 1233 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt |
1011 | // Since we are stuffing the angular velocity directly into the object, the computed | 1234 | // up to one for full over). |
1012 | // velocity needs to be scaled by the timestep. | 1235 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1013 | // Also remove any motion that is on the object so added motion is only from vehicle. | 1236 | |
1014 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) | 1237 | // Figure out the yaw value for this much roll. |
1015 | - Prim.ForceRotationalVelocity); | 1238 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; |
1016 | Prim.ForceRotationalVelocity = applyAngularForce; | 1239 | // Keep the sign |
1017 | 1240 | if (rollComponents.Y < 0f) | |
1018 | VDetailLog("{0},MoveAngular,done,newRotVel={1},lastAngular={2}", | 1241 | turnComponent = -turnComponent; |
1019 | Prim.LocalID, applyAngularForce, m_lastAngularVelocity); | 1242 | |
1243 | // TODO: there must be a better computation of the banking force. | ||
1244 | float bankingTurnForce = turnComponent; | ||
1245 | |||
1246 | // actual error = static turn error + dynamic turn error | ||
1247 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | ||
1248 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1249 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | ||
1250 | |||
1251 | // Build the force vector to change rotation from what it is to what it should be | ||
1252 | ret.Z = -mixedBankingError; | ||
1253 | |||
1254 | // Don't do it all at once. | ||
1255 | ret /= m_bankingTimescale; | ||
1256 | |||
1257 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | ||
1258 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | ||
1020 | } | 1259 | } |
1260 | return ret; | ||
1021 | } | 1261 | } |
1022 | 1262 | ||
1023 | // This is from previous instantiations of XXXDynamics.cs. | 1263 | // This is from previous instantiations of XXXDynamics.cs. |
@@ -1026,7 +1266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1026 | // Should this be in MoveAngular()? | 1266 | // Should this be in MoveAngular()? |
1027 | internal void LimitRotation(float timestep) | 1267 | internal void LimitRotation(float timestep) |
1028 | { | 1268 | { |
1029 | Quaternion rotq = Prim.ForceOrientation; | 1269 | Quaternion rotq = VehicleOrientation; |
1030 | Quaternion m_rot = rotq; | 1270 | Quaternion m_rot = rotq; |
1031 | if (m_RollreferenceFrame != Quaternion.Identity) | 1271 | if (m_RollreferenceFrame != Quaternion.Identity) |
1032 | { | 1272 | { |
@@ -1054,12 +1294,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1054 | } | 1294 | } |
1055 | if (rotq != m_rot) | 1295 | if (rotq != m_rot) |
1056 | { | 1296 | { |
1057 | Prim.ForceOrientation = m_rot; | 1297 | VehicleOrientation = m_rot; |
1058 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1298 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1059 | } | 1299 | } |
1060 | 1300 | ||
1061 | } | 1301 | } |
1062 | 1302 | ||
1303 | private float ClampInRange(float low, float val, float high) | ||
1304 | { | ||
1305 | return Math.Max(low, Math.Min(val, high)); | ||
1306 | } | ||
1307 | |||
1063 | // Invoke the detailed logger and output something if it's enabled. | 1308 | // Invoke the detailed logger and output something if it's enabled. |
1064 | private void VDetailLog(string msg, params Object[] args) | 1309 | private void VDetailLog(string msg, params Object[] args) |
1065 | { | 1310 | { |