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 | |
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')
16 files changed, 1200 insertions, 690 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..21aa9be 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -165,8 +165,8 @@ public sealed class BSCharacter : BSPhysObject | |||
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
166 | 166 | ||
167 | // Do this after the object has been added to the world | 167 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 168 | BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 169 | (uint)CollisionFilterGroups.AvatarGroup, |
170 | (uint)CollisionFilterGroups.AvatarMask); | 170 | (uint)CollisionFilterGroups.AvatarMask); |
171 | } | 171 | } |
172 | 172 | ||
@@ -307,7 +307,7 @@ public sealed class BSCharacter : BSPhysObject | |||
307 | } | 307 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 309 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 310 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 311 | if (Position.Z < waterHeight) |
312 | { | 312 | { |
313 | _position.Z = waterHeight; | 313 | _position.Z = waterHeight; |
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 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs index 663b6f4..390c2f9 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -1,191 +1,185 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyrightD | 9 | * * Redistributions in binary form must reproduce the above copyrightD |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
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 | using System; | 27 | using System; |
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using Nini.Config; | 31 | using Nini.Config; |
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | 35 | ||
36 | public struct MaterialAttributes | 36 | public struct MaterialAttributes |
37 | { | 37 | { |
38 | // Material type values that correspond with definitions for LSL | 38 | // Material type values that correspond with definitions for LSL |
39 | public enum Material : int | 39 | public enum Material : int |
40 | { | 40 | { |
41 | Stone = 0, | 41 | Stone = 0, |
42 | Metal, | 42 | Metal, |
43 | Glass, | 43 | Glass, |
44 | Wood, | 44 | Wood, |
45 | Flesh, | 45 | Flesh, |
46 | Plastic, | 46 | Plastic, |
47 | Rubber, | 47 | Rubber, |
48 | Light, | 48 | Light, |
49 | // Hereafter are BulletSim additions | 49 | // Hereafter are BulletSim additions |
50 | Avatar, | 50 | Avatar, |
51 | NumberOfTypes // the count of types in the enum. | 51 | NumberOfTypes // the count of types in the enum. |
52 | } | 52 | } |
53 | // Names must be in the order of the above enum. | 53 | // Names must be in the order of the above enum. |
54 | public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", | 54 | public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", |
55 | "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; | 55 | "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; |
56 | public static string[] MaterialAttribs = { "Density", "Friction", "Restitution", | 56 | public static string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; |
57 | "ccdMotionThreshold", "ccdSweptSphereRadius" }; | 57 | |
58 | 58 | public MaterialAttributes(string t, float d, float f, float r) | |
59 | public MaterialAttributes(string t, float d, float f, float r, float ccdM, float ccdS) | 59 | { |
60 | { | 60 | type = t; |
61 | type = t; | 61 | density = d; |
62 | density = d; | 62 | friction = f; |
63 | friction = f; | 63 | restitution = r; |
64 | restitution = r; | 64 | } |
65 | ccdMotionThreshold = ccdM; | 65 | public string type; |
66 | ccdSweptSphereRadius = ccdS; | 66 | public float density; |
67 | } | 67 | public float friction; |
68 | public string type; | 68 | public float restitution; |
69 | public float density; | 69 | } |
70 | public float friction; | 70 | |
71 | public float restitution; | 71 | public static class BSMaterials |
72 | public float ccdMotionThreshold; | 72 | { |
73 | public float ccdSweptSphereRadius; | 73 | public static MaterialAttributes[] Attributes; |
74 | } | 74 | |
75 | 75 | static BSMaterials() | |
76 | public static class BSMaterials | 76 | { |
77 | { | 77 | // Attribute sets for both the non-physical and physical instances of materials. |
78 | public static MaterialAttributes[] Attributes; | 78 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; |
79 | 79 | } | |
80 | static BSMaterials() | 80 | |
81 | { | 81 | // This is where all the default material attributes are defined. |
82 | // Attribute sets for both the non-physical and physical instances of materials. | 82 | public static void InitializeFromDefaults(ConfigurationParameters parms) |
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | 83 | { |
84 | } | 84 | // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL |
85 | 85 | // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", | |
86 | // This is where all the default material attributes are defined. | 86 | // "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; |
87 | public static void InitializeFromDefaults(ConfigurationParameters parms) | 87 | float dFriction = parms.defaultFriction; |
88 | { | 88 | float dRestitution = parms.defaultRestitution; |
89 | // public static string[] MaterialNames = { "Stone", "Metal", "Glass", "Wood", | 89 | float dDensity = parms.defaultDensity; |
90 | // "Flesh", "Plastic", "Rubber", "Light", "Avatar" }; | 90 | Attributes[(int)MaterialAttributes.Material.Stone] = |
91 | float dFriction = parms.defaultFriction; | 91 | new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); |
92 | float dRestitution = parms.defaultRestitution; | 92 | Attributes[(int)MaterialAttributes.Material.Metal] = |
93 | float dDensity = parms.defaultDensity; | 93 | new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); |
94 | float dCcdM = parms.ccdMotionThreshold; | 94 | Attributes[(int)MaterialAttributes.Material.Glass] = |
95 | float dCcdS = parms.ccdSweptSphereRadius; | 95 | new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); |
96 | Attributes[(int)MaterialAttributes.Material.Stone] = | 96 | Attributes[(int)MaterialAttributes.Material.Wood] = |
97 | new MaterialAttributes("stone",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 97 | new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); |
98 | Attributes[(int)MaterialAttributes.Material.Metal] = | 98 | Attributes[(int)MaterialAttributes.Material.Flesh] = |
99 | new MaterialAttributes("metal",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 99 | new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); |
100 | Attributes[(int)MaterialAttributes.Material.Glass] = | 100 | Attributes[(int)MaterialAttributes.Material.Plastic] = |
101 | new MaterialAttributes("glass",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 101 | new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); |
102 | Attributes[(int)MaterialAttributes.Material.Wood] = | 102 | Attributes[(int)MaterialAttributes.Material.Rubber] = |
103 | new MaterialAttributes("wood",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 103 | new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); |
104 | Attributes[(int)MaterialAttributes.Material.Flesh] = | 104 | Attributes[(int)MaterialAttributes.Material.Light] = |
105 | new MaterialAttributes("flesh",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 105 | new MaterialAttributes("light",dDensity, dFriction, dRestitution); |
106 | Attributes[(int)MaterialAttributes.Material.Plastic] = | 106 | Attributes[(int)MaterialAttributes.Material.Avatar] = |
107 | new MaterialAttributes("plastic",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 107 | new MaterialAttributes("avatar",60f, 0.2f, 0f); |
108 | Attributes[(int)MaterialAttributes.Material.Rubber] = | 108 | |
109 | new MaterialAttributes("rubber",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 109 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = |
110 | Attributes[(int)MaterialAttributes.Material.Light] = | 110 | new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); |
111 | new MaterialAttributes("light",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 111 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = |
112 | Attributes[(int)MaterialAttributes.Material.Avatar] = | 112 | new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f); |
113 | new MaterialAttributes("avatar",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 113 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = |
114 | 114 | new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f); | |
115 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | 115 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = |
116 | new MaterialAttributes("stonePhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 116 | new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f); |
117 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | 117 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = |
118 | new MaterialAttributes("metalPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 118 | new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f); |
119 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | 119 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = |
120 | new MaterialAttributes("glassPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 120 | new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f); |
121 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | 121 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = |
122 | new MaterialAttributes("woodPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 122 | new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f); |
123 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | 123 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = |
124 | new MaterialAttributes("fleshPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 124 | new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); |
125 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | 125 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = |
126 | new MaterialAttributes("plasticPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 126 | new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f); |
127 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | 127 | } |
128 | new MaterialAttributes("rubberPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 128 | |
129 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | 129 | // Under the [BulletSim] section, one can change the individual material |
130 | new MaterialAttributes("lightPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 130 | // attribute values. The format of the configuration parameter is: |
131 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | 131 | // <materialName><Attribute>["Physical"] = floatValue |
132 | new MaterialAttributes("avatarPhysical",dDensity,dFriction,dRestitution, dCcdM, dCcdS); | 132 | // For instance: |
133 | } | 133 | // [BulletSim] |
134 | 134 | // StoneFriction = 0.2 | |
135 | // Under the [BulletSim] section, one can change the individual material | 135 | // FleshRestitutionPhysical = 0.8 |
136 | // attribute values. The format of the configuration parameter is: | 136 | // Materials can have different parameters for their static and |
137 | // <materialName><Attribute>["Physical"] = floatValue | 137 | // physical instantiations. When setting the non-physical value, |
138 | // For instance: | 138 | // both values are changed. Setting the physical value only changes |
139 | // [BulletSim] | 139 | // the physical value. |
140 | // StoneFriction = 0.2 | 140 | public static void InitializefromParameters(IConfig pConfig) |
141 | // FleshRestitutionPhysical = 0.8 | 141 | { |
142 | // Materials can have different parameters for their static and | 142 | int matType = 0; |
143 | // physical instantiations. When setting the non-physical value, | 143 | foreach (string matName in MaterialAttributes.MaterialNames) |
144 | // both values are changed. Setting the physical value only changes | 144 | { |
145 | // the physical value. | 145 | foreach (string attribName in MaterialAttributes.MaterialAttribs) |
146 | public static void InitializefromParameters(IConfig pConfig) | 146 | { |
147 | { | 147 | string paramName = matName + attribName; |
148 | int matType = 0; | 148 | if (pConfig.Contains(paramName)) |
149 | foreach (string matName in MaterialAttributes.MaterialNames) | 149 | { |
150 | { | 150 | float paramValue = pConfig.GetFloat(paramName); |
151 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | 151 | SetAttributeValue(matType, attribName, paramValue); |
152 | { | 152 | // set the physical value also |
153 | string paramName = matName + attribName; | 153 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); |
154 | if (pConfig.Contains(paramName)) | 154 | } |
155 | { | 155 | paramName += "Physical"; |
156 | float paramValue = pConfig.GetFloat(paramName); | 156 | if (pConfig.Contains(paramName)) |
157 | SetAttributeValue(matType, attribName, paramValue); | 157 | { |
158 | // set the physical value also | 158 | float paramValue = pConfig.GetFloat(paramName); |
159 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | 159 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); |
160 | } | 160 | } |
161 | paramName += "Physical"; | 161 | } |
162 | if (pConfig.Contains(paramName)) | 162 | matType++; |
163 | { | 163 | } |
164 | float paramValue = pConfig.GetFloat(paramName); | 164 | } |
165 | SetAttributeValue(matType + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | 165 | |
166 | } | 166 | private static void SetAttributeValue(int matType, string attribName, float val) |
167 | } | 167 | { |
168 | matType++; | 168 | MaterialAttributes thisAttrib = Attributes[matType]; |
169 | } | 169 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); |
170 | } | 170 | if (fieldInfo != null) |
171 | 171 | { | |
172 | private static void SetAttributeValue(int matType, string attribName, float val) | 172 | fieldInfo.SetValue(thisAttrib, val); |
173 | { | 173 | Attributes[matType] = thisAttrib; |
174 | MaterialAttributes thisAttrib = Attributes[matType]; | 174 | } |
175 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName); | 175 | } |
176 | if (fieldInfo != null) | 176 | |
177 | { | 177 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) |
178 | fieldInfo.SetValue(thisAttrib, val); | 178 | { |
179 | Attributes[matType] = thisAttrib; | 179 | int ind = (int)type; |
180 | } | 180 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; |
181 | } | 181 | return Attributes[ind]; |
182 | 182 | } | |
183 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | 183 | |
184 | { | 184 | } |
185 | int ind = (int)type; | 185 | } |
186 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
187 | return Attributes[ind]; | ||
188 | } | ||
189 | |||
190 | } | ||
191 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index 480da2c..851d508 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,3 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
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. | ||
26 | * | ||
27 | */ | ||
1 | using System; | 28 | using System; |
2 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
3 | using System.Text; | 30 | using System.Text; |
@@ -7,6 +34,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
7 | { | 34 | { |
8 | public abstract class BSMotor | 35 | public abstract class BSMotor |
9 | { | 36 | { |
37 | // Timescales and other things can be turned off by setting them to 'infinite'. | ||
38 | public const float Infinite = 12345f; | ||
39 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); | ||
40 | |||
10 | public BSMotor(string useName) | 41 | public BSMotor(string useName) |
11 | { | 42 | { |
12 | UseName = useName; | 43 | UseName = useName; |
@@ -15,7 +46,9 @@ public abstract class BSMotor | |||
15 | public virtual void Reset() { } | 46 | public virtual void Reset() { } |
16 | public virtual void Zero() { } | 47 | public virtual void Zero() { } |
17 | 48 | ||
49 | // A name passed at motor creation for easily identifyable debugging messages. | ||
18 | public string UseName { get; private set; } | 50 | public string UseName { get; private set; } |
51 | |||
19 | // Used only for outputting debug information. Might not be set so check for null. | 52 | // Used only for outputting debug information. Might not be set so check for null. |
20 | public BSScene PhysicsScene { get; set; } | 53 | public BSScene PhysicsScene { get; set; } |
21 | protected void MDetailLog(string msg, params Object[] parms) | 54 | protected void MDetailLog(string msg, params Object[] parms) |
@@ -30,10 +63,23 @@ public abstract class BSMotor | |||
30 | } | 63 | } |
31 | } | 64 | } |
32 | // Can all the incremental stepping be replaced with motor classes? | 65 | // Can all the incremental stepping be replaced with motor classes? |
66 | |||
67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. | ||
68 | // The TargetValue is decays in TargetValueDecayTimeScale and | ||
69 | // the CurrentValue will be held back by FrictionTimeScale. | ||
70 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay. | ||
71 | |||
72 | // For instance, if something is moving at speed X and the desired speed is Y, | ||
73 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new | ||
74 | // values of CurrentValue are returned that approach the TargetValue. | ||
75 | // The feature of decaying TargetValue is so vehicles will eventually | ||
76 | // come to a stop rather than run forever. This can be disabled by | ||
77 | // setting TargetValueDecayTimescale to 'infinite'. | ||
78 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. | ||
33 | public class BSVMotor : BSMotor | 79 | public class BSVMotor : BSMotor |
34 | { | 80 | { |
35 | public Vector3 FrameOfReference { get; set; } | 81 | // public Vector3 FrameOfReference { get; set; } |
36 | public Vector3 Offset { get; set; } | 82 | // public Vector3 Offset { get; set; } |
37 | 83 | ||
38 | public float TimeScale { get; set; } | 84 | public float TimeScale { get; set; } |
39 | public float TargetValueDecayTimeScale { get; set; } | 85 | public float TargetValueDecayTimeScale { get; set; } |
@@ -46,8 +92,9 @@ public class BSVMotor : BSMotor | |||
46 | public BSVMotor(string useName) | 92 | public BSVMotor(string useName) |
47 | : base(useName) | 93 | : base(useName) |
48 | { | 94 | { |
49 | TimeScale = TargetValueDecayTimeScale = Efficiency = 1f; | 95 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
50 | FrictionTimescale = Vector3.Zero; | 96 | Efficiency = 1f; |
97 | FrictionTimescale = BSMotor.InfiniteVector; | ||
51 | CurrentValue = TargetValue = Vector3.Zero; | 98 | CurrentValue = TargetValue = Vector3.Zero; |
52 | } | 99 | } |
53 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 100 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) |
@@ -67,6 +114,14 @@ public class BSVMotor : BSMotor | |||
67 | { | 114 | { |
68 | TargetValue = target; | 115 | TargetValue = target; |
69 | } | 116 | } |
117 | |||
118 | // A form of stepping that does not take the time quantum into account. | ||
119 | // The caller must do the right thing later. | ||
120 | public Vector3 Step() | ||
121 | { | ||
122 | return Step(1f); | ||
123 | } | ||
124 | |||
70 | public Vector3 Step(float timeStep) | 125 | public Vector3 Step(float timeStep) |
71 | { | 126 | { |
72 | Vector3 returnCurrent = Vector3.Zero; | 127 | Vector3 returnCurrent = Vector3.Zero; |
@@ -78,23 +133,36 @@ public class BSVMotor : BSMotor | |||
78 | // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete | 133 | // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete |
79 | Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; | 134 | Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; |
80 | CurrentValue += addAmount; | 135 | CurrentValue += addAmount; |
136 | |||
81 | returnCurrent = CurrentValue; | 137 | returnCurrent = CurrentValue; |
82 | 138 | ||
83 | // The desired value reduces to zero when also reduces the difference with current. | 139 | // The desired value reduces to zero which also reduces the difference with current. |
84 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 140 | // If the decay time is infinite, don't decay at all. |
85 | TargetValue *= (1f - decayFactor); | 141 | float decayFactor = 0f; |
142 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
143 | { | ||
144 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
145 | TargetValue *= (1f - decayFactor); | ||
146 | } | ||
86 | 147 | ||
87 | Vector3 frictionFactor = Vector3.Zero; | 148 | Vector3 frictionFactor = Vector3.Zero; |
88 | frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | 149 | if (FrictionTimescale != BSMotor.InfiniteVector) |
89 | CurrentValue *= (Vector3.One - frictionFactor); | 150 | { |
151 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
152 | // Individual friction components can be 'infinite' so compute each separately. | ||
153 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; | ||
154 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; | ||
155 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; | ||
156 | CurrentValue *= (Vector3.One - frictionFactor); | ||
157 | } | ||
90 | 158 | ||
91 | MDetailLog("{0},BSVMotor.Step,nonZero,{1},origTarget={2},origCurr={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", | 159 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},timeScale={5},addAmnt={6},targetDecay={7},decayFact={8},fricTS={9},frictFact={10}", |
92 | BSScene.DetailLogZero, UseName, origTarget, origCurrVal, | 160 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, |
93 | timeStep, TimeScale, addAmount, | 161 | timeStep, TimeScale, addAmount, |
94 | TargetValueDecayTimeScale, decayFactor, | 162 | TargetValueDecayTimeScale, decayFactor, |
95 | FrictionTimescale, frictionFactor); | 163 | FrictionTimescale, frictionFactor); |
96 | MDetailLog("{0},BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", | 164 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", |
97 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, | 165 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, |
98 | addAmount, decayFactor, frictionFactor, returnCurrent); | 166 | addAmount, decayFactor, frictionFactor, returnCurrent); |
99 | } | 167 | } |
100 | else | 168 | else |
@@ -103,7 +171,7 @@ public class BSVMotor : BSMotor | |||
103 | CurrentValue = Vector3.Zero; | 171 | CurrentValue = Vector3.Zero; |
104 | TargetValue = Vector3.Zero; | 172 | TargetValue = Vector3.Zero; |
105 | 173 | ||
106 | MDetailLog("{0},BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", | 174 | MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", |
107 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); | 175 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); |
108 | 176 | ||
109 | } | 177 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index caa6c46..62aaf80 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -253,8 +253,9 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 253 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 255 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 256 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 257 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); |
258 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
258 | }); | 259 | }); |
259 | } | 260 | } |
260 | 261 | ||
@@ -329,7 +330,7 @@ public sealed class BSPrim : BSPhysObject | |||
329 | 330 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 331 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 332 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 333 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 334 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 335 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) |
335 | { | 336 | { |
@@ -347,7 +348,9 @@ public sealed class BSPrim : BSPhysObject | |||
347 | if (ret) | 348 | if (ret) |
348 | { | 349 | { |
349 | // Apply upforce and overcome gravity. | 350 | // Apply upforce and overcome gravity. |
350 | AddForce(upForce - PhysicsScene.DefaultGravity, false, inTaintTime); | 351 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; |
352 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); | ||
353 | AddForce(correctionForce, false, inTaintTime); | ||
351 | } | 354 | } |
352 | return ret; | 355 | return ret; |
353 | } | 356 | } |
@@ -643,9 +646,13 @@ public sealed class BSPrim : BSPhysObject | |||
643 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 646 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
644 | 647 | ||
645 | // Collision filter can be set only when the object is in the world | 648 | // Collision filter can be set only when the object is in the world |
646 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | 649 | if (PhysBody.collisionGroup != 0 || PhysBody.collisionMask != 0) |
647 | { | 650 | { |
648 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | 651 | if (!BulletSimAPI.SetCollisionGroupMask2(PhysBody.ptr, (uint)PhysBody.collisionGroup, (uint)PhysBody.collisionMask)) |
652 | { | ||
653 | PhysicsScene.Logger.ErrorFormat("{0} Failure setting prim collision mask. localID={1}, grp={2:X}, mask={3:X}", | ||
654 | LogHeader, LocalID, PhysBody.collisionGroup, PhysBody.collisionMask); | ||
655 | } | ||
649 | } | 656 | } |
650 | 657 | ||
651 | // Recompute any linkset parameters. | 658 | // Recompute any linkset parameters. |
@@ -684,11 +691,11 @@ public sealed class BSPrim : BSPhysObject | |||
684 | // There can be special things needed for implementing linksets | 691 | // There can be special things needed for implementing linksets |
685 | Linkset.MakeStatic(this); | 692 | Linkset.MakeStatic(this); |
686 | // The activation state is 'disabled' so Bullet will not try to act on it. | 693 | // The activation state is 'disabled' so Bullet will not try to act on it. |
687 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 694 | // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
688 | // Start it out sleeping and physical actions could wake it up. | 695 | // Start it out sleeping and physical actions could wake it up. |
689 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 696 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); |
690 | 697 | ||
691 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 698 | PhysBody.collisionGroup = CollisionFilterGroups.StaticObjectGroup; |
692 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 699 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; |
693 | } | 700 | } |
694 | else | 701 | else |
@@ -734,7 +741,7 @@ public sealed class BSPrim : BSPhysObject | |||
734 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 741 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); |
735 | // BulletSimAPI.Activate2(BSBody.ptr, true); | 742 | // BulletSimAPI.Activate2(BSBody.ptr, true); |
736 | 743 | ||
737 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 744 | PhysBody.collisionGroup = CollisionFilterGroups.ObjectGroup; |
738 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | 745 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; |
739 | } | 746 | } |
740 | } | 747 | } |
@@ -762,7 +769,7 @@ public sealed class BSPrim : BSPhysObject | |||
762 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 769 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
763 | } | 770 | } |
764 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 771 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
765 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 772 | PhysBody.collisionGroup = CollisionFilterGroups.VolumeDetectGroup; |
766 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 773 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; |
767 | } | 774 | } |
768 | } | 775 | } |
@@ -838,15 +845,6 @@ public sealed class BSPrim : BSPhysObject | |||
838 | } | 845 | } |
839 | public override OMV.Vector3 RotationalVelocity { | 846 | public override OMV.Vector3 RotationalVelocity { |
840 | get { | 847 | get { |
841 | /* | ||
842 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
843 | // if close to zero, report zero | ||
844 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
845 | // zero the property in the physics engine. | ||
846 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
847 | return pv; | ||
848 | */ | ||
849 | |||
850 | return _rotationalVelocity; | 848 | return _rotationalVelocity; |
851 | } | 849 | } |
852 | set { | 850 | set { |
@@ -1012,6 +1010,9 @@ public sealed class BSPrim : BSPhysObject | |||
1012 | }); | 1010 | }); |
1013 | } | 1011 | } |
1014 | // A torque impulse. | 1012 | // A torque impulse. |
1013 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1014 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1015 | // Computed as: angularVelocity += impulse * inertia; | ||
1015 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1016 | { | 1017 | { |
1017 | OMV.Vector3 applyImpulse = impulse; | 1018 | OMV.Vector3 applyImpulse = impulse; |
@@ -1380,54 +1381,16 @@ public sealed class BSPrim : BSPhysObject | |||
1380 | 1381 | ||
1381 | public override void UpdateProperties(EntityProperties entprop) | 1382 | public override void UpdateProperties(EntityProperties entprop) |
1382 | { | 1383 | { |
1383 | /* | 1384 | // Updates only for individual prims and for the root object of a linkset. |
1384 | UpdatedProperties changed = 0; | 1385 | if (Linkset.IsRoot(this)) |
1385 | // assign to the local variables so the normal set action does not happen | ||
1386 | // if (_position != entprop.Position) | ||
1387 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1388 | { | ||
1389 | _position = entprop.Position; | ||
1390 | changed |= UpdatedProperties.Position; | ||
1391 | } | ||
1392 | // if (_orientation != entprop.Rotation) | ||
1393 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1394 | { | ||
1395 | _orientation = entprop.Rotation; | ||
1396 | changed |= UpdatedProperties.Rotation; | ||
1397 | } | ||
1398 | // if (_velocity != entprop.Velocity) | ||
1399 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1400 | { | ||
1401 | _velocity = entprop.Velocity; | ||
1402 | changed |= UpdatedProperties.Velocity; | ||
1403 | } | ||
1404 | // if (_acceleration != entprop.Acceleration) | ||
1405 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1406 | { | ||
1407 | _acceleration = entprop.Acceleration; | ||
1408 | changed |= UpdatedProperties.Acceleration; | ||
1409 | } | ||
1410 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1411 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1412 | { | ||
1413 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1414 | changed |= UpdatedProperties.RotationalVel; | ||
1415 | } | ||
1416 | if (changed != 0) | ||
1417 | { | 1386 | { |
1418 | // Only update the position of single objects and linkset roots | 1387 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1419 | if (Linkset.IsRoot(this)) | 1388 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1389 | if (_vehicle.IsActive) | ||
1420 | { | 1390 | { |
1421 | base.RequestPhysicsterseUpdate(); | 1391 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1422 | } | 1392 | } |
1423 | } | ||
1424 | */ | ||
1425 | 1393 | ||
1426 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1427 | |||
1428 | // Updates only for individual prims and for the root object of a linkset. | ||
1429 | if (Linkset.IsRoot(this)) | ||
1430 | { | ||
1431 | // Assign directly to the local variables so the normal set action does not happen | 1394 | // Assign directly to the local variables so the normal set action does not happen |
1432 | _position = entprop.Position; | 1395 | _position = entprop.Position; |
1433 | _orientation = entprop.Rotation; | 1396 | _orientation = entprop.Rotation; |
@@ -1436,7 +1399,7 @@ public sealed class BSPrim : BSPhysObject | |||
1436 | _rotationalVelocity = entprop.RotationalVelocity; | 1399 | _rotationalVelocity = entprop.RotationalVelocity; |
1437 | 1400 | ||
1438 | // The sanity check can change the velocity and/or position. | 1401 | // The sanity check can change the velocity and/or position. |
1439 | if (PositionSanityCheck(true)) | 1402 | if (IsPhysical && PositionSanityCheck(true)) |
1440 | { | 1403 | { |
1441 | entprop.Position = _position; | 1404 | entprop.Position = _position; |
1442 | entprop.Velocity = _velocity; | 1405 | entprop.Velocity = _velocity; |
@@ -1446,12 +1409,10 @@ public sealed class BSPrim : BSPhysObject | |||
1446 | LastEntityProperties = CurrentEntityProperties; | 1409 | LastEntityProperties = CurrentEntityProperties; |
1447 | CurrentEntityProperties = entprop; | 1410 | CurrentEntityProperties = entprop; |
1448 | 1411 | ||
1449 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | 1412 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1450 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1413 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1451 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1414 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
1452 | 1415 | ||
1453 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | ||
1454 | |||
1455 | base.RequestPhysicsterseUpdate(); | 1416 | base.RequestPhysicsterseUpdate(); |
1456 | } | 1417 | } |
1457 | /* | 1418 | /* |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 805e670..f72bd74 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -96,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
96 | public long SimulationStep { get { return m_simulationStep; } } | 96 | public long SimulationStep { get { return m_simulationStep; } } |
97 | private int m_taintsToProcessPerStep; | 97 | private int m_taintsToProcessPerStep; |
98 | 98 | ||
99 | public delegate void PreStepAction(float timeStep); | ||
100 | public event PreStepAction BeforeStep; | ||
101 | |||
99 | // A value of the time now so all the collision and update routines do not have to get their own | 102 | // A value of the time now so all the collision and update routines do not have to get their own |
100 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 103 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
101 | public int SimulationNowTime { get; private set; } | 104 | public int SimulationNowTime { get; private set; } |
@@ -127,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
127 | public const uint GROUNDPLANE_ID = 1; | 130 | public const uint GROUNDPLANE_ID = 1; |
128 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here | 131 | public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here |
129 | 132 | ||
130 | private float m_waterLevel; | 133 | public float SimpleWaterLevel { get; set; } |
131 | public BSTerrainManager TerrainManager { get; private set; } | 134 | public BSTerrainManager TerrainManager { get; private set; } |
132 | 135 | ||
133 | public ConfigurationParameters Params | 136 | public ConfigurationParameters Params |
@@ -182,6 +185,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
182 | private string m_physicsLoggingDir; | 185 | private string m_physicsLoggingDir; |
183 | private string m_physicsLoggingPrefix; | 186 | private string m_physicsLoggingPrefix; |
184 | private int m_physicsLoggingFileMinutes; | 187 | private int m_physicsLoggingFileMinutes; |
188 | private bool m_physicsLoggingDoFlush; | ||
185 | // 'true' of the vehicle code is to log lots of details | 189 | // 'true' of the vehicle code is to log lots of details |
186 | public bool VehicleLoggingEnabled { get; private set; } | 190 | public bool VehicleLoggingEnabled { get; private set; } |
187 | 191 | ||
@@ -290,6 +294,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
290 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 294 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
291 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 295 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
292 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 296 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
297 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
293 | // Very detailed logging for vehicle debugging | 298 | // Very detailed logging for vehicle debugging |
294 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 299 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
295 | 300 | ||
@@ -485,8 +490,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
485 | ProcessTaints(); | 490 | ProcessTaints(); |
486 | 491 | ||
487 | // Some of the prims operate with special vehicle properties | 492 | // Some of the prims operate with special vehicle properties |
488 | ProcessVehicles(timeStep); | 493 | DoPreStepActions(timeStep); |
489 | ProcessTaints(); // the vehicles might have added taints | 494 | |
495 | // the prestep actions might have added taints | ||
496 | ProcessTaints(); | ||
490 | 497 | ||
491 | // step the physical world one interval | 498 | // step the physical world one interval |
492 | m_simulationStep++; | 499 | m_simulationStep++; |
@@ -515,9 +522,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
515 | collidersCount = 0; | 522 | collidersCount = 0; |
516 | } | 523 | } |
517 | 524 | ||
518 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 525 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. |
519 | 526 | ||
520 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 527 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
521 | SimulationNowTime = Util.EnvironmentTickCount(); | 528 | SimulationNowTime = Util.EnvironmentTickCount(); |
522 | 529 | ||
523 | // If there were collisions, process them by sending the event to the prim. | 530 | // If there were collisions, process them by sending the event to the prim. |
@@ -563,6 +570,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
563 | ObjectsWithCollisions.Remove(po); | 570 | ObjectsWithCollisions.Remove(po); |
564 | ObjectsWithNoMoreCollisions.Clear(); | 571 | ObjectsWithNoMoreCollisions.Clear(); |
565 | } | 572 | } |
573 | // Done with collisions. | ||
566 | 574 | ||
567 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 575 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
568 | if (updatedEntityCount > 0) | 576 | if (updatedEntityCount > 0) |
@@ -586,9 +594,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
586 | 594 | ||
587 | // The physics engine returns the number of milliseconds it simulated this call. | 595 | // The physics engine returns the number of milliseconds it simulated this call. |
588 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 596 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
589 | // We multiply by 55 to give a recognizable running rate (55 or less). | 597 | // Multiply by 55 to give a nominal frame rate of 55. |
590 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 598 | return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; |
591 | // return timeStep * 1000 * 55; | ||
592 | } | 599 | } |
593 | 600 | ||
594 | // Something has collided | 601 | // Something has collided |
@@ -634,12 +641,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
634 | 641 | ||
635 | public override void SetWaterLevel(float baseheight) | 642 | public override void SetWaterLevel(float baseheight) |
636 | { | 643 | { |
637 | m_waterLevel = baseheight; | 644 | SimpleWaterLevel = baseheight; |
638 | } | ||
639 | // Someday.... | ||
640 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
641 | { | ||
642 | return m_waterLevel; | ||
643 | } | 645 | } |
644 | 646 | ||
645 | public override void DeleteTerrain() | 647 | public override void DeleteTerrain() |
@@ -910,6 +912,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
910 | } | 912 | } |
911 | } | 913 | } |
912 | 914 | ||
915 | private void DoPreStepActions(float timeStep) | ||
916 | { | ||
917 | ProcessVehicles(timeStep); | ||
918 | |||
919 | PreStepAction actions = BeforeStep; | ||
920 | if (actions != null) | ||
921 | actions(timeStep); | ||
922 | |||
923 | } | ||
924 | |||
913 | // Some prims have extra vehicle actions | 925 | // Some prims have extra vehicle actions |
914 | // Called at taint time! | 926 | // Called at taint time! |
915 | private void ProcessVehicles(float timeStep) | 927 | private void ProcessVehicles(float timeStep) |
@@ -974,6 +986,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
974 | // Should handle fetching the right type from the ini file and converting it. | 986 | // Should handle fetching the right type from the ini file and converting it. |
975 | // -- a delegate for getting the value as a float | 987 | // -- a delegate for getting the value as a float |
976 | // -- a delegate for setting the value from a float | 988 | // -- a delegate for setting the value from a float |
989 | // -- an optional delegate to update the value in the world. Most often used to | ||
990 | // push the new value to an in-world object. | ||
977 | // | 991 | // |
978 | // The single letter parameters for the delegates are: | 992 | // The single letter parameters for the delegates are: |
979 | // s = BSScene | 993 | // s = BSScene |
@@ -1172,7 +1186,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1172 | (s) => { return s.m_params[0].avatarFriction; }, | 1186 | (s) => { return s.m_params[0].avatarFriction; }, |
1173 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1187 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1174 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 1188 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
1175 | 0.99f, | 1189 | 10.0f, |
1176 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | 1190 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, |
1177 | (s) => { return s.m_params[0].avatarStandingFriction; }, | 1191 | (s) => { return s.m_params[0].avatarStandingFriction; }, |
1178 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | 1192 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), |
@@ -1493,7 +1507,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1493 | { | 1507 | { |
1494 | PhysicsLogging.Write(msg, args); | 1508 | PhysicsLogging.Write(msg, args); |
1495 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 1509 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1496 | // PhysicsLogging.Flush(); | 1510 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1497 | } | 1511 | } |
1498 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1512 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1499 | public const string DetailLogZero = "0000000000"; | 1513 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..e77b6ba 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs | |||
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable | |||
65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); | 65 | private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); |
66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); | 66 | private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); |
67 | 67 | ||
68 | private bool DDetail = false; | ||
69 | |||
68 | public BSShapeCollection(BSScene physScene) | 70 | public BSShapeCollection(BSScene physScene) |
69 | { | 71 | { |
70 | PhysicsScene = physScene; | 72 | PhysicsScene = physScene; |
73 | // Set the next to 'true' for very detailed shape update detailed logging (detailed details?) | ||
74 | // While detailed debugging is still active, this is better than commenting out all the | ||
75 | // DetailLog statements. When debugging slows down, this and the protected logging | ||
76 | // statements can be commented/removed. | ||
77 | DDetail = true; | ||
71 | } | 78 | } |
72 | 79 | ||
73 | public void Dispose() | 80 | public void Dispose() |
@@ -126,13 +133,13 @@ public sealed class BSShapeCollection : IDisposable | |||
126 | { | 133 | { |
127 | lock (m_collectionActivityLock) | 134 | lock (m_collectionActivityLock) |
128 | { | 135 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 136 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 137 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() |
131 | { | 138 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 139 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
133 | { | 140 | { |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 141 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | 142 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
136 | } | 143 | } |
137 | }); | 144 | }); |
138 | } | 145 | } |
@@ -149,7 +156,7 @@ public sealed class BSShapeCollection : IDisposable | |||
149 | { | 156 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 157 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() |
151 | { | 158 | { |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 159 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", |
153 | body.ID, body, inTaintTime); | 160 | body.ID, body, inTaintTime); |
154 | // If the caller needs to know the old body is going away, pass the event up. | 161 | // If the caller needs to know the old body is going away, pass the event up. |
155 | if (bodyCallback != null) bodyCallback(body); | 162 | if (bodyCallback != null) bodyCallback(body); |
@@ -157,7 +164,7 @@ public sealed class BSShapeCollection : IDisposable | |||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 164 | if (BulletSimAPI.IsInWorld2(body.ptr)) |
158 | { | 165 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 166 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 167 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 168 | } |
162 | 169 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 170 | // Zero any reference to the shape so it is not freed when the body is deleted. |
@@ -184,7 +191,7 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 191 | { |
185 | // There is an existing instance of this mesh. | 192 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 193 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 194 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 195 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 196 | } |
190 | else | 197 | else |
@@ -194,7 +201,7 @@ public sealed class BSShapeCollection : IDisposable | |||
194 | meshDesc.shapeKey = shape.shapeKey; | 201 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 202 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 203 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 204 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 205 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 206 | ret = true; |
200 | } | 207 | } |
@@ -207,7 +214,7 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 214 | { |
208 | // There is an existing instance of this hull. | 215 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 216 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 217 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 218 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 219 | } |
213 | else | 220 | else |
@@ -216,7 +223,7 @@ public sealed class BSShapeCollection : IDisposable | |||
216 | hullDesc.ptr = shape.ptr; | 223 | hullDesc.ptr = shape.ptr; |
217 | hullDesc.shapeKey = shape.shapeKey; | 224 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 225 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 226 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 227 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 228 | ret = true; |
222 | 229 | ||
@@ -246,7 +253,7 @@ public sealed class BSShapeCollection : IDisposable | |||
246 | if (shape.isNativeShape) | 253 | if (shape.isNativeShape) |
247 | { | 254 | { |
248 | // Native shapes are not tracked and are released immediately | 255 | // Native shapes are not tracked and are released immediately |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 256 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 257 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); |
251 | if (shapeCallback != null) shapeCallback(shape); | 258 | if (shapeCallback != null) shapeCallback(shape); |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 259 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); |
@@ -286,7 +293,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 293 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 294 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 295 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 296 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 297 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 298 | ||
292 | } | 299 | } |
@@ -307,7 +314,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 314 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 315 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 316 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 317 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 318 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 319 | } |
313 | } | 320 | } |
@@ -325,13 +332,13 @@ public sealed class BSShapeCollection : IDisposable | |||
325 | // Failed the sanity check!! | 332 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 333 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", |
327 | LogHeader, shape.type, shape.ptr.ToString("X")); | 334 | LogHeader, shape.type, shape.ptr.ToString("X")); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 335 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 336 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); |
330 | return; | 337 | return; |
331 | } | 338 | } |
332 | 339 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 340 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 341 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 342 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 343 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 344 | { |
@@ -379,7 +386,7 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 386 | } |
380 | } | 387 | } |
381 | 388 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 389 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 390 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 391 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 392 | { |
@@ -410,7 +417,7 @@ public sealed class BSShapeCollection : IDisposable | |||
410 | // an avatar capsule is close to a native shape (it is not shared) | 417 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 418 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 419 | FixedShapeKey.KEY_CAPSULE, shapeCallback); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 420 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
414 | ret = true; | 421 | ret = true; |
415 | haveShape = true; | 422 | haveShape = true; |
416 | } | 423 | } |
@@ -420,7 +427,7 @@ public sealed class BSShapeCollection : IDisposable | |||
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 427 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 428 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 429 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 430 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 431 | haveShape = true; |
425 | } | 432 | } |
426 | 433 | ||
@@ -465,7 +472,7 @@ public sealed class BSShapeCollection : IDisposable | |||
465 | { | 472 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 473 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 474 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 475 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
469 | prim.LocalID, forceRebuild, prim.PhysShape); | 476 | prim.LocalID, forceRebuild, prim.PhysShape); |
470 | } | 477 | } |
471 | } | 478 | } |
@@ -479,7 +486,7 @@ public sealed class BSShapeCollection : IDisposable | |||
479 | { | 486 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 487 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 488 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 489 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
483 | prim.LocalID, forceRebuild, prim.PhysShape); | 490 | prim.LocalID, forceRebuild, prim.PhysShape); |
484 | } | 491 | } |
485 | } | 492 | } |
@@ -504,13 +511,13 @@ public sealed class BSShapeCollection : IDisposable | |||
504 | { | 511 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 512 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 513 | ret = GetReferenceToHull(prim,shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 514 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 515 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 516 | } |
510 | else | 517 | else |
511 | { | 518 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 519 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 520 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 521 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 522 | } |
516 | return ret; | 523 | return ret; |
@@ -528,7 +535,7 @@ public sealed class BSShapeCollection : IDisposable | |||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 535 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 536 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 537 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 538 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 539 | prim.LocalID, newShape, prim.Scale); |
533 | 540 | ||
534 | prim.PhysShape = newShape; | 541 | prim.PhysShape = newShape; |
@@ -554,7 +561,7 @@ public sealed class BSShapeCollection : IDisposable | |||
554 | newShape = new BulletShape( | 561 | newShape = new BulletShape( |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 562 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) |
556 | , shapeType); | 563 | , shapeType); |
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 564 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
558 | } | 565 | } |
559 | else | 566 | else |
560 | { | 567 | { |
@@ -589,7 +596,7 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 596 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 597 | return false; |
591 | 598 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 599 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 600 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
594 | 601 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 602 | // Since we're recreating new, get rid of the reference to the previous shape |
@@ -620,8 +627,7 @@ public sealed class BSShapeCollection : IDisposable | |||
620 | } | 627 | } |
621 | else | 628 | else |
622 | { | 629 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 630 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
625 | 631 | ||
626 | if (meshData != null) | 632 | if (meshData != null) |
627 | { | 633 | { |
@@ -663,7 +669,7 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 669 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 670 | return false; |
665 | 671 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 672 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 673 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 674 | ||
669 | // Remove usage of the previous shape. | 675 | // Remove usage of the previous shape. |
@@ -694,8 +700,8 @@ public sealed class BSShapeCollection : IDisposable | |||
694 | else | 700 | else |
695 | { | 701 | { |
696 | // Build a new hull in the physical world | 702 | // Build a new hull in the physical world |
697 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 703 | // Pass true for physicalness as this creates some sort of bounding box which we don't need |
698 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | 704 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false); |
699 | if (meshData != null) | 705 | if (meshData != null) |
700 | { | 706 | { |
701 | 707 | ||
@@ -809,7 +815,7 @@ public sealed class BSShapeCollection : IDisposable | |||
809 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. | 815 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 816 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 817 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 818 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 819 | prim.LocalID, cShape, prim.PhysShape); |
814 | 820 | ||
815 | prim.PhysShape = cShape; | 821 | prim.PhysShape = cShape; |
@@ -936,13 +942,13 @@ public sealed class BSShapeCollection : IDisposable | |||
936 | { | 942 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 943 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 945 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
940 | } | 946 | } |
941 | else | 947 | else |
942 | { | 948 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 949 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 950 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 951 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
946 | } | 952 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | 953 | aBody = new BulletBody(prim.LocalID, bodyPtr); |
948 | 954 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 1450f66..83b9c37 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -121,8 +121,8 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
121 | // redo its bounding box now that it is in the world | 121 | // redo its bounding box now that it is in the world |
122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 122 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); |
123 | 123 | ||
124 | BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, | 124 | BulletSimAPI.SetCollisionGroupMask2(m_mapInfo.terrainBody.ptr, |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 125 | (uint)CollisionFilterGroups.TerrainGroup, |
126 | (uint)CollisionFilterGroups.TerrainMask); | 126 | (uint)CollisionFilterGroups.TerrainMask); |
127 | 127 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 128 | // Make it so the terrain will not move or be considered for movement. |
@@ -148,7 +148,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
148 | } | 148 | } |
149 | 149 | ||
150 | // The passed position is relative to the base of the region. | 150 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 151 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 152 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 154 | ||
@@ -166,5 +166,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 166 | } |
167 | return ret; | 167 | return ret; |
168 | } | 168 | } |
169 | |||
170 | // The passed position is relative to the base of the region. | ||
171 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
172 | { | ||
173 | return PhysicsScene.SimpleWaterLevel; | ||
174 | } | ||
169 | } | 175 | } |
170 | } | 176 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index cd623f1..83df360 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,7 +62,8 @@ public abstract class BSTerrainPhys : IDisposable | |||
62 | ID = id; | 62 | ID = id; |
63 | } | 63 | } |
64 | public abstract void Dispose(); | 64 | public abstract void Dispose(); |
65 | public abstract float GetHeightAtXYZ(Vector3 pos); | 65 | public abstract float GetTerrainHeightAtXYZ(Vector3 pos); |
66 | public abstract float GetWaterLevelAtXYZ(Vector3 pos); | ||
66 | } | 67 | } |
67 | 68 | ||
68 | // ========================================================================================== | 69 | // ========================================================================================== |
@@ -75,6 +76,7 @@ public sealed class BSTerrainManager | |||
75 | public const float HEIGHT_INITIALIZATION = 24.987f; | 76 | public const float HEIGHT_INITIALIZATION = 24.987f; |
76 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; | 77 | public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; |
77 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; | 78 | public const float HEIGHT_GETHEIGHT_RET = 24.765f; |
79 | public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f; | ||
78 | 80 | ||
79 | // If the min and max height are equal, we reduce the min by this | 81 | // If the min and max height are equal, we reduce the min by this |
80 | // amount to make sure that a bounding box is built for the terrain. | 82 | // amount to make sure that a bounding box is built for the terrain. |
@@ -138,8 +140,8 @@ public sealed class BSTerrainManager | |||
138 | // Ground plane does not move | 140 | // Ground plane does not move |
139 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 141 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); |
140 | // Everything collides with the ground plane. | 142 | // Everything collides with the ground plane. |
141 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 143 | BulletSimAPI.SetCollisionGroupMask2(m_groundPlane.ptr, |
142 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 144 | (uint)CollisionFilterGroups.GroundPlaneGroup, (uint)CollisionFilterGroups.GroundPlaneMask); |
143 | 145 | ||
144 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 146 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
145 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 147 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
@@ -358,7 +360,7 @@ public sealed class BSTerrainManager | |||
358 | BSTerrainPhys physTerrain; | 360 | BSTerrainPhys physTerrain; |
359 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | 361 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) |
360 | { | 362 | { |
361 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 363 | ret = physTerrain.GetTerrainHeightAtXYZ(loc - terrainBaseXYZ); |
362 | } | 364 | } |
363 | else | 365 | else |
364 | { | 366 | { |
@@ -370,6 +372,33 @@ public sealed class BSTerrainManager | |||
370 | return ret; | 372 | return ret; |
371 | } | 373 | } |
372 | 374 | ||
375 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
376 | { | ||
377 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
378 | |||
379 | float tX = pos.X; | ||
380 | float tY = pos.Y; | ||
381 | |||
382 | Vector3 terrainBaseXYZ = Vector3.Zero; | ||
383 | terrainBaseXYZ.X = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
384 | terrainBaseXYZ.Y = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
385 | |||
386 | lock (m_terrains) | ||
387 | { | ||
388 | BSTerrainPhys physTerrain; | ||
389 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | ||
390 | { | ||
391 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
392 | } | ||
393 | else | ||
394 | { | ||
395 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | ||
396 | LogHeader, PhysicsScene.RegionName, tX, tY); | ||
397 | } | ||
398 | } | ||
399 | return ret; | ||
400 | } | ||
401 | |||
373 | // Although no one seems to check this, I do support combining. | 402 | // Although no one seems to check this, I do support combining. |
374 | public bool SupportsCombining() | 403 | public bool SupportsCombining() |
375 | { | 404 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index d7afdeb..6ce767d 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -88,9 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
88 | // Something is very messed up and a crash is in our future. | 88 | // Something is very messed up and a crash is in our future. |
89 | return; | 89 | return; |
90 | } | 90 | } |
91 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}", | ||
92 | ID, indicesCount, indices.Length, verticesCount, vertices.Length); | ||
91 | 93 | ||
92 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, | 94 | m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, |
93 | indicesCount, indices, verticesCount, vertices), | 95 | indicesCount, indices, verticesCount, vertices), |
94 | BSPhysicsShapeType.SHAPE_MESH); | 96 | BSPhysicsShapeType.SHAPE_MESH); |
95 | if (m_terrainShape.ptr == IntPtr.Zero) | 97 | if (m_terrainShape.ptr == IntPtr.Zero) |
96 | { | 98 | { |
@@ -122,14 +124,14 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
122 | // Static objects are not very massive. | 124 | // Static objects are not very massive. |
123 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); | 125 | BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); |
124 | 126 | ||
125 | // Return the new terrain to the world of physical objects | 127 | // Put the new terrain to the world of physical objects |
126 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 128 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
127 | 129 | ||
128 | // redo its bounding box now that it is in the world | 130 | // Redo its bounding box now that it is in the world |
129 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 131 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
130 | 132 | ||
131 | BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, | 133 | BulletSimAPI.SetCollisionGroupMask2(m_terrainBody.ptr, |
132 | (uint)CollisionFilterGroups.TerrainFilter, | 134 | (uint)CollisionFilterGroups.TerrainGroup, |
133 | (uint)CollisionFilterGroups.TerrainMask); | 135 | (uint)CollisionFilterGroups.TerrainMask); |
134 | 136 | ||
135 | // Make it so the terrain will not move or be considered for movement. | 137 | // Make it so the terrain will not move or be considered for movement. |
@@ -146,7 +148,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
146 | } | 148 | } |
147 | } | 149 | } |
148 | 150 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 151 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 152 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 153 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 154 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,6 +169,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 169 | return ret; |
168 | } | 170 | } |
169 | 171 | ||
172 | // The passed position is relative to the base of the region. | ||
173 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
174 | { | ||
175 | return PhysicsScene.SimpleWaterLevel; | ||
176 | } | ||
177 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 178 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 179 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 180 | public static bool ConvertHeightmapToMesh( |
@@ -188,6 +196,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 196 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 197 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 198 | ||
199 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
200 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
201 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
202 | // column of vertices are used to complete the triangles of the last row and column | ||
203 | // of the heightmap. | ||
191 | try | 204 | try |
192 | { | 205 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 206 | // One vertice per heightmap value plus the vertices off the top and bottom edge. |
@@ -200,16 +213,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | float magY = (float)sizeY / extentY; | 213 | float magY = (float)sizeY / extentY; |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 214 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 215 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); |
216 | float minHeight = float.MaxValue; | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 217 | // Note that sizeX+1 vertices are created since there is land between this and the next region. |
204 | for (int yy = 0; yy <= sizeY; yy++) | 218 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 219 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 220 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 221 | { |
208 | int offset = yy * sizeX + xx; | 222 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 223 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 224 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 225 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 226 | float height = heightMap[offset]; |
227 | minHeight = Math.Min(minHeight, height); | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 228 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 229 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; |
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 230 | vertices[verticesCount + 2] = height + extentBase.Z; |
@@ -222,7 +237,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
222 | { | 237 | { |
223 | for (int xx = 0; xx < sizeX; xx++) | 238 | for (int xx = 0; xx < sizeX; xx++) |
224 | { | 239 | { |
225 | int offset = yy * sizeX + xx; | 240 | int offset = yy * (sizeX + 1) + xx; |
226 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 241 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
227 | indices[indicesCount + 0] = offset; | 242 | indices[indicesCount + 0] = offset; |
228 | indices[indicesCount + 1] = offset + 1; | 243 | indices[indicesCount + 1] = offset + 1; |
@@ -233,6 +248,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
233 | indicesCount += 6; | 248 | indicesCount += 6; |
234 | } | 249 | } |
235 | } | 250 | } |
251 | |||
236 | ret = true; | 252 | ret = true; |
237 | } | 253 | } |
238 | catch (Exception e) | 254 | catch (Exception e) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 12baee9..2671995 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -57,12 +57,12 @@ public struct BulletBody | |||
57 | { | 57 | { |
58 | ID = id; | 58 | ID = id; |
59 | ptr = xx; | 59 | ptr = xx; |
60 | collisionFilter = 0; | 60 | collisionGroup = 0; |
61 | collisionMask = 0; | 61 | collisionMask = 0; |
62 | } | 62 | } |
63 | public IntPtr ptr; | 63 | public IntPtr ptr; |
64 | public uint ID; | 64 | public uint ID; |
65 | public CollisionFilterGroups collisionFilter; | 65 | public CollisionFilterGroups collisionGroup; |
66 | public CollisionFilterGroups collisionMask; | 66 | public CollisionFilterGroups collisionMask; |
67 | public override string ToString() | 67 | public override string ToString() |
68 | { | 68 | { |
@@ -71,10 +71,10 @@ public struct BulletBody | |||
71 | buff.Append(ID.ToString()); | 71 | buff.Append(ID.ToString()); |
72 | buff.Append(",p="); | 72 | buff.Append(",p="); |
73 | buff.Append(ptr.ToString("X")); | 73 | buff.Append(ptr.ToString("X")); |
74 | if (collisionFilter != 0 || collisionMask != 0) | 74 | if (collisionGroup != 0 || collisionMask != 0) |
75 | { | 75 | { |
76 | buff.Append(",f="); | 76 | buff.Append(",g="); |
77 | buff.Append(collisionFilter.ToString("X")); | 77 | buff.Append(collisionGroup.ToString("X")); |
78 | buff.Append(",m="); | 78 | buff.Append(",m="); |
79 | buff.Append(collisionMask.ToString("X")); | 79 | buff.Append(collisionMask.ToString("X")); |
80 | } | 80 | } |
@@ -357,9 +357,10 @@ public enum CollisionFlags : uint | |||
357 | CF_CHARACTER_OBJECT = 1 << 4, | 357 | CF_CHARACTER_OBJECT = 1 << 4, |
358 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | 358 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, |
359 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 359 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
360 | // Following used by BulletSim to control collisions | 360 | // Following used by BulletSim to control collisions and updates |
361 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 361 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, |
362 | BS_FLOATS_ON_WATER = 1 << 11, | 362 | BS_FLOATS_ON_WATER = 1 << 11, |
363 | BS_VEHICLE_COLLISIONS = 1 << 12, | ||
363 | BS_NONE = 0, | 364 | BS_NONE = 0, |
364 | BS_ALL = 0xFFFFFFFF, | 365 | BS_ALL = 0xFFFFFFFF, |
365 | 366 | ||
@@ -376,36 +377,36 @@ public enum CollisionFilterGroups : uint | |||
376 | // Don't use the bit definitions!! Define the use in a | 377 | // Don't use the bit definitions!! Define the use in a |
377 | // filter/mask definition below. This way collision interactions | 378 | // filter/mask definition below. This way collision interactions |
378 | // are more easily debugged. | 379 | // are more easily debugged. |
379 | BNoneFilter = 0, | 380 | BNoneGroup = 0, |
380 | BDefaultFilter = 1 << 0, | 381 | BDefaultGroup = 1 << 0, |
381 | BStaticFilter = 1 << 1, | 382 | BStaticGroup = 1 << 1, |
382 | BKinematicFilter = 1 << 2, | 383 | BKinematicGroup = 1 << 2, |
383 | BDebrisFilter = 1 << 3, | 384 | BDebrisGroup = 1 << 3, |
384 | BSensorTrigger = 1 << 4, | 385 | BSensorTrigger = 1 << 4, |
385 | BCharacterFilter = 1 << 5, | 386 | BCharacterGroup = 1 << 5, |
386 | BAllFilter = 0xFFFFFFFF, | 387 | BAllGroup = 0xFFFFFFFF, |
387 | // Filter groups defined by BulletSim | 388 | // Filter groups defined by BulletSim |
388 | BGroundPlaneFilter = 1 << 10, | 389 | BGroundPlaneGroup = 1 << 10, |
389 | BTerrainFilter = 1 << 11, | 390 | BTerrainGroup = 1 << 11, |
390 | BRaycastFilter = 1 << 12, | 391 | BRaycastGroup = 1 << 12, |
391 | BSolidFilter = 1 << 13, | 392 | BSolidGroup = 1 << 13, |
392 | BLinksetFilter = 1 << 14, | 393 | BLinksetGroup = 1 << 14, |
393 | 394 | ||
394 | // The collsion filters and masked are defined in one place -- don't want them scattered | 395 | // The collsion filters and masked are defined in one place -- don't want them scattered |
395 | AvatarFilter = BCharacterFilter, | 396 | AvatarGroup = BCharacterGroup, |
396 | AvatarMask = BAllFilter, | 397 | AvatarMask = BAllGroup, |
397 | ObjectFilter = BSolidFilter, | 398 | ObjectGroup = BSolidGroup, |
398 | ObjectMask = BAllFilter, | 399 | ObjectMask = BAllGroup, |
399 | StaticObjectFilter = BStaticFilter, | 400 | StaticObjectGroup = BStaticGroup, |
400 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | 401 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much |
401 | LinksetFilter = BLinksetFilter, | 402 | LinksetGroup = BLinksetGroup, |
402 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | 403 | LinksetMask = BAllGroup & ~BLinksetGroup, // linkset objects don't collide with each other |
403 | VolumeDetectFilter = BSensorTrigger, | 404 | VolumeDetectGroup = BSensorTrigger, |
404 | VolumeDetectMask = ~BSensorTrigger, | 405 | VolumeDetectMask = ~BSensorTrigger, |
405 | TerrainFilter = BTerrainFilter, | 406 | TerrainGroup = BTerrainGroup, |
406 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | 407 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide |
407 | GroundPlaneFilter = BGroundPlaneFilter, | 408 | GroundPlaneGroup = BGroundPlaneGroup, |
408 | GroundPlaneMask = BAllFilter | 409 | GroundPlaneMask = BAllGroup |
409 | 410 | ||
410 | }; | 411 | }; |
411 | 412 | ||
@@ -945,7 +946,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | |||
945 | public static extern int GetNumConstraintRefs2(IntPtr obj); | 946 | public static extern int GetNumConstraintRefs2(IntPtr obj); |
946 | 947 | ||
947 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 948 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
948 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | 949 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); |
949 | 950 | ||
950 | // ===================================================================================== | 951 | // ===================================================================================== |
951 | // btCollisionShape entries | 952 | // btCollisionShape entries |
@@ -1007,13 +1008,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | |||
1007 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | 1008 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); |
1008 | 1009 | ||
1009 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1010 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1011 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
1012 | |||
1013 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1010 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | 1014 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); |
1011 | 1015 | ||
1012 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1016 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1013 | public static extern void DumpAllInfo2(IntPtr sim); | 1017 | public static extern void DumpActivationInfo2(IntPtr sim); |
1014 | 1018 | ||
1015 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1019 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1016 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 1020 | public static extern void DumpAllInfo2(IntPtr sim); |
1017 | 1021 | ||
1018 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 1022 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1019 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 1023 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..d51003c --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,142 @@ | |||
1 | CRASHES | ||
2 | ================================================= | ||
3 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
4 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
5 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
6 | Causes many errors. Doesn't stop after first error with box shape. | ||
7 | Eventually crashes when deleting the object. | ||
8 | |||
9 | VEHICLES TODO LIST: | ||
10 | ================================================= | ||
11 | Neb car jiggling left and right | ||
12 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
13 | Vehicles (Move smoothly) | ||
14 | Add vehicle collisions so IsColliding is properly reported. | ||
15 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
16 | Some vehicles should not be able to turn if no speed or off ground. | ||
17 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
18 | Implement function efficiency for lineaar and angular motion. | ||
19 | Should vehicle angular/linear movement friction happen after all the components | ||
20 | or does it only apply to the basic movement? | ||
21 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
22 | Need to force a position update for the root prim after compound shape destruction | ||
23 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
24 | Implement referenceFrame for all the motion routines. | ||
25 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
26 | |||
27 | BULLETSIM TODO LIST: | ||
28 | ================================================= | ||
29 | Disable activity of passive linkset children. | ||
30 | Since the linkset is a compound object, the old prims are left lying | ||
31 | around and need to be phantomized so they don't collide, ... | ||
32 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
33 | BSPrim.Force should set a continious force on the prim. The force should be | ||
34 | applied each tick. Some limits? | ||
35 | Single prim vehicles don't seem to properly vehiclize. | ||
36 | Gun sending shooter flying. | ||
37 | Collision margin (gap between physical objects lying on each other) | ||
38 | Boundry checking (crashes related to crossing boundry) | ||
39 | Add check for border edge position for avatars and objects. | ||
40 | Verify the events are created for border crossings. | ||
41 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
42 | Avatar running (what does phys engine need to do?) | ||
43 | Small physical objects do not interact correctly | ||
44 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
45 | The chain will fall apart and pairs will dance around on ground | ||
46 | Chains of 1x1x.2 will stay connected but will dance. | ||
47 | Chains above 2x2x.4 are move stable and get stablier as torui get larger. | ||
48 | Add material type linkage and input all the material property definitions. | ||
49 | Skeleton classes and table are in the sources but are not filled or used. | ||
50 | Add PID motor for avatar movement (slow to stop, ...) | ||
51 | setForce should set a constant force. Different than AddImpulse. | ||
52 | Implement raycast. | ||
53 | Implement ShapeCollection.Dispose() | ||
54 | Implement water as a plain so raycasting and collisions can happen with same. | ||
55 | |||
56 | Find/remove avatar collision with ID=0. | ||
57 | Test avatar walking up stairs. How does compare with SL. | ||
58 | Radius of the capsule affects ability to climb edges. | ||
59 | Tune terrain/object friction to be closer to SL. | ||
60 | Debounce avatar contact so legs don't keep folding up when standing. | ||
61 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
62 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
63 | |||
64 | Speed up creation of large physical linksets | ||
65 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical | ||
66 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
67 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
68 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
69 | Check whether SimMotionState needs large if statement (see TODO). | ||
70 | |||
71 | Implement 'top colliders' info. | ||
72 | Avatar jump | ||
73 | Performance measurement and changes to make quicker. | ||
74 | Implement detailed physics stats (GetStats()). | ||
75 | |||
76 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
77 | Have UserPointer point to struct with localID and linksetID? | ||
78 | Objects in original linkset still collide with each other? | ||
79 | |||
80 | Measure performance improvement from hulls | ||
81 | Test not using ghost objects for volume detect implementation. | ||
82 | Performance of closures and delegates for taint processing | ||
83 | Are there faster ways? | ||
84 | Is any slowdown introduced by the existing implementation significant? | ||
85 | Is there are more efficient method of implementing pre and post step actions? | ||
86 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
87 | |||
88 | Physics Arena central pyramid: why is one side permiable? | ||
89 | |||
90 | INTERNAL IMPROVEMENT/CLEANUP | ||
91 | ================================================= | ||
92 | Remove unused fields from ShapeData (not used in API2) | ||
93 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
94 | Standardize access to building and reference code. | ||
95 | The skeleton classes are in the sources but are not complete or linked in. | ||
96 | Generalize Dynamics and PID with standardized motors. | ||
97 | Generalize Linkset and vehicles into PropertyManagers | ||
98 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
99 | Possibly generalized a 'pre step action' registration. | ||
100 | Complete implemention of preStepActions | ||
101 | Replace vehicle step call with prestep event. | ||
102 | Is there a need for postStepActions? postStepTaints? | ||
103 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
104 | Linkset implementation using manual prim movement. | ||
105 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
106 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
107 | Remove HeightmapInfo from terrain specification. | ||
108 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
109 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
110 | bob at the water level. BSPrim.PositionSanityCheck(). | ||
111 | |||
112 | THREADING | ||
113 | ================================================= | ||
114 | Do taint action immediately if not actually executing Bullet. | ||
115 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
116 | |||
117 | DONE DONE DONE DONE | ||
118 | ================================================= | ||
119 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
120 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
121 | Would have better and adjustable resolution. | ||
122 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
123 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
124 | Terrain as mesh. (Resolution: done) | ||
125 | How are static linksets seen by the physics engine? | ||
126 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
127 | Convert BSCharacter to use all API2 (Resolution: done) | ||
128 | Avatar pushing difficult (too heavy?) | ||
129 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
130 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
131 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
132 | Debug Bullet internal stats output (why is timing all wrong?) | ||
133 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
134 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
135 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
136 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
137 | Compound shapes will need the LocalID in the shapes and collision | ||
138 | processing to get it from there. | ||
139 | Light cycle falling over when driving (Resolution: implemented VerticalAttractor) | ||
140 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
141 | Package Bullet source mods for Bullet internal stats output | ||
142 | (Resolution: move code into WorldData.h rather than relying on patches) \ No newline at end of file | ||
diff --git a/OpenSim/Region/Physics/Manager/IMesher.cs b/OpenSim/Region/Physics/Manager/IMesher.cs index 3a9ca1b..10c4bd3 100644 --- a/OpenSim/Region/Physics/Manager/IMesher.cs +++ b/OpenSim/Region/Physics/Manager/IMesher.cs | |||
@@ -36,6 +36,7 @@ namespace OpenSim.Region.Physics.Manager | |||
36 | { | 36 | { |
37 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); | 37 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod); |
38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); | 38 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical); |
39 | IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache); | ||
39 | } | 40 | } |
40 | 41 | ||
41 | // Values for level of detail to be passed to the mesher. | 42 | // Values for level of detail to be passed to the mesher. |
diff --git a/OpenSim/Region/Physics/Manager/ZeroMesher.cs b/OpenSim/Region/Physics/Manager/ZeroMesher.cs index ba19db6..270d2ec 100644 --- a/OpenSim/Region/Physics/Manager/ZeroMesher.cs +++ b/OpenSim/Region/Physics/Manager/ZeroMesher.cs | |||
@@ -64,11 +64,16 @@ namespace OpenSim.Region.Physics.Manager | |||
64 | { | 64 | { |
65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 65 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
66 | { | 66 | { |
67 | return CreateMesh(primName, primShape, size, lod, false); | 67 | return CreateMesh(primName, primShape, size, lod, false, false); |
68 | } | 68 | } |
69 | 69 | ||
70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 70 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
71 | { | 71 | { |
72 | return CreateMesh(primName, primShape, size, lod, false, false); | ||
73 | } | ||
74 | |||
75 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
76 | { | ||
72 | // Remove the reference to the encoded JPEG2000 data so it can be GCed | 77 | // Remove the reference to the encoded JPEG2000 data so it can be GCed |
73 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; | 78 | primShape.SculptData = OpenMetaverse.Utils.EmptyBytes; |
74 | 79 | ||
diff --git a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs index 3bd15ce..8145d61 100644 --- a/OpenSim/Region/Physics/Meshing/Meshmerizer.cs +++ b/OpenSim/Region/Physics/Meshing/Meshmerizer.cs | |||
@@ -321,7 +321,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
321 | 321 | ||
322 | if (primShape.SculptData.Length <= 0) | 322 | if (primShape.SculptData.Length <= 0) |
323 | { | 323 | { |
324 | m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | 324 | // XXX: At the moment we can not log here since ODEPrim, for instance, ends up triggering this |
325 | // method twice - once before it has loaded sculpt data from the asset service and once afterwards. | ||
326 | // The first time will always call with unloaded SculptData if this needs to be uploaded. | ||
327 | // m_log.ErrorFormat("[MESH]: asset data for {0} is zero length", primName); | ||
325 | return false; | 328 | return false; |
326 | } | 329 | } |
327 | 330 | ||
@@ -699,11 +702,16 @@ namespace OpenSim.Region.Physics.Meshing | |||
699 | 702 | ||
700 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) | 703 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod) |
701 | { | 704 | { |
702 | return CreateMesh(primName, primShape, size, lod, false); | 705 | return CreateMesh(primName, primShape, size, lod, false, true); |
703 | } | 706 | } |
704 | 707 | ||
705 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) | 708 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical) |
706 | { | 709 | { |
710 | return CreateMesh(primName, primShape, size, lod, isPhysical, true); | ||
711 | } | ||
712 | |||
713 | public IMesh CreateMesh(String primName, PrimitiveBaseShape primShape, Vector3 size, float lod, bool isPhysical, bool shouldCache) | ||
714 | { | ||
707 | #if SPAM | 715 | #if SPAM |
708 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); | 716 | m_log.DebugFormat("[MESH]: Creating mesh for {0}", primName); |
709 | #endif | 717 | #endif |
@@ -713,9 +721,12 @@ namespace OpenSim.Region.Physics.Meshing | |||
713 | 721 | ||
714 | // If this mesh has been created already, return it instead of creating another copy | 722 | // If this mesh has been created already, return it instead of creating another copy |
715 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory | 723 | // For large regions with 100k+ prims and hundreds of copies of each, this can save a GB or more of memory |
716 | key = primShape.GetMeshKey(size, lod); | 724 | if (shouldCache) |
717 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | 725 | { |
718 | return mesh; | 726 | key = primShape.GetMeshKey(size, lod); |
727 | if (m_uniqueMeshes.TryGetValue(key, out mesh)) | ||
728 | return mesh; | ||
729 | } | ||
719 | 730 | ||
720 | if (size.X < 0.01f) size.X = 0.01f; | 731 | if (size.X < 0.01f) size.X = 0.01f; |
721 | if (size.Y < 0.01f) size.Y = 0.01f; | 732 | if (size.Y < 0.01f) size.Y = 0.01f; |
@@ -738,7 +749,10 @@ namespace OpenSim.Region.Physics.Meshing | |||
738 | // trim the vertex and triangle lists to free up memory | 749 | // trim the vertex and triangle lists to free up memory |
739 | mesh.TrimExcess(); | 750 | mesh.TrimExcess(); |
740 | 751 | ||
741 | m_uniqueMeshes.Add(key, mesh); | 752 | if (shouldCache) |
753 | { | ||
754 | m_uniqueMeshes.Add(key, mesh); | ||
755 | } | ||
742 | } | 756 | } |
743 | 757 | ||
744 | return mesh; | 758 | return mesh; |
diff --git a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs index 5a0b8d1..0d66496 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODEPrim.cs | |||
@@ -3361,6 +3361,11 @@ Console.WriteLine(" JointCreateFixed"); | |||
3361 | _pbs.SculptData = new byte[asset.Data.Length]; | 3361 | _pbs.SculptData = new byte[asset.Data.Length]; |
3362 | asset.Data.CopyTo(_pbs.SculptData, 0); | 3362 | asset.Data.CopyTo(_pbs.SculptData, 0); |
3363 | // m_assetFailed = false; | 3363 | // m_assetFailed = false; |
3364 | |||
3365 | // m_log.DebugFormat( | ||
3366 | // "[ODE PRIM]: Received mesh/sculpt data asset {0} with {1} bytes for {2} at {3} in {4}", | ||
3367 | // _pbs.SculptTexture, _pbs.SculptData.Length, Name, _position, _parent_scene.Name); | ||
3368 | |||
3364 | m_taintshape = true; | 3369 | m_taintshape = true; |
3365 | _parent_scene.AddPhysicsActorTaint(this); | 3370 | _parent_scene.AddPhysicsActorTaint(this); |
3366 | } | 3371 | } |