diff options
Diffstat (limited to '')
19 files changed, 2281 insertions, 1099 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index 4c195e1..4dd6264 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -105,12 +105,12 @@ public sealed class BSCharacter : BSPhysObject | |||
105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 105 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", |
106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 106 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); |
107 | 107 | ||
108 | // do actual create at taint time | 108 | // do actual creation in taint time |
109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 109 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() |
110 | { | 110 | { |
111 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 111 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
112 | // New body and shape into PhysBody and PhysShape | 112 | // New body and shape into PhysBody and PhysShape |
113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); | 113 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); |
114 | 114 | ||
115 | SetPhysicalProperties(); | 115 | SetPhysicalProperties(); |
116 | }); | 116 | }); |
@@ -124,7 +124,9 @@ public sealed class BSCharacter : BSPhysObject | |||
124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 124 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() |
125 | { | 125 | { |
126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 126 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
127 | PhysBody.Clear(); | ||
127 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 128 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
129 | PhysShape.Clear(); | ||
128 | }); | 130 | }); |
129 | } | 131 | } |
130 | 132 | ||
@@ -165,9 +167,8 @@ public sealed class BSCharacter : BSPhysObject | |||
165 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 167 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
166 | 168 | ||
167 | // Do this after the object has been added to the world | 169 | // Do this after the object has been added to the world |
168 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, | 170 | PhysBody.collisionType = CollisionType.Avatar; |
169 | (uint)CollisionFilterGroups.AvatarFilter, | 171 | PhysBody.ApplyCollisionMask(); |
170 | (uint)CollisionFilterGroups.AvatarMask); | ||
171 | } | 172 | } |
172 | 173 | ||
173 | public override void RequestPhysicsterseUpdate() | 174 | public override void RequestPhysicsterseUpdate() |
@@ -187,6 +188,11 @@ public sealed class BSCharacter : BSPhysObject | |||
187 | set { | 188 | set { |
188 | // When an avatar's size is set, only the height is changed. | 189 | // When an avatar's size is set, only the height is changed. |
189 | _size = value; | 190 | _size = value; |
191 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | ||
192 | // replace with the default values. | ||
193 | if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth; | ||
194 | if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth; | ||
195 | |||
190 | ComputeAvatarScale(_size); | 196 | ComputeAvatarScale(_size); |
191 | ComputeAvatarVolumeAndMass(); | 197 | ComputeAvatarVolumeAndMass(); |
192 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 198 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
@@ -194,15 +200,18 @@ public sealed class BSCharacter : BSPhysObject | |||
194 | 200 | ||
195 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 201 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() |
196 | { | 202 | { |
197 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | 203 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) |
198 | UpdatePhysicalMassProperties(RawMass); | 204 | { |
205 | BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); | ||
206 | UpdatePhysicalMassProperties(RawMass); | ||
207 | // Make sure this change appears as a property update event | ||
208 | BulletSimAPI.PushUpdate2(PhysBody.ptr); | ||
209 | } | ||
199 | }); | 210 | }); |
200 | 211 | ||
201 | } | 212 | } |
202 | } | 213 | } |
203 | 214 | ||
204 | public override OMV.Vector3 Scale { get; set; } | ||
205 | |||
206 | public override PrimitiveBaseShape Shape | 215 | public override PrimitiveBaseShape Shape |
207 | { | 216 | { |
208 | set { BaseShape = value; } | 217 | set { BaseShape = value; } |
@@ -236,7 +245,8 @@ public sealed class BSCharacter : BSPhysObject | |||
236 | // Zero some other properties directly into the physics engine | 245 | // Zero some other properties directly into the physics engine |
237 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
238 | { | 247 | { |
239 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 248 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
240 | }); | 250 | }); |
241 | } | 251 | } |
242 | public override void ZeroAngularMotion(bool inTaintTime) | 252 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -245,10 +255,13 @@ public sealed class BSCharacter : BSPhysObject | |||
245 | 255 | ||
246 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 256 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() |
247 | { | 257 | { |
248 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 258 | if (PhysBody.HasPhysicalBody) |
249 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 259 | { |
250 | // The next also get rid of applied linear force but the linear velocity is untouched. | 260 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
251 | BulletSimAPI.ClearForces2(PhysBody.ptr); | 261 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); |
262 | // The next also get rid of applied linear force but the linear velocity is untouched. | ||
263 | BulletSimAPI.ClearForces2(PhysBody.ptr); | ||
264 | } | ||
252 | }); | 265 | }); |
253 | } | 266 | } |
254 | 267 | ||
@@ -273,7 +286,8 @@ public sealed class BSCharacter : BSPhysObject | |||
273 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 286 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() |
274 | { | 287 | { |
275 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 288 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
276 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 289 | if (PhysBody.HasPhysicalBody) |
290 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
277 | }); | 291 | }); |
278 | } | 292 | } |
279 | } | 293 | } |
@@ -297,6 +311,15 @@ public sealed class BSCharacter : BSPhysObject | |||
297 | { | 311 | { |
298 | bool ret = false; | 312 | bool ret = false; |
299 | 313 | ||
314 | // TODO: check for out of bounds | ||
315 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
316 | { | ||
317 | // The character is out of the known/simulated area. | ||
318 | // Upper levels of code will handle the transition to other areas so, for | ||
319 | // the time, we just ignore the position. | ||
320 | return ret; | ||
321 | } | ||
322 | |||
300 | // If below the ground, move the avatar up | 323 | // If below the ground, move the avatar up |
301 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 324 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
302 | if (Position.Z < terrainHeight) | 325 | if (Position.Z < terrainHeight) |
@@ -307,7 +330,7 @@ public sealed class BSCharacter : BSPhysObject | |||
307 | } | 330 | } |
308 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 331 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
309 | { | 332 | { |
310 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 333 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
311 | if (Position.Z < waterHeight) | 334 | if (Position.Z < waterHeight) |
312 | { | 335 | { |
313 | _position.Z = waterHeight; | 336 | _position.Z = waterHeight; |
@@ -315,7 +338,6 @@ public sealed class BSCharacter : BSPhysObject | |||
315 | } | 338 | } |
316 | } | 339 | } |
317 | 340 | ||
318 | // TODO: check for out of bounds | ||
319 | return ret; | 341 | return ret; |
320 | } | 342 | } |
321 | 343 | ||
@@ -332,7 +354,8 @@ public sealed class BSCharacter : BSPhysObject | |||
332 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 354 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() |
333 | { | 355 | { |
334 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 356 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
335 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 357 | if (PhysBody.HasPhysicalBody) |
358 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
336 | }); | 359 | }); |
337 | ret = true; | 360 | ret = true; |
338 | } | 361 | } |
@@ -359,7 +382,8 @@ public sealed class BSCharacter : BSPhysObject | |||
359 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 382 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() |
360 | { | 383 | { |
361 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 384 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); |
362 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 385 | if (PhysBody.HasPhysicalBody) |
386 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
363 | }); | 387 | }); |
364 | } | 388 | } |
365 | } | 389 | } |
@@ -398,7 +422,8 @@ public sealed class BSCharacter : BSPhysObject | |||
398 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) | 422 | if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) |
399 | { | 423 | { |
400 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; | 424 | _currentFriction = PhysicsScene.Params.avatarStandingFriction; |
401 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 425 | if (PhysBody.HasPhysicalBody) |
426 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
402 | } | 427 | } |
403 | } | 428 | } |
404 | else | 429 | else |
@@ -406,7 +431,8 @@ public sealed class BSCharacter : BSPhysObject | |||
406 | if (_currentFriction != PhysicsScene.Params.avatarFriction) | 431 | if (_currentFriction != PhysicsScene.Params.avatarFriction) |
407 | { | 432 | { |
408 | _currentFriction = PhysicsScene.Params.avatarFriction; | 433 | _currentFriction = PhysicsScene.Params.avatarFriction; |
409 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | 434 | if (PhysBody.HasPhysicalBody) |
435 | BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); | ||
410 | } | 436 | } |
411 | } | 437 | } |
412 | _velocity = value; | 438 | _velocity = value; |
@@ -443,8 +469,11 @@ public sealed class BSCharacter : BSPhysObject | |||
443 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); | 469 | // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); |
444 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 470 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() |
445 | { | 471 | { |
446 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | 472 | if (PhysBody.HasPhysicalBody) |
447 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 473 | { |
474 | // _position = BulletSimAPI.GetPosition2(BSBody.ptr); | ||
475 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
476 | } | ||
448 | }); | 477 | }); |
449 | } | 478 | } |
450 | } | 479 | } |
@@ -517,10 +546,13 @@ public sealed class BSCharacter : BSPhysObject | |||
517 | _floatOnWater = value; | 546 | _floatOnWater = value; |
518 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 547 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() |
519 | { | 548 | { |
520 | if (_floatOnWater) | 549 | if (PhysBody.HasPhysicalBody) |
521 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 550 | { |
522 | else | 551 | if (_floatOnWater) |
523 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | 552 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); |
553 | else | ||
554 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); | ||
555 | } | ||
524 | }); | 556 | }); |
525 | } | 557 | } |
526 | } | 558 | } |
@@ -553,7 +585,8 @@ public sealed class BSCharacter : BSPhysObject | |||
553 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 585 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
554 | // Buoyancy is faked by changing the gravity applied to the object | 586 | // Buoyancy is faked by changing the gravity applied to the object |
555 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 587 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); |
556 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 588 | if (PhysBody.HasPhysicalBody) |
589 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
557 | } | 590 | } |
558 | } | 591 | } |
559 | 592 | ||
@@ -599,7 +632,8 @@ public sealed class BSCharacter : BSPhysObject | |||
599 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() | 632 | PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() |
600 | { | 633 | { |
601 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); | 634 | DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); |
602 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 635 | if (PhysBody.HasPhysicalBody) |
636 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
603 | }); | 637 | }); |
604 | } | 638 | } |
605 | else | 639 | else |
@@ -616,9 +650,6 @@ public sealed class BSCharacter : BSPhysObject | |||
616 | 650 | ||
617 | private void ComputeAvatarScale(OMV.Vector3 size) | 651 | private void ComputeAvatarScale(OMV.Vector3 size) |
618 | { | 652 | { |
619 | // The 'size' given by the simulator is the mid-point of the avatar | ||
620 | // and X and Y are unspecified. | ||
621 | |||
622 | OMV.Vector3 newScale = size; | 653 | OMV.Vector3 newScale = size; |
623 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; | 654 | // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; |
624 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; | 655 | // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; |
@@ -677,7 +708,7 @@ public sealed class BSCharacter : BSPhysObject | |||
677 | } | 708 | } |
678 | 709 | ||
679 | // Tell the linkset about value changes | 710 | // Tell the linkset about value changes |
680 | Linkset.UpdateProperties(this); | 711 | Linkset.UpdateProperties(this, true); |
681 | 712 | ||
682 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 713 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
683 | // base.RequestPhysicsterseUpdate(); | 714 | // base.RequestPhysicsterseUpdate(); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs index 65fac00..6b1e304 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs | |||
@@ -57,7 +57,7 @@ public abstract class BSConstraint : IDisposable | |||
57 | if (m_enabled) | 57 | if (m_enabled) |
58 | { | 58 | { |
59 | m_enabled = false; | 59 | m_enabled = false; |
60 | if (m_constraint.ptr != IntPtr.Zero) | 60 | if (m_constraint.HasPhysicalConstraint) |
61 | { | 61 | { |
62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); | 62 | bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); |
63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", | 63 | m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", |
@@ -65,7 +65,7 @@ public abstract class BSConstraint : IDisposable | |||
65 | m_body1.ID, m_body1.ptr.ToString("X"), | 65 | m_body1.ID, m_body1.ptr.ToString("X"), |
66 | m_body2.ID, m_body2.ptr.ToString("X"), | 66 | m_body2.ID, m_body2.ptr.ToString("X"), |
67 | success); | 67 | success); |
68 | m_constraint.ptr = System.IntPtr.Zero; | 68 | m_constraint.Clear(); |
69 | } | 69 | } |
70 | } | 70 | } |
71 | } | 71 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs index 23ef052..b073555 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs | |||
@@ -65,7 +65,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
65 | m_world = world; | 65 | m_world = world; |
66 | m_body1 = obj1; | 66 | m_body1 = obj1; |
67 | m_body2 = obj2; | 67 | m_body2 = obj2; |
68 | if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) | 68 | if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody) |
69 | { | 69 | { |
70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", | 70 | world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", |
71 | BSScene.DetailLogZero, world.worldID, | 71 | BSScene.DetailLogZero, world.worldID, |
@@ -83,7 +83,7 @@ public sealed class BSConstraint6Dof : BSConstraint | |||
83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", | 83 | world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", |
84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), | 84 | BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), |
85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); | 85 | obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); |
86 | if (m_constraint.ptr == IntPtr.Zero) | 86 | if (!m_constraint.HasPhysicalConstraint) |
87 | { | 87 | { |
88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", | 88 | world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", |
89 | LogHeader, obj1.ID, obj2.ID); | 89 | LogHeader, obj1.ID, obj2.ID); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index dbc9039..5887249 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 |
@@ -80,10 +67,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
80 | private Quaternion m_referenceFrame = Quaternion.Identity; | 67 | private Quaternion m_referenceFrame = Quaternion.Identity; |
81 | 68 | ||
82 | // Linear properties | 69 | // Linear properties |
70 | private BSVMotor m_linearMotor = new BSVMotor("LinearMotor"); | ||
83 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time | 71 | private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time |
84 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center | 72 | private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center |
85 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL | 73 | private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL |
86 | private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body | ||
87 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; | 74 | private Vector3 m_linearFrictionTimescale = Vector3.Zero; |
88 | private float m_linearMotorDecayTimescale = 0; | 75 | private float m_linearMotorDecayTimescale = 0; |
89 | private float m_linearMotorTimescale = 0; | 76 | private float m_linearMotorTimescale = 0; |
@@ -93,13 +80,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
93 | // private Vector3 m_linearMotorOffset = Vector3.Zero; | 80 | // private Vector3 m_linearMotorOffset = Vector3.Zero; |
94 | 81 | ||
95 | //Angular properties | 82 | //Angular properties |
83 | private BSVMotor m_angularMotor = new BSVMotor("AngularMotor"); | ||
96 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 84 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor |
97 | // private int m_angularMotorApply = 0; // application frame counter | 85 | // private int m_angularMotorApply = 0; // application frame counter |
98 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity | 86 | private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity |
99 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 87 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate |
100 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 88 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate |
101 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 89 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate |
102 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | 90 | private Vector3 m_lastAngularVelocity = Vector3.Zero; |
103 | 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 |
104 | 92 | ||
105 | //Deflection properties | 93 | //Deflection properties |
@@ -124,8 +112,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
124 | // 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. |
125 | 113 | ||
126 | //Attractor properties | 114 | //Attractor properties |
127 | private float m_verticalAttractionEfficiency = 1.0f; // damped | 115 | private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction"); |
128 | 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; | ||
129 | 120 | ||
130 | public BSDynamics(BSScene myScene, BSPrim myPrim) | 121 | public BSDynamics(BSScene myScene, BSPrim myPrim) |
131 | { | 122 | { |
@@ -137,7 +128,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
137 | // Return 'true' if this vehicle is doing vehicle things | 128 | // Return 'true' if this vehicle is doing vehicle things |
138 | public bool IsActive | 129 | public bool IsActive |
139 | { | 130 | { |
140 | get { return Type != Vehicle.TYPE_NONE; } | 131 | get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; } |
141 | } | 132 | } |
142 | 133 | ||
143 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 134 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) |
@@ -152,13 +143,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
152 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); | 143 | m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); |
153 | break; | 144 | break; |
154 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: | 145 | case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: |
155 | m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); | 146 | m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
147 | m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale; | ||
156 | break; | 148 | break; |
157 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: | 149 | case Vehicle.ANGULAR_MOTOR_TIMESCALE: |
158 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); | 150 | m_angularMotorTimescale = Math.Max(pValue, 0.01f); |
151 | m_angularMotor.TimeScale = m_angularMotorTimescale; | ||
159 | break; | 152 | break; |
160 | case Vehicle.BANKING_EFFICIENCY: | 153 | case Vehicle.BANKING_EFFICIENCY: |
161 | m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); | 154 | m_bankingEfficiency = ClampInRange(-1f, pValue, 1f); |
162 | break; | 155 | break; |
163 | case Vehicle.BANKING_MIX: | 156 | case Vehicle.BANKING_MIX: |
164 | m_bankingMix = Math.Max(pValue, 0.01f); | 157 | m_bankingMix = Math.Max(pValue, 0.01f); |
@@ -167,10 +160,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
167 | m_bankingTimescale = Math.Max(pValue, 0.01f); | 160 | m_bankingTimescale = Math.Max(pValue, 0.01f); |
168 | break; | 161 | break; |
169 | case Vehicle.BUOYANCY: | 162 | case Vehicle.BUOYANCY: |
170 | m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); | 163 | m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f); |
171 | break; | 164 | break; |
172 | case Vehicle.HOVER_EFFICIENCY: | 165 | case Vehicle.HOVER_EFFICIENCY: |
173 | m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); | 166 | m_VhoverEfficiency = ClampInRange(0f, pValue, 1f); |
174 | break; | 167 | break; |
175 | case Vehicle.HOVER_HEIGHT: | 168 | case Vehicle.HOVER_HEIGHT: |
176 | m_VhoverHeight = pValue; | 169 | m_VhoverHeight = pValue; |
@@ -185,33 +178,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
185 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); | 178 | m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); |
186 | break; | 179 | break; |
187 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: | 180 | case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: |
188 | m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); | 181 | m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120); |
182 | m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale; | ||
189 | break; | 183 | break; |
190 | case Vehicle.LINEAR_MOTOR_TIMESCALE: | 184 | case Vehicle.LINEAR_MOTOR_TIMESCALE: |
191 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); | 185 | m_linearMotorTimescale = Math.Max(pValue, 0.01f); |
186 | m_linearMotor.TimeScale = m_linearMotorTimescale; | ||
192 | break; | 187 | break; |
193 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: | 188 | case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: |
194 | m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); | 189 | m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f); |
190 | m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency; | ||
195 | break; | 191 | break; |
196 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: | 192 | case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: |
197 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); | 193 | m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); |
194 | m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale; | ||
198 | break; | 195 | break; |
199 | 196 | ||
200 | // 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 |
201 | // set all of the components to the same value | 198 | // set all of the components to the same value |
202 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 199 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
203 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); | 200 | m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); |
201 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
204 | break; | 202 | break; |
205 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 203 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
206 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); | 204 | m_angularMotorDirection = new Vector3(pValue, pValue, pValue); |
207 | // m_angularMotorApply = 100; | 205 | m_angularMotor.SetTarget(m_angularMotorDirection); |
208 | break; | 206 | break; |
209 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 207 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
210 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); | 208 | m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); |
209 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
211 | break; | 210 | break; |
212 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 211 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
213 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); | 212 | m_linearMotorDirection = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); | 213 | m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); |
214 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
215 | break; | 215 | break; |
216 | case Vehicle.LINEAR_MOTOR_OFFSET: | 216 | case Vehicle.LINEAR_MOTOR_OFFSET: |
217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); | 217 | m_linearMotorOffset = new Vector3(pValue, pValue, pValue); |
@@ -227,21 +227,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
227 | { | 227 | { |
228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 228 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 229 | m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
230 | m_angularMotor.FrictionTimescale = m_angularFrictionTimescale; | ||
230 | break; | 231 | break; |
231 | case Vehicle.ANGULAR_MOTOR_DIRECTION: | 232 | case Vehicle.ANGULAR_MOTOR_DIRECTION: |
232 | // Limit requested angular speed to 2 rps= 4 pi rads/sec | 233 | // Limit requested angular speed to 2 rps= 4 pi rads/sec |
233 | pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); | 234 | pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f); |
234 | pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); | 235 | pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f); |
235 | pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); | 236 | pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f); |
236 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 237 | m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
237 | // m_angularMotorApply = 100; | 238 | m_angularMotor.SetTarget(m_angularMotorDirection); |
238 | break; | 239 | break; |
239 | case Vehicle.LINEAR_FRICTION_TIMESCALE: | 240 | case Vehicle.LINEAR_FRICTION_TIMESCALE: |
240 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); | 241 | m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); |
242 | m_linearMotor.FrictionTimescale = m_linearFrictionTimescale; | ||
241 | break; | 243 | break; |
242 | case Vehicle.LINEAR_MOTOR_DIRECTION: | 244 | case Vehicle.LINEAR_MOTOR_DIRECTION: |
243 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); | 245 | m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); |
244 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); | 246 | m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); |
247 | m_linearMotor.SetTarget(m_linearMotorDirection); | ||
245 | break; | 248 | break; |
246 | case Vehicle.LINEAR_MOTOR_OFFSET: | 249 | case Vehicle.LINEAR_MOTOR_OFFSET: |
247 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); | 250 | m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); |
@@ -303,7 +306,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
303 | m_VhoverEfficiency = 0; | 306 | m_VhoverEfficiency = 0; |
304 | m_VhoverTimescale = 0; | 307 | m_VhoverTimescale = 0; |
305 | m_VehicleBuoyancy = 0; | 308 | m_VehicleBuoyancy = 0; |
306 | 309 | ||
307 | m_linearDeflectionEfficiency = 1; | 310 | m_linearDeflectionEfficiency = 1; |
308 | m_linearDeflectionTimescale = 1; | 311 | m_linearDeflectionTimescale = 1; |
309 | 312 | ||
@@ -319,6 +322,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
319 | 322 | ||
320 | m_referenceFrame = Quaternion.Identity; | 323 | m_referenceFrame = Quaternion.Identity; |
321 | m_flags = (VehicleFlag)0; | 324 | m_flags = (VehicleFlag)0; |
325 | |||
322 | break; | 326 | break; |
323 | 327 | ||
324 | case Vehicle.TYPE_SLED: | 328 | case Vehicle.TYPE_SLED: |
@@ -351,10 +355,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
351 | m_bankingMix = 1; | 355 | m_bankingMix = 1; |
352 | 356 | ||
353 | m_referenceFrame = Quaternion.Identity; | 357 | m_referenceFrame = Quaternion.Identity; |
354 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); | 358 | m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY |
355 | m_flags &= | 359 | | VehicleFlag.HOVER_TERRAIN_ONLY |
356 | ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | | 360 | | VehicleFlag.HOVER_GLOBAL_HEIGHT |
357 | VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); | 361 | | VehicleFlag.HOVER_UP_ONLY); |
362 | m_flags |= (VehicleFlag.NO_DEFLECTION_UP | ||
363 | | VehicleFlag.LIMIT_ROLL_ONLY | ||
364 | | VehicleFlag.LIMIT_MOTOR_UP); | ||
365 | |||
358 | break; | 366 | break; |
359 | case Vehicle.TYPE_CAR: | 367 | case Vehicle.TYPE_CAR: |
360 | m_linearMotorDirection = Vector3.Zero; | 368 | m_linearMotorDirection = Vector3.Zero; |
@@ -498,6 +506,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
498 | m_bankingEfficiency = 0; | 506 | m_bankingEfficiency = 0; |
499 | m_bankingMix = 0.7f; | 507 | m_bankingMix = 0.7f; |
500 | m_bankingTimescale = 5; | 508 | m_bankingTimescale = 5; |
509 | |||
501 | m_referenceFrame = Quaternion.Identity; | 510 | m_referenceFrame = Quaternion.Identity; |
502 | 511 | ||
503 | m_referenceFrame = Quaternion.Identity; | 512 | m_referenceFrame = Quaternion.Identity; |
@@ -510,6 +519,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
510 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); | 519 | | VehicleFlag.HOVER_GLOBAL_HEIGHT); |
511 | break; | 520 | break; |
512 | } | 521 | } |
522 | |||
523 | // Update any physical parameters based on this type. | ||
524 | Refresh(); | ||
525 | |||
526 | m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale, | ||
527 | m_linearMotorDecayTimescale, m_linearFrictionTimescale, | ||
528 | 1f); | ||
529 | m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
530 | |||
531 | m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale, | ||
532 | m_angularMotorDecayTimescale, m_angularFrictionTimescale, | ||
533 | 1f); | ||
534 | m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging) | ||
535 | |||
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) | ||
513 | } | 542 | } |
514 | 543 | ||
515 | // Some of the properties of this prim may have changed. | 544 | // Some of the properties of this prim may have changed. |
@@ -518,13 +547,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
518 | { | 547 | { |
519 | if (IsActive) | 548 | if (IsActive) |
520 | { | 549 | { |
521 | // Friction effects are handled by this vehicle code | 550 | // Remember the mass so we don't have to fetch it every step |
522 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); | 551 | m_vehicleMass = Prim.Linkset.LinksetMass; |
523 | BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f); | 552 | |
524 | 553 | // Friction affects are handled by this vehicle code | |
525 | // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); | 554 | float friction = 0f; |
526 | 555 | BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, friction); | |
527 | VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); | 556 | |
557 | // Moderate angular movement introduced by Bullet. | ||
558 | // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle. | ||
559 | // Maybe compute linear and angular factor and damping from params. | ||
560 | float angularDamping = PhysicsScene.Params.vehicleAngularDamping; | ||
561 | BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, angularDamping); | ||
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 | |||
566 | // DEBUG DEBUG DEBUG: use uniform inertia to smooth movement added by Bullet | ||
567 | // Vector3 localInertia = new Vector3(1f, 1f, 1f); | ||
568 | // Vector3 localInertia = new Vector3(m_vehicleMass, m_vehicleMass, m_vehicleMass); | ||
569 | Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(Prim.PhysShape.ptr, m_vehicleMass); | ||
570 | BulletSimAPI.SetMassProps2(Prim.PhysBody.ptr, m_vehicleMass, localInertia); | ||
571 | BulletSimAPI.UpdateInertiaTensor2(Prim.PhysBody.ptr); | ||
572 | |||
573 | VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}", | ||
574 | Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping); | ||
575 | } | ||
576 | else | ||
577 | { | ||
578 | BulletSimAPI.RemoveFromCollisionFlags2(Prim.PhysBody.ptr, CollisionFlags.BS_VEHICLE_COLLISIONS); | ||
528 | } | 579 | } |
529 | } | 580 | } |
530 | 581 | ||
@@ -546,116 +597,294 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
546 | Refresh(); | 597 | Refresh(); |
547 | } | 598 | } |
548 | 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 | m_knownChanged = 0; | ||
668 | } | ||
669 | |||
670 | // Since the computation of terrain height can be a little involved, this routine | ||
671 | // is used ot fetch the height only once for each vehicle simulation step. | ||
672 | private float GetTerrainHeight(Vector3 pos) | ||
673 | { | ||
674 | if (m_knownTerrainHeight == null) | ||
675 | m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | ||
676 | return (float)m_knownTerrainHeight; | ||
677 | } | ||
678 | |||
679 | // Since the computation of water level can be a little involved, this routine | ||
680 | // is used ot fetch the level only once for each vehicle simulation step. | ||
681 | private float GetWaterLevel(Vector3 pos) | ||
682 | { | ||
683 | if (m_knownWaterLevel == null) | ||
684 | m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos); | ||
685 | return (float)m_knownWaterLevel; | ||
686 | } | ||
687 | |||
688 | private Vector3 VehiclePosition | ||
689 | { | ||
690 | get | ||
691 | { | ||
692 | if (m_knownPosition == null) | ||
693 | m_knownPosition = Prim.ForcePosition; | ||
694 | return (Vector3)m_knownPosition; | ||
695 | } | ||
696 | set | ||
697 | { | ||
698 | m_knownPosition = value; | ||
699 | m_knownChanged |= m_knownChangedPosition; | ||
700 | } | ||
701 | } | ||
702 | |||
703 | private Quaternion VehicleOrientation | ||
704 | { | ||
705 | get | ||
706 | { | ||
707 | if (m_knownOrientation == null) | ||
708 | m_knownOrientation = Prim.ForceOrientation; | ||
709 | return (Quaternion)m_knownOrientation; | ||
710 | } | ||
711 | set | ||
712 | { | ||
713 | m_knownOrientation = value; | ||
714 | m_knownChanged |= m_knownChangedOrientation; | ||
715 | } | ||
716 | } | ||
717 | |||
718 | private Vector3 VehicleVelocity | ||
719 | { | ||
720 | get | ||
721 | { | ||
722 | if (m_knownVelocity == null) | ||
723 | m_knownVelocity = Prim.ForceVelocity; | ||
724 | return (Vector3)m_knownVelocity; | ||
725 | } | ||
726 | set | ||
727 | { | ||
728 | m_knownVelocity = value; | ||
729 | m_knownChanged |= m_knownChangedVelocity; | ||
730 | } | ||
731 | } | ||
732 | |||
733 | private void VehicleAddForce(Vector3 aForce) | ||
734 | { | ||
735 | m_knownForce += aForce; | ||
736 | m_knownChanged |= m_knownChangedForce; | ||
737 | } | ||
738 | |||
739 | private Vector3 VehicleRotationalVelocity | ||
740 | { | ||
741 | get | ||
742 | { | ||
743 | if (m_knownRotationalVelocity == null) | ||
744 | m_knownRotationalVelocity = Prim.ForceRotationalVelocity; | ||
745 | return (Vector3)m_knownRotationalVelocity; | ||
746 | } | ||
747 | set | ||
748 | { | ||
749 | m_knownRotationalVelocity = value; | ||
750 | m_knownChanged |= m_knownChangedRotationalVelocity; | ||
751 | } | ||
752 | } | ||
753 | private void VehicleAddAngularForce(Vector3 aForce) | ||
754 | { | ||
755 | m_knownRotationalForce += aForce; | ||
756 | m_knownChanged |= m_knownChangedRotationalForce; | ||
757 | } | ||
758 | private float VehicleForwardSpeed | ||
759 | { | ||
760 | get | ||
761 | { | ||
762 | if (m_knownForwardSpeed == null) | ||
763 | m_knownForwardSpeed = (VehicleVelocity * Quaternion.Inverse(VehicleOrientation)).X; | ||
764 | return (float)m_knownForwardSpeed; | ||
765 | } | ||
766 | } | ||
767 | |||
768 | #endregion // Known vehicle value functions | ||
769 | |||
549 | // One step of the vehicle properties for the next 'pTimestep' seconds. | 770 | // One step of the vehicle properties for the next 'pTimestep' seconds. |
550 | internal void Step(float pTimestep) | 771 | internal void Step(float pTimestep) |
551 | { | 772 | { |
552 | if (!IsActive) return; | 773 | if (!IsActive) return; |
553 | 774 | ||
554 | // DEBUG | 775 | ForgetKnownVehicleProperties(); |
555 | // Because Bullet does apply forces to the vehicle, our last computed | ||
556 | // linear and angular velocities are not what is happening now. | ||
557 | // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity; | ||
558 | // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep; | ||
559 | // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time | ||
560 | // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG: | ||
561 | // END DEBUG | ||
562 | |||
563 | m_vehicleMass = Prim.Linkset.LinksetMass; | ||
564 | 776 | ||
565 | MoveLinear(pTimestep); | 777 | MoveLinear(pTimestep); |
566 | // Commented out for debug | ||
567 | MoveAngular(pTimestep); | 778 | MoveAngular(pTimestep); |
568 | // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG | ||
569 | // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG | ||
570 | 779 | ||
571 | LimitRotation(pTimestep); | 780 | LimitRotation(pTimestep); |
572 | 781 | ||
573 | // remember the position so next step we can limit absolute movement effects | 782 | // remember the position so next step we can limit absolute movement effects |
574 | m_lastPositionVector = Prim.ForcePosition; | 783 | m_lastPositionVector = VehiclePosition; |
575 | 784 | ||
576 | VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG | 785 | // If we forced the changing of some vehicle parameters, update the values and |
577 | Prim.LocalID, | 786 | // for the physics engine to note the changes so an UpdateProperties event will happen. |
578 | BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), | 787 | PushKnownChanged(); |
579 | BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), | 788 | |
580 | Prim.Inertia, | ||
581 | m_vehicleMass | ||
582 | ); | ||
583 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", | 789 | VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", |
584 | Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); | 790 | Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity); |
585 | }// end Step | 791 | } |
586 | 792 | ||
587 | // Apply the effect of the linear motor. | 793 | // Apply the effect of the linear motor and other linear motions (like hover and float). |
588 | // Also does hover and float. | ||
589 | private void MoveLinear(float pTimestep) | 794 | private void MoveLinear(float pTimestep) |
590 | { | 795 | { |
591 | // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates | 796 | Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep); |
592 | // m_lastLinearVelocityVector is the current speed we are moving in that direction | ||
593 | if (m_linearMotorDirection.LengthSquared() > 0.001f) | ||
594 | { | ||
595 | Vector3 origDir = m_linearMotorDirection; // DEBUG | ||
596 | Vector3 origVel = m_lastLinearVelocityVector; // DEBUG | ||
597 | // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison | ||
598 | Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG | ||
599 | 797 | ||
600 | // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete | 798 | // The movement computed in the linear motor is relative to the vehicle |
601 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; | 799 | // coordinates. Rotate the movement to world coordinates. |
602 | m_lastLinearVelocityVector += addAmount; | 800 | linearMotorContribution *= VehicleOrientation; |
603 | 801 | ||
604 | float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; | 802 | // ================================================================== |
605 | m_linearMotorDirection *= (1f - decayFactor); | 803 | // Buoyancy: force to overcome gravity. |
804 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | ||
805 | // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity. | ||
806 | Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy; | ||
606 | 807 | ||
607 | // Rotate new object velocity from vehicle relative to world coordinates | 808 | Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep); |
608 | m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation; | ||
609 | 809 | ||
610 | // Apply friction for next time | 810 | Vector3 hoverContribution = ComputeLinearHover(pTimestep); |
611 | Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep; | ||
612 | m_lastLinearVelocityVector *= (Vector3.One - frictionFactor); | ||
613 | 811 | ||
614 | VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", | 812 | ComputeLinearBlockingEndPoint(pTimestep); |
615 | Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, | ||
616 | m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); | ||
617 | } | ||
618 | else | ||
619 | { | ||
620 | // if what remains of direction is very small, zero it. | ||
621 | m_linearMotorDirection = Vector3.Zero; | ||
622 | m_lastLinearVelocityVector = Vector3.Zero; | ||
623 | m_newVelocity = Vector3.Zero; | ||
624 | 813 | ||
625 | VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 814 | Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep); |
626 | } | ||
627 | 815 | ||
628 | // m_newVelocity is velocity computed from linear motor in world coordinates | 816 | // ================================================================== |
817 | Vector3 newVelocity = linearMotorContribution | ||
818 | + terrainHeightContribution | ||
819 | + hoverContribution | ||
820 | + limitMotorUpContribution; | ||
629 | 821 | ||
630 | // Gravity and Buoyancy | 822 | Vector3 newForce = buoyancyContribution; |
631 | // There is some gravity, make a gravity force vector that is applied after object velocity. | 823 | |
632 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 824 | // If not changing some axis, reduce out velocity |
633 | Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); | 825 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
826 | newVelocity.X = 0; | ||
827 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
828 | newVelocity.Y = 0; | ||
829 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
830 | newVelocity.Z = 0; | ||
634 | 831 | ||
635 | /* | 832 | // ================================================================== |
636 | * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... | 833 | // Clamp high or low velocities |
637 | // Preserve the current Z velocity | 834 | float newVelocityLengthSq = newVelocity.LengthSquared(); |
638 | Vector3 vel_now = m_prim.Velocity; | 835 | // if (newVelocityLengthSq > 1e6f) |
639 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 836 | if (newVelocityLengthSq > 1000f) |
640 | */ | 837 | { |
838 | newVelocity /= newVelocity.Length(); | ||
839 | newVelocity *= 1000f; | ||
840 | } | ||
841 | // else if (newVelocityLengthSq < 1e-6f) | ||
842 | else if (newVelocityLengthSq < 0.001f) | ||
843 | newVelocity = Vector3.Zero; | ||
844 | |||
845 | // ================================================================== | ||
846 | // Stuff new linear velocity into the vehicle. | ||
847 | // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us. | ||
848 | VehicleVelocity = newVelocity; | ||
849 | |||
850 | // Other linear forces are applied as forces. | ||
851 | Vector3 totalDownForce = newForce * m_vehicleMass; | ||
852 | if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f)) | ||
853 | { | ||
854 | VehicleAddForce(totalDownForce); | ||
855 | } | ||
856 | |||
857 | VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}", | ||
858 | Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding); | ||
859 | VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}", | ||
860 | Prim.LocalID, | ||
861 | linearMotorContribution, terrainHeightContribution, hoverContribution, | ||
862 | limitMotorUpContribution, buoyancyContribution | ||
863 | ); | ||
641 | 864 | ||
642 | Vector3 pos = Prim.ForcePosition; | 865 | } // end MoveLinear() |
643 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | ||
644 | 866 | ||
867 | public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep) | ||
868 | { | ||
869 | Vector3 ret = Vector3.Zero; | ||
645 | // If below the terrain, move us above the ground a little. | 870 | // If below the terrain, move us above the ground a little. |
646 | float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); | 871 | // TODO: Consider taking the rotated size of the object or possibly casting a ray. |
647 | // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. | 872 | if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition)) |
648 | // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass. | ||
649 | // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation; | ||
650 | // if (rotatedSize.Z < terrainHeight) | ||
651 | if (pos.Z < terrainHeight) | ||
652 | { | 873 | { |
653 | pos.Z = terrainHeight + 2; | 874 | // TODO: correct position by applying force rather than forcing position. |
654 | Prim.ForcePosition = pos; | 875 | Vector3 newPosition = VehiclePosition; |
655 | VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); | 876 | newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f; |
877 | VehiclePosition = newPosition; | ||
878 | VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}", | ||
879 | Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition); | ||
656 | } | 880 | } |
881 | return ret; | ||
882 | } | ||
883 | |||
884 | public Vector3 ComputeLinearHover(float pTimestep) | ||
885 | { | ||
886 | Vector3 ret = Vector3.Zero; | ||
657 | 887 | ||
658 | // Check if hovering | ||
659 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped | 888 | // m_VhoverEfficiency: 0=bouncy, 1=totally damped |
660 | // m_VhoverTimescale: time to achieve height | 889 | // m_VhoverTimescale: time to achieve height |
661 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) | 890 | if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) |
@@ -663,11 +892,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
663 | // We should hover, get the target height | 892 | // We should hover, get the target height |
664 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 893 | if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
665 | { | 894 | { |
666 | m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; | 895 | m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight; |
667 | } | 896 | } |
668 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 897 | if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
669 | { | 898 | { |
670 | m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; | 899 | m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight; |
671 | } | 900 | } |
672 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 901 | if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
673 | { | 902 | { |
@@ -677,45 +906,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
677 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) | 906 | if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) |
678 | { | 907 | { |
679 | // If body is already heigher, use its height as target height | 908 | // If body is already heigher, use its height as target height |
680 | if (pos.Z > m_VhoverTargetHeight) | 909 | if (VehiclePosition.Z > m_VhoverTargetHeight) |
681 | m_VhoverTargetHeight = pos.Z; | 910 | m_VhoverTargetHeight = VehiclePosition.Z; |
682 | } | 911 | } |
912 | |||
683 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) | 913 | if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) |
684 | { | 914 | { |
685 | if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) | 915 | if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f) |
686 | { | 916 | { |
917 | Vector3 pos = VehiclePosition; | ||
687 | pos.Z = m_VhoverTargetHeight; | 918 | pos.Z = m_VhoverTargetHeight; |
688 | Prim.ForcePosition = pos; | 919 | VehiclePosition = pos; |
689 | } | 920 | } |
690 | } | 921 | } |
691 | else | 922 | else |
692 | { | 923 | { |
693 | float verticalError = pos.Z - m_VhoverTargetHeight; | 924 | // Error is positive if below the target and negative if above. |
694 | // RA: where does the 50 come from? | 925 | float verticalError = m_VhoverTargetHeight - VehiclePosition.Z; |
695 | float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); | 926 | float verticalCorrectionVelocity = verticalError / m_VhoverTimescale; |
696 | // Replace Vertical speed with correction figure if significant | 927 | |
697 | if (Math.Abs(verticalError) > 0.01f) | 928 | // TODO: implement m_VhoverEfficiency correctly |
698 | { | 929 | if (Math.Abs(verticalError) > m_VhoverEfficiency) |
699 | m_newVelocity.Z += verticalCorrectionVelocity; | ||
700 | //KF: m_VhoverEfficiency is not yet implemented | ||
701 | } | ||
702 | else if (verticalError < -0.01) | ||
703 | { | ||
704 | m_newVelocity.Z -= verticalCorrectionVelocity; | ||
705 | } | ||
706 | else | ||
707 | { | 930 | { |
708 | m_newVelocity.Z = 0f; | 931 | ret = new Vector3(0f, 0f, verticalCorrectionVelocity); |
709 | } | 932 | } |
710 | } | 933 | } |
711 | 934 | ||
712 | VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); | 935 | VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}", |
936 | Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight); | ||
713 | } | 937 | } |
714 | 938 | ||
939 | return ret; | ||
940 | } | ||
941 | |||
942 | public bool ComputeLinearBlockingEndPoint(float pTimestep) | ||
943 | { | ||
944 | bool changed = false; | ||
945 | |||
946 | Vector3 pos = VehiclePosition; | ||
715 | Vector3 posChange = pos - m_lastPositionVector; | 947 | Vector3 posChange = pos - m_lastPositionVector; |
716 | if (m_BlockingEndPoint != Vector3.Zero) | 948 | if (m_BlockingEndPoint != Vector3.Zero) |
717 | { | 949 | { |
718 | bool changed = false; | ||
719 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 950 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
720 | { | 951 | { |
721 | pos.X -= posChange.X + 1; | 952 | pos.X -= posChange.X + 1; |
@@ -743,233 +974,110 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
743 | } | 974 | } |
744 | if (changed) | 975 | if (changed) |
745 | { | 976 | { |
746 | Prim.ForcePosition = pos; | 977 | VehiclePosition = pos; |
747 | VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | 978 | VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", |
748 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); | 979 | Prim.LocalID, m_BlockingEndPoint, posChange, pos); |
749 | } | 980 | } |
750 | } | 981 | } |
982 | return changed; | ||
983 | } | ||
751 | 984 | ||
752 | #region downForce | 985 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
753 | Vector3 downForce = Vector3.Zero; | 986 | // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when |
987 | // used with conjunction with banking: the strength of the banking will decay when the | ||
988 | // vehicle no longer experiences collisions. The decay timescale is the same as | ||
989 | // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering | ||
990 | // when they are in mid jump. | ||
991 | // TODO: this code is wrong. Also, what should it do for boats (height from water)? | ||
992 | // This is just using the ground and a general collision check. Should really be using | ||
993 | // a downward raycast to find what is below. | ||
994 | public Vector3 ComputeLinearMotorUp(float pTimestep) | ||
995 | { | ||
996 | Vector3 ret = Vector3.Zero; | ||
997 | float distanceAboveGround = 0f; | ||
754 | 998 | ||
755 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) | 999 | if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) |
756 | { | 1000 | { |
757 | // If the vehicle is motoring into the sky, get it going back down. | 1001 | float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition); |
758 | // Is this an angular force or both linear and angular?? | 1002 | distanceAboveGround = VehiclePosition.Z - targetHeight; |
759 | float distanceAboveGround = pos.Z - terrainHeight; | 1003 | // Not colliding if the vehicle is off the ground |
760 | if (distanceAboveGround > 2f) | 1004 | if (!Prim.IsColliding) |
761 | { | 1005 | { |
762 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); | 1006 | // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep); |
763 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); | 1007 | // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); |
764 | downForce = new Vector3(0, 0, -distanceAboveGround); | 1008 | ret = new Vector3(0, 0, -distanceAboveGround); |
765 | } | 1009 | } |
766 | // TODO: this calculation is all wrong. From the description at | 1010 | // TODO: this calculation is wrong. From the description at |
767 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce | 1011 | // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce |
768 | // has a decay factor. This says this force should | 1012 | // has a decay factor. This says this force should |
769 | // be computed with a motor. | 1013 | // be computed with a motor. |
770 | VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", | 1014 | // TODO: add interaction with banking. |
771 | Prim.LocalID, distanceAboveGround, downForce); | ||
772 | } | ||
773 | #endregion // downForce | ||
774 | |||
775 | // If not changing some axis, reduce out velocity | ||
776 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | ||
777 | m_newVelocity.X = 0; | ||
778 | if ((m_flags & (VehicleFlag.NO_Y)) != 0) | ||
779 | m_newVelocity.Y = 0; | ||
780 | if ((m_flags & (VehicleFlag.NO_Z)) != 0) | ||
781 | m_newVelocity.Z = 0; | ||
782 | |||
783 | // Clamp REALLY high or low velocities | ||
784 | if (m_newVelocity.LengthSquared() > 1e6f) | ||
785 | { | ||
786 | m_newVelocity /= m_newVelocity.Length(); | ||
787 | m_newVelocity *= 1000f; | ||
788 | } | 1015 | } |
789 | else if (m_newVelocity.LengthSquared() < 1e-6f) | 1016 | VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}", |
790 | m_newVelocity = Vector3.Zero; | 1017 | Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret); |
791 | 1018 | return ret; | |
792 | // Stuff new linear velocity into the vehicle | 1019 | } |
793 | Prim.ForceVelocity = m_newVelocity; | ||
794 | // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG | ||
795 | |||
796 | Vector3 totalDownForce = downForce + grav; | ||
797 | if (totalDownForce != Vector3.Zero) | ||
798 | { | ||
799 | Prim.AddForce(totalDownForce * m_vehicleMass, false); | ||
800 | // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false); | ||
801 | } | ||
802 | |||
803 | VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", | ||
804 | Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); | ||
805 | |||
806 | } // end MoveLinear() | ||
807 | 1020 | ||
808 | // ======================================================================= | 1021 | // ======================================================================= |
1022 | // ======================================================================= | ||
809 | // Apply the effect of the angular motor. | 1023 | // Apply the effect of the angular motor. |
1024 | // The 'contribution' is how much angular correction velocity each function wants. | ||
1025 | // All the contributions are added together and the resulting velocity is | ||
1026 | // set directly on the vehicle. | ||
810 | private void MoveAngular(float pTimestep) | 1027 | private void MoveAngular(float pTimestep) |
811 | { | 1028 | { |
812 | // m_angularMotorDirection // angular velocity requested by LSL motor | 1029 | // The user wants how many radians per second angular change? |
813 | // m_angularMotorApply // application frame counter | 1030 | Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep); |
814 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) | 1031 | |
815 | // m_angularMotorTimescale // motor angular velocity ramp up rate | 1032 | // ================================================================== |
816 | // m_angularMotorDecayTimescale // motor angular velocity decay rate | 1033 | // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags : |
817 | // m_angularFrictionTimescale // body angular velocity decay rate | 1034 | // This flag prevents linear deflection parallel to world z-axis. This is useful |
818 | // m_lastAngularVelocity // what was last applied to body | 1035 | // for preventing ground vehicles with large linear deflection, like bumper cars, |
819 | 1036 | // from climbing their linear deflection into the sky. | |
820 | if (m_angularMotorDirection.LengthSquared() > 0.0001) | 1037 | // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement |
821 | { | 1038 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) |
822 | Vector3 origVel = m_angularMotorVelocity; | ||
823 | Vector3 origDir = m_angularMotorDirection; | ||
824 | |||
825 | // new velocity += error / ( time to get there / step interval) | ||
826 | // requested direction - current vehicle direction | ||
827 | m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep); | ||
828 | // decay requested direction | ||
829 | m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale)); | ||
830 | |||
831 | VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}", | ||
832 | Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity); | ||
833 | } | ||
834 | else | ||
835 | { | 1039 | { |
836 | m_angularMotorVelocity = Vector3.Zero; | 1040 | angularMotorContribution.X = 0f; |
1041 | angularMotorContribution.Y = 0f; | ||
1042 | VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution); | ||
837 | } | 1043 | } |
838 | 1044 | ||
839 | #region Vertical attactor | 1045 | Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction(); |
840 | |||
841 | Vector3 vertattr = Vector3.Zero; | ||
842 | Vector3 deflection = Vector3.Zero; | ||
843 | Vector3 banking = Vector3.Zero; | ||
844 | |||
845 | // If vertical attaction timescale is reasonable and we applied an angular force last time... | ||
846 | if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero) | ||
847 | { | ||
848 | float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale; | ||
849 | if (Prim.IsColliding) | ||
850 | VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale); | ||
851 | |||
852 | VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
853 | |||
854 | // Create a vector of the vehicle "up" in world coordinates | ||
855 | Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation; | ||
856 | // verticalError.X and .Y are the World error amounts. They are 0 when there is no | ||
857 | // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its | ||
858 | // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall | ||
859 | // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be | ||
860 | // modulated to prevent a stable inverted body. | ||
861 | |||
862 | // Error is 0 (no error) to +/- 2 (max error) | ||
863 | if (verticalError.Z < 0.0f) | ||
864 | { | ||
865 | verticalError.X = 2.0f - verticalError.X; | ||
866 | verticalError.Y = 2.0f - verticalError.Y; | ||
867 | } | ||
868 | // scale it by VAservo (timestep and timescale) | ||
869 | verticalError = verticalError * VAservo; | ||
870 | |||
871 | // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y | ||
872 | // then .X increases, so change Body angular velocity X based on Y, and Y based on X. | ||
873 | // Z is not changed. | ||
874 | vertattr.X = verticalError.Y; | ||
875 | vertattr.Y = - verticalError.X; | ||
876 | vertattr.Z = 0f; | ||
877 | 1046 | ||
878 | // scaling appears better usingsquare-law | 1047 | Vector3 deflectionContribution = ComputeAngularDeflection(); |
879 | Vector3 angularVelocity = Prim.ForceRotationalVelocity; | ||
880 | float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); | ||
881 | vertattr.X += bounce * angularVelocity.X; | ||
882 | vertattr.Y += bounce * angularVelocity.Y; | ||
883 | 1048 | ||
884 | VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", | 1049 | Vector3 bankingContribution = ComputeAngularBanking(); |
885 | Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr); | ||
886 | 1050 | ||
887 | } | 1051 | // ================================================================== |
888 | #endregion // Vertical attactor | 1052 | m_lastVertAttractor = verticalAttractionContribution; |
889 | 1053 | ||
890 | #region Deflection | 1054 | m_lastAngularVelocity = angularMotorContribution |
1055 | + verticalAttractionContribution | ||
1056 | + deflectionContribution | ||
1057 | + bankingContribution; | ||
891 | 1058 | ||
892 | if (m_angularDeflectionEfficiency != 0) | 1059 | // ================================================================== |
1060 | // Apply the correction velocity. | ||
1061 | // TODO: Should this be applied as an angular force (torque)? | ||
1062 | if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | ||
893 | { | 1063 | { |
894 | // Compute a scaled vector that points in the preferred axis (X direction) | 1064 | VehicleRotationalVelocity = m_lastAngularVelocity; |
895 | Vector3 scaledDefaultDirection = | ||
896 | new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0); | ||
897 | // Adding the current vehicle orientation and reference frame displaces the orientation to the frame. | ||
898 | // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point. | ||
899 | Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame); | ||
900 | |||
901 | // Scale by efficiency and timescale | ||
902 | deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep; | ||
903 | |||
904 | VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}", | ||
905 | Prim.LocalID, preferredAxisOfMotion, deflection); | ||
906 | // This deflection computation is not correct. | ||
907 | deflection = Vector3.Zero; | ||
908 | } | ||
909 | |||
910 | #endregion | ||
911 | |||
912 | #region Banking | ||
913 | 1065 | ||
914 | if (m_bankingEfficiency != 0) | 1066 | VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}", |
1067 | Prim.LocalID, | ||
1068 | angularMotorContribution, verticalAttractionContribution, | ||
1069 | bankingContribution, deflectionContribution, | ||
1070 | m_lastAngularVelocity | ||
1071 | ); | ||
1072 | } | ||
1073 | else | ||
915 | { | 1074 | { |
916 | Vector3 dir = Vector3.One * Prim.ForceOrientation; | 1075 | // The vehicle is not adding anything angular wise. |
917 | float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); | 1076 | VehicleRotationalVelocity = Vector3.Zero; |
918 | //Changes which way it banks in and out of turns | 1077 | VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID); |
919 | |||
920 | //Use the square of the efficiency, as it looks much more how SL banking works | ||
921 | float effSquared = (m_bankingEfficiency*m_bankingEfficiency); | ||
922 | if (m_bankingEfficiency < 0) | ||
923 | effSquared *= -1; //Keep the negative! | ||
924 | |||
925 | float mix = Math.Abs(m_bankingMix); | ||
926 | if (m_angularMotorVelocity.X == 0) | ||
927 | { | ||
928 | /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f)) | ||
929 | { | ||
930 | Vector3 axisAngle; | ||
931 | float angle; | ||
932 | parent.Orientation.GetAxisAngle(out axisAngle, out angle); | ||
933 | Vector3 rotatedVel = parent.Velocity * parent.Orientation; | ||
934 | if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0)) | ||
935 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10; | ||
936 | else | ||
937 | m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10; | ||
938 | }*/ | ||
939 | } | ||
940 | else | ||
941 | banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4; | ||
942 | if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix) | ||
943 | //If they are colliding, we probably shouldn't shove the prim around... probably | ||
944 | { | ||
945 | float angVelZ = m_angularMotorVelocity.X*-1; | ||
946 | /*if(angVelZ > mix) | ||
947 | angVelZ = mix; | ||
948 | else if(angVelZ < -mix) | ||
949 | angVelZ = -mix;*/ | ||
950 | //This controls how fast and how far the banking occurs | ||
951 | Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0); | ||
952 | if (bankingRot.X > 3) | ||
953 | bankingRot.X = 3; | ||
954 | else if (bankingRot.X < -3) | ||
955 | bankingRot.X = -3; | ||
956 | bankingRot *= Prim.ForceOrientation; | ||
957 | banking += bankingRot; | ||
958 | } | ||
959 | m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency; | ||
960 | VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}", | ||
961 | Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking); | ||
962 | } | 1078 | } |
963 | 1079 | ||
964 | #endregion | 1080 | // ================================================================== |
965 | |||
966 | m_lastVertAttractor = vertattr; | ||
967 | |||
968 | // Sum velocities | ||
969 | m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection; | ||
970 | |||
971 | #region Linear Motor Offset | ||
972 | |||
973 | //Offset section | 1081 | //Offset section |
974 | if (m_linearMotorOffset != Vector3.Zero) | 1082 | if (m_linearMotorOffset != Vector3.Zero) |
975 | { | 1083 | { |
@@ -985,8 +1093,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
985 | // | 1093 | // |
986 | // The torque created is the linear velocity crossed with the offset | 1094 | // The torque created is the linear velocity crossed with the offset |
987 | 1095 | ||
988 | // NOTE: this computation does should be in the linear section | 1096 | // TODO: this computation should be in the linear section |
989 | // because there we know the impulse being applied. | 1097 | // because that is where we know the impulse being applied. |
990 | Vector3 torqueFromOffset = Vector3.Zero; | 1098 | Vector3 torqueFromOffset = Vector3.Zero; |
991 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); | 1099 | // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); |
992 | if (float.IsNaN(torqueFromOffset.X)) | 1100 | if (float.IsNaN(torqueFromOffset.X)) |
@@ -995,47 +1103,175 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
995 | torqueFromOffset.Y = 0; | 1103 | torqueFromOffset.Y = 0; |
996 | if (float.IsNaN(torqueFromOffset.Z)) | 1104 | if (float.IsNaN(torqueFromOffset.Z)) |
997 | torqueFromOffset.Z = 0; | 1105 | torqueFromOffset.Z = 0; |
998 | torqueFromOffset *= m_vehicleMass; | 1106 | |
999 | Prim.ApplyTorqueImpulse(torqueFromOffset, true); | 1107 | VehicleAddAngularForce(torqueFromOffset * m_vehicleMass); |
1000 | VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); | 1108 | VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); |
1001 | } | 1109 | } |
1002 | 1110 | ||
1003 | #endregion | 1111 | } |
1112 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1113 | // Some vehicles, like boats, should always keep their up-side up. This can be done by | ||
1114 | // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to | ||
1115 | // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the | ||
1116 | // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency, | ||
1117 | // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An | ||
1118 | // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an | ||
1119 | // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay. | ||
1120 | public Vector3 ComputeAngularVerticalAttraction() | ||
1121 | { | ||
1122 | Vector3 ret = Vector3.Zero; | ||
1004 | 1123 | ||
1005 | if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) | 1124 | // If vertical attaction timescale is reasonable |
1125 | if (m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1006 | { | 1126 | { |
1007 | m_lastAngularVelocity.X = 0; | 1127 | // Take a vector pointing up and convert it from world to vehicle relative coords. |
1008 | m_lastAngularVelocity.Y = 0; | 1128 | Vector3 verticalError = Vector3.UnitZ * VehicleOrientation; |
1009 | VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1129 | |
1130 | // If vertical attraction correction is needed, the vector that was pointing up (UnitZ) | ||
1131 | // is now: | ||
1132 | // leaning to one side: rotated around the X axis with the Y value going | ||
1133 | // from zero (nearly straight up) to one (completely to the side)) or | ||
1134 | // leaning front-to-back: rotated around the Y axis with the value of X being between | ||
1135 | // zero and one. | ||
1136 | // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees. | ||
1137 | |||
1138 | // If verticalError.Z is negative, the vehicle is upside down. Add additional push. | ||
1139 | if (verticalError.Z < 0f) | ||
1140 | { | ||
1141 | verticalError.X = 2f - verticalError.X; | ||
1142 | verticalError.Y = 2f - verticalError.Y; | ||
1143 | } | ||
1144 | |||
1145 | // Y error means needed rotation around X axis and visa versa. | ||
1146 | ret.X = verticalError.Y; | ||
1147 | ret.Y = - verticalError.X; | ||
1148 | ret.Z = 0f; | ||
1149 | |||
1150 | // Scale the correction force by how far we're off from vertical. | ||
1151 | // Z error of one says little error. As Z gets smaller, the vehicle is leaning farther over. | ||
1152 | float clampedSqrZError = ClampInRange(0.01f, verticalError.Z * verticalError.Z, 1f); | ||
1153 | float vertForce = 1f / clampedSqrZError; | ||
1154 | |||
1155 | ret *= vertForce; | ||
1156 | |||
1157 | // Correction happens over a number of seconds. | ||
1158 | Vector3 unscaledContrib = ret; | ||
1159 | ret /= m_verticalAttractionTimescale; | ||
1160 | |||
1161 | VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},vertForce={3},eff={4},vertAttr={5}", | ||
1162 | Prim.LocalID, verticalError, unscaledContrib, vertForce, m_verticalAttractionEfficiency, ret); | ||
1010 | } | 1163 | } |
1164 | return ret; | ||
1165 | } | ||
1166 | |||
1167 | // Return the angular correction to correct the direction the vehicle is pointing to be | ||
1168 | // the direction is should want to be pointing. | ||
1169 | // The vehicle is moving in some direction and correct its orientation to it is pointing | ||
1170 | // in that direction. | ||
1171 | // TODO: implement reference frame. | ||
1172 | public Vector3 ComputeAngularDeflection() | ||
1173 | { | ||
1174 | Vector3 ret = Vector3.Zero; | ||
1175 | return ret; // DEBUG DEBUG DEBUG debug one force at a time | ||
1011 | 1176 | ||
1012 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 1177 | if (m_angularDeflectionEfficiency != 0) |
1013 | { | 1178 | { |
1014 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 1179 | // The direction the vehicle is moving |
1015 | Prim.ZeroAngularMotion(true); | 1180 | Vector3 movingDirection = VehicleVelocity; |
1016 | VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); | 1181 | movingDirection.Normalize(); |
1182 | |||
1183 | // The direction the vehicle is pointing | ||
1184 | Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation; | ||
1185 | pointingDirection.Normalize(); | ||
1186 | |||
1187 | // The difference between what is and what should be | ||
1188 | Vector3 deflectionError = movingDirection - pointingDirection; | ||
1189 | |||
1190 | // Scale the correction by recovery timescale and efficiency | ||
1191 | ret = (-deflectionError * VehicleForwardSpeed) * m_angularDeflectionEfficiency; | ||
1192 | ret /= m_angularDeflectionTimescale; | ||
1193 | |||
1194 | VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}", | ||
1195 | Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret); | ||
1017 | } | 1196 | } |
1018 | else | 1197 | return ret; |
1198 | } | ||
1199 | |||
1200 | // Return an angular change to rotate the vehicle around the Z axis when the vehicle | ||
1201 | // is tipped around the X axis. | ||
1202 | // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial: | ||
1203 | // The vertical attractor feature must be enabled in order for the banking behavior to | ||
1204 | // function. The way banking works is this: a rotation around the vehicle's roll-axis will | ||
1205 | // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude | ||
1206 | // of the yaw effect will be proportional to the | ||
1207 | // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's | ||
1208 | // velocity along its preferred axis of motion. | ||
1209 | // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any | ||
1210 | // positive rotation (by the right-hand rule) about the roll-axis will effect a | ||
1211 | // (negative) torque around the yaw-axis, making it turn to the right--that is the | ||
1212 | // vehicle will lean into the turn, which is how real airplanes and motorcycle's work. | ||
1213 | // Negating the banking coefficient will make it so that the vehicle leans to the | ||
1214 | // outside of the turn (not very "physical" but might allow interesting vehicles so why not?). | ||
1215 | // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making | ||
1216 | // banking vehicles do what you want rather than what the laws of physics allow. | ||
1217 | // For example, consider a real motorcycle...it must be moving forward in order for | ||
1218 | // it to turn while banking, however video-game motorcycles are often configured | ||
1219 | // to turn in place when at a dead stop--because they are often easier to control | ||
1220 | // that way using the limited interface of the keyboard or game controller. The | ||
1221 | // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic | ||
1222 | // banking by functioning as a slider between a banking that is correspondingly | ||
1223 | // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the | ||
1224 | // banking effect depends only on the vehicle's rotation about its roll-axis compared | ||
1225 | // to "dynamic" where the banking is also proportional to its velocity along its | ||
1226 | // roll-axis. Finding the best value of the "mixture" will probably require trial and error. | ||
1227 | // The time it takes for the banking behavior to defeat a preexisting angular velocity about the | ||
1228 | // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to | ||
1229 | // bank quickly then give it a banking timescale of about a second or less, otherwise you can | ||
1230 | // make a sluggish vehicle by giving it a timescale of several seconds. | ||
1231 | public Vector3 ComputeAngularBanking() | ||
1232 | { | ||
1233 | Vector3 ret = Vector3.Zero; | ||
1234 | |||
1235 | if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff) | ||
1019 | { | 1236 | { |
1020 | // Apply to the body. | 1237 | // This works by rotating a unit vector to the orientation of the vehicle. The |
1021 | // The above calculates the absolute angular velocity needed. Angular velocity is massless. | 1238 | // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt |
1022 | // Since we are stuffing the angular velocity directly into the object, the computed | 1239 | // up to one for full over). |
1023 | // velocity needs to be scaled by the timestep. | 1240 | Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation; |
1024 | Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); | 1241 | |
1025 | Prim.ForceRotationalVelocity = applyAngularForce; | 1242 | // Figure out the yaw value for this much roll. |
1026 | 1243 | float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency; | |
1027 | // Decay the angular movement for next time | 1244 | // Keep the sign |
1028 | Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; | 1245 | if (rollComponents.Y < 0f) |
1029 | m_lastAngularVelocity *= Vector3.One - decayamount; | 1246 | turnComponent = -turnComponent; |
1030 | 1247 | ||
1031 | VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", | 1248 | // TODO: there must be a better computation of the banking force. |
1032 | Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); | 1249 | float bankingTurnForce = turnComponent; |
1250 | |||
1251 | // actual error = static turn error + dynamic turn error | ||
1252 | float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed; | ||
1253 | // TODO: the banking effect should not go to infinity but what to limit it to? | ||
1254 | mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f); | ||
1255 | |||
1256 | // Build the force vector to change rotation from what it is to what it should be | ||
1257 | ret.Z = -mixedBankingError; | ||
1258 | |||
1259 | // Don't do it all at once. | ||
1260 | ret /= m_bankingTimescale; | ||
1261 | |||
1262 | VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}", | ||
1263 | Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret); | ||
1033 | } | 1264 | } |
1034 | } //end MoveAngular | 1265 | return ret; |
1266 | } | ||
1035 | 1267 | ||
1268 | // This is from previous instantiations of XXXDynamics.cs. | ||
1269 | // Applies roll reference frame. | ||
1270 | // TODO: is this the right way to separate the code to do this operation? | ||
1271 | // Should this be in MoveAngular()? | ||
1036 | internal void LimitRotation(float timestep) | 1272 | internal void LimitRotation(float timestep) |
1037 | { | 1273 | { |
1038 | Quaternion rotq = Prim.ForceOrientation; | 1274 | Quaternion rotq = VehicleOrientation; |
1039 | Quaternion m_rot = rotq; | 1275 | Quaternion m_rot = rotq; |
1040 | if (m_RollreferenceFrame != Quaternion.Identity) | 1276 | if (m_RollreferenceFrame != Quaternion.Identity) |
1041 | { | 1277 | { |
@@ -1063,12 +1299,17 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
1063 | } | 1299 | } |
1064 | if (rotq != m_rot) | 1300 | if (rotq != m_rot) |
1065 | { | 1301 | { |
1066 | Prim.ForceOrientation = m_rot; | 1302 | VehicleOrientation = m_rot; |
1067 | VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); | 1303 | VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); |
1068 | } | 1304 | } |
1069 | 1305 | ||
1070 | } | 1306 | } |
1071 | 1307 | ||
1308 | private float ClampInRange(float low, float val, float high) | ||
1309 | { | ||
1310 | return Math.Max(low, Math.Min(val, high)); | ||
1311 | } | ||
1312 | |||
1072 | // Invoke the detailed logger and output something if it's enabled. | 1313 | // Invoke the detailed logger and output something if it's enabled. |
1073 | private void VDetailLog(string msg, params Object[] args) | 1314 | private void VDetailLog(string msg, params Object[] args) |
1074 | { | 1315 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs index 0df4310..2017fa5 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs | |||
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse; | |||
32 | 32 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 34 | { |
35 | |||
36 | // A BSPrim can get individual information about its linkedness attached | ||
37 | // to it through an instance of a subclass of LinksetInfo. | ||
38 | // Each type of linkset will define the information needed for its type. | ||
39 | public abstract class BSLinksetInfo | ||
40 | { | ||
41 | public virtual void Clear() { } | ||
42 | } | ||
43 | |||
35 | public abstract class BSLinkset | 44 | public abstract class BSLinkset |
36 | { | 45 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET]"; | 46 | // private static string LogHeader = "[BULLETSIM LINKSET]"; |
@@ -87,13 +96,6 @@ public abstract class BSLinkset | |||
87 | return BSPhysicsShapeType.SHAPE_UNKNOWN; | 96 | return BSPhysicsShapeType.SHAPE_UNKNOWN; |
88 | } | 97 | } |
89 | 98 | ||
90 | // Linksets move around the children so the linkset might need to compute the child position | ||
91 | public virtual OMV.Vector3 Position(BSPhysObject member) | ||
92 | { return member.RawPosition; } | ||
93 | public virtual OMV.Quaternion Orientation(BSPhysObject member) | ||
94 | { return member.RawOrientation; } | ||
95 | // TODO: does this need to be done for Velocity and RotationalVelocityy? | ||
96 | |||
97 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims | 99 | // We keep the prim's mass in the linkset structure since it could be dependent on other prims |
98 | protected float m_mass; | 100 | protected float m_mass; |
99 | public float LinksetMass | 101 | public float LinksetMass |
@@ -116,7 +118,7 @@ public abstract class BSLinkset | |||
116 | get { return ComputeLinksetGeometricCenter(); } | 118 | get { return ComputeLinksetGeometricCenter(); } |
117 | } | 119 | } |
118 | 120 | ||
119 | protected void Initialize(BSScene scene, BSPhysObject parent) | 121 | protected BSLinkset(BSScene scene, BSPhysObject parent) |
120 | { | 122 | { |
121 | // A simple linkset of one (no children) | 123 | // A simple linkset of one (no children) |
122 | LinksetID = m_nextLinksetID++; | 124 | LinksetID = m_nextLinksetID++; |
@@ -127,6 +129,7 @@ public abstract class BSLinkset | |||
127 | LinksetRoot = parent; | 129 | LinksetRoot = parent; |
128 | m_children = new HashSet<BSPhysObject>(); | 130 | m_children = new HashSet<BSPhysObject>(); |
129 | m_mass = parent.RawMass; | 131 | m_mass = parent.RawMass; |
132 | Rebuilding = false; | ||
130 | } | 133 | } |
131 | 134 | ||
132 | // Link to a linkset where the child knows the parent. | 135 | // Link to a linkset where the child knows the parent. |
@@ -219,7 +222,7 @@ public abstract class BSLinkset | |||
219 | // I am the root of a linkset and a new child is being added | 222 | // I am the root of a linkset and a new child is being added |
220 | // Called while LinkActivity is locked. | 223 | // Called while LinkActivity is locked. |
221 | protected abstract void AddChildToLinkset(BSPhysObject child); | 224 | protected abstract void AddChildToLinkset(BSPhysObject child); |
222 | 225 | ||
223 | // I am the root of a linkset and one of my children is being removed. | 226 | // I am the root of a linkset and one of my children is being removed. |
224 | // Safe to call even if the child is not really in my linkset. | 227 | // Safe to call even if the child is not really in my linkset. |
225 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); | 228 | protected abstract void RemoveChildFromLinkset(BSPhysObject child); |
@@ -229,6 +232,10 @@ public abstract class BSLinkset | |||
229 | // May be called at runtime or taint-time. | 232 | // May be called at runtime or taint-time. |
230 | public abstract void Refresh(BSPhysObject requestor); | 233 | public abstract void Refresh(BSPhysObject requestor); |
231 | 234 | ||
235 | // Flag denoting the linkset is in the process of being rebuilt. | ||
236 | // Used to know not the schedule a rebuild in the middle of a rebuild. | ||
237 | protected bool Rebuilding { get; set; } | ||
238 | |||
232 | // The object is going dynamic (physical). Do any setup necessary | 239 | // The object is going dynamic (physical). Do any setup necessary |
233 | // for a dynamic linkset. | 240 | // for a dynamic linkset. |
234 | // Only the state of the passed object can be modified. The rest of the linkset | 241 | // Only the state of the passed object can be modified. The rest of the linkset |
@@ -245,8 +252,9 @@ public abstract class BSLinkset | |||
245 | 252 | ||
246 | // Called when a parameter update comes from the physics engine for any object | 253 | // Called when a parameter update comes from the physics engine for any object |
247 | // of the linkset is received. | 254 | // of the linkset is received. |
255 | // Passed flag is update came from physics engine (true) or the user (false). | ||
248 | // Called at taint-time!! | 256 | // Called at taint-time!! |
249 | public abstract void UpdateProperties(BSPhysObject physObject); | 257 | public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate); |
250 | 258 | ||
251 | // Routine used when rebuilding the body of the root of the linkset | 259 | // Routine used when rebuilding the body of the root of the linkset |
252 | // Destroy all the constraints have have been made to root. | 260 | // Destroy all the constraints have have been made to root. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs index b9c2cf9..2a7b72c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs | |||
@@ -28,22 +28,54 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | 30 | ||
31 | using OpenSim.Framework; | ||
32 | |||
31 | using OMV = OpenMetaverse; | 33 | using OMV = OpenMetaverse; |
32 | 34 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | { | 36 | { |
37 | |||
38 | // When a child is linked, the relationship position of the child to the parent | ||
39 | // is remembered so the child's world position can be recomputed when it is | ||
40 | // removed from the linkset. | ||
41 | sealed class BSLinksetCompoundInfo : BSLinksetInfo | ||
42 | { | ||
43 | public OMV.Vector3 OffsetPos; | ||
44 | public OMV.Quaternion OffsetRot; | ||
45 | public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r) | ||
46 | { | ||
47 | OffsetPos = p; | ||
48 | OffsetRot = r; | ||
49 | } | ||
50 | public override void Clear() | ||
51 | { | ||
52 | OffsetPos = OMV.Vector3.Zero; | ||
53 | OffsetRot = OMV.Quaternion.Identity; | ||
54 | } | ||
55 | public override string ToString() | ||
56 | { | ||
57 | StringBuilder buff = new StringBuilder(); | ||
58 | buff.Append("<p="); | ||
59 | buff.Append(OffsetPos.ToString()); | ||
60 | buff.Append(",r="); | ||
61 | buff.Append(OffsetRot.ToString()); | ||
62 | buff.Append(">"); | ||
63 | return buff.ToString(); | ||
64 | } | ||
65 | }; | ||
66 | |||
35 | public sealed class BSLinksetCompound : BSLinkset | 67 | public sealed class BSLinksetCompound : BSLinkset |
36 | { | 68 | { |
37 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; | 69 | private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; |
38 | 70 | ||
39 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) | 71 | public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 72 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 73 | } |
43 | 74 | ||
44 | // For compound implimented linksets, if there are children, use compound shape for the root. | 75 | // For compound implimented linksets, if there are children, use compound shape for the root. |
45 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) | 76 | public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) |
46 | { | 77 | { |
78 | // Returning 'unknown' means we don't have a preference. | ||
47 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; | 79 | BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; |
48 | if (IsRoot(requestor) && HasAnyChildren) | 80 | if (IsRoot(requestor) && HasAnyChildren) |
49 | { | 81 | { |
@@ -55,23 +87,27 @@ public sealed class BSLinksetCompound : BSLinkset | |||
55 | 87 | ||
56 | // When physical properties are changed the linkset needs to recalculate | 88 | // When physical properties are changed the linkset needs to recalculate |
57 | // its internal properties. | 89 | // its internal properties. |
58 | // This is queued in the 'post taint' queue so the | ||
59 | // refresh will happen once after all the other taints are applied. | ||
60 | public override void Refresh(BSPhysObject requestor) | 90 | public override void Refresh(BSPhysObject requestor) |
61 | { | 91 | { |
62 | // External request for Refresh (from BSPrim) is not necessary | 92 | // Something changed so do the rebuilding thing |
63 | // InternalRefresh(requestor); | 93 | // ScheduleRebuild(); |
64 | } | 94 | } |
65 | 95 | ||
66 | private void InternalRefresh(BSPhysObject requestor) | 96 | // Schedule a refresh to happen after all the other taint processing. |
97 | private void ScheduleRebuild(BSPhysObject requestor) | ||
67 | { | 98 | { |
68 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); | 99 | DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,rebuilding={1}", |
69 | // Queue to happen after all the other taint processing | 100 | requestor.LocalID, Rebuilding); |
70 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() | 101 | // When rebuilding, it is possible to set properties that would normally require a rebuild. |
102 | // If already rebuilding, don't request another rebuild. | ||
103 | if (!Rebuilding) | ||
71 | { | 104 | { |
72 | if (IsRoot(requestor) && HasAnyChildren) | 105 | PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", LinksetRoot.LocalID, delegate() |
73 | RecomputeLinksetCompound(); | 106 | { |
74 | }); | 107 | if (HasAnyChildren) |
108 | RecomputeLinksetCompound(); | ||
109 | }); | ||
110 | } | ||
75 | } | 111 | } |
76 | 112 | ||
77 | // The object is going dynamic (physical). Do any setup necessary | 113 | // The object is going dynamic (physical). Do any setup necessary |
@@ -84,12 +120,23 @@ public sealed class BSLinksetCompound : BSLinkset | |||
84 | { | 120 | { |
85 | bool ret = false; | 121 | bool ret = false; |
86 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 122 | DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
87 | if (!IsRoot(child)) | 123 | if (IsRoot(child)) |
124 | { | ||
125 | // The root is going dynamic. Make sure mass is properly set. | ||
126 | m_mass = ComputeLinksetMass(); | ||
127 | ScheduleRebuild(LinksetRoot); | ||
128 | } | ||
129 | else | ||
88 | { | 130 | { |
89 | // Physical children are removed from the world as the shape ofthe root compound | 131 | // The origional prims are removed from the world as the shape of the root compound |
90 | // shape takes over. | 132 | // shape takes over. |
91 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 133 | BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
92 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 134 | BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
135 | // We don't want collisions from the old linkset children. | ||
136 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
137 | |||
138 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
139 | |||
93 | ret = true; | 140 | ret = true; |
94 | } | 141 | } |
95 | return ret; | 142 | return ret; |
@@ -104,33 +151,39 @@ public sealed class BSLinksetCompound : BSLinkset | |||
104 | { | 151 | { |
105 | bool ret = false; | 152 | bool ret = false; |
106 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | 153 | DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); |
107 | if (!IsRoot(child)) | 154 | if (IsRoot(child)) |
155 | { | ||
156 | ScheduleRebuild(LinksetRoot); | ||
157 | } | ||
158 | else | ||
108 | { | 159 | { |
109 | // The non-physical children can come back to life. | 160 | // The non-physical children can come back to life. |
110 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 161 | BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
111 | // Don't force activation so setting of DISABLE_SIMULATION can stay. | 162 | |
163 | child.PhysBody.collisionType = CollisionType.LinksetChild; | ||
164 | |||
165 | // Don't force activation so setting of DISABLE_SIMULATION can stay if used. | ||
112 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); | 166 | BulletSimAPI.Activate2(child.PhysBody.ptr, false); |
113 | ret = true; | 167 | ret = true; |
114 | } | 168 | } |
115 | return ret; | 169 | return ret; |
116 | } | 170 | } |
117 | 171 | ||
118 | // Called at taint-time!! | 172 | public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate) |
119 | public override void UpdateProperties(BSPhysObject updated) | ||
120 | { | 173 | { |
121 | // Nothing to do for constraints on property updates | 174 | // The user moving a child around requires the rebuilding of the linkset compound shape |
122 | } | 175 | // One problem is this happens when a border is crossed -- the simulator implementation |
123 | 176 | // is to store the position into the group which causes the move of the object | |
124 | // The children move around in relationship to the root. | 177 | // but it also means all the child positions get updated. |
125 | // Just grab the current values of wherever it is right now. | 178 | // What would cause an unnecessary rebuild so we make sure the linkset is in a |
126 | public override OMV.Vector3 Position(BSPhysObject member) | 179 | // region before bothering to do a rebuild. |
127 | { | 180 | if (!IsRoot(updated) |
128 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | 181 | && !physicalUpdate |
129 | } | 182 | && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition)) |
130 | 183 | { | |
131 | public override OMV.Quaternion Orientation(BSPhysObject member) | 184 | updated.LinksetInfo = null; |
132 | { | 185 | ScheduleRebuild(updated); |
133 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | 186 | } |
134 | } | 187 | } |
135 | 188 | ||
136 | // Routine called when rebuilding the body of some member of the linkset. | 189 | // Routine called when rebuilding the body of some member of the linkset. |
@@ -146,20 +199,58 @@ public sealed class BSLinksetCompound : BSLinkset | |||
146 | 199 | ||
147 | if (!IsRoot(child)) | 200 | if (!IsRoot(child)) |
148 | { | 201 | { |
149 | // Cause the current shape to be freed and the new one to be built. | 202 | // Because it is a convenient time, recompute child world position and rotation based on |
150 | InternalRefresh(LinksetRoot); | 203 | // its position in the linkset. |
151 | ret = true; | 204 | RecomputeChildWorldPosition(child, true); |
152 | } | 205 | } |
153 | 206 | ||
207 | // Cannot schedule a refresh/rebuild here because this routine is called when | ||
208 | // the linkset is being rebuilt. | ||
209 | // InternalRefresh(LinksetRoot); | ||
210 | |||
154 | return ret; | 211 | return ret; |
155 | } | 212 | } |
156 | 213 | ||
157 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', | 214 | // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', |
158 | // this routine will restore the removed constraints. | 215 | // this routine will restore the removed constraints. |
159 | // Called at taint-time!! | 216 | // Called at taint-time!! |
160 | public override void RestoreBodyDependencies(BSPrim child) | 217 | public override void RestoreBodyDependencies(BSPrim child) |
161 | { | 218 | { |
162 | // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. | 219 | } |
220 | |||
221 | // When the linkset is built, the child shape is added to the compound shape relative to the | ||
222 | // root shape. The linkset then moves around but this does not move the actual child | ||
223 | // prim. The child prim's location must be recomputed based on the location of the root shape. | ||
224 | private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime) | ||
225 | { | ||
226 | BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo; | ||
227 | if (lci != null) | ||
228 | { | ||
229 | if (inTaintTime) | ||
230 | { | ||
231 | OMV.Vector3 oldPos = child.RawPosition; | ||
232 | child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos; | ||
233 | child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}", | ||
235 | child.LocalID, oldPos, lci, child.RawPosition); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | // TaintedObject is not used here so the raw position is set now and not at taint-time. | ||
240 | child.Position = LinksetRoot.RawPosition + lci.OffsetPos; | ||
241 | child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot; | ||
242 | } | ||
243 | } | ||
244 | else | ||
245 | { | ||
246 | // This happens when children have been added to the linkset but the linkset | ||
247 | // has not been constructed yet. So like, at taint time, adding children to a linkset | ||
248 | // and then changing properties of the children (makePhysical, for instance) | ||
249 | // but the post-print action of actually rebuilding the linkset has not yet happened. | ||
250 | // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}", | ||
251 | // LogHeader, child.LocalID); | ||
252 | DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID); | ||
253 | } | ||
163 | } | 254 | } |
164 | 255 | ||
165 | // ================================================================ | 256 | // ================================================================ |
@@ -174,14 +265,14 @@ public sealed class BSLinksetCompound : BSLinkset | |||
174 | 265 | ||
175 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 266 | DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
176 | 267 | ||
177 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 268 | // Rebuild the compound shape with the new child shape included |
178 | InternalRefresh(LinksetRoot); | 269 | ScheduleRebuild(child); |
179 | } | 270 | } |
180 | return; | 271 | return; |
181 | } | 272 | } |
182 | 273 | ||
183 | // Remove the specified child from the linkset. | 274 | // Remove the specified child from the linkset. |
184 | // Safe to call even if the child is not really in my linkset. | 275 | // Safe to call even if the child is not really in the linkset. |
185 | protected override void RemoveChildFromLinkset(BSPhysObject child) | 276 | protected override void RemoveChildFromLinkset(BSPhysObject child) |
186 | { | 277 | { |
187 | if (m_children.Remove(child)) | 278 | if (m_children.Remove(child)) |
@@ -192,6 +283,7 @@ public sealed class BSLinksetCompound : BSLinkset | |||
192 | child.LocalID, child.PhysBody.ptr.ToString("X")); | 283 | child.LocalID, child.PhysBody.ptr.ToString("X")); |
193 | 284 | ||
194 | // Cause the child's body to be rebuilt and thus restored to normal operation | 285 | // Cause the child's body to be rebuilt and thus restored to normal operation |
286 | RecomputeChildWorldPosition(child, false); | ||
195 | child.ForceBodyShapeRebuild(false); | 287 | child.ForceBodyShapeRebuild(false); |
196 | 288 | ||
197 | if (!HasAnyChildren) | 289 | if (!HasAnyChildren) |
@@ -201,8 +293,8 @@ public sealed class BSLinksetCompound : BSLinkset | |||
201 | } | 293 | } |
202 | else | 294 | else |
203 | { | 295 | { |
204 | // Schedule a rebuild of the linkset before the next simulation tick. | 296 | // Rebuild the compound shape with the child removed |
205 | InternalRefresh(LinksetRoot); | 297 | ScheduleRebuild(child); |
206 | } | 298 | } |
207 | } | 299 | } |
208 | return; | 300 | return; |
@@ -215,54 +307,83 @@ public sealed class BSLinksetCompound : BSLinkset | |||
215 | // Called at taint time!! | 307 | // Called at taint time!! |
216 | private void RecomputeLinksetCompound() | 308 | private void RecomputeLinksetCompound() |
217 | { | 309 | { |
218 | // Cause the root shape to be rebuilt as a compound object with just the root in it | 310 | try |
219 | LinksetRoot.ForceBodyShapeRebuild(true); | 311 | { |
312 | // Suppress rebuilding while rebuilding | ||
313 | Rebuilding = true; | ||
220 | 314 | ||
221 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", | 315 | // Cause the root shape to be rebuilt as a compound object with just the root in it |
222 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); | 316 | LinksetRoot.ForceBodyShapeRebuild(true); |
223 | 317 | ||
224 | // Add a shape for each of the other children in the linkset | 318 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}", |
225 | ForEachMember(delegate(BSPhysObject cPrim) | 319 | LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren); |
226 | { | 320 | |
227 | if (!IsRoot(cPrim)) | 321 | // Add a shape for each of the other children in the linkset |
322 | ForEachMember(delegate(BSPhysObject cPrim) | ||
228 | { | 323 | { |
229 | // Each child position and rotation is given relative to the root. | 324 | if (!IsRoot(cPrim)) |
230 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | 325 | { |
231 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | 326 | // Compute the displacement of the child from the root of the linkset. |
232 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | 327 | // This info is saved in the child prim so the relationship does not |
328 | // change over time and the new child position can be computed | ||
329 | // when the linkset is being disassembled (the linkset may have moved). | ||
330 | BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo; | ||
331 | if (lci == null) | ||
332 | { | ||
333 | // Each child position and rotation is given relative to the root. | ||
334 | OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation); | ||
335 | OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation; | ||
336 | OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation; | ||
337 | |||
338 | // Save relative position for recomputing child's world position after moving linkset. | ||
339 | lci = new BSLinksetCompoundInfo(displacementPos, displacementRot); | ||
340 | cPrim.LinksetInfo = lci; | ||
341 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci); | ||
342 | } | ||
233 | 343 | ||
234 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", | 344 | DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", |
235 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); | 345 | LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot); |
236 | 346 | ||
237 | if (cPrim.PhysShape.isNativeShape) | 347 | if (cPrim.PhysShape.isNativeShape) |
238 | { | 348 | { |
239 | // Native shapes are not shared so we need to create a new one. | 349 | // A native shape is turning into a hull collision shape because native |
240 | // A mesh or hull is created because scale is not available on a native shape. | 350 | // shapes are not shared so we have to hullify it so it will be tracked |
241 | // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) | 351 | // and freed at the correct time. This also solves the scaling problem |
242 | BulletShape saveShape = cPrim.PhysShape; | 352 | // (native shapes scaled but hull/meshes are assumed to not be). |
243 | cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape | 353 | // TODO: decide of the native shape can just be used in the compound shape. |
244 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); | 354 | // Use call to CreateGeomNonSpecial(). |
245 | BulletShape newShape = cPrim.PhysShape; | 355 | BulletShape saveShape = cPrim.PhysShape; |
246 | cPrim.PhysShape = saveShape; | 356 | cPrim.PhysShape.Clear(); // Don't let the create free the child's shape |
247 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot); | 357 | // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null); |
248 | } | 358 | PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null); |
249 | else | 359 | BulletShape newShape = cPrim.PhysShape; |
250 | { | 360 | cPrim.PhysShape = saveShape; |
251 | // For the shared shapes (meshes and hulls), just use the shape in the child. | 361 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, lci.OffsetPos, lci.OffsetRot); |
252 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | 362 | } |
363 | else | ||
253 | { | 364 | { |
254 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | 365 | // For the shared shapes (meshes and hulls), just use the shape in the child. |
255 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | 366 | // The reference count added here will be decremented when the compound shape |
367 | // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced). | ||
368 | if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) | ||
369 | { | ||
370 | PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", | ||
371 | LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); | ||
372 | } | ||
373 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, lci.OffsetPos, lci.OffsetRot); | ||
256 | } | 374 | } |
257 | BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot); | ||
258 | } | 375 | } |
259 | } | 376 | return false; // 'false' says to move onto the next child in the list |
260 | return false; // 'false' says to move onto the next child in the list | 377 | }); |
261 | }); | ||
262 | 378 | ||
263 | // With all of the linkset packed into the root prim, it has the mass of everyone. | 379 | // With all of the linkset packed into the root prim, it has the mass of everyone. |
264 | float linksetMass = LinksetMass; | 380 | float linksetMass = LinksetMass; |
265 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); | 381 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass); |
382 | } | ||
383 | finally | ||
384 | { | ||
385 | Rebuilding = false; | ||
386 | } | ||
266 | 387 | ||
267 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); | 388 | BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); |
268 | 389 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index c855fda..8c36c31 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
36 | { | 36 | { |
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | 37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; |
38 | 38 | ||
39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) | 39 | public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent) |
40 | { | 40 | { |
41 | base.Initialize(scene, parent); | ||
42 | } | 41 | } |
43 | 42 | ||
44 | // When physical properties are changed the linkset needs to recalculate | 43 | // When physical properties are changed the linkset needs to recalculate |
@@ -79,23 +78,11 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
79 | } | 78 | } |
80 | 79 | ||
81 | // Called at taint-time!! | 80 | // Called at taint-time!! |
82 | public override void UpdateProperties(BSPhysObject updated) | 81 | public override void UpdateProperties(BSPhysObject updated, bool inTaintTime) |
83 | { | 82 | { |
84 | // Nothing to do for constraints on property updates | 83 | // Nothing to do for constraints on property updates |
85 | } | 84 | } |
86 | 85 | ||
87 | // The children of the linkset are moved around by the constraints. | ||
88 | // Just grab the current values of wherever it is right now. | ||
89 | public override OMV.Vector3 Position(BSPhysObject member) | ||
90 | { | ||
91 | return BulletSimAPI.GetPosition2(member.PhysBody.ptr); | ||
92 | } | ||
93 | |||
94 | public override OMV.Quaternion Orientation(BSPhysObject member) | ||
95 | { | ||
96 | return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); | ||
97 | } | ||
98 | |||
99 | // Routine called when rebuilding the body of some member of the linkset. | 86 | // Routine called when rebuilding the body of some member of the linkset. |
100 | // Destroy all the constraints have have been made to root and set | 87 | // Destroy all the constraints have have been made to root and set |
101 | // up to rebuild the constraints before the next simulation step. | 88 | // up to rebuild the constraints before the next simulation step. |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs new file mode 100755 index 0000000..c113a43 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs | |||
@@ -0,0 +1,200 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | |||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
34 | { | ||
35 | |||
36 | public struct MaterialAttributes | ||
37 | { | ||
38 | // Material type values that correspond with definitions for LSL | ||
39 | public enum Material : int | ||
40 | { | ||
41 | Stone = 0, | ||
42 | Metal, | ||
43 | Glass, | ||
44 | Wood, | ||
45 | Flesh, | ||
46 | Plastic, | ||
47 | Rubber, | ||
48 | Light, | ||
49 | // Hereafter are BulletSim additions | ||
50 | Avatar, | ||
51 | NumberOfTypes // the count of types in the enum. | ||
52 | } | ||
53 | |||
54 | // Names must be in the order of the above enum. | ||
55 | // These names must coorespond to the lower case field names in the MaterialAttributes | ||
56 | // structure as reflection is used to select the field to put the value in. | ||
57 | public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"}; | ||
58 | |||
59 | public MaterialAttributes(string t, float d, float f, float r) | ||
60 | { | ||
61 | type = t; | ||
62 | density = d; | ||
63 | friction = f; | ||
64 | restitution = r; | ||
65 | } | ||
66 | public string type; | ||
67 | public float density; | ||
68 | public float friction; | ||
69 | public float restitution; | ||
70 | } | ||
71 | |||
72 | public static class BSMaterials | ||
73 | { | ||
74 | // Attributes for each material type | ||
75 | private static readonly MaterialAttributes[] Attributes; | ||
76 | |||
77 | // Map of material name to material type code | ||
78 | public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap; | ||
79 | |||
80 | static BSMaterials() | ||
81 | { | ||
82 | // Attribute sets for both the non-physical and physical instances of materials. | ||
83 | Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2]; | ||
84 | |||
85 | // Map of name to type code. | ||
86 | MaterialMap = new Dictionary<string, MaterialAttributes.Material>(); | ||
87 | MaterialMap.Add("Stone", MaterialAttributes.Material.Stone); | ||
88 | MaterialMap.Add("Metal", MaterialAttributes.Material.Metal); | ||
89 | MaterialMap.Add("Glass", MaterialAttributes.Material.Glass); | ||
90 | MaterialMap.Add("Wood", MaterialAttributes.Material.Wood); | ||
91 | MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh); | ||
92 | MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic); | ||
93 | MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber); | ||
94 | MaterialMap.Add("Light", MaterialAttributes.Material.Light); | ||
95 | MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar); | ||
96 | } | ||
97 | |||
98 | // This is where all the default material attributes are defined. | ||
99 | public static void InitializeFromDefaults(ConfigurationParameters parms) | ||
100 | { | ||
101 | // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL | ||
102 | float dDensity = parms.defaultDensity; | ||
103 | float dFriction = parms.defaultFriction; | ||
104 | float dRestitution = parms.defaultRestitution; | ||
105 | Attributes[(int)MaterialAttributes.Material.Stone] = | ||
106 | new MaterialAttributes("stone",dDensity, 0.8f, 0.4f); | ||
107 | Attributes[(int)MaterialAttributes.Material.Metal] = | ||
108 | new MaterialAttributes("metal",dDensity, 0.3f, 0.4f); | ||
109 | Attributes[(int)MaterialAttributes.Material.Glass] = | ||
110 | new MaterialAttributes("glass",dDensity, 0.2f, 0.7f); | ||
111 | Attributes[(int)MaterialAttributes.Material.Wood] = | ||
112 | new MaterialAttributes("wood",dDensity, 0.6f, 0.5f); | ||
113 | Attributes[(int)MaterialAttributes.Material.Flesh] = | ||
114 | new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f); | ||
115 | Attributes[(int)MaterialAttributes.Material.Plastic] = | ||
116 | new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f); | ||
117 | Attributes[(int)MaterialAttributes.Material.Rubber] = | ||
118 | new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f); | ||
119 | Attributes[(int)MaterialAttributes.Material.Light] = | ||
120 | new MaterialAttributes("light",dDensity, dFriction, dRestitution); | ||
121 | Attributes[(int)MaterialAttributes.Material.Avatar] = | ||
122 | new MaterialAttributes("avatar",60f, 0.2f, 0f); | ||
123 | |||
124 | Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
125 | new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f); | ||
126 | Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
127 | new MaterialAttributes("metalPhysical",dDensity, 0.8f, 0.4f); | ||
128 | Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
129 | new MaterialAttributes("glassPhysical",dDensity, 0.8f, 0.7f); | ||
130 | Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
131 | new MaterialAttributes("woodPhysical",dDensity, 0.8f, 0.5f); | ||
132 | Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
133 | new MaterialAttributes("fleshPhysical",dDensity, 0.8f, 0.3f); | ||
134 | Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
135 | new MaterialAttributes("plasticPhysical",dDensity, 0.8f, 0.7f); | ||
136 | Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
137 | new MaterialAttributes("rubberPhysical",dDensity, 0.8f, 0.9f); | ||
138 | Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
139 | new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution); | ||
140 | Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] = | ||
141 | new MaterialAttributes("avatarPhysical",60f, 0.2f, 0f); | ||
142 | } | ||
143 | |||
144 | // Under the [BulletSim] section, one can change the individual material | ||
145 | // attribute values. The format of the configuration parameter is: | ||
146 | // <materialName><Attribute>["Physical"] = floatValue | ||
147 | // For instance: | ||
148 | // [BulletSim] | ||
149 | // StoneFriction = 0.2 | ||
150 | // FleshRestitutionPhysical = 0.8 | ||
151 | // Materials can have different parameters for their static and | ||
152 | // physical instantiations. When setting the non-physical value, | ||
153 | // both values are changed. Setting the physical value only changes | ||
154 | // the physical value. | ||
155 | public static void InitializefromParameters(IConfig pConfig) | ||
156 | { | ||
157 | foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap) | ||
158 | { | ||
159 | string matName = kvp.Key; | ||
160 | foreach (string attribName in MaterialAttributes.MaterialAttribs) | ||
161 | { | ||
162 | string paramName = matName + attribName; | ||
163 | if (pConfig.Contains(paramName)) | ||
164 | { | ||
165 | float paramValue = pConfig.GetFloat(paramName); | ||
166 | SetAttributeValue((int)kvp.Value, attribName, paramValue); | ||
167 | // set the physical value also | ||
168 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
169 | } | ||
170 | paramName += "Physical"; | ||
171 | if (pConfig.Contains(paramName)) | ||
172 | { | ||
173 | float paramValue = pConfig.GetFloat(paramName); | ||
174 | SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | // Use reflection to set the value in the attribute structure. | ||
181 | private static void SetAttributeValue(int matType, string attribName, float val) | ||
182 | { | ||
183 | MaterialAttributes thisAttrib = Attributes[matType]; | ||
184 | FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower()); | ||
185 | if (fieldInfo != null) | ||
186 | { | ||
187 | fieldInfo.SetValue(thisAttrib, val); | ||
188 | Attributes[matType] = thisAttrib; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | // Given a material type, return a structure of attributes. | ||
193 | public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical) | ||
194 | { | ||
195 | int ind = (int)type; | ||
196 | if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes; | ||
197 | return Attributes[ind]; | ||
198 | } | ||
199 | } | ||
200 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs index bc6e4c4..e0faf4e 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs | |||
@@ -1,104 +1,220 @@ | |||
1 | using System; | 1 | /* |
2 | using System.Collections.Generic; | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | using System.Text; | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | using OpenMetaverse; | 4 | * |
5 | 5 | * Redistribution and use in source and binary forms, with or without | |
6 | namespace OpenSim.Region.Physics.BulletSPlugin | 6 | * modification, are permitted provided that the following conditions are met: |
7 | { | 7 | * * Redistributions of source code must retain the above copyright |
8 | public abstract class BSMotor | 8 | * notice, this list of conditions and the following disclaimer. |
9 | { | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | public virtual void Reset() { } | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | public virtual void Zero() { } | 11 | * documentation and/or other materials provided with the distribution. |
12 | } | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | // Can all the incremental stepping be replaced with motor classes? | 13 | * names of its contributors may be used to endorse or promote products |
14 | public class BSVMotor : BSMotor | 14 | * derived from this software without specific prior written permission. |
15 | { | 15 | * |
16 | public Vector3 FrameOfReference { get; set; } | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | public Vector3 Offset { get; set; } | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
19 | public float TimeScale { get; set; } | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | public float TargetValueDecayTimeScale { get; set; } | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | public Vector3 CurrentValueReductionTimescale { get; set; } | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | public float Efficiency { get; set; } | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
24 | public Vector3 TargetValue { get; private set; } | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | public Vector3 CurrentValue { get; private set; } | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | 26 | * | |
27 | 27 | */ | |
28 | 28 | using System; | |
29 | BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) | 29 | using System.Collections.Generic; |
30 | { | 30 | using System.Text; |
31 | TimeScale = timeScale; | 31 | using OpenMetaverse; |
32 | TargetValueDecayTimeScale = decayTimeScale; | 32 | |
33 | CurrentValueReductionTimescale = frictionTimeScale; | 33 | namespace OpenSim.Region.Physics.BulletSPlugin |
34 | Efficiency = efficiency; | 34 | { |
35 | } | 35 | public abstract class BSMotor |
36 | public void SetCurrent(Vector3 current) | 36 | { |
37 | { | 37 | // Timescales and other things can be turned off by setting them to 'infinite'. |
38 | CurrentValue = current; | 38 | public const float Infinite = 12345f; |
39 | } | 39 | public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite); |
40 | public void SetTarget(Vector3 target) | 40 | |
41 | { | 41 | public BSMotor(string useName) |
42 | TargetValue = target; | 42 | { |
43 | } | 43 | UseName = useName; |
44 | public Vector3 Step(float timeStep) | 44 | PhysicsScene = null; |
45 | { | 45 | } |
46 | if (CurrentValue.LengthSquared() > 0.001f) | 46 | public virtual void Reset() { } |
47 | { | 47 | public virtual void Zero() { } |
48 | // Vector3 origDir = Target; // DEBUG | 48 | |
49 | // Vector3 origVel = CurrentValue; // DEBUG | 49 | // A name passed at motor creation for easily identifyable debugging messages. |
50 | 50 | public string UseName { get; private set; } | |
51 | // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete | 51 | |
52 | Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; | 52 | // Used only for outputting debug information. Might not be set so check for null. |
53 | CurrentValue += addAmount; | 53 | public BSScene PhysicsScene { get; set; } |
54 | 54 | protected void MDetailLog(string msg, params Object[] parms) | |
55 | float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | 55 | { |
56 | TargetValue *= (1f - decayFactor); | 56 | if (PhysicsScene != null) |
57 | 57 | { | |
58 | Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; | 58 | if (PhysicsScene.VehicleLoggingEnabled) |
59 | CurrentValue *= (Vector3.One - frictionFactor); | 59 | { |
60 | } | 60 | PhysicsScene.DetailLog(msg, parms); |
61 | else | 61 | } |
62 | { | 62 | } |
63 | // if what remains of direction is very small, zero it. | 63 | } |
64 | TargetValue = Vector3.Zero; | 64 | } |
65 | CurrentValue = Vector3.Zero; | 65 | // Can all the incremental stepping be replaced with motor classes? |
66 | 66 | ||
67 | // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); | 67 | // Motor which moves CurrentValue to TargetValue over TimeScale seconds. |
68 | } | 68 | // The TargetValue decays in TargetValueDecayTimeScale and |
69 | return CurrentValue; | 69 | // the CurrentValue will be held back by FrictionTimeScale. |
70 | } | 70 | // TimeScale and TargetDelayTimeScale may be 'infinite' which means go decay. |
71 | } | 71 | |
72 | 72 | // For instance, if something is moving at speed X and the desired speed is Y, | |
73 | public class BSFMotor : BSMotor | 73 | // CurrentValue is X and TargetValue is Y. As the motor is stepped, new |
74 | { | 74 | // values of CurrentValue are returned that approach the TargetValue. |
75 | public float TimeScale { get; set; } | 75 | // The feature of decaying TargetValue is so vehicles will eventually |
76 | public float DecayTimeScale { get; set; } | 76 | // come to a stop rather than run forever. This can be disabled by |
77 | public float Friction { get; set; } | 77 | // setting TargetValueDecayTimescale to 'infinite'. |
78 | public float Efficiency { get; set; } | 78 | // The change from CurrentValue to TargetValue is linear over TimeScale seconds. |
79 | 79 | public class BSVMotor : BSMotor | |
80 | public float Target { get; private set; } | 80 | { |
81 | public float CurrentValue { get; private set; } | 81 | // public Vector3 FrameOfReference { get; set; } |
82 | 82 | // public Vector3 Offset { get; set; } | |
83 | BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) | 83 | |
84 | { | 84 | public float TimeScale { get; set; } |
85 | } | 85 | public float TargetValueDecayTimeScale { get; set; } |
86 | public void SetCurrent(float target) | 86 | public Vector3 FrictionTimescale { get; set; } |
87 | { | 87 | public float Efficiency { get; set; } |
88 | } | 88 | |
89 | public void SetTarget(float target) | 89 | public Vector3 TargetValue { get; private set; } |
90 | { | 90 | public Vector3 CurrentValue { get; private set; } |
91 | } | 91 | |
92 | public float Step(float timeStep) | 92 | public BSVMotor(string useName) |
93 | { | 93 | : base(useName) |
94 | return 0f; | 94 | { |
95 | } | 95 | TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite; |
96 | } | 96 | Efficiency = 1f; |
97 | public class BSPIDMotor : BSMotor | 97 | FrictionTimescale = BSMotor.InfiniteVector; |
98 | { | 98 | CurrentValue = TargetValue = Vector3.Zero; |
99 | // TODO: write and use this one | 99 | } |
100 | BSPIDMotor() | 100 | public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) |
101 | { | 101 | : this(useName) |
102 | } | 102 | { |
103 | } | 103 | TimeScale = timeScale; |
104 | } | 104 | TargetValueDecayTimeScale = decayTimeScale; |
105 | FrictionTimescale = frictionTimeScale; | ||
106 | Efficiency = efficiency; | ||
107 | CurrentValue = TargetValue = Vector3.Zero; | ||
108 | } | ||
109 | public void SetCurrent(Vector3 current) | ||
110 | { | ||
111 | CurrentValue = current; | ||
112 | } | ||
113 | public void SetTarget(Vector3 target) | ||
114 | { | ||
115 | TargetValue = target; | ||
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 | |||
125 | public Vector3 Step(float timeStep) | ||
126 | { | ||
127 | Vector3 returnCurrent = Vector3.Zero; | ||
128 | if (!CurrentValue.ApproxEquals(TargetValue, 0.01f)) | ||
129 | { | ||
130 | Vector3 origTarget = TargetValue; // DEBUG | ||
131 | Vector3 origCurrVal = CurrentValue; // DEBUG | ||
132 | |||
133 | // Addition = (desiredVector - currentAppliedVector) / secondsItShouldTakeToComplete | ||
134 | Vector3 addAmount = (TargetValue - CurrentValue)/TimeScale * timeStep; | ||
135 | CurrentValue += addAmount; | ||
136 | |||
137 | // The desired value reduces to zero which also reduces the difference with current. | ||
138 | // If the decay time is infinite, don't decay at all. | ||
139 | float decayFactor = 0f; | ||
140 | if (TargetValueDecayTimeScale != BSMotor.Infinite) | ||
141 | { | ||
142 | decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; | ||
143 | TargetValue *= (1f - decayFactor); | ||
144 | } | ||
145 | |||
146 | Vector3 frictionFactor = Vector3.Zero; | ||
147 | if (FrictionTimescale != BSMotor.InfiniteVector) | ||
148 | { | ||
149 | // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep; | ||
150 | // Individual friction components can be 'infinite' so compute each separately. | ||
151 | frictionFactor.X = FrictionTimescale.X == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.X) * timeStep; | ||
152 | frictionFactor.Y = FrictionTimescale.Y == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Y) * timeStep; | ||
153 | frictionFactor.Z = FrictionTimescale.Z == BSMotor.Infinite ? 0f : (1f / FrictionTimescale.Z) * timeStep; | ||
154 | CurrentValue *= (Vector3.One - frictionFactor); | ||
155 | } | ||
156 | |||
157 | returnCurrent = CurrentValue; | ||
158 | |||
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}", | ||
160 | BSScene.DetailLogZero, UseName, origCurrVal, origTarget, | ||
161 | timeStep, TimeScale, addAmount, | ||
162 | TargetValueDecayTimeScale, decayFactor, | ||
163 | FrictionTimescale, frictionFactor); | ||
164 | MDetailLog("{0}, BSVMotor.Step,nonZero,{1},curr={2},target={3},add={4},decay={5},frict={6},ret={7}", | ||
165 | BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, | ||
166 | addAmount, decayFactor, frictionFactor, returnCurrent); | ||
167 | } | ||
168 | else | ||
169 | { | ||
170 | // Difference between what we have and target is small. Motor is done. | ||
171 | CurrentValue = Vector3.Zero; | ||
172 | TargetValue = Vector3.Zero; | ||
173 | |||
174 | MDetailLog("{0}, BSVMotor.Step,zero,{1},curr={2},target={3},ret={4}", | ||
175 | BSScene.DetailLogZero, UseName, TargetValue, CurrentValue, returnCurrent); | ||
176 | |||
177 | } | ||
178 | return returnCurrent; | ||
179 | } | ||
180 | public override string ToString() | ||
181 | { | ||
182 | return String.Format("<{0},curr={1},targ={2},decayTS={3},frictTS={4}>", | ||
183 | UseName, CurrentValue, TargetValue, TargetValueDecayTimeScale, FrictionTimescale); | ||
184 | } | ||
185 | } | ||
186 | |||
187 | public class BSFMotor : BSMotor | ||
188 | { | ||
189 | public float TimeScale { get; set; } | ||
190 | public float DecayTimeScale { get; set; } | ||
191 | public float Friction { get; set; } | ||
192 | public float Efficiency { get; set; } | ||
193 | |||
194 | public float Target { get; private set; } | ||
195 | public float CurrentValue { get; private set; } | ||
196 | |||
197 | public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency) | ||
198 | : base(useName) | ||
199 | { | ||
200 | } | ||
201 | public void SetCurrent(float target) | ||
202 | { | ||
203 | } | ||
204 | public void SetTarget(float target) | ||
205 | { | ||
206 | } | ||
207 | public float Step(float timeStep) | ||
208 | { | ||
209 | return 0f; | ||
210 | } | ||
211 | } | ||
212 | public class BSPIDMotor : BSMotor | ||
213 | { | ||
214 | // TODO: write and use this one | ||
215 | public BSPIDMotor(string useName) | ||
216 | : base(useName) | ||
217 | { | ||
218 | } | ||
219 | } | ||
220 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs index f6a890e..92a5f2f 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs | |||
@@ -60,6 +60,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
60 | Linkset = BSLinkset.Factory(PhysicsScene, this); | 60 | Linkset = BSLinkset.Factory(PhysicsScene, this); |
61 | LastAssetBuildFailed = false; | 61 | LastAssetBuildFailed = false; |
62 | 62 | ||
63 | // Default material type | ||
64 | Material = MaterialAttributes.Material.Wood; | ||
65 | |||
63 | CollisionCollection = new CollisionEventUpdate(); | 66 | CollisionCollection = new CollisionEventUpdate(); |
64 | SubscribedEventsMs = 0; | 67 | SubscribedEventsMs = 0; |
65 | CollidingStep = 0; | 68 | CollidingStep = 0; |
@@ -72,6 +75,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
72 | public string TypeName { get; protected set; } | 75 | public string TypeName { get; protected set; } |
73 | 76 | ||
74 | public BSLinkset Linkset { get; set; } | 77 | public BSLinkset Linkset { get; set; } |
78 | public BSLinksetInfo LinksetInfo { get; set; } | ||
75 | 79 | ||
76 | // Return the object mass without calculating it or having side effects | 80 | // Return the object mass without calculating it or having side effects |
77 | public abstract float RawMass { get; } | 81 | public abstract float RawMass { get; } |
@@ -105,10 +109,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
105 | public EntityProperties CurrentEntityProperties { get; set; } | 109 | public EntityProperties CurrentEntityProperties { get; set; } |
106 | public EntityProperties LastEntityProperties { get; set; } | 110 | public EntityProperties LastEntityProperties { get; set; } |
107 | 111 | ||
108 | public abstract OMV.Vector3 Scale { get; set; } | 112 | public virtual OMV.Vector3 Scale { get; set; } |
109 | public abstract bool IsSolid { get; } | 113 | public abstract bool IsSolid { get; } |
110 | public abstract bool IsStatic { get; } | 114 | public abstract bool IsStatic { get; } |
111 | 115 | ||
116 | // Materialness | ||
117 | public MaterialAttributes.Material Material { get; private set; } | ||
118 | public override void SetMaterial(int material) | ||
119 | { | ||
120 | Material = (MaterialAttributes.Material)material; | ||
121 | } | ||
122 | |||
112 | // Stop all physical motion. | 123 | // Stop all physical motion. |
113 | public abstract void ZeroMotion(bool inTaintTime); | 124 | public abstract void ZeroMotion(bool inTaintTime); |
114 | public abstract void ZeroAngularMotion(bool inTaintTime); | 125 | public abstract void ZeroAngularMotion(bool inTaintTime); |
@@ -128,6 +139,17 @@ public abstract class BSPhysObject : PhysicsActor | |||
128 | public abstract OMV.Quaternion RawOrientation { get; set; } | 139 | public abstract OMV.Quaternion RawOrientation { get; set; } |
129 | public abstract OMV.Quaternion ForceOrientation { get; set; } | 140 | public abstract OMV.Quaternion ForceOrientation { get; set; } |
130 | 141 | ||
142 | // The system is telling us the velocity it wants to move at. | ||
143 | protected OMV.Vector3 m_targetVelocity; | ||
144 | public override OMV.Vector3 TargetVelocity | ||
145 | { | ||
146 | get { return m_targetVelocity; } | ||
147 | set | ||
148 | { | ||
149 | m_targetVelocity = value; | ||
150 | Velocity = value; | ||
151 | } | ||
152 | } | ||
131 | public abstract OMV.Vector3 ForceVelocity { get; set; } | 153 | public abstract OMV.Vector3 ForceVelocity { get; set; } |
132 | 154 | ||
133 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } | 155 | public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } |
@@ -192,7 +214,7 @@ public abstract class BSPhysObject : PhysicsActor | |||
192 | { | 214 | { |
193 | bool ret = true; | 215 | bool ret = true; |
194 | // If the 'no collision' call, force it to happen right now so quick collision_end | 216 | // If the 'no collision' call, force it to happen right now so quick collision_end |
195 | bool force = CollisionCollection.Count == 0; | 217 | bool force = (CollisionCollection.Count == 0); |
196 | 218 | ||
197 | // throttle the collisions to the number of milliseconds specified in the subscription | 219 | // throttle the collisions to the number of milliseconds specified in the subscription |
198 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) | 220 | if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) |
@@ -210,8 +232,10 @@ public abstract class BSPhysObject : PhysicsActor | |||
210 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); | 232 | // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); |
211 | base.SendCollisionUpdate(CollisionCollection); | 233 | base.SendCollisionUpdate(CollisionCollection); |
212 | 234 | ||
213 | // The collisionCollection structure is passed around in the simulator. | 235 | // The CollisionCollection instance is passed around in the simulator. |
214 | // Make sure we don't have a handle to that one and that a new one is used for next time. | 236 | // Make sure we don't have a handle to that one and that a new one is used for next time. |
237 | // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here, | ||
238 | // a race condition is created for the other users of this instance. | ||
215 | CollisionCollection = new CollisionEventUpdate(); | 239 | CollisionCollection = new CollisionEventUpdate(); |
216 | } | 240 | } |
217 | return ret; | 241 | return ret; |
@@ -229,7 +253,8 @@ public abstract class BSPhysObject : PhysicsActor | |||
229 | 253 | ||
230 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() | 254 | PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() |
231 | { | 255 | { |
232 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 256 | if (PhysBody.HasPhysicalBody) |
257 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
233 | }); | 258 | }); |
234 | } | 259 | } |
235 | else | 260 | else |
@@ -243,7 +268,9 @@ public abstract class BSPhysObject : PhysicsActor | |||
243 | SubscribedEventsMs = 0; | 268 | SubscribedEventsMs = 0; |
244 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() | 269 | PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() |
245 | { | 270 | { |
246 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | 271 | // Make sure there is a body there because sometimes destruction happens in an un-ideal order. |
272 | if (PhysBody.HasPhysicalBody) | ||
273 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); | ||
247 | }); | 274 | }); |
248 | } | 275 | } |
249 | // Return 'true' if the simulator wants collision events | 276 | // Return 'true' if the simulator wants collision events |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 2b3fa25..758d92b 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject | |||
45 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 45 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
46 | 46 | ||
47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. | 47 | // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. |
48 | // Often Scale is unity because the meshmerizer will apply _size when creating the mesh. | ||
49 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user | 48 | private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user |
50 | 49 | ||
51 | private bool _grabbed; | 50 | private bool _grabbed; |
@@ -93,7 +92,7 @@ public sealed class BSPrim : BSPhysObject | |||
93 | _physicsActorType = (int)ActorTypes.Prim; | 92 | _physicsActorType = (int)ActorTypes.Prim; |
94 | _position = pos; | 93 | _position = pos; |
95 | _size = size; | 94 | _size = size; |
96 | Scale = size; // the scale will be set by CreateGeom depending on object type | 95 | Scale = size; // prims are the size the user wants them to be (different for BSCharactes). |
97 | _orientation = rotation; | 96 | _orientation = rotation; |
98 | _buoyancy = 1f; | 97 | _buoyancy = 1f; |
99 | _velocity = OMV.Vector3.Zero; | 98 | _velocity = OMV.Vector3.Zero; |
@@ -108,8 +107,8 @@ public sealed class BSPrim : BSPhysObject | |||
108 | _mass = CalculateMass(); | 107 | _mass = CalculateMass(); |
109 | 108 | ||
110 | // No body or shape yet | 109 | // No body or shape yet |
111 | PhysBody = new BulletBody(LocalID, IntPtr.Zero); | 110 | PhysBody = new BulletBody(LocalID); |
112 | PhysShape = new BulletShape(IntPtr.Zero); | 111 | PhysShape = new BulletShape(); |
113 | 112 | ||
114 | DetailLog("{0},BSPrim.constructor,call", LocalID); | 113 | DetailLog("{0},BSPrim.constructor,call", LocalID); |
115 | // do the actual object creation at taint time | 114 | // do the actual object creation at taint time |
@@ -143,7 +142,9 @@ public sealed class BSPrim : BSPhysObject | |||
143 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); | 142 | DetailLog("{0},BSPrim.Destroy,taint,", LocalID); |
144 | // If there are physical body and shape, release my use of same. | 143 | // If there are physical body and shape, release my use of same. |
145 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 144 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); |
145 | PhysBody.Clear(); | ||
146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 146 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); |
147 | PhysShape.Clear(); | ||
147 | }); | 148 | }); |
148 | } | 149 | } |
149 | 150 | ||
@@ -157,12 +158,10 @@ public sealed class BSPrim : BSPhysObject | |||
157 | // We presume the scale and size are the same. If scale must be changed for | 158 | // We presume the scale and size are the same. If scale must be changed for |
158 | // the physical shape, that is done when the geometry is built. | 159 | // the physical shape, that is done when the geometry is built. |
159 | _size = value; | 160 | _size = value; |
161 | Scale = _size; | ||
160 | ForceBodyShapeRebuild(false); | 162 | ForceBodyShapeRebuild(false); |
161 | } | 163 | } |
162 | } | 164 | } |
163 | // Scale is what we set in the physics engine. It is different than 'size' in that | ||
164 | // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>. | ||
165 | public override OMV.Vector3 Scale { get; set; } | ||
166 | 165 | ||
167 | public override PrimitiveBaseShape Shape { | 166 | public override PrimitiveBaseShape Shape { |
168 | set { | 167 | set { |
@@ -189,13 +188,17 @@ public sealed class BSPrim : BSPhysObject | |||
189 | } | 188 | } |
190 | } | 189 | } |
191 | public override bool Selected { | 190 | public override bool Selected { |
192 | set { | 191 | set |
193 | _isSelected = value; | 192 | { |
194 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() | 193 | if (value != _isSelected) |
195 | { | 194 | { |
196 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | 195 | _isSelected = value; |
197 | SetObjectDynamic(false); | 196 | PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() |
198 | }); | 197 | { |
198 | DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); | ||
199 | SetObjectDynamic(false); | ||
200 | }); | ||
201 | } | ||
199 | } | 202 | } |
200 | } | 203 | } |
201 | public override void CrossingFailure() { return; } | 204 | public override void CrossingFailure() { return; } |
@@ -244,7 +247,8 @@ public sealed class BSPrim : BSPhysObject | |||
244 | // Zero some other properties in the physics engine | 247 | // Zero some other properties in the physics engine |
245 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 248 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
246 | { | 249 | { |
247 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | 250 | if (PhysBody.HasPhysicalBody) |
251 | BulletSimAPI.ClearAllForces2(PhysBody.ptr); | ||
248 | }); | 252 | }); |
249 | } | 253 | } |
250 | public override void ZeroAngularMotion(bool inTaintTime) | 254 | public override void ZeroAngularMotion(bool inTaintTime) |
@@ -253,8 +257,12 @@ public sealed class BSPrim : BSPhysObject | |||
253 | // Zero some other properties in the physics engine | 257 | // Zero some other properties in the physics engine |
254 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() | 258 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() |
255 | { | 259 | { |
256 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 260 | // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity); |
257 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); | 261 | if (PhysBody.HasPhysicalBody) |
262 | { | ||
263 | BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
264 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
265 | } | ||
258 | }); | 266 | }); |
259 | } | 267 | } |
260 | 268 | ||
@@ -271,9 +279,12 @@ public sealed class BSPrim : BSPhysObject | |||
271 | } | 279 | } |
272 | public override OMV.Vector3 Position { | 280 | public override OMV.Vector3 Position { |
273 | get { | 281 | get { |
282 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
283 | * and does not fetch this position info for children. Thus this is commented out. | ||
274 | // child prims move around based on their parent. Need to get the latest location | 284 | // child prims move around based on their parent. Need to get the latest location |
275 | if (!Linkset.IsRoot(this)) | 285 | if (!Linkset.IsRoot(this)) |
276 | _position = Linkset.Position(this); | 286 | _position = Linkset.PositionGet(this); |
287 | */ | ||
277 | 288 | ||
278 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. | 289 | // don't do the GetObjectPosition for root elements because this function is called a zillion times. |
279 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 290 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
@@ -281,18 +292,22 @@ public sealed class BSPrim : BSPhysObject | |||
281 | } | 292 | } |
282 | set { | 293 | set { |
283 | // If the position must be forced into the physics engine, use ForcePosition. | 294 | // If the position must be forced into the physics engine, use ForcePosition. |
295 | // All positions are given in world positions. | ||
284 | if (_position == value) | 296 | if (_position == value) |
285 | { | 297 | { |
298 | DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation); | ||
286 | return; | 299 | return; |
287 | } | 300 | } |
288 | _position = value; | 301 | _position = value; |
289 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
290 | PositionSanityCheck(false); | 302 | PositionSanityCheck(false); |
303 | |||
304 | // A linkset might need to know if a component information changed. | ||
305 | Linkset.UpdateProperties(this, false); | ||
306 | |||
291 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() | 307 | PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() |
292 | { | 308 | { |
293 | // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 309 | DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); |
294 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 310 | ForcePosition = _position; |
295 | ActivateIfPhysical(false); | ||
296 | }); | 311 | }); |
297 | } | 312 | } |
298 | } | 313 | } |
@@ -303,9 +318,11 @@ public sealed class BSPrim : BSPhysObject | |||
303 | } | 318 | } |
304 | set { | 319 | set { |
305 | _position = value; | 320 | _position = value; |
306 | // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. | 321 | if (PhysBody.HasPhysicalBody) |
307 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 322 | { |
308 | ActivateIfPhysical(false); | 323 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); |
324 | ActivateIfPhysical(false); | ||
325 | } | ||
309 | } | 326 | } |
310 | } | 327 | } |
311 | 328 | ||
@@ -316,39 +333,46 @@ public sealed class BSPrim : BSPhysObject | |||
316 | { | 333 | { |
317 | bool ret = false; | 334 | bool ret = false; |
318 | 335 | ||
336 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | ||
337 | { | ||
338 | // The physical object is out of the known/simulated area. | ||
339 | // Upper levels of code will handle the transition to other areas so, for | ||
340 | // the time, we just ignore the position. | ||
341 | return ret; | ||
342 | } | ||
343 | |||
319 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 344 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); |
320 | OMV.Vector3 upForce = OMV.Vector3.Zero; | 345 | OMV.Vector3 upForce = OMV.Vector3.Zero; |
321 | if (Position.Z < terrainHeight) | 346 | if (RawPosition.Z < terrainHeight) |
322 | { | 347 | { |
323 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 348 | DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); |
324 | float targetHeight = terrainHeight + (Size.Z / 2f); | 349 | float targetHeight = terrainHeight + (Size.Z / 2f); |
325 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. | 350 | // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. |
326 | upForce.Z = (terrainHeight - Position.Z) * 1f; | 351 | upForce.Z = (terrainHeight - RawPosition.Z) * 1f; |
327 | ret = true; | 352 | ret = true; |
328 | } | 353 | } |
329 | 354 | ||
330 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 355 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
331 | { | 356 | { |
332 | float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); | 357 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); |
333 | // TODO: a floating motor so object will bob in the water | 358 | // TODO: a floating motor so object will bob in the water |
334 | if (Math.Abs(Position.Z - waterHeight) > 0.1f) | 359 | if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f) |
335 | { | 360 | { |
336 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. | 361 | // Upforce proportional to the distance away from the water. Correct the error in 1 sec. |
337 | upForce.Z = (waterHeight - Position.Z) * 1f; | 362 | upForce.Z = (waterHeight - RawPosition.Z) * 1f; |
338 | ret = true; | 363 | ret = true; |
339 | } | 364 | } |
340 | } | 365 | } |
341 | 366 | ||
342 | // TODO: check for out of bounds | ||
343 | |||
344 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. | 367 | // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. |
368 | // TODO: This should be intergrated with a geneal physics action mechanism. | ||
369 | // TODO: This should be moderated with PID'ness. | ||
345 | if (ret) | 370 | if (ret) |
346 | { | 371 | { |
347 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() | 372 | // Apply upforce and overcome gravity. |
348 | { | 373 | OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity; |
349 | // Apply upforce and overcome gravity. | 374 | DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce); |
350 | ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; | 375 | AddForce(correctionForce, false, inTaintTime); |
351 | }); | ||
352 | } | 376 | } |
353 | return ret; | 377 | return ret; |
354 | } | 378 | } |
@@ -408,7 +432,8 @@ public sealed class BSPrim : BSPhysObject | |||
408 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() | 432 | PhysicsScene.TaintedObject("BSPrim.setForce", delegate() |
409 | { | 433 | { |
410 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); | 434 | // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); |
411 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | 435 | if (PhysBody.HasPhysicalBody) |
436 | BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); | ||
412 | }); | 437 | }); |
413 | } | 438 | } |
414 | } | 439 | } |
@@ -502,7 +527,8 @@ public sealed class BSPrim : BSPhysObject | |||
502 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() | 527 | PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() |
503 | { | 528 | { |
504 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); | 529 | // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); |
505 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | 530 | if (PhysBody.HasPhysicalBody) |
531 | BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); | ||
506 | }); | 532 | }); |
507 | } | 533 | } |
508 | } | 534 | } |
@@ -537,23 +563,32 @@ public sealed class BSPrim : BSPhysObject | |||
537 | } | 563 | } |
538 | public override OMV.Quaternion Orientation { | 564 | public override OMV.Quaternion Orientation { |
539 | get { | 565 | get { |
566 | /* NOTE: this refetch is not necessary. The simulator knows about linkset children | ||
567 | * and does not fetch this position info for children. Thus this is commented out. | ||
540 | // Children move around because tied to parent. Get a fresh value. | 568 | // Children move around because tied to parent. Get a fresh value. |
541 | if (!Linkset.IsRoot(this)) | 569 | if (!Linkset.IsRoot(this)) |
542 | { | 570 | { |
543 | _orientation = Linkset.Orientation(this); | 571 | _orientation = Linkset.OrientationGet(this); |
544 | } | 572 | } |
573 | */ | ||
545 | return _orientation; | 574 | return _orientation; |
546 | } | 575 | } |
547 | set { | 576 | set { |
548 | if (_orientation == value) | 577 | if (_orientation == value) |
549 | return; | 578 | return; |
550 | _orientation = value; | 579 | _orientation = value; |
551 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? | 580 | |
581 | // A linkset might need to know if a component information changed. | ||
582 | Linkset.UpdateProperties(this, false); | ||
583 | |||
552 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() | 584 | PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() |
553 | { | 585 | { |
554 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); | 586 | if (PhysBody.HasPhysicalBody) |
555 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 587 | { |
556 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | 588 | // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); |
589 | // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
590 | BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); | ||
591 | } | ||
557 | }); | 592 | }); |
558 | } | 593 | } |
559 | } | 594 | } |
@@ -644,10 +679,7 @@ public sealed class BSPrim : BSPhysObject | |||
644 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); | 679 | BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); |
645 | 680 | ||
646 | // Collision filter can be set only when the object is in the world | 681 | // Collision filter can be set only when the object is in the world |
647 | if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0) | 682 | PhysBody.ApplyCollisionMask(); |
648 | { | ||
649 | BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask); | ||
650 | } | ||
651 | 683 | ||
652 | // Recompute any linkset parameters. | 684 | // Recompute any linkset parameters. |
653 | // When going from non-physical to physical, this re-enables the constraints that | 685 | // When going from non-physical to physical, this re-enables the constraints that |
@@ -672,8 +704,12 @@ public sealed class BSPrim : BSPhysObject | |||
672 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 704 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
673 | // Stop all movement | 705 | // Stop all movement |
674 | ZeroMotion(true); | 706 | ZeroMotion(true); |
675 | // Center of mass is at the center of the object | 707 | |
676 | // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); | 708 | // Set various physical properties so other object interact properly |
709 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false); | ||
710 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); | ||
711 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
712 | |||
677 | // Mass is zero which disables a bunch of physics stuff in Bullet | 713 | // Mass is zero which disables a bunch of physics stuff in Bullet |
678 | UpdatePhysicalMassProperties(0f); | 714 | UpdatePhysicalMassProperties(0f); |
679 | // Set collision detection parameters | 715 | // Set collision detection parameters |
@@ -682,24 +718,27 @@ public sealed class BSPrim : BSPhysObject | |||
682 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); | 718 | BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); |
683 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); | 719 | BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); |
684 | } | 720 | } |
685 | // There can be special things needed for implementing linksets | 721 | |
686 | Linkset.MakeStatic(this); | ||
687 | // The activation state is 'disabled' so Bullet will not try to act on it. | 722 | // The activation state is 'disabled' so Bullet will not try to act on it. |
688 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); | 723 | // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); |
689 | // Start it out sleeping and physical actions could wake it up. | 724 | // Start it out sleeping and physical actions could wake it up. |
690 | // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); | 725 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING); |
726 | |||
727 | // This collides like a static object | ||
728 | PhysBody.collisionType = CollisionType.Static; | ||
691 | 729 | ||
692 | PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; | 730 | // There can be special things needed for implementing linksets |
693 | PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; | 731 | Linkset.MakeStatic(this); |
694 | } | 732 | } |
695 | else | 733 | else |
696 | { | 734 | { |
697 | // Not a Bullet static object | 735 | // Not a Bullet static object |
698 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); | 736 | CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); |
699 | 737 | ||
700 | // Set various physical properties so internal dynamic properties will get computed correctly as they are set | 738 | // Set various physical properties so other object interact properly |
701 | BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); | 739 | MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true); |
702 | BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); | 740 | BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction); |
741 | BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution); | ||
703 | 742 | ||
704 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 | 743 | // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 |
705 | // Since this can be called multiple times, only zero forces when becoming physical | 744 | // Since this can be called multiple times, only zero forces when becoming physical |
@@ -727,16 +766,15 @@ public sealed class BSPrim : BSPhysObject | |||
727 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); | 766 | BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); |
728 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); | 767 | BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); |
729 | 768 | ||
730 | // There might be special things needed for implementing linksets. | 769 | // This collides like an object. |
731 | Linkset.MakeDynamic(this); | 770 | PhysBody.collisionType = CollisionType.Dynamic; |
732 | 771 | ||
733 | // Force activation of the object so Bullet will act on it. | 772 | // Force activation of the object so Bullet will act on it. |
734 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. | 773 | // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. |
735 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); | 774 | BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); |
736 | // BulletSimAPI.Activate2(BSBody.ptr, true); | ||
737 | 775 | ||
738 | PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; | 776 | // There might be special things needed for implementing linksets. |
739 | PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; | 777 | Linkset.MakeDynamic(this); |
740 | } | 778 | } |
741 | } | 779 | } |
742 | 780 | ||
@@ -763,8 +801,9 @@ public sealed class BSPrim : BSPhysObject | |||
763 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); | 801 | m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); |
764 | } | 802 | } |
765 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); | 803 | CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); |
766 | PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; | 804 | |
767 | PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; | 805 | // Change collision info from a static object to a ghosty collision object |
806 | PhysBody.collisionType = CollisionType.VolumeDetect; | ||
768 | } | 807 | } |
769 | } | 808 | } |
770 | 809 | ||
@@ -839,15 +878,6 @@ public sealed class BSPrim : BSPhysObject | |||
839 | } | 878 | } |
840 | public override OMV.Vector3 RotationalVelocity { | 879 | public override OMV.Vector3 RotationalVelocity { |
841 | get { | 880 | get { |
842 | /* | ||
843 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
844 | // if close to zero, report zero | ||
845 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
846 | // zero the property in the physics engine. | ||
847 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
848 | return pv; | ||
849 | */ | ||
850 | |||
851 | return _rotationalVelocity; | 881 | return _rotationalVelocity; |
852 | } | 882 | } |
853 | set { | 883 | set { |
@@ -856,7 +886,8 @@ public sealed class BSPrim : BSPhysObject | |||
856 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() | 886 | PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() |
857 | { | 887 | { |
858 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | 888 | DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); |
859 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | 889 | if (PhysBody.HasPhysicalBody) |
890 | BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); | ||
860 | }); | 891 | }); |
861 | } | 892 | } |
862 | } | 893 | } |
@@ -891,8 +922,11 @@ public sealed class BSPrim : BSPhysObject | |||
891 | _buoyancy = value; | 922 | _buoyancy = value; |
892 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 923 | // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
893 | // Buoyancy is faked by changing the gravity applied to the object | 924 | // Buoyancy is faked by changing the gravity applied to the object |
894 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 925 | if (PhysBody.HasPhysicalBody) |
895 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | 926 | { |
927 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | ||
928 | BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); | ||
929 | } | ||
896 | } | 930 | } |
897 | } | 931 | } |
898 | 932 | ||
@@ -960,7 +994,8 @@ public sealed class BSPrim : BSPhysObject | |||
960 | } | 994 | } |
961 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); | 995 | DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum); |
962 | if (fSum != OMV.Vector3.Zero) | 996 | if (fSum != OMV.Vector3.Zero) |
963 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | 997 | if (PhysBody.HasPhysicalBody) |
998 | BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum); | ||
964 | }); | 999 | }); |
965 | } | 1000 | } |
966 | 1001 | ||
@@ -971,7 +1006,8 @@ public sealed class BSPrim : BSPhysObject | |||
971 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() | 1006 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate() |
972 | { | 1007 | { |
973 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); | 1008 | DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse); |
974 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | 1009 | if (PhysBody.HasPhysicalBody) |
1010 | BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse); | ||
975 | }); | 1011 | }); |
976 | } | 1012 | } |
977 | 1013 | ||
@@ -1007,18 +1043,23 @@ public sealed class BSPrim : BSPhysObject | |||
1007 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); | 1043 | DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum); |
1008 | if (fSum != OMV.Vector3.Zero) | 1044 | if (fSum != OMV.Vector3.Zero) |
1009 | { | 1045 | { |
1010 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | 1046 | if (PhysBody.HasPhysicalBody) |
1047 | BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum); | ||
1011 | _torque = fSum; | 1048 | _torque = fSum; |
1012 | } | 1049 | } |
1013 | }); | 1050 | }); |
1014 | } | 1051 | } |
1015 | // A torque impulse. | 1052 | // A torque impulse. |
1053 | // ApplyTorqueImpulse adds torque directly to the angularVelocity. | ||
1054 | // AddAngularForce accumulates the force and applied it to the angular velocity all at once. | ||
1055 | // Computed as: angularVelocity += impulse * inertia; | ||
1016 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) | 1056 | public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) |
1017 | { | 1057 | { |
1018 | OMV.Vector3 applyImpulse = impulse; | 1058 | OMV.Vector3 applyImpulse = impulse; |
1019 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() | 1059 | PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() |
1020 | { | 1060 | { |
1021 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | 1061 | if (PhysBody.HasPhysicalBody) |
1062 | BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); | ||
1022 | }); | 1063 | }); |
1023 | } | 1064 | } |
1024 | 1065 | ||
@@ -1326,7 +1367,7 @@ public sealed class BSPrim : BSPhysObject | |||
1326 | // Rebuild the geometry and object. | 1367 | // Rebuild the geometry and object. |
1327 | // This is called when the shape changes so we need to recreate the mesh/hull. | 1368 | // This is called when the shape changes so we need to recreate the mesh/hull. |
1328 | // Called at taint-time!!! | 1369 | // Called at taint-time!!! |
1329 | private void CreateGeomAndObject(bool forceRebuild) | 1370 | public void CreateGeomAndObject(bool forceRebuild) |
1330 | { | 1371 | { |
1331 | // If this prim is part of a linkset, we must remove and restore the physical | 1372 | // If this prim is part of a linkset, we must remove and restore the physical |
1332 | // links if the body is rebuilt. | 1373 | // links if the body is rebuilt. |
@@ -1336,12 +1377,11 @@ public sealed class BSPrim : BSPhysObject | |||
1336 | // Create the correct physical representation for this type of object. | 1377 | // Create the correct physical representation for this type of object. |
1337 | // Updates PhysBody and PhysShape with the new information. | 1378 | // Updates PhysBody and PhysShape with the new information. |
1338 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. | 1379 | // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. |
1339 | // Returns 'true' if either the body or the shape was changed. | ||
1340 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) | 1380 | PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) |
1341 | { | 1381 | { |
1342 | // Called if the current prim body is about to be destroyed. | 1382 | // Called if the current prim body is about to be destroyed. |
1343 | // Remove all the physical dependencies on the old body. | 1383 | // Remove all the physical dependencies on the old body. |
1344 | // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) | 1384 | // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...) |
1345 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); | 1385 | needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); |
1346 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); | 1386 | needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); |
1347 | }); | 1387 | }); |
@@ -1381,54 +1421,16 @@ public sealed class BSPrim : BSPhysObject | |||
1381 | 1421 | ||
1382 | public override void UpdateProperties(EntityProperties entprop) | 1422 | public override void UpdateProperties(EntityProperties entprop) |
1383 | { | 1423 | { |
1384 | /* | 1424 | // Updates only for individual prims and for the root object of a linkset. |
1385 | UpdatedProperties changed = 0; | 1425 | if (Linkset.IsRoot(this)) |
1386 | // assign to the local variables so the normal set action does not happen | ||
1387 | // if (_position != entprop.Position) | ||
1388 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1389 | { | ||
1390 | _position = entprop.Position; | ||
1391 | changed |= UpdatedProperties.Position; | ||
1392 | } | ||
1393 | // if (_orientation != entprop.Rotation) | ||
1394 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1395 | { | ||
1396 | _orientation = entprop.Rotation; | ||
1397 | changed |= UpdatedProperties.Rotation; | ||
1398 | } | ||
1399 | // if (_velocity != entprop.Velocity) | ||
1400 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1401 | { | ||
1402 | _velocity = entprop.Velocity; | ||
1403 | changed |= UpdatedProperties.Velocity; | ||
1404 | } | ||
1405 | // if (_acceleration != entprop.Acceleration) | ||
1406 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1407 | { | ||
1408 | _acceleration = entprop.Acceleration; | ||
1409 | changed |= UpdatedProperties.Acceleration; | ||
1410 | } | ||
1411 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1412 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1413 | { | ||
1414 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1415 | changed |= UpdatedProperties.RotationalVel; | ||
1416 | } | ||
1417 | if (changed != 0) | ||
1418 | { | 1426 | { |
1419 | // Only update the position of single objects and linkset roots | 1427 | // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet |
1420 | if (Linkset.IsRoot(this)) | 1428 | // TODO: handle physics introduced by Bullet with computed vehicle physics. |
1429 | if (_vehicle.IsActive) | ||
1421 | { | 1430 | { |
1422 | base.RequestPhysicsterseUpdate(); | 1431 | entprop.RotationalVelocity = OMV.Vector3.Zero; |
1423 | } | 1432 | } |
1424 | } | ||
1425 | */ | ||
1426 | |||
1427 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1428 | 1433 | ||
1429 | // Updates only for individual prims and for the root object of a linkset. | ||
1430 | if (Linkset.IsRoot(this)) | ||
1431 | { | ||
1432 | // Assign directly to the local variables so the normal set action does not happen | 1434 | // Assign directly to the local variables so the normal set action does not happen |
1433 | _position = entprop.Position; | 1435 | _position = entprop.Position; |
1434 | _orientation = entprop.Rotation; | 1436 | _orientation = entprop.Rotation; |
@@ -1437,21 +1439,19 @@ public sealed class BSPrim : BSPhysObject | |||
1437 | _rotationalVelocity = entprop.RotationalVelocity; | 1439 | _rotationalVelocity = entprop.RotationalVelocity; |
1438 | 1440 | ||
1439 | // The sanity check can change the velocity and/or position. | 1441 | // The sanity check can change the velocity and/or position. |
1440 | if (PositionSanityCheck(true)) | 1442 | if (IsPhysical && PositionSanityCheck(true)) |
1441 | { | 1443 | { |
1442 | entprop.Position = _position; | 1444 | entprop.Position = _position; |
1443 | entprop.Velocity = _velocity; | 1445 | entprop.Velocity = _velocity; |
1444 | } | 1446 | } |
1445 | 1447 | ||
1446 | // remember the current and last set values | 1448 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG |
1447 | LastEntityProperties = CurrentEntityProperties; | ||
1448 | CurrentEntityProperties = entprop; | ||
1449 | |||
1450 | OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; | ||
1451 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", | 1449 | DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", |
1452 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); | 1450 | LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); |
1453 | 1451 | ||
1454 | // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG | 1452 | // remember the current and last set values |
1453 | LastEntityProperties = CurrentEntityProperties; | ||
1454 | CurrentEntityProperties = entprop; | ||
1455 | 1455 | ||
1456 | base.RequestPhysicsterseUpdate(); | 1456 | base.RequestPhysicsterseUpdate(); |
1457 | } | 1457 | } |
@@ -1466,7 +1466,7 @@ public sealed class BSPrim : BSPhysObject | |||
1466 | */ | 1466 | */ |
1467 | 1467 | ||
1468 | // The linkset implimentation might want to know about this. | 1468 | // The linkset implimentation might want to know about this. |
1469 | Linkset.UpdateProperties(this); | 1469 | Linkset.UpdateProperties(this, true); |
1470 | } | 1470 | } |
1471 | } | 1471 | } |
1472 | } | 1472 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 27a78d1..069cb0d 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -39,23 +39,10 @@ using log4net; | |||
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
42 | // Test sculpties (verified that they don't work) | ||
43 | // Compute physics FPS reasonably | ||
44 | // Based on material, set density and friction | 42 | // Based on material, set density and friction |
45 | // Don't use constraints in linksets of non-physical objects. Means having to move children manually. | ||
46 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | ||
47 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | ||
48 | // At the moment, physical and phantom causes object to drop through the terrain | ||
49 | // Physical phantom objects and related typing (collision options ) | ||
50 | // Check out llVolumeDetect. Must do something for that. | ||
51 | // Use collision masks for collision with terrain and phantom objects | ||
52 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | 43 | // More efficient memory usage when passing hull information from BSPrim to BulletSim |
53 | // Should prim.link() and prim.delink() membership checking happen at taint time? | ||
54 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once. | ||
55 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | 44 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect |
56 | // Implement LockAngularMotion | 45 | // Implement LockAngularMotion |
57 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | ||
58 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | ||
59 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 46 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
60 | // Check terrain size. 128 or 127? | 47 | // Check terrain size. 128 or 127? |
61 | // Raycast | 48 | // Raycast |
@@ -109,6 +96,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
109 | public long SimulationStep { get { return m_simulationStep; } } | 96 | public long SimulationStep { get { return m_simulationStep; } } |
110 | private int m_taintsToProcessPerStep; | 97 | private int m_taintsToProcessPerStep; |
111 | 98 | ||
99 | public delegate void PreStepAction(float timeStep); | ||
100 | public event PreStepAction BeforeStep; | ||
101 | |||
112 | // 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 |
113 | // 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 |
114 | public int SimulationNowTime { get; private set; } | 104 | public int SimulationNowTime { get; private set; } |
@@ -140,7 +130,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
140 | public const uint GROUNDPLANE_ID = 1; | 130 | public const uint GROUNDPLANE_ID = 1; |
141 | 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 |
142 | 132 | ||
143 | private float m_waterLevel; | 133 | public float SimpleWaterLevel { get; set; } |
144 | public BSTerrainManager TerrainManager { get; private set; } | 134 | public BSTerrainManager TerrainManager { get; private set; } |
145 | 135 | ||
146 | public ConfigurationParameters Params | 136 | public ConfigurationParameters Params |
@@ -195,8 +185,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
195 | private string m_physicsLoggingDir; | 185 | private string m_physicsLoggingDir; |
196 | private string m_physicsLoggingPrefix; | 186 | private string m_physicsLoggingPrefix; |
197 | private int m_physicsLoggingFileMinutes; | 187 | private int m_physicsLoggingFileMinutes; |
188 | private bool m_physicsLoggingDoFlush; | ||
198 | // 'true' of the vehicle code is to log lots of details | 189 | // 'true' of the vehicle code is to log lots of details |
199 | public bool VehicleLoggingEnabled { get; private set; } | 190 | public bool VehicleLoggingEnabled { get; private set; } |
191 | public bool VehiclePhysicalLoggingEnabled { get; private set; } | ||
200 | 192 | ||
201 | #region Construction and Initialization | 193 | #region Construction and Initialization |
202 | public BSScene(string identifier) | 194 | public BSScene(string identifier) |
@@ -234,6 +226,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
234 | if (m_physicsLoggingEnabled) | 226 | if (m_physicsLoggingEnabled) |
235 | { | 227 | { |
236 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | 228 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); |
229 | PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages. | ||
237 | } | 230 | } |
238 | else | 231 | else |
239 | { | 232 | { |
@@ -302,12 +295,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
302 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | 295 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); |
303 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); | 296 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); |
304 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | 297 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); |
298 | m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false); | ||
305 | // Very detailed logging for vehicle debugging | 299 | // Very detailed logging for vehicle debugging |
306 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | 300 | VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); |
301 | VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false); | ||
307 | 302 | ||
308 | // Do any replacements in the parameters | 303 | // Do any replacements in the parameters |
309 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); | 304 | m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); |
310 | } | 305 | } |
306 | |||
307 | // The material characteristics. | ||
308 | BSMaterials.InitializeFromDefaults(Params); | ||
309 | if (pConfig != null) | ||
310 | { | ||
311 | // Let the user add new and interesting material property values. | ||
312 | BSMaterials.InitializefromParameters(pConfig); | ||
313 | } | ||
311 | } | 314 | } |
312 | } | 315 | } |
313 | 316 | ||
@@ -345,8 +348,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
345 | // make sure no stepping happens while we're deleting stuff | 348 | // make sure no stepping happens while we're deleting stuff |
346 | m_initialized = false; | 349 | m_initialized = false; |
347 | 350 | ||
348 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
349 | |||
350 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) | 351 | foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) |
351 | { | 352 | { |
352 | kvp.Value.Destroy(); | 353 | kvp.Value.Destroy(); |
@@ -366,6 +367,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
366 | Shapes = null; | 367 | Shapes = null; |
367 | } | 368 | } |
368 | 369 | ||
370 | if (TerrainManager != null) | ||
371 | { | ||
372 | TerrainManager.ReleaseGroundPlaneAndTerrain(); | ||
373 | TerrainManager.Dispose(); | ||
374 | TerrainManager = null; | ||
375 | } | ||
376 | |||
369 | // Anything left in the unmanaged code should be cleaned out | 377 | // Anything left in the unmanaged code should be cleaned out |
370 | BulletSimAPI.Shutdown2(World.ptr); | 378 | BulletSimAPI.Shutdown2(World.ptr); |
371 | 379 | ||
@@ -490,8 +498,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
490 | ProcessTaints(); | 498 | ProcessTaints(); |
491 | 499 | ||
492 | // Some of the prims operate with special vehicle properties | 500 | // Some of the prims operate with special vehicle properties |
493 | ProcessVehicles(timeStep); | 501 | DoPreStepActions(timeStep); |
494 | ProcessTaints(); // the vehicles might have added taints | 502 | |
503 | // the prestep actions might have added taints | ||
504 | ProcessTaints(); | ||
495 | 505 | ||
496 | // step the physical world one interval | 506 | // step the physical world one interval |
497 | m_simulationStep++; | 507 | m_simulationStep++; |
@@ -499,16 +509,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
499 | 509 | ||
500 | try | 510 | try |
501 | { | 511 | { |
502 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 512 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG |
503 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); | 513 | if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); |
504 | 514 | ||
505 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, | 515 | numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, |
506 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); | 516 | out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr); |
507 | 517 | ||
508 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); | 518 | if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); |
509 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", | 519 | DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}", |
510 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); | 520 | DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, |
511 | if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG | 521 | updatedEntityCount, collidersCount, ObjectsWithCollisions.Count); |
522 | if (VehiclePhysicalLoggingEnabled) DumpVehicles(); // DEBUG | ||
512 | } | 523 | } |
513 | catch (Exception e) | 524 | catch (Exception e) |
514 | { | 525 | { |
@@ -520,9 +531,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
520 | collidersCount = 0; | 531 | collidersCount = 0; |
521 | } | 532 | } |
522 | 533 | ||
523 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in | 534 | // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in. |
524 | 535 | ||
525 | // Get a value for 'now' so all the collision and update routines don't have to get their own | 536 | // Get a value for 'now' so all the collision and update routines don't have to get their own. |
526 | SimulationNowTime = Util.EnvironmentTickCount(); | 537 | SimulationNowTime = Util.EnvironmentTickCount(); |
527 | 538 | ||
528 | // If there were collisions, process them by sending the event to the prim. | 539 | // If there were collisions, process them by sending the event to the prim. |
@@ -562,12 +573,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
562 | 573 | ||
563 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. | 574 | // Objects that are done colliding are removed from the ObjectsWithCollisions list. |
564 | // Not done above because it is inside an iteration of ObjectWithCollisions. | 575 | // Not done above because it is inside an iteration of ObjectWithCollisions. |
576 | // This complex collision processing is required to create an empty collision | ||
577 | // event call after all collisions have happened on an object. This enables | ||
578 | // the simulator to generate the 'collision end' event. | ||
565 | if (ObjectsWithNoMoreCollisions.Count > 0) | 579 | if (ObjectsWithNoMoreCollisions.Count > 0) |
566 | { | 580 | { |
567 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) | 581 | foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) |
568 | ObjectsWithCollisions.Remove(po); | 582 | ObjectsWithCollisions.Remove(po); |
569 | ObjectsWithNoMoreCollisions.Clear(); | 583 | ObjectsWithNoMoreCollisions.Clear(); |
570 | } | 584 | } |
585 | // Done with collisions. | ||
571 | 586 | ||
572 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine | 587 | // If any of the objects had updated properties, tell the object it has been changed by the physics engine |
573 | if (updatedEntityCount > 0) | 588 | if (updatedEntityCount > 0) |
@@ -585,15 +600,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
585 | 600 | ||
586 | ProcessPostStepTaints(); | 601 | ProcessPostStepTaints(); |
587 | 602 | ||
588 | // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. | 603 | // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world. |
589 | // Only enable this in a limited test world with few objects. | 604 | // Only enable this in a limited test world with few objects. |
590 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG | 605 | // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG |
591 | 606 | ||
592 | // The physics engine returns the number of milliseconds it simulated this call. | 607 | // The physics engine returns the number of milliseconds it simulated this call. |
593 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. | 608 | // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. |
594 | // We multiply by 55 to give a recognizable running rate (55 or less). | 609 | // Multiply by 55 to give a nominal frame rate of 55. |
595 | return numSubSteps * m_fixedTimeStep * 1000 * 55; | 610 | return (float)numSubSteps * m_fixedTimeStep * 1000f * 55f; |
596 | // return timeStep * 1000 * 55; | ||
597 | } | 611 | } |
598 | 612 | ||
599 | // Something has collided | 613 | // Something has collided |
@@ -639,12 +653,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
639 | 653 | ||
640 | public override void SetWaterLevel(float baseheight) | 654 | public override void SetWaterLevel(float baseheight) |
641 | { | 655 | { |
642 | m_waterLevel = baseheight; | 656 | SimpleWaterLevel = baseheight; |
643 | } | ||
644 | // Someday.... | ||
645 | public float GetWaterLevelAtXYZ(Vector3 loc) | ||
646 | { | ||
647 | return m_waterLevel; | ||
648 | } | 657 | } |
649 | 658 | ||
650 | public override void DeleteTerrain() | 659 | public override void DeleteTerrain() |
@@ -915,6 +924,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
915 | } | 924 | } |
916 | } | 925 | } |
917 | 926 | ||
927 | private void DoPreStepActions(float timeStep) | ||
928 | { | ||
929 | ProcessVehicles(timeStep); | ||
930 | |||
931 | PreStepAction actions = BeforeStep; | ||
932 | if (actions != null) | ||
933 | actions(timeStep); | ||
934 | |||
935 | } | ||
936 | |||
918 | // Some prims have extra vehicle actions | 937 | // Some prims have extra vehicle actions |
919 | // Called at taint time! | 938 | // Called at taint time! |
920 | private void ProcessVehicles(float timeStep) | 939 | private void ProcessVehicles(float timeStep) |
@@ -979,6 +998,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
979 | // Should handle fetching the right type from the ini file and converting it. | 998 | // Should handle fetching the right type from the ini file and converting it. |
980 | // -- a delegate for getting the value as a float | 999 | // -- a delegate for getting the value as a float |
981 | // -- a delegate for setting the value from a float | 1000 | // -- a delegate for setting the value from a float |
1001 | // -- an optional delegate to update the value in the world. Most often used to | ||
1002 | // push the new value to an in-world object. | ||
982 | // | 1003 | // |
983 | // The single letter parameters for the delegates are: | 1004 | // The single letter parameters for the delegates are: |
984 | // s = BSScene | 1005 | // s = BSScene |
@@ -1069,7 +1090,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1069 | (s,p,l,v) => { s.PID_P = v; } ), | 1090 | (s,p,l,v) => { s.PID_P = v; } ), |
1070 | 1091 | ||
1071 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", | 1092 | new ParameterDefn("DefaultFriction", "Friction factor used on new objects", |
1072 | 0.5f, | 1093 | 0.2f, |
1073 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, | 1094 | (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); }, |
1074 | (s) => { return s.m_params[0].defaultFriction; }, | 1095 | (s) => { return s.m_params[0].defaultFriction; }, |
1075 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), | 1096 | (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ), |
@@ -1084,7 +1105,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1084 | (s) => { return s.m_params[0].defaultRestitution; }, | 1105 | (s) => { return s.m_params[0].defaultRestitution; }, |
1085 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), | 1106 | (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ), |
1086 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", | 1107 | new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)", |
1087 | 0f, | 1108 | 0.04f, |
1088 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, | 1109 | (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); }, |
1089 | (s) => { return s.m_params[0].collisionMargin; }, | 1110 | (s) => { return s.m_params[0].collisionMargin; }, |
1090 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), | 1111 | (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ), |
@@ -1151,7 +1172,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1151 | (s) => { return s.m_params[0].terrainImplementation; }, | 1172 | (s) => { return s.m_params[0].terrainImplementation; }, |
1152 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), | 1173 | (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ), |
1153 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , | 1174 | new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" , |
1154 | 0.5f, | 1175 | 0.3f, |
1155 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, | 1176 | (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); }, |
1156 | (s) => { return s.m_params[0].terrainFriction; }, | 1177 | (s) => { return s.m_params[0].terrainFriction; }, |
1157 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), | 1178 | (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ), |
@@ -1165,13 +1186,19 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1165 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, | 1186 | (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); }, |
1166 | (s) => { return s.m_params[0].terrainRestitution; }, | 1187 | (s) => { return s.m_params[0].terrainRestitution; }, |
1167 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), | 1188 | (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ), |
1189 | new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" , | ||
1190 | 0.04f, | ||
1191 | (s,cf,p,v) => { s.m_params[0].terrainCollisionMargin = cf.GetFloat(p, v); }, | ||
1192 | (s) => { return s.m_params[0].terrainCollisionMargin; }, | ||
1193 | (s,p,l,v) => { s.m_params[0].terrainCollisionMargin = v; /* TODO: set on real terrain */ } ), | ||
1194 | |||
1168 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", | 1195 | new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.", |
1169 | 0.2f, | 1196 | 0.2f, |
1170 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, | 1197 | (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); }, |
1171 | (s) => { return s.m_params[0].avatarFriction; }, | 1198 | (s) => { return s.m_params[0].avatarFriction; }, |
1172 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), | 1199 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ), |
1173 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", | 1200 | new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.", |
1174 | 10f, | 1201 | 10.0f, |
1175 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, | 1202 | (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); }, |
1176 | (s) => { return s.m_params[0].avatarStandingFriction; }, | 1203 | (s) => { return s.m_params[0].avatarStandingFriction; }, |
1177 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), | 1204 | (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ), |
@@ -1206,6 +1233,11 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1206 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, | 1233 | (s) => { return s.m_params[0].avatarContactProcessingThreshold; }, |
1207 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), | 1234 | (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ), |
1208 | 1235 | ||
1236 | new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)", | ||
1237 | 0.95f, | ||
1238 | (s,cf,p,v) => { s.m_params[0].vehicleAngularDamping = cf.GetFloat(p, v); }, | ||
1239 | (s) => { return s.m_params[0].vehicleAngularDamping; }, | ||
1240 | (s,p,l,v) => { s.m_params[0].vehicleAngularDamping = v; } ), | ||
1209 | 1241 | ||
1210 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", | 1242 | new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)", |
1211 | 0f, | 1243 | 0f, |
@@ -1487,7 +1519,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters | |||
1487 | { | 1519 | { |
1488 | PhysicsLogging.Write(msg, args); | 1520 | PhysicsLogging.Write(msg, args); |
1489 | // Add the Flush() if debugging crashes. Gets all the messages written out. | 1521 | // Add the Flush() if debugging crashes. Gets all the messages written out. |
1490 | // PhysicsLogging.Flush(); | 1522 | if (m_physicsLoggingDoFlush) PhysicsLogging.Flush(); |
1491 | } | 1523 | } |
1492 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. | 1524 | // Used to fill in the LocalID when there isn't one. It's the correct number of characters. |
1493 | public const string DetailLogZero = "0000000000"; | 1525 | public const string DetailLogZero = "0000000000"; |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs index 892c34b..d6e2fe9 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() |
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable | |||
119 | return ret; | 126 | return ret; |
120 | } | 127 | } |
121 | 128 | ||
129 | public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim) | ||
130 | { | ||
131 | return GetBodyAndShape(forceRebuild, sim, prim, null, null); | ||
132 | } | ||
133 | |||
122 | // Track another user of a body. | 134 | // Track another user of a body. |
123 | // We presume the caller has allocated the body. | 135 | // We presume the caller has allocated the body. |
124 | // Bodies only have one user so the body is just put into the world if not already there. | 136 | // Bodies only have one user so the body is just put into the world if not already there. |
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable | |||
126 | { | 138 | { |
127 | lock (m_collectionActivityLock) | 139 | lock (m_collectionActivityLock) |
128 | { | 140 | { |
129 | DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); | 141 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); |
130 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() | 142 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() |
131 | { | 143 | { |
132 | if (!BulletSimAPI.IsInWorld2(body.ptr)) | 144 | if (!BulletSimAPI.IsInWorld2(body.ptr)) |
133 | { | 145 | { |
134 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); | 146 | BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); |
135 | DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); | 147 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); |
136 | } | 148 | } |
137 | }); | 149 | }); |
138 | } | 150 | } |
@@ -142,14 +154,14 @@ public sealed class BSShapeCollection : IDisposable | |||
142 | // Called when releasing use of a BSBody. BSShape is handled separately. | 154 | // Called when releasing use of a BSBody. BSShape is handled separately. |
143 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) | 155 | public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) |
144 | { | 156 | { |
145 | if (body.ptr == IntPtr.Zero) | 157 | if (!body.HasPhysicalBody) |
146 | return; | 158 | return; |
147 | 159 | ||
148 | lock (m_collectionActivityLock) | 160 | lock (m_collectionActivityLock) |
149 | { | 161 | { |
150 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() | 162 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() |
151 | { | 163 | { |
152 | DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", | 164 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", |
153 | body.ID, body, inTaintTime); | 165 | body.ID, body, inTaintTime); |
154 | // If the caller needs to know the old body is going away, pass the event up. | 166 | // If the caller needs to know the old body is going away, pass the event up. |
155 | if (bodyCallback != null) bodyCallback(body); | 167 | if (bodyCallback != null) bodyCallback(body); |
@@ -157,7 +169,7 @@ public sealed class BSShapeCollection : IDisposable | |||
157 | if (BulletSimAPI.IsInWorld2(body.ptr)) | 169 | if (BulletSimAPI.IsInWorld2(body.ptr)) |
158 | { | 170 | { |
159 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); | 171 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); |
160 | DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); | 172 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); |
161 | } | 173 | } |
162 | 174 | ||
163 | // Zero any reference to the shape so it is not freed when the body is deleted. | 175 | // Zero any reference to the shape so it is not freed when the body is deleted. |
@@ -184,7 +196,7 @@ public sealed class BSShapeCollection : IDisposable | |||
184 | { | 196 | { |
185 | // There is an existing instance of this mesh. | 197 | // There is an existing instance of this mesh. |
186 | meshDesc.referenceCount++; | 198 | meshDesc.referenceCount++; |
187 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", | 199 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", |
188 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 200 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
189 | } | 201 | } |
190 | else | 202 | else |
@@ -194,7 +206,7 @@ public sealed class BSShapeCollection : IDisposable | |||
194 | meshDesc.shapeKey = shape.shapeKey; | 206 | meshDesc.shapeKey = shape.shapeKey; |
195 | // We keep a reference to the underlying IMesh data so a hull can be built | 207 | // We keep a reference to the underlying IMesh data so a hull can be built |
196 | meshDesc.referenceCount = 1; | 208 | meshDesc.referenceCount = 1; |
197 | DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", | 209 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", |
198 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); | 210 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); |
199 | ret = true; | 211 | ret = true; |
200 | } | 212 | } |
@@ -207,7 +219,7 @@ public sealed class BSShapeCollection : IDisposable | |||
207 | { | 219 | { |
208 | // There is an existing instance of this hull. | 220 | // There is an existing instance of this hull. |
209 | hullDesc.referenceCount++; | 221 | hullDesc.referenceCount++; |
210 | DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", | 222 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", |
211 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 223 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
212 | } | 224 | } |
213 | else | 225 | else |
@@ -216,7 +228,7 @@ public sealed class BSShapeCollection : IDisposable | |||
216 | hullDesc.ptr = shape.ptr; | 228 | hullDesc.ptr = shape.ptr; |
217 | hullDesc.shapeKey = shape.shapeKey; | 229 | hullDesc.shapeKey = shape.shapeKey; |
218 | hullDesc.referenceCount = 1; | 230 | hullDesc.referenceCount = 1; |
219 | DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", | 231 | if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", |
220 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); | 232 | BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); |
221 | ret = true; | 233 | ret = true; |
222 | 234 | ||
@@ -236,17 +248,17 @@ public sealed class BSShapeCollection : IDisposable | |||
236 | // Release the usage of a shape. | 248 | // Release the usage of a shape. |
237 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) | 249 | public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) |
238 | { | 250 | { |
239 | if (shape.ptr == IntPtr.Zero) | 251 | if (!shape.HasPhysicalShape) |
240 | return; | 252 | return; |
241 | 253 | ||
242 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() | 254 | PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() |
243 | { | 255 | { |
244 | if (shape.ptr != IntPtr.Zero) | 256 | if (shape.HasPhysicalShape) |
245 | { | 257 | { |
246 | if (shape.isNativeShape) | 258 | if (shape.isNativeShape) |
247 | { | 259 | { |
248 | // Native shapes are not tracked and are released immediately | 260 | // Native shapes are not tracked and are released immediately |
249 | DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", | 261 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", |
250 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); | 262 | BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); |
251 | if (shapeCallback != null) shapeCallback(shape); | 263 | if (shapeCallback != null) shapeCallback(shape); |
252 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); | 264 | BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); |
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable | |||
286 | if (shapeCallback != null) shapeCallback(shape); | 298 | if (shapeCallback != null) shapeCallback(shape); |
287 | meshDesc.lastReferenced = System.DateTime.Now; | 299 | meshDesc.lastReferenced = System.DateTime.Now; |
288 | Meshes[shape.shapeKey] = meshDesc; | 300 | Meshes[shape.shapeKey] = meshDesc; |
289 | DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", | 301 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", |
290 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); | 302 | BSScene.DetailLogZero, shape, meshDesc.referenceCount); |
291 | 303 | ||
292 | } | 304 | } |
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable | |||
307 | 319 | ||
308 | hullDesc.lastReferenced = System.DateTime.Now; | 320 | hullDesc.lastReferenced = System.DateTime.Now; |
309 | Hulls[shape.shapeKey] = hullDesc; | 321 | Hulls[shape.shapeKey] = hullDesc; |
310 | DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", | 322 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", |
311 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); | 323 | BSScene.DetailLogZero, shape, hullDesc.referenceCount); |
312 | } | 324 | } |
313 | } | 325 | } |
@@ -325,13 +337,13 @@ public sealed class BSShapeCollection : IDisposable | |||
325 | // Failed the sanity check!! | 337 | // Failed the sanity check!! |
326 | PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", | 338 | 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")); | 339 | LogHeader, shape.type, shape.ptr.ToString("X")); |
328 | DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", | 340 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", |
329 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); | 341 | BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); |
330 | return; | 342 | return; |
331 | } | 343 | } |
332 | 344 | ||
333 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); | 345 | int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); |
334 | DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); | 346 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); |
335 | 347 | ||
336 | for (int ii = numChildren - 1; ii >= 0; ii--) | 348 | for (int ii = numChildren - 1; ii >= 0; ii--) |
337 | { | 349 | { |
@@ -379,7 +391,7 @@ public sealed class BSShapeCollection : IDisposable | |||
379 | } | 391 | } |
380 | } | 392 | } |
381 | 393 | ||
382 | DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); | 394 | if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); |
383 | 395 | ||
384 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) | 396 | if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) |
385 | { | 397 | { |
@@ -408,19 +420,19 @@ public sealed class BSShapeCollection : IDisposable | |||
408 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) | 420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) |
409 | { | 421 | { |
410 | // an avatar capsule is close to a native shape (it is not shared) | 422 | // an avatar capsule is close to a native shape (it is not shared) |
411 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, | 423 | GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, |
412 | FixedShapeKey.KEY_CAPSULE, shapeCallback); | 424 | FixedShapeKey.KEY_CAPSULE, shapeCallback); |
413 | DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); | 425 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape); |
414 | ret = true; | 426 | ret = true; |
415 | haveShape = true; | 427 | haveShape = true; |
416 | } | 428 | } |
417 | 429 | ||
418 | // Compound shapes are handled special as they are rebuilt from scratch. | 430 | // Compound shapes are handled special as they are rebuilt from scratch. |
419 | // This isn't too great a hardship since most of the child shapes will already been created. | 431 | // This isn't too great a hardship since most of the child shapes will have already been created. |
420 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) | 432 | if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) |
421 | { | 433 | { |
422 | ret = GetReferenceToCompoundShape(prim, shapeCallback); | 434 | ret = GetReferenceToCompoundShape(prim, shapeCallback); |
423 | DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); | 435 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); |
424 | haveShape = true; | 436 | haveShape = true; |
425 | } | 437 | } |
426 | 438 | ||
@@ -433,7 +445,7 @@ public sealed class BSShapeCollection : IDisposable | |||
433 | } | 445 | } |
434 | 446 | ||
435 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. | 447 | // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. |
436 | private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 448 | public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
437 | { | 449 | { |
438 | bool ret = false; | 450 | bool ret = false; |
439 | bool haveShape = false; | 451 | bool haveShape = false; |
@@ -453,19 +465,27 @@ public sealed class BSShapeCollection : IDisposable | |||
453 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 | 465 | && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 |
454 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) | 466 | && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) |
455 | { | 467 | { |
468 | // Get the scale of any existing shape so we can see if the new shape is same native type and same size. | ||
469 | OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero; | ||
470 | if (prim.PhysShape.HasPhysicalShape) | ||
471 | scaleOfExistingShape = BulletSimAPI.GetLocalScaling2(prim.PhysShape.ptr); | ||
472 | |||
473 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}", | ||
474 | prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type); | ||
475 | |||
456 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal | 476 | // It doesn't look like Bullet scales spheres so make sure the scales are all equal |
457 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) | 477 | if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) |
458 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) | 478 | && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) |
459 | { | 479 | { |
460 | haveShape = true; | 480 | haveShape = true; |
461 | if (forceRebuild | 481 | if (forceRebuild |
462 | || prim.Scale != prim.Size | 482 | || prim.Scale != scaleOfExistingShape |
463 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE | 483 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE |
464 | ) | 484 | ) |
465 | { | 485 | { |
466 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, | 486 | ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, |
467 | FixedShapeKey.KEY_SPHERE, shapeCallback); | 487 | FixedShapeKey.KEY_SPHERE, shapeCallback); |
468 | DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", | 488 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", |
469 | prim.LocalID, forceRebuild, prim.PhysShape); | 489 | prim.LocalID, forceRebuild, prim.PhysShape); |
470 | } | 490 | } |
471 | } | 491 | } |
@@ -473,13 +493,13 @@ public sealed class BSShapeCollection : IDisposable | |||
473 | { | 493 | { |
474 | haveShape = true; | 494 | haveShape = true; |
475 | if (forceRebuild | 495 | if (forceRebuild |
476 | || prim.Scale != prim.Size | 496 | || prim.Scale != scaleOfExistingShape |
477 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX | 497 | || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX |
478 | ) | 498 | ) |
479 | { | 499 | { |
480 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, | 500 | ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, |
481 | FixedShapeKey.KEY_BOX, shapeCallback); | 501 | FixedShapeKey.KEY_BOX, shapeCallback); |
482 | DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", | 502 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", |
483 | prim.LocalID, forceRebuild, prim.PhysShape); | 503 | prim.LocalID, forceRebuild, prim.PhysShape); |
484 | } | 504 | } |
485 | } | 505 | } |
@@ -504,13 +524,13 @@ public sealed class BSShapeCollection : IDisposable | |||
504 | { | 524 | { |
505 | // Update prim.BSShape to reference a hull of this shape. | 525 | // Update prim.BSShape to reference a hull of this shape. |
506 | ret = GetReferenceToHull(prim,shapeCallback); | 526 | ret = GetReferenceToHull(prim,shapeCallback); |
507 | DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", | 527 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", |
508 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 528 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
509 | } | 529 | } |
510 | else | 530 | else |
511 | { | 531 | { |
512 | ret = GetReferenceToMesh(prim, shapeCallback); | 532 | ret = GetReferenceToMesh(prim, shapeCallback); |
513 | DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", | 533 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", |
514 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); | 534 | prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); |
515 | } | 535 | } |
516 | return ret; | 536 | return ret; |
@@ -528,9 +548,10 @@ public sealed class BSShapeCollection : IDisposable | |||
528 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); | 548 | BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); |
529 | 549 | ||
530 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. | 550 | // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. |
531 | DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", | 551 | if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", |
532 | prim.LocalID, newShape, prim.Scale); | 552 | prim.LocalID, newShape, prim.Scale); |
533 | 553 | ||
554 | // native shapes are scaled by Bullet | ||
534 | prim.PhysShape = newShape; | 555 | prim.PhysShape = newShape; |
535 | return true; | 556 | return true; |
536 | } | 557 | } |
@@ -554,16 +575,14 @@ public sealed class BSShapeCollection : IDisposable | |||
554 | newShape = new BulletShape( | 575 | newShape = new BulletShape( |
555 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) | 576 | BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) |
556 | , shapeType); | 577 | , shapeType); |
557 | DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); | 578 | if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); |
558 | } | 579 | } |
559 | else | 580 | else |
560 | { | 581 | { |
561 | // Native shapes are scaled in Bullet so set the scaling to the size | 582 | // Native shapes are scaled in Bullet so set the scaling to the size |
562 | prim.Scale = prim.Size; | ||
563 | nativeShapeData.Scale = prim.Scale; | ||
564 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); | 583 | newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType); |
565 | } | 584 | } |
566 | if (newShape.ptr == IntPtr.Zero) | 585 | if (!newShape.HasPhysicalShape) |
567 | { | 586 | { |
568 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", | 587 | PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", |
569 | LogHeader, prim.LocalID, shapeType); | 588 | LogHeader, prim.LocalID, shapeType); |
@@ -580,7 +599,7 @@ public sealed class BSShapeCollection : IDisposable | |||
580 | // Called at taint-time! | 599 | // Called at taint-time! |
581 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) | 600 | private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) |
582 | { | 601 | { |
583 | BulletShape newShape = new BulletShape(IntPtr.Zero); | 602 | BulletShape newShape = new BulletShape(); |
584 | 603 | ||
585 | float lod; | 604 | float lod; |
586 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); | 605 | System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); |
@@ -589,7 +608,7 @@ public sealed class BSShapeCollection : IDisposable | |||
589 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) | 608 | if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) |
590 | return false; | 609 | return false; |
591 | 610 | ||
592 | DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", | 611 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", |
593 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); | 612 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); |
594 | 613 | ||
595 | // Since we're recreating new, get rid of the reference to the previous shape | 614 | // Since we're recreating new, get rid of the reference to the previous shape |
@@ -601,8 +620,6 @@ public sealed class BSShapeCollection : IDisposable | |||
601 | 620 | ||
602 | ReferenceShape(newShape); | 621 | ReferenceShape(newShape); |
603 | 622 | ||
604 | // meshes are already scaled by the meshmerizer | ||
605 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
606 | prim.PhysShape = newShape; | 623 | prim.PhysShape = newShape; |
607 | 624 | ||
608 | return true; // 'true' means a new shape has been added to this prim | 625 | return true; // 'true' means a new shape has been added to this prim |
@@ -620,8 +637,7 @@ public sealed class BSShapeCollection : IDisposable | |||
620 | } | 637 | } |
621 | else | 638 | else |
622 | { | 639 | { |
623 | // Pass false for physicalness as this creates some sort of bounding box which we don't need | 640 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
624 | meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); | ||
625 | 641 | ||
626 | if (meshData != null) | 642 | if (meshData != null) |
627 | { | 643 | { |
@@ -663,7 +679,7 @@ public sealed class BSShapeCollection : IDisposable | |||
663 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) | 679 | if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) |
664 | return false; | 680 | return false; |
665 | 681 | ||
666 | DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", | 682 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", |
667 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); | 683 | prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); |
668 | 684 | ||
669 | // Remove usage of the previous shape. | 685 | // Remove usage of the previous shape. |
@@ -674,8 +690,6 @@ public sealed class BSShapeCollection : IDisposable | |||
674 | 690 | ||
675 | ReferenceShape(newShape); | 691 | ReferenceShape(newShape); |
676 | 692 | ||
677 | // hulls are already scaled by the meshmerizer | ||
678 | prim.Scale = new OMV.Vector3(1f, 1f, 1f); | ||
679 | prim.PhysShape = newShape; | 693 | prim.PhysShape = newShape; |
680 | return true; // 'true' means a new shape has been added to this prim | 694 | return true; // 'true' means a new shape has been added to this prim |
681 | } | 695 | } |
@@ -694,8 +708,8 @@ public sealed class BSShapeCollection : IDisposable | |||
694 | else | 708 | else |
695 | { | 709 | { |
696 | // Build a new hull in the physical world | 710 | // 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 | 711 | // 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); | 712 | IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false); |
699 | if (meshData != null) | 713 | if (meshData != null) |
700 | { | 714 | { |
701 | 715 | ||
@@ -784,7 +798,7 @@ public sealed class BSShapeCollection : IDisposable | |||
784 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); | 798 | BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL); |
785 | newShape.shapeKey = newHullKey; | 799 | newShape.shapeKey = newHullKey; |
786 | 800 | ||
787 | return newShape; // 'true' means a new shape has been added to this prim | 801 | return newShape; |
788 | } | 802 | } |
789 | 803 | ||
790 | // Callback from convex hull creater with a newly created hull. | 804 | // Callback from convex hull creater with a newly created hull. |
@@ -809,7 +823,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. | 823 | // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. |
810 | CreateGeomMeshOrHull(prim, shapeCallback); | 824 | CreateGeomMeshOrHull(prim, shapeCallback); |
811 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); | 825 | BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); |
812 | DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", | 826 | if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", |
813 | prim.LocalID, cShape, prim.PhysShape); | 827 | prim.LocalID, cShape, prim.PhysShape); |
814 | 828 | ||
815 | prim.PhysShape = cShape; | 829 | prim.PhysShape = cShape; |
@@ -851,7 +865,7 @@ public sealed class BSShapeCollection : IDisposable | |||
851 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) | 865 | private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) |
852 | { | 866 | { |
853 | // If the shape was successfully created, nothing more to do | 867 | // If the shape was successfully created, nothing more to do |
854 | if (newShape.ptr != IntPtr.Zero) | 868 | if (newShape.HasPhysicalShape) |
855 | return newShape; | 869 | return newShape; |
856 | 870 | ||
857 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset | 871 | // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset |
@@ -910,7 +924,7 @@ public sealed class BSShapeCollection : IDisposable | |||
910 | bool ret = false; | 924 | bool ret = false; |
911 | 925 | ||
912 | // the mesh, hull or native shape must have already been created in Bullet | 926 | // the mesh, hull or native shape must have already been created in Bullet |
913 | bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); | 927 | bool mustRebuild = !prim.PhysBody.HasPhysicalBody; |
914 | 928 | ||
915 | // If there is an existing body, verify it's of an acceptable type. | 929 | // If there is an existing body, verify it's of an acceptable type. |
916 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. | 930 | // If not a solid object, body is a GhostObject. Otherwise a RigidBody. |
@@ -936,13 +950,13 @@ public sealed class BSShapeCollection : IDisposable | |||
936 | { | 950 | { |
937 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, | 951 | bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, |
938 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 952 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
939 | DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 953 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
940 | } | 954 | } |
941 | else | 955 | else |
942 | { | 956 | { |
943 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, | 957 | bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, |
944 | prim.LocalID, prim.RawPosition, prim.RawOrientation); | 958 | prim.LocalID, prim.RawPosition, prim.RawOrientation); |
945 | DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); | 959 | if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X")); |
946 | } | 960 | } |
947 | aBody = new BulletBody(prim.LocalID, bodyPtr); | 961 | aBody = new BulletBody(prim.LocalID, bodyPtr); |
948 | 962 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs index 3ca756c..2b120d6 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs | |||
@@ -93,7 +93,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
93 | { | 93 | { |
94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, | 94 | m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID, |
95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, | 95 | m_mapInfo.minCoords, m_mapInfo.maxCoords, |
96 | m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN); | 96 | m_mapInfo.heightMap, PhysicsScene.Params.terrainCollisionMargin); |
97 | 97 | ||
98 | // Create the terrain shape from the mapInfo | 98 | // Create the terrain shape from the mapInfo |
99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), | 99 | m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), |
@@ -121,9 +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 | m_mapInfo.terrainBody.collisionType = CollisionType.Terrain; |
125 | (uint)CollisionFilterGroups.TerrainFilter, | 125 | m_mapInfo.terrainBody.ApplyCollisionMask(); |
126 | (uint)CollisionFilterGroups.TerrainMask); | ||
127 | 126 | ||
128 | // Make it so the terrain will not move or be considered for movement. | 127 | // Make it so the terrain will not move or be considered for movement. |
129 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 128 | BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); |
@@ -136,7 +135,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
136 | { | 135 | { |
137 | if (m_mapInfo != null) | 136 | if (m_mapInfo != null) |
138 | { | 137 | { |
139 | if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) | 138 | if (m_mapInfo.terrainBody.HasPhysicalBody) |
140 | { | 139 | { |
141 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); | 140 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); |
142 | // Frees both the body and the shape. | 141 | // Frees both the body and the shape. |
@@ -148,7 +147,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
148 | } | 147 | } |
149 | 148 | ||
150 | // The passed position is relative to the base of the region. | 149 | // The passed position is relative to the base of the region. |
151 | public override float GetHeightAtXYZ(Vector3 pos) | 150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
152 | { | 151 | { |
153 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; | 152 | float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; |
154 | 153 | ||
@@ -166,5 +165,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys | |||
166 | } | 165 | } |
167 | return ret; | 166 | return ret; |
168 | } | 167 | } |
168 | |||
169 | // The passed position is relative to the base of the region. | ||
170 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
171 | { | ||
172 | return PhysicsScene.SimpleWaterLevel; | ||
173 | } | ||
169 | } | 174 | } |
170 | } | 175 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs index 23fcfd3..3428b9c 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs | |||
@@ -62,11 +62,12 @@ 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 | // ========================================================================================== |
69 | public sealed class BSTerrainManager | 70 | public sealed class BSTerrainManager : IDisposable |
70 | { | 71 | { |
71 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; | 72 | static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; |
72 | 73 | ||
@@ -75,13 +76,12 @@ 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. |
81 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; | 83 | public const float HEIGHT_EQUAL_FUDGE = 0.2f; |
82 | 84 | ||
83 | public const float TERRAIN_COLLISION_MARGIN = 0.0f; | ||
84 | |||
85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. | 85 | // Until the whole simulator is changed to pass us the region size, we rely on constants. |
86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); | 86 | public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); |
87 | 87 | ||
@@ -122,6 +122,11 @@ public sealed class BSTerrainManager | |||
122 | MegaRegionParentPhysicsScene = null; | 122 | MegaRegionParentPhysicsScene = null; |
123 | } | 123 | } |
124 | 124 | ||
125 | public void Dispose() | ||
126 | { | ||
127 | ReleaseGroundPlaneAndTerrain(); | ||
128 | } | ||
129 | |||
125 | // Create the initial instance of terrain and the underlying ground plane. | 130 | // Create the initial instance of terrain and the underlying ground plane. |
126 | // This is called from the initialization routine so we presume it is | 131 | // This is called from the initialization routine so we presume it is |
127 | // safe to call Bullet in real time. We hope no one is moving prims around yet. | 132 | // safe to call Bullet in real time. We hope no one is moving prims around yet. |
@@ -129,7 +134,8 @@ public sealed class BSTerrainManager | |||
129 | { | 134 | { |
130 | // The ground plane is here to catch things that are trying to drop to negative infinity | 135 | // The ground plane is here to catch things that are trying to drop to negative infinity |
131 | BulletShape groundPlaneShape = new BulletShape( | 136 | BulletShape groundPlaneShape = new BulletShape( |
132 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), | 137 | BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, |
138 | PhysicsScene.Params.terrainCollisionMargin), | ||
133 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); | 139 | BSPhysicsShapeType.SHAPE_GROUNDPLANE); |
134 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, | 140 | m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, |
135 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, | 141 | BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, |
@@ -139,8 +145,8 @@ public sealed class BSTerrainManager | |||
139 | // Ground plane does not move | 145 | // Ground plane does not move |
140 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); | 146 | BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); |
141 | // Everything collides with the ground plane. | 147 | // Everything collides with the ground plane. |
142 | BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, | 148 | m_groundPlane.collisionType = CollisionType.Groundplane; |
143 | (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); | 149 | m_groundPlane.ApplyCollisionMask(); |
144 | 150 | ||
145 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. | 151 | // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. |
146 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); | 152 | BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); |
@@ -150,13 +156,13 @@ public sealed class BSTerrainManager | |||
150 | // Release all the terrain structures we might have allocated | 156 | // Release all the terrain structures we might have allocated |
151 | public void ReleaseGroundPlaneAndTerrain() | 157 | public void ReleaseGroundPlaneAndTerrain() |
152 | { | 158 | { |
153 | if (m_groundPlane.ptr != IntPtr.Zero) | 159 | if (m_groundPlane.HasPhysicalBody) |
154 | { | 160 | { |
155 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) | 161 | if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) |
156 | { | 162 | { |
157 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); | 163 | BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); |
158 | } | 164 | } |
159 | m_groundPlane.ptr = IntPtr.Zero; | 165 | m_groundPlane.Clear(); |
160 | } | 166 | } |
161 | 167 | ||
162 | ReleaseTerrain(); | 168 | ReleaseTerrain(); |
@@ -165,17 +171,22 @@ public sealed class BSTerrainManager | |||
165 | // Release all the terrain we have allocated | 171 | // Release all the terrain we have allocated |
166 | public void ReleaseTerrain() | 172 | public void ReleaseTerrain() |
167 | { | 173 | { |
168 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) | 174 | lock (m_terrains) |
169 | { | 175 | { |
170 | kvp.Value.Dispose(); | 176 | foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) |
177 | { | ||
178 | kvp.Value.Dispose(); | ||
179 | } | ||
180 | m_terrains.Clear(); | ||
171 | } | 181 | } |
172 | m_terrains.Clear(); | ||
173 | } | 182 | } |
174 | 183 | ||
175 | // The simulator wants to set a new heightmap for the terrain. | 184 | // The simulator wants to set a new heightmap for the terrain. |
176 | public void SetTerrain(float[] heightMap) { | 185 | public void SetTerrain(float[] heightMap) { |
177 | float[] localHeightMap = heightMap; | 186 | float[] localHeightMap = heightMap; |
178 | PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() | 187 | // If there are multiple requests for changes to the same terrain between ticks, |
188 | // only do that last one. | ||
189 | PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate() | ||
179 | { | 190 | { |
180 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) | 191 | if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) |
181 | { | 192 | { |
@@ -211,6 +222,7 @@ public sealed class BSTerrainManager | |||
211 | // terrain shape is created and added to the body. | 222 | // terrain shape is created and added to the body. |
212 | // This call is most often used to update the heightMap and parameters of the terrain. | 223 | // This call is most often used to update the heightMap and parameters of the terrain. |
213 | // (The above does suggest that some simplification/refactoring is in order.) | 224 | // (The above does suggest that some simplification/refactoring is in order.) |
225 | // Called during taint-time. | ||
214 | private void UpdateTerrain(uint id, float[] heightMap, | 226 | private void UpdateTerrain(uint id, float[] heightMap, |
215 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) | 227 | Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) |
216 | { | 228 | { |
@@ -220,7 +232,7 @@ public sealed class BSTerrainManager | |||
220 | // Find high and low points of passed heightmap. | 232 | // Find high and low points of passed heightmap. |
221 | // The min and max passed in is usually the area objects can be in (maximum | 233 | // The min and max passed in is usually the area objects can be in (maximum |
222 | // object height, for instance). The terrain wants the bounding box for the | 234 | // object height, for instance). The terrain wants the bounding box for the |
223 | // terrain so we replace passed min and max Z with the actual terrain min/max Z. | 235 | // terrain so replace passed min and max Z with the actual terrain min/max Z. |
224 | float minZ = float.MaxValue; | 236 | float minZ = float.MaxValue; |
225 | float maxZ = float.MinValue; | 237 | float maxZ = float.MinValue; |
226 | foreach (float height in heightMap) | 238 | foreach (float height in heightMap) |
@@ -238,15 +250,15 @@ public sealed class BSTerrainManager | |||
238 | 250 | ||
239 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); | 251 | Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); |
240 | 252 | ||
241 | BSTerrainPhys terrainPhys; | 253 | lock (m_terrains) |
242 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) | ||
243 | { | 254 | { |
244 | // There is already a terrain in this spot. Free the old and build the new. | 255 | BSTerrainPhys terrainPhys; |
245 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | 256 | if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys)) |
246 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
247 | |||
248 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate() | ||
249 | { | 257 | { |
258 | // There is already a terrain in this spot. Free the old and build the new. | ||
259 | DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", | ||
260 | BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords); | ||
261 | |||
250 | // Remove old terrain from the collection | 262 | // Remove old terrain from the collection |
251 | m_terrains.Remove(terrainRegionBase); | 263 | m_terrains.Remove(terrainRegionBase); |
252 | // Release any physical memory it may be using. | 264 | // Release any physical memory it may be using. |
@@ -271,35 +283,24 @@ public sealed class BSTerrainManager | |||
271 | // I hate doing this, but just bail | 283 | // I hate doing this, but just bail |
272 | return; | 284 | return; |
273 | } | 285 | } |
274 | }); | 286 | } |
275 | } | 287 | else |
276 | else | 288 | { |
277 | { | 289 | // We don't know about this terrain so either we are creating a new terrain or |
278 | // We don't know about this terrain so either we are creating a new terrain or | 290 | // our mega-prim child is giving us a new terrain to add to the phys world |
279 | // our mega-prim child is giving us a new terrain to add to the phys world | ||
280 | |||
281 | // if this is a child terrain, calculate a unique terrain id | ||
282 | uint newTerrainID = id; | ||
283 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
284 | newTerrainID = ++m_terrainCount; | ||
285 | |||
286 | float[] heightMapX = heightMap; | ||
287 | Vector3 minCoordsX = minCoords; | ||
288 | Vector3 maxCoordsX = maxCoords; | ||
289 | 291 | ||
290 | DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", | 292 | // if this is a child terrain, calculate a unique terrain id |
291 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); | 293 | uint newTerrainID = id; |
294 | if (newTerrainID >= BSScene.CHILDTERRAIN_ID) | ||
295 | newTerrainID = ++m_terrainCount; | ||
292 | 296 | ||
293 | // Code that must happen at taint-time | 297 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}", |
294 | PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() | 298 | BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); |
295 | { | ||
296 | DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}", | ||
297 | BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y); | ||
298 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); | 299 | BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); |
299 | m_terrains.Add(terrainRegionBase, newTerrainPhys); | 300 | m_terrains.Add(terrainRegionBase, newTerrainPhys); |
300 | 301 | ||
301 | m_terrainModified = true; | 302 | m_terrainModified = true; |
302 | }); | 303 | } |
303 | } | 304 | } |
304 | } | 305 | } |
305 | 306 | ||
@@ -331,6 +332,13 @@ public sealed class BSTerrainManager | |||
331 | return newTerrainPhys; | 332 | return newTerrainPhys; |
332 | } | 333 | } |
333 | 334 | ||
335 | // Return 'true' of this position is somewhere in known physical terrain space | ||
336 | public bool IsWithinKnownTerrain(Vector3 pos) | ||
337 | { | ||
338 | Vector3 terrainBaseXYZ; | ||
339 | BSTerrainPhys physTerrain; | ||
340 | return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ); | ||
341 | } | ||
334 | 342 | ||
335 | // Given an X and Y, find the height of the terrain. | 343 | // Given an X and Y, find the height of the terrain. |
336 | // Since we could be handling multiple terrains for a mega-region, | 344 | // Since we could be handling multiple terrains for a mega-region, |
@@ -341,40 +349,74 @@ public sealed class BSTerrainManager | |||
341 | private float lastHeightTX = 999999f; | 349 | private float lastHeightTX = 999999f; |
342 | private float lastHeightTY = 999999f; | 350 | private float lastHeightTY = 999999f; |
343 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; | 351 | private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; |
344 | public float GetTerrainHeightAtXYZ(Vector3 loc) | 352 | public float GetTerrainHeightAtXYZ(Vector3 pos) |
345 | { | 353 | { |
346 | float tX = loc.X; | 354 | float tX = pos.X; |
347 | float tY = loc.Y; | 355 | float tY = pos.Y; |
348 | // You'd be surprized at the number of times this routine is called | 356 | // You'd be surprized at the number of times this routine is called |
349 | // with the same parameters as last time. | 357 | // with the same parameters as last time. |
350 | if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) | 358 | if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY)) |
351 | return lastHeight; | 359 | return lastHeight; |
360 | m_terrainModified = false; | ||
352 | 361 | ||
353 | lastHeightTX = tX; | 362 | lastHeightTX = tX; |
354 | lastHeightTY = tY; | 363 | lastHeightTY = tY; |
355 | float ret = HEIGHT_GETHEIGHT_RET; | 364 | float ret = HEIGHT_GETHEIGHT_RET; |
356 | 365 | ||
357 | int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | 366 | Vector3 terrainBaseXYZ; |
358 | int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
359 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
360 | |||
361 | BSTerrainPhys physTerrain; | 367 | BSTerrainPhys physTerrain; |
362 | if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) | 368 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) |
363 | { | 369 | { |
364 | ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); | 370 | ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ); |
365 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}", | ||
366 | BSScene.DetailLogZero, loc, terrainBaseXYZ, ret); | ||
367 | } | 371 | } |
368 | else | 372 | else |
369 | { | 373 | { |
370 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", | 374 | PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", |
371 | LogHeader, PhysicsScene.RegionName, tX, tY); | 375 | LogHeader, PhysicsScene.RegionName, tX, tY); |
376 | DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}", | ||
377 | BSScene.DetailLogZero, pos, terrainBaseXYZ); | ||
372 | } | 378 | } |
373 | m_terrainModified = false; | 379 | |
374 | lastHeight = ret; | 380 | lastHeight = ret; |
375 | return ret; | 381 | return ret; |
376 | } | 382 | } |
377 | 383 | ||
384 | public float GetWaterLevelAtXYZ(Vector3 pos) | ||
385 | { | ||
386 | float ret = WATER_HEIGHT_GETHEIGHT_RET; | ||
387 | |||
388 | Vector3 terrainBaseXYZ; | ||
389 | BSTerrainPhys physTerrain; | ||
390 | if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ)) | ||
391 | { | ||
392 | ret = physTerrain.GetWaterLevelAtXYZ(pos); | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}", | ||
397 | LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret); | ||
398 | } | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | // Given an address, return 'true' of there is a description of that terrain and output | ||
403 | // the descriptor class and the 'base' fo the addresses therein. | ||
404 | private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase) | ||
405 | { | ||
406 | int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; | ||
407 | int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y; | ||
408 | Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f); | ||
409 | |||
410 | BSTerrainPhys physTerrain = null; | ||
411 | lock (m_terrains) | ||
412 | { | ||
413 | m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain); | ||
414 | } | ||
415 | outTerrainBase = terrainBaseXYZ; | ||
416 | outPhysTerrain = physTerrain; | ||
417 | return (physTerrain != null); | ||
418 | } | ||
419 | |||
378 | // Although no one seems to check this, I do support combining. | 420 | // Although no one seems to check this, I do support combining. |
379 | public bool SupportsCombining() | 421 | public bool SupportsCombining() |
380 | { | 422 | { |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs index dca7150..6dc0d92 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs | |||
@@ -88,11 +88,13 @@ 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.HasPhysicalShape) |
96 | { | 98 | { |
97 | // DISASTER!! | 99 | // DISASTER!! |
98 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); | 100 | PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); |
@@ -105,7 +107,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
105 | Quaternion rot = Quaternion.Identity; | 107 | Quaternion rot = Quaternion.Identity; |
106 | 108 | ||
107 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); | 109 | m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); |
108 | if (m_terrainBody.ptr == IntPtr.Zero) | 110 | if (!m_terrainBody.HasPhysicalBody) |
109 | { | 111 | { |
110 | // DISASTER!! | 112 | // DISASTER!! |
111 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); | 113 | physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); |
@@ -122,15 +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 | m_terrainBody.collisionType = CollisionType.Terrain; |
132 | (uint)CollisionFilterGroups.TerrainFilter, | 134 | m_terrainBody.ApplyCollisionMask(); |
133 | (uint)CollisionFilterGroups.TerrainMask); | ||
134 | 135 | ||
135 | // Make it so the terrain will not move or be considered for movement. | 136 | // Make it so the terrain will not move or be considered for movement. |
136 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); | 137 | BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); |
@@ -138,7 +139,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
138 | 139 | ||
139 | public override void Dispose() | 140 | public override void Dispose() |
140 | { | 141 | { |
141 | if (m_terrainBody.ptr != IntPtr.Zero) | 142 | if (m_terrainBody.HasPhysicalBody) |
142 | { | 143 | { |
143 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); | 144 | BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); |
144 | // Frees both the body and the shape. | 145 | // Frees both the body and the shape. |
@@ -146,7 +147,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
146 | } | 147 | } |
147 | } | 148 | } |
148 | 149 | ||
149 | public override float GetHeightAtXYZ(Vector3 pos) | 150 | public override float GetTerrainHeightAtXYZ(Vector3 pos) |
150 | { | 151 | { |
151 | // For the moment use the saved heightmap to get the terrain height. | 152 | // For the moment use the saved heightmap to get the terrain height. |
152 | // TODO: raycast downward to find the true terrain below the position. | 153 | // TODO: raycast downward to find the true terrain below the position. |
@@ -167,6 +168,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
167 | return ret; | 168 | return ret; |
168 | } | 169 | } |
169 | 170 | ||
171 | // The passed position is relative to the base of the region. | ||
172 | public override float GetWaterLevelAtXYZ(Vector3 pos) | ||
173 | { | ||
174 | return PhysicsScene.SimpleWaterLevel; | ||
175 | } | ||
176 | |||
170 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). | 177 | // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). |
171 | // Return 'true' if successfully created. | 178 | // Return 'true' if successfully created. |
172 | public static bool ConvertHeightmapToMesh( | 179 | public static bool ConvertHeightmapToMesh( |
@@ -188,6 +195,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
188 | // Simple mesh creation which assumes magnification == 1. | 195 | // Simple mesh creation which assumes magnification == 1. |
189 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. | 196 | // TODO: do a more general solution that scales, adds new vertices and smoothes the result. |
190 | 197 | ||
198 | // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop | ||
199 | // from zero to <= sizeX). The triangle indices are then generated as two triangles | ||
200 | // per heightmap point. There are sizeX by sizeY of these squares. The extra row and | ||
201 | // column of vertices are used to complete the triangles of the last row and column | ||
202 | // of the heightmap. | ||
191 | try | 203 | try |
192 | { | 204 | { |
193 | // One vertice per heightmap value plus the vertices off the top and bottom edge. | 205 | // One vertice per heightmap value plus the vertices off the top and bottom edge. |
@@ -200,16 +212,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
200 | float magY = (float)sizeY / extentY; | 212 | float magY = (float)sizeY / extentY; |
201 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", | 213 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", |
202 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); | 214 | BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); |
215 | float minHeight = float.MaxValue; | ||
203 | // Note that sizeX+1 vertices are created since there is land between this and the next region. | 216 | // 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++) | 217 | for (int yy = 0; yy <= sizeY; yy++) |
205 | { | 218 | { |
206 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times | 219 | for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times |
207 | { | 220 | { |
208 | int offset = yy * sizeX + xx; | 221 | int offset = yy * sizeX + xx; |
209 | // Extend the height from the height from the last row or column | 222 | // Extend the height with the height from the last row or column |
210 | if (yy == sizeY) offset -= sizeX; | 223 | if (yy == sizeY) offset -= sizeX; |
211 | if (xx == sizeX) offset -= 1; | 224 | if (xx == sizeX) offset -= 1; |
212 | float height = heightMap[offset]; | 225 | float height = heightMap[offset]; |
226 | minHeight = Math.Min(minHeight, height); | ||
213 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; | 227 | vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; |
214 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; | 228 | vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; |
215 | vertices[verticesCount + 2] = height + extentBase.Z; | 229 | vertices[verticesCount + 2] = height + extentBase.Z; |
@@ -217,14 +231,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
217 | } | 231 | } |
218 | } | 232 | } |
219 | verticesCount = verticesCount / 3; | 233 | verticesCount = verticesCount / 3; |
220 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}", | ||
221 | BSScene.DetailLogZero, verticesCount); | ||
222 | 234 | ||
223 | for (int yy = 0; yy < sizeY; yy++) | 235 | for (int yy = 0; yy < sizeY; yy++) |
224 | { | 236 | { |
225 | for (int xx = 0; xx < sizeX; xx++) | 237 | for (int xx = 0; xx < sizeX; xx++) |
226 | { | 238 | { |
227 | int offset = yy * sizeX + xx; | 239 | int offset = yy * (sizeX + 1) + xx; |
228 | // Each vertices is presumed to be the upper left corner of a box of two triangles | 240 | // Each vertices is presumed to be the upper left corner of a box of two triangles |
229 | indices[indicesCount + 0] = offset; | 241 | indices[indicesCount + 0] = offset; |
230 | indices[indicesCount + 1] = offset + 1; | 242 | indices[indicesCount + 1] = offset + 1; |
@@ -235,8 +247,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys | |||
235 | indicesCount += 6; | 247 | indicesCount += 6; |
236 | } | 248 | } |
237 | } | 249 | } |
238 | physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG | 250 | |
239 | LogHeader, indicesCount); // DEBUG | ||
240 | ret = true; | 251 | ret = true; |
241 | } | 252 | } |
242 | catch (Exception e) | 253 | catch (Exception e) |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index e60a760..962b540 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -25,6 +25,7 @@ | |||
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.Runtime.InteropServices; | 29 | using System.Runtime.InteropServices; |
29 | using System.Security; | 30 | using System.Security; |
30 | using System.Text; | 31 | using System.Text; |
@@ -32,93 +33,6 @@ using OpenMetaverse; | |||
32 | 33 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin { | 34 | namespace OpenSim.Region.Physics.BulletSPlugin { |
34 | 35 | ||
35 | // Classes to allow some type checking for the API | ||
36 | // These hold pointers to allocated objects in the unmanaged space. | ||
37 | |||
38 | // The physics engine controller class created at initialization | ||
39 | public struct BulletSim | ||
40 | { | ||
41 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
42 | { | ||
43 | ptr = xx; | ||
44 | worldID = worldId; | ||
45 | physicsScene = bss; | ||
46 | } | ||
47 | public IntPtr ptr; | ||
48 | public uint worldID; | ||
49 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
50 | public BSScene physicsScene; | ||
51 | } | ||
52 | |||
53 | // An allocated Bullet btRigidBody | ||
54 | public struct BulletBody | ||
55 | { | ||
56 | public BulletBody(uint id, IntPtr xx) | ||
57 | { | ||
58 | ID = id; | ||
59 | ptr = xx; | ||
60 | collisionFilter = 0; | ||
61 | collisionMask = 0; | ||
62 | } | ||
63 | public IntPtr ptr; | ||
64 | public uint ID; | ||
65 | public CollisionFilterGroups collisionFilter; | ||
66 | public CollisionFilterGroups collisionMask; | ||
67 | public override string ToString() | ||
68 | { | ||
69 | StringBuilder buff = new StringBuilder(); | ||
70 | buff.Append("<id="); | ||
71 | buff.Append(ID.ToString()); | ||
72 | buff.Append(",p="); | ||
73 | buff.Append(ptr.ToString("X")); | ||
74 | if (collisionFilter != 0 || collisionMask != 0) | ||
75 | { | ||
76 | buff.Append(",f="); | ||
77 | buff.Append(collisionFilter.ToString("X")); | ||
78 | buff.Append(",m="); | ||
79 | buff.Append(collisionMask.ToString("X")); | ||
80 | } | ||
81 | buff.Append(">"); | ||
82 | return buff.ToString(); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | public struct BulletShape | ||
87 | { | ||
88 | public BulletShape(IntPtr xx) | ||
89 | { | ||
90 | ptr = xx; | ||
91 | type=BSPhysicsShapeType.SHAPE_UNKNOWN; | ||
92 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
93 | isNativeShape = false; | ||
94 | } | ||
95 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
96 | { | ||
97 | ptr = xx; | ||
98 | type = typ; | ||
99 | shapeKey = 0; | ||
100 | isNativeShape = false; | ||
101 | } | ||
102 | public IntPtr ptr; | ||
103 | public BSPhysicsShapeType type; | ||
104 | public System.UInt64 shapeKey; | ||
105 | public bool isNativeShape; | ||
106 | public override string ToString() | ||
107 | { | ||
108 | StringBuilder buff = new StringBuilder(); | ||
109 | buff.Append("<p="); | ||
110 | buff.Append(ptr.ToString("X")); | ||
111 | buff.Append(",s="); | ||
112 | buff.Append(type.ToString()); | ||
113 | buff.Append(",k="); | ||
114 | buff.Append(shapeKey.ToString("X")); | ||
115 | buff.Append(",n="); | ||
116 | buff.Append(isNativeShape.ToString()); | ||
117 | buff.Append(">"); | ||
118 | return buff.ToString(); | ||
119 | } | ||
120 | } | ||
121 | |||
122 | // Constraint type values as defined by Bullet | 36 | // Constraint type values as defined by Bullet |
123 | public enum ConstraintType : int | 37 | public enum ConstraintType : int |
124 | { | 38 | { |
@@ -132,44 +46,6 @@ public enum ConstraintType : int | |||
132 | MAX_CONSTRAINT_TYPE | 46 | MAX_CONSTRAINT_TYPE |
133 | } | 47 | } |
134 | 48 | ||
135 | // An allocated Bullet btConstraint | ||
136 | public struct BulletConstraint | ||
137 | { | ||
138 | public BulletConstraint(IntPtr xx) | ||
139 | { | ||
140 | ptr = xx; | ||
141 | } | ||
142 | public IntPtr ptr; | ||
143 | } | ||
144 | |||
145 | // An allocated HeightMapThing which holds various heightmap info. | ||
146 | // Made a class rather than a struct so there would be only one | ||
147 | // instance of this and C# will pass around pointers rather | ||
148 | // than making copies. | ||
149 | public class BulletHeightMapInfo | ||
150 | { | ||
151 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
152 | ID = id; | ||
153 | Ptr = xx; | ||
154 | heightMap = hm; | ||
155 | terrainRegionBase = Vector3.Zero; | ||
156 | minCoords = new Vector3(100f, 100f, 25f); | ||
157 | maxCoords = new Vector3(101f, 101f, 26f); | ||
158 | minZ = maxZ = 0f; | ||
159 | sizeX = sizeY = 256f; | ||
160 | } | ||
161 | public uint ID; | ||
162 | public IntPtr Ptr; | ||
163 | public float[] heightMap; | ||
164 | public Vector3 terrainRegionBase; | ||
165 | public Vector3 minCoords; | ||
166 | public Vector3 maxCoords; | ||
167 | public float sizeX, sizeY; | ||
168 | public float minZ, maxZ; | ||
169 | public BulletShape terrainShape; | ||
170 | public BulletBody terrainBody; | ||
171 | } | ||
172 | |||
173 | // =============================================================================== | 49 | // =============================================================================== |
174 | [StructLayout(LayoutKind.Sequential)] | 50 | [StructLayout(LayoutKind.Sequential)] |
175 | public struct ConvexHull | 51 | public struct ConvexHull |
@@ -287,6 +163,8 @@ public struct ConfigurationParameters | |||
287 | public float terrainFriction; | 163 | public float terrainFriction; |
288 | public float terrainHitFraction; | 164 | public float terrainHitFraction; |
289 | public float terrainRestitution; | 165 | public float terrainRestitution; |
166 | public float terrainCollisionMargin; | ||
167 | |||
290 | public float avatarFriction; | 168 | public float avatarFriction; |
291 | public float avatarStandingFriction; | 169 | public float avatarStandingFriction; |
292 | public float avatarDensity; | 170 | public float avatarDensity; |
@@ -296,6 +174,8 @@ public struct ConfigurationParameters | |||
296 | public float avatarCapsuleHeight; | 174 | public float avatarCapsuleHeight; |
297 | public float avatarContactProcessingThreshold; | 175 | public float avatarContactProcessingThreshold; |
298 | 176 | ||
177 | public float vehicleAngularDamping; | ||
178 | |||
299 | public float maxPersistantManifoldPoolSize; | 179 | public float maxPersistantManifoldPoolSize; |
300 | public float maxCollisionAlgorithmPoolSize; | 180 | public float maxCollisionAlgorithmPoolSize; |
301 | public float shouldDisableContactPoolDynamicAllocation; | 181 | public float shouldDisableContactPoolDynamicAllocation; |
@@ -353,56 +233,35 @@ public enum CollisionFlags : uint | |||
353 | CF_CHARACTER_OBJECT = 1 << 4, | 233 | CF_CHARACTER_OBJECT = 1 << 4, |
354 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, | 234 | CF_DISABLE_VISUALIZE_OBJECT = 1 << 5, |
355 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | 235 | CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6, |
356 | // Following used by BulletSim to control collisions | 236 | // Following used by BulletSim to control collisions and updates |
357 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, | 237 | BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10, |
358 | BS_FLOATS_ON_WATER = 1 << 11, | 238 | BS_FLOATS_ON_WATER = 1 << 11, |
239 | BS_VEHICLE_COLLISIONS = 1 << 12, | ||
359 | BS_NONE = 0, | 240 | BS_NONE = 0, |
360 | BS_ALL = 0xFFFFFFFF, | 241 | BS_ALL = 0xFFFFFFFF |
361 | |||
362 | // These are the collision flags switched depending on physical state. | ||
363 | // The other flags are used for other things and should not be fooled with. | ||
364 | BS_ACTIVE = CF_STATIC_OBJECT | ||
365 | | CF_KINEMATIC_OBJECT | ||
366 | | CF_NO_CONTACT_RESPONSE | ||
367 | }; | 242 | }; |
368 | 243 | ||
369 | // Values for collisions groups and masks | 244 | // Values f collisions groups and masks |
370 | public enum CollisionFilterGroups : uint | 245 | public enum CollisionFilterGroups : uint |
371 | { | 246 | { |
372 | // Don't use the bit definitions!! Define the use in a | 247 | // Don't use the bit definitions!! Define the use in a |
373 | // filter/mask definition below. This way collision interactions | 248 | // filter/mask definition below. This way collision interactions |
374 | // are more easily debugged. | 249 | // are more easily found and debugged. |
375 | BNoneFilter = 0, | 250 | BNoneGroup = 0, |
376 | BDefaultFilter = 1 << 0, | 251 | BDefaultGroup = 1 << 0, |
377 | BStaticFilter = 1 << 1, | 252 | BStaticGroup = 1 << 1, |
378 | BKinematicFilter = 1 << 2, | 253 | BKinematicGroup = 1 << 2, |
379 | BDebrisFilter = 1 << 3, | 254 | BDebrisGroup = 1 << 3, |
380 | BSensorTrigger = 1 << 4, | 255 | BSensorTrigger = 1 << 4, |
381 | BCharacterFilter = 1 << 5, | 256 | BCharacterGroup = 1 << 5, |
382 | BAllFilter = 0xFFFFFFFF, | 257 | BAllGroup = 0xFFFFFFFF, |
383 | // Filter groups defined by BulletSim | 258 | // Filter groups defined by BulletSim |
384 | BGroundPlaneFilter = 1 << 10, | 259 | BGroundPlaneGroup = 1 << 10, |
385 | BTerrainFilter = 1 << 11, | 260 | BTerrainGroup = 1 << 11, |
386 | BRaycastFilter = 1 << 12, | 261 | BRaycastGroup = 1 << 12, |
387 | BSolidFilter = 1 << 13, | 262 | BSolidGroup = 1 << 13, |
388 | BLinksetFilter = 1 << 14, | 263 | // BLinksetGroup = xx // a linkset proper is either static or dynamic |
389 | 264 | BLinksetChildGroup = 1 << 14, | |
390 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
391 | AvatarFilter = BCharacterFilter, | ||
392 | AvatarMask = BAllFilter, | ||
393 | ObjectFilter = BSolidFilter, | ||
394 | ObjectMask = BAllFilter, | ||
395 | StaticObjectFilter = BStaticFilter, | ||
396 | StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other | ||
397 | LinksetFilter = BLinksetFilter, | ||
398 | LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other | ||
399 | VolumeDetectFilter = BSensorTrigger, | ||
400 | VolumeDetectMask = ~BSensorTrigger, | ||
401 | TerrainFilter = BTerrainFilter, | ||
402 | TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide | ||
403 | GroundPlaneFilter = BGroundPlaneFilter, | ||
404 | GroundPlaneMask = BAllFilter | ||
405 | |||
406 | }; | 265 | }; |
407 | 266 | ||
408 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 | 267 | // CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0 |
@@ -429,7 +288,7 @@ public enum ConstraintParamAxis : int | |||
429 | 288 | ||
430 | // =============================================================================== | 289 | // =============================================================================== |
431 | static class BulletSimAPI { | 290 | static class BulletSimAPI { |
432 | 291 | // =============================================================================== | |
433 | // Link back to the managed code for outputting log messages | 292 | // Link back to the managed code for outputting log messages |
434 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] | 293 | [UnmanagedFunctionPointer(CallingConvention.Cdecl)] |
435 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | 294 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); |
@@ -482,6 +341,9 @@ public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData) | |||
482 | public static extern bool IsNativeShape2(IntPtr shape); | 341 | public static extern bool IsNativeShape2(IntPtr shape); |
483 | 342 | ||
484 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 343 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
344 | public static extern void SetShapeCollisionMargin(IntPtr shape, float margin); | ||
345 | |||
346 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
485 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); | 347 | public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale); |
486 | 348 | ||
487 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 349 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -938,7 +800,7 @@ public static extern IntPtr GetConstraintRef2(IntPtr obj, int index); | |||
938 | public static extern int GetNumConstraintRefs2(IntPtr obj); | 800 | public static extern int GetNumConstraintRefs2(IntPtr obj); |
939 | 801 | ||
940 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 802 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
941 | public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask); | 803 | public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask); |
942 | 804 | ||
943 | // ===================================================================================== | 805 | // ===================================================================================== |
944 | // btCollisionShape entries | 806 | // btCollisionShape entries |
@@ -1000,13 +862,16 @@ public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject); | |||
1000 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); | 862 | public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape); |
1001 | 863 | ||
1002 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 864 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
865 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | ||
866 | |||
867 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
1003 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); | 868 | public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain); |
1004 | 869 | ||
1005 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 870 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1006 | public static extern void DumpAllInfo2(IntPtr sim); | 871 | public static extern void DumpActivationInfo2(IntPtr sim); |
1007 | 872 | ||
1008 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 873 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1009 | public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo); | 874 | public static extern void DumpAllInfo2(IntPtr sim); |
1010 | 875 | ||
1011 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 876 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
1012 | public static extern void DumpPhysicsStatistics2(IntPtr sim); | 877 | public static extern void DumpPhysicsStatistics2(IntPtr sim); |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs new file mode 100755 index 0000000..662177f --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs | |||
@@ -0,0 +1,278 @@ | |||
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 copyrightD | ||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | using OMV = OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Region.Physics.BulletSPlugin | ||
33 | { | ||
34 | // Classes to allow some type checking for the API | ||
35 | // These hold pointers to allocated objects in the unmanaged space. | ||
36 | |||
37 | // The physics engine controller class created at initialization | ||
38 | public struct BulletSim | ||
39 | { | ||
40 | public BulletSim(uint worldId, BSScene bss, IntPtr xx) | ||
41 | { | ||
42 | ptr = xx; | ||
43 | worldID = worldId; | ||
44 | physicsScene = bss; | ||
45 | } | ||
46 | public IntPtr ptr; | ||
47 | public uint worldID; | ||
48 | // The scene is only in here so very low level routines have a handle to print debug/error messages | ||
49 | public BSScene physicsScene; | ||
50 | } | ||
51 | |||
52 | // An allocated Bullet btRigidBody | ||
53 | public struct BulletBody | ||
54 | { | ||
55 | public BulletBody(uint id) : this(id, IntPtr.Zero) | ||
56 | { | ||
57 | } | ||
58 | public BulletBody(uint id, IntPtr xx) | ||
59 | { | ||
60 | ID = id; | ||
61 | ptr = xx; | ||
62 | collisionType = CollisionType.Static; | ||
63 | } | ||
64 | public IntPtr ptr; | ||
65 | public uint ID; | ||
66 | public CollisionType collisionType; | ||
67 | |||
68 | public void Clear() | ||
69 | { | ||
70 | ptr = IntPtr.Zero; | ||
71 | } | ||
72 | public bool HasPhysicalBody { get { return ptr != IntPtr.Zero; } } | ||
73 | |||
74 | // Apply the specificed collision mask into the physical world | ||
75 | public void ApplyCollisionMask() | ||
76 | { | ||
77 | // Should assert the body has been added to the physical world. | ||
78 | // (The collision masks are stored in the collision proxy cache which only exists for | ||
79 | // a collision body that is in the world.) | ||
80 | BulletSimAPI.SetCollisionGroupMask2(ptr, | ||
81 | BulletSimData.CollisionTypeMasks[collisionType].group, | ||
82 | BulletSimData.CollisionTypeMasks[collisionType].mask); | ||
83 | } | ||
84 | |||
85 | public override string ToString() | ||
86 | { | ||
87 | StringBuilder buff = new StringBuilder(); | ||
88 | buff.Append("<id="); | ||
89 | buff.Append(ID.ToString()); | ||
90 | buff.Append(",p="); | ||
91 | buff.Append(ptr.ToString("X")); | ||
92 | buff.Append(",c="); | ||
93 | buff.Append(collisionType); | ||
94 | buff.Append(">"); | ||
95 | return buff.ToString(); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | public struct BulletShape | ||
100 | { | ||
101 | public BulletShape(IntPtr xx) : this(xx, BSPhysicsShapeType.SHAPE_UNKNOWN) | ||
102 | { | ||
103 | } | ||
104 | public BulletShape(IntPtr xx, BSPhysicsShapeType typ) | ||
105 | { | ||
106 | ptr = xx; | ||
107 | type = typ; | ||
108 | shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE; | ||
109 | isNativeShape = false; | ||
110 | } | ||
111 | public IntPtr ptr; | ||
112 | public BSPhysicsShapeType type; | ||
113 | public System.UInt64 shapeKey; | ||
114 | public bool isNativeShape; | ||
115 | |||
116 | public void Clear() | ||
117 | { | ||
118 | ptr = IntPtr.Zero; | ||
119 | } | ||
120 | public bool HasPhysicalShape { get { return ptr != IntPtr.Zero; } } | ||
121 | |||
122 | public override string ToString() | ||
123 | { | ||
124 | StringBuilder buff = new StringBuilder(); | ||
125 | buff.Append("<p="); | ||
126 | buff.Append(ptr.ToString("X")); | ||
127 | buff.Append(",s="); | ||
128 | buff.Append(type.ToString()); | ||
129 | buff.Append(",k="); | ||
130 | buff.Append(shapeKey.ToString("X")); | ||
131 | buff.Append(",n="); | ||
132 | buff.Append(isNativeShape.ToString()); | ||
133 | buff.Append(">"); | ||
134 | return buff.ToString(); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // An allocated Bullet btConstraint | ||
139 | public struct BulletConstraint | ||
140 | { | ||
141 | public BulletConstraint(IntPtr xx) | ||
142 | { | ||
143 | ptr = xx; | ||
144 | } | ||
145 | public IntPtr ptr; | ||
146 | |||
147 | public void Clear() | ||
148 | { | ||
149 | ptr = IntPtr.Zero; | ||
150 | } | ||
151 | public bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } } | ||
152 | } | ||
153 | |||
154 | // An allocated HeightMapThing which holds various heightmap info. | ||
155 | // Made a class rather than a struct so there would be only one | ||
156 | // instance of this and C# will pass around pointers rather | ||
157 | // than making copies. | ||
158 | public class BulletHeightMapInfo | ||
159 | { | ||
160 | public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) { | ||
161 | ID = id; | ||
162 | Ptr = xx; | ||
163 | heightMap = hm; | ||
164 | terrainRegionBase = OMV.Vector3.Zero; | ||
165 | minCoords = new OMV.Vector3(100f, 100f, 25f); | ||
166 | maxCoords = new OMV.Vector3(101f, 101f, 26f); | ||
167 | minZ = maxZ = 0f; | ||
168 | sizeX = sizeY = 256f; | ||
169 | } | ||
170 | public uint ID; | ||
171 | public IntPtr Ptr; | ||
172 | public float[] heightMap; | ||
173 | public OMV.Vector3 terrainRegionBase; | ||
174 | public OMV.Vector3 minCoords; | ||
175 | public OMV.Vector3 maxCoords; | ||
176 | public float sizeX, sizeY; | ||
177 | public float minZ, maxZ; | ||
178 | public BulletShape terrainShape; | ||
179 | public BulletBody terrainBody; | ||
180 | } | ||
181 | |||
182 | // The general class of collsion object. | ||
183 | public enum CollisionType | ||
184 | { | ||
185 | Avatar, | ||
186 | Groundplane, | ||
187 | Terrain, | ||
188 | Static, | ||
189 | Dynamic, | ||
190 | VolumeDetect, | ||
191 | // Linkset, // A linkset should be either Static or Dynamic | ||
192 | LinksetChild, | ||
193 | Unknown | ||
194 | }; | ||
195 | |||
196 | // Hold specification of group and mask collision flags for a CollisionType | ||
197 | public struct CollisionTypeFilterGroup | ||
198 | { | ||
199 | public CollisionTypeFilterGroup(CollisionType t, uint g, uint m) | ||
200 | { | ||
201 | type = t; | ||
202 | group = g; | ||
203 | mask = m; | ||
204 | } | ||
205 | public CollisionType type; | ||
206 | public uint group; | ||
207 | public uint mask; | ||
208 | }; | ||
209 | |||
210 | /* NOTE: old definitions kept for reference. Delete when things are working. | ||
211 | // The collsion filters and masked are defined in one place -- don't want them scattered | ||
212 | AvatarGroup = BCharacterGroup, | ||
213 | AvatarMask = BAllGroup, | ||
214 | ObjectGroup = BSolidGroup, | ||
215 | ObjectMask = BAllGroup, | ||
216 | StaticObjectGroup = BStaticGroup, | ||
217 | StaticObjectMask = AvatarGroup | ObjectGroup, // static things don't interact with much | ||
218 | LinksetGroup = BLinksetGroup, | ||
219 | LinksetMask = BAllGroup, | ||
220 | LinksetChildGroup = BLinksetChildGroup, | ||
221 | LinksetChildMask = BNoneGroup, // Linkset children disappear from the world | ||
222 | VolumeDetectGroup = BSensorTrigger, | ||
223 | VolumeDetectMask = ~BSensorTrigger, | ||
224 | TerrainGroup = BTerrainGroup, | ||
225 | TerrainMask = BAllGroup & ~BStaticGroup, // static objects on the ground don't collide | ||
226 | GroundPlaneGroup = BGroundPlaneGroup, | ||
227 | GroundPlaneMask = BAllGroup | ||
228 | */ | ||
229 | |||
230 | public static class BulletSimData | ||
231 | { | ||
232 | |||
233 | // Map of collisionTypes to flags for collision groups and masks. | ||
234 | // As mentioned above, don't use the CollisionFilterGroups definitions directly in the code | ||
235 | // but, instead, use references to this dictionary. Finding and debugging | ||
236 | // collision flag problems will be made easier. | ||
237 | public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks | ||
238 | = new Dictionary<CollisionType, CollisionTypeFilterGroup>() | ||
239 | { | ||
240 | { CollisionType.Avatar, | ||
241 | new CollisionTypeFilterGroup(CollisionType.Avatar, | ||
242 | (uint)CollisionFilterGroups.BCharacterGroup, | ||
243 | (uint)CollisionFilterGroups.BAllGroup) | ||
244 | }, | ||
245 | { CollisionType.Groundplane, | ||
246 | new CollisionTypeFilterGroup(CollisionType.Groundplane, | ||
247 | (uint)CollisionFilterGroups.BGroundPlaneGroup, | ||
248 | (uint)CollisionFilterGroups.BAllGroup) | ||
249 | }, | ||
250 | { CollisionType.Terrain, | ||
251 | new CollisionTypeFilterGroup(CollisionType.Terrain, | ||
252 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
253 | (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup)) | ||
254 | }, | ||
255 | { CollisionType.Static, | ||
256 | new CollisionTypeFilterGroup(CollisionType.Static, | ||
257 | (uint)CollisionFilterGroups.BStaticGroup, | ||
258 | (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup)) | ||
259 | }, | ||
260 | { CollisionType.Dynamic, | ||
261 | new CollisionTypeFilterGroup(CollisionType.Dynamic, | ||
262 | (uint)CollisionFilterGroups.BSolidGroup, | ||
263 | (uint)(CollisionFilterGroups.BAllGroup)) | ||
264 | }, | ||
265 | { CollisionType.VolumeDetect, | ||
266 | new CollisionTypeFilterGroup(CollisionType.VolumeDetect, | ||
267 | (uint)CollisionFilterGroups.BSensorTrigger, | ||
268 | (uint)(~CollisionFilterGroups.BSensorTrigger)) | ||
269 | }, | ||
270 | { CollisionType.LinksetChild, | ||
271 | new CollisionTypeFilterGroup(CollisionType.LinksetChild, | ||
272 | (uint)CollisionFilterGroups.BTerrainGroup, | ||
273 | (uint)(CollisionFilterGroups.BNoneGroup)) | ||
274 | }, | ||
275 | }; | ||
276 | |||
277 | } | ||
278 | } | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt new file mode 100755 index 0000000..0d9a156 --- /dev/null +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt | |||
@@ -0,0 +1,204 @@ | |||
1 | CURRENT PRIORITIES | ||
2 | ================================================= | ||
3 | Eliminate all crashes (DONEish) | ||
4 | Editing/deleting physical linkset (DONE) | ||
5 | Border crossing of physical linkset (DONE) | ||
6 | Enable vehicle border crossings (at least as poorly as ODE) | ||
7 | Avatar created in previous region and not new region when crossing border | ||
8 | Vehicle recreated in new sim at small Z value (offset from root value?) (DONE) | ||
9 | Calibrate turning radius | ||
10 | limitMotorUp calibration (more down?) | ||
11 | study PID motors (include 'efficiency' implementation | ||
12 | Add to avatar movement | ||
13 | |||
14 | CRASHES | ||
15 | ================================================= | ||
16 | 20121129.1411: editting/moving phys object across region boundries causes crash | ||
17 | getPos-> btRigidBody::upcast -> getBodyType -> BOOM | ||
18 | 20121128.1600: mesh object not rezzing (no physics mesh). | ||
19 | Causes many errors. Doesn't stop after first error with box shape. | ||
20 | Eventually crashes when deleting the object. | ||
21 | 20121206.1434: rez Sam-pan into OSGrid BulletSim11 region | ||
22 | Immediate simulator crash. Mono does not output any stacktrace and | ||
23 | log just stops after reporting taint-time linking of the linkset. | ||
24 | |||
25 | VEHICLES TODO LIST: | ||
26 | ================================================= | ||
27 | Border crossing with linked vehicle causes crash | ||
28 | Neb vehicle taking > 25ms of physics time!! | ||
29 | Vehicles (Move smoothly) | ||
30 | Add vehicle collisions so IsColliding is properly reported. | ||
31 | Needed for banking, limitMotorUp, movementLimiting, ... | ||
32 | Some vehicles should not be able to turn if no speed or off ground. | ||
33 | Cannot edit/move a vehicle being ridden: it jumps back to the origional position. | ||
34 | Neb car jiggling left and right | ||
35 | Happens on terrain and any other mesh object. Flat cubes are much smoother. | ||
36 | This has been reduced but not eliminated. | ||
37 | Light cycle falling over when driving | ||
38 | Implement referenceFrame for all the motion routines. | ||
39 | Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE. | ||
40 | Verify that angular motion specified around Z moves in the vehicle coordinates. | ||
41 | Verify llGetVel() is returning a smooth and good value for vehicle movement. | ||
42 | llGetVel() should return the root's velocity if requested in a child prim. | ||
43 | Implement function efficiency for lineaar and angular motion. | ||
44 | Should vehicle angular/linear movement friction happen after all the components | ||
45 | or does it only apply to the basic movement? | ||
46 | After getting off a vehicle, the root prim is phantom (can be walked through) | ||
47 | Need to force a position update for the root prim after compound shape destruction | ||
48 | Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint) | ||
49 | For limitMotorUp, use raycast down to find if vehicle is in the air. | ||
50 | Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties(). | ||
51 | A kludge that isn't fixing the real problem of Bullet adding extra motion. | ||
52 | |||
53 | BULLETSIM TODO LIST: | ||
54 | ================================================= | ||
55 | Revisit CollisionMargin. Builders notice the 0.04 spacing between prims. | ||
56 | Avatar height off after unsitting (floats off ground) | ||
57 | Editting appearance then moving restores. | ||
58 | Must not be initializing height when recreating capsule after unsit. | ||
59 | Duplicating a physical prim causes old prim to jump away | ||
60 | Dup a phys prim and the original become unselected and thus interacts w/ selected prim. | ||
61 | Scenes with hundred of thousands of static objects take a lot of physics CPU time. | ||
62 | BSPrim.Force should set a continious force on the prim. The force should be | ||
63 | applied each tick. Some limits? | ||
64 | Gun sending shooter flying. | ||
65 | Collision margin (gap between physical objects lying on each other) | ||
66 | Boundry checking (crashes related to crossing boundry) | ||
67 | Add check for border edge position for avatars and objects. | ||
68 | Verify the events are created for border crossings. | ||
69 | Avatar rotation (check out changes to ScenePresence for physical rotation) | ||
70 | Avatar running (what does phys engine need to do?) | ||
71 | Small physical objects do not interact correctly | ||
72 | Create chain of .5x.5x.1 torui and make all but top physical so to hang. | ||
73 | The chain will fall apart and pairs will dance around on ground | ||
74 | Chains of 1x1x.2 will stay connected but will dance. | ||
75 | Chains above 2x2x.4 are move stable and get stablier as torui get larger. | ||
76 | Add PID motor for avatar movement (slow to stop, ...) | ||
77 | setForce should set a constant force. Different than AddImpulse. | ||
78 | Implement raycast. | ||
79 | Implement ShapeCollection.Dispose() | ||
80 | Implement water as a plain so raycasting and collisions can happen with same. | ||
81 | Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE | ||
82 | Also osGetPhysicsEngineVerion() maybe. | ||
83 | Linkset.Position and Linkset.Orientation requre rewrite to properly return | ||
84 | child position. LinksetConstraint acts like it's at taint time!! | ||
85 | |||
86 | LINKSETS | ||
87 | ====================================================== | ||
88 | Linksets should allow collisions to individual children | ||
89 | Add LocalID to children shapes in LinksetCompound and create events for individuals | ||
90 | LinksetCompound: when one of the children changes orientation (like tires | ||
91 | turning on a vehicle, the whole compound object is rebuilt. Optimize this | ||
92 | so orientation/position of individual children can change without a rebuild. | ||
93 | Verify/think through scripts in children of linksets. What do they reference | ||
94 | and return when getting position, velocity, ... | ||
95 | Confirm constraint linksets still work after making all the changes for compound linksets. | ||
96 | Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt. | ||
97 | For compound linksets, add ability to remove or reposition individual child shapes. | ||
98 | Disable activity of passive linkset children. | ||
99 | Since the linkset is a compound object, the old prims are left lying | ||
100 | around and need to be phantomized so they don't collide, ... | ||
101 | Speed up creation of large physical linksets | ||
102 | For instance, sitting in Neb's car (130 prims) takes several seconds to become physical | ||
103 | Eliminate collisions between objects in a linkset. (LinksetConstraint) | ||
104 | Have UserPointer point to struct with localID and linksetID? | ||
105 | Objects in original linkset still collide with each other? | ||
106 | |||
107 | MORE | ||
108 | ====================================================== | ||
109 | Find/remove avatar collision with ID=0. | ||
110 | Test avatar walking up stairs. How does compare with SL. | ||
111 | Radius of the capsule affects ability to climb edges. | ||
112 | Tune terrain/object friction to be closer to SL. | ||
113 | Debounce avatar contact so legs don't keep folding up when standing. | ||
114 | Implement LSL physics controls. Like STATUS_ROTATE_X. | ||
115 | Add border extensions to terrain to help region crossings and objects leaving region. | ||
116 | |||
117 | Performance test with lots of avatars. Can BulletSim support a thousand? | ||
118 | Optimize collisions in C++: only send up to the object subscribed to collisions. | ||
119 | Use collision subscription and remove the collsion(A,B) and collision(B,A) | ||
120 | Check whether SimMotionState needs large if statement (see TODO). | ||
121 | |||
122 | Implement 'top colliders' info. | ||
123 | Avatar jump | ||
124 | Performance measurement and changes to make quicker. | ||
125 | Implement detailed physics stats (GetStats()). | ||
126 | |||
127 | Measure performance improvement from hulls | ||
128 | Test not using ghost objects for volume detect implementation. | ||
129 | Performance of closures and delegates for taint processing | ||
130 | Are there faster ways? | ||
131 | Is any slowdown introduced by the existing implementation significant? | ||
132 | Is there are more efficient method of implementing pre and post step actions? | ||
133 | See http://www.codeproject.com/Articles/29922/Weak-Events-in-C | ||
134 | |||
135 | Physics Arena central pyramid: why is one side permiable? | ||
136 | |||
137 | INTERNAL IMPROVEMENT/CLEANUP | ||
138 | ================================================= | ||
139 | Consider moving prim/character body and shape destruction in destroy() | ||
140 | to postTimeTime rather than protecting all the potential sets that | ||
141 | might have been queued up. | ||
142 | Remove unused fields from ShapeData (not used in API2) | ||
143 | Breakout code for mesh/hull/compound/native into separate BSShape* classes | ||
144 | Standardize access to building and reference code. | ||
145 | The skeleton classes are in the sources but are not complete or linked in. | ||
146 | Make BSBody and BSShape real classes to centralize creation/changin/destruction | ||
147 | Convert state and parameter calls from BulletSimAPI direct calls to | ||
148 | calls on BSBody and BSShape | ||
149 | Generalize Dynamics and PID with standardized motors. | ||
150 | Generalize Linkset and vehicles into PropertyManagers | ||
151 | Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies | ||
152 | Potentially add events for shape destruction, etc. | ||
153 | Complete implemention of preStepActions | ||
154 | Replace vehicle step call with prestep event. | ||
155 | Is there a need for postStepActions? postStepTaints? | ||
156 | Implement linkset by setting position of children when root updated. (LinksetManual) | ||
157 | Linkset implementation using manual prim movement. | ||
158 | LinkablePrim class? Would that simplify/centralize the linkset logic? | ||
159 | BSScene.UpdateParameterSet() is broken. How to set params on objects? | ||
160 | Remove HeightmapInfo from terrain specification | ||
161 | Since C++ code does not need terrain height, this structure et al are not needed. | ||
162 | Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will | ||
163 | bob at the water level. BSPrim.PositionSanityCheck(). | ||
164 | Should taints check for existance or activeness of target? | ||
165 | When destroying linksets/etc, taints can be generated for objects that are | ||
166 | actually gone when the taint happens. Crashes don't happen because the taint closure | ||
167 | keeps the object from being freed, but that is just an accident. | ||
168 | Possibly have and 'active' flag that is checked by the taint processor? | ||
169 | |||
170 | THREADING | ||
171 | ================================================= | ||
172 | Do taint action immediately if not actually executing Bullet. | ||
173 | Add lock around Bullet execution and just do taint actions if simulation is not happening. | ||
174 | |||
175 | DONE DONE DONE DONE | ||
176 | ================================================= | ||
177 | Cleanup code in BSDynamics by using motors. (Resolution: started) | ||
178 | Consider implementing terrain with a mesh rather than heightmap. (Resolution: done) | ||
179 | Would have better and adjustable resolution. | ||
180 | Build terrain mesh so heighmap is height of the center of the square meter. | ||
181 | Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional. | ||
182 | Terrain as mesh. (Resolution: done) | ||
183 | How are static linksets seen by the physics engine? | ||
184 | Resolution: they are not linked in physics. When moved, all the children are repositioned. | ||
185 | Convert BSCharacter to use all API2 (Resolution: done) | ||
186 | Avatar pushing difficult (too heavy?) | ||
187 | Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done) | ||
188 | Remove old code in DLL (all non-API2 stuff). (Resolution: done) | ||
189 | Measurements of mega-physical prim performance (with graph) (Resolution: done, email) | ||
190 | Debug Bullet internal stats output (why is timing all wrong?) | ||
191 | Resolution: Bullet stats logging only works with a single instance of Bullet (one region). | ||
192 | Implement meshes or just verify that they work. (Resolution: they do!) | ||
193 | Do prim hash codes work for sculpties and meshes? (Resolution: yes) | ||
194 | Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound) | ||
195 | Compound shapes will need the LocalID in the shapes and collision | ||
196 | processing to get it from there. | ||
197 | Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.) | ||
198 | Package Bullet source mods for Bullet internal stats output | ||
199 | (Resolution: move code into WorldData.h rather than relying on patches) | ||
200 | Single prim vehicles don't seem to properly vehiclize. | ||
201 | (Resolution: mass was not getting set properly for single prim linksets) | ||
202 | Add material type linkage and input all the material property definitions. | ||
203 | Skeleton classes and table are in the sources but are not filled or used. | ||
204 | (Resolution: | ||