diff options
Diffstat (limited to 'OpenSim/Region/Physics/OdePlugin')
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | 247 | ||||
-rw-r--r-- | OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | 220 |
2 files changed, 369 insertions, 98 deletions
diff --git a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs index 8e92171..b824cbe 100644 --- a/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs +++ b/OpenSim/Region/Physics/OdePlugin/ODECharacter.cs | |||
@@ -34,6 +34,26 @@ using OpenSim.Region.Physics.Manager; | |||
34 | 34 | ||
35 | namespace OpenSim.Region.Physics.OdePlugin | 35 | namespace OpenSim.Region.Physics.OdePlugin |
36 | { | 36 | { |
37 | /// <summary> | ||
38 | /// Various properties that ODE uses for AMotors but isn't exposed in ODE.NET so we must define them ourselves. | ||
39 | /// </summary> | ||
40 | |||
41 | public enum dParam : int | ||
42 | { | ||
43 | LowStop = 0, | ||
44 | HiStop = 1, | ||
45 | Vel = 2, | ||
46 | FMax = 3, | ||
47 | FudgeFactor = 4, | ||
48 | Bounce = 5, | ||
49 | CFM = 6, | ||
50 | ERP = 7, | ||
51 | StopCFM = 8, | ||
52 | LoStop2 = 256, | ||
53 | HiStop2 = 257, | ||
54 | LoStop3 = 512, | ||
55 | HiStop3 = 513 | ||
56 | } | ||
37 | public class OdeCharacter : PhysicsActor | 57 | public class OdeCharacter : PhysicsActor |
38 | { | 58 | { |
39 | private PhysicsVector _position; | 59 | private PhysicsVector _position; |
@@ -45,7 +65,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
45 | private PhysicsVector _target_velocity; | 65 | private PhysicsVector _target_velocity; |
46 | private PhysicsVector _acceleration; | 66 | private PhysicsVector _acceleration; |
47 | private PhysicsVector m_rotationalVelocity; | 67 | private PhysicsVector m_rotationalVelocity; |
48 | private float m_density = 50f; | 68 | private float m_mass = 80f; |
69 | private float m_density = 60f; | ||
49 | private bool m_pidControllerActive = true; | 70 | private bool m_pidControllerActive = true; |
50 | private static float PID_D = 3020.0f; | 71 | private static float PID_D = 3020.0f; |
51 | private static float PID_P = 7000.0f; | 72 | private static float PID_P = 7000.0f; |
@@ -96,34 +117,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
96 | 117 | ||
97 | lock (OdeScene.OdeLock) | 118 | lock (OdeScene.OdeLock) |
98 | { | 119 | { |
99 | int dAMotorEuler = 1; | 120 | AvatarGeomAndBodyCreation(pos.X, pos.Y, pos.Z); |
100 | Shell = d.CreateCapsule(parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
101 | d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
102 | Body = d.BodyCreate(parent_scene.world); | ||
103 | d.BodySetMass(Body, ref ShellMass); | ||
104 | d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); | ||
105 | d.GeomSetBody(Shell, Body); | ||
106 | |||
107 | |||
108 | d.BodySetRotation(Body, ref m_StandUpRotation); | ||
109 | |||
110 | |||
111 | //Amotor = d.JointCreateAMotor(parent_scene.world, IntPtr.Zero); | ||
112 | //d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
113 | //d.JointSetAMotorMode(Amotor, dAMotorEuler); | ||
114 | //d.JointSetAMotorNumAxes(Amotor, 3); | ||
115 | //d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); | ||
116 | //d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); | ||
117 | ///d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); | ||
118 | //d.JointSetAMotorAngle(Amotor, 0, 0); | ||
119 | //d.JointSetAMotorAngle(Amotor, 1, 0); | ||
120 | //d.JointSetAMotorAngle(Amotor, 2, 0); | ||
121 | //d.JointSetAMotorParam(Amotor, 0, -0); | ||
122 | //d.JointSetAMotorParam(Amotor, 0x200, -0); | ||
123 | //d.JointSetAMotorParam(Amotor, 0x100, -0); | ||
124 | // d.JointSetAMotorParam(Amotor, 0, 0); | ||
125 | // d.JointSetAMotorParam(Amotor, 3, 0); | ||
126 | // d.JointSetAMotorParam(Amotor, 2, 0); | ||
127 | } | 121 | } |
128 | m_name = avName; | 122 | m_name = avName; |
129 | parent_scene.geom_name_map[Shell] = avName; | 123 | parent_scene.geom_name_map[Shell] = avName; |
@@ -136,6 +130,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
136 | set { return; } | 130 | set { return; } |
137 | } | 131 | } |
138 | 132 | ||
133 | /// <summary> | ||
134 | /// If this is set, the avatar will move faster | ||
135 | /// </summary> | ||
139 | public override bool SetAlwaysRun | 136 | public override bool SetAlwaysRun |
140 | { | 137 | { |
141 | get { return m_alwaysRun; } | 138 | get { return m_alwaysRun; } |
@@ -160,6 +157,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
160 | set { flying = value; } | 157 | set { flying = value; } |
161 | } | 158 | } |
162 | 159 | ||
160 | /// <summary> | ||
161 | /// Returns if the avatar is colliding in general. | ||
162 | /// This includes the ground and objects and avatar. | ||
163 | /// </summary> | ||
163 | public override bool IsColliding | 164 | public override bool IsColliding |
164 | { | 165 | { |
165 | get { return m_iscolliding; } | 166 | get { return m_iscolliding; } |
@@ -208,11 +209,17 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
208 | } | 209 | } |
209 | } | 210 | } |
210 | 211 | ||
212 | /// <summary> | ||
213 | /// Returns if an avatar is colliding with the ground | ||
214 | /// </summary> | ||
211 | public override bool CollidingGround | 215 | public override bool CollidingGround |
212 | { | 216 | { |
213 | get { return m_iscollidingGround; } | 217 | get { return m_iscollidingGround; } |
214 | set | 218 | set |
215 | { | 219 | { |
220 | // Collisions against the ground are not really reliable | ||
221 | // So, to get a consistant value we have to average the current result over time | ||
222 | // Currently we use 1 second = 10 calls to this. | ||
216 | int i; | 223 | int i; |
217 | int truecount = 0; | 224 | int truecount = 0; |
218 | int falsecount = 0; | 225 | int falsecount = 0; |
@@ -256,6 +263,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
256 | } | 263 | } |
257 | } | 264 | } |
258 | 265 | ||
266 | /// <summary> | ||
267 | /// Returns if the avatar is colliding with an object | ||
268 | /// </summary> | ||
259 | public override bool CollidingObj | 269 | public override bool CollidingObj |
260 | { | 270 | { |
261 | get { return m_iscollidingObj; } | 271 | get { return m_iscollidingObj; } |
@@ -269,11 +279,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
269 | } | 279 | } |
270 | } | 280 | } |
271 | 281 | ||
282 | /// <summary> | ||
283 | /// turn the PID controller on or off. | ||
284 | /// The PID Controller will turn on all by itself in many situations | ||
285 | /// </summary> | ||
286 | /// <param name="status"></param> | ||
272 | public void SetPidStatus(bool status) | 287 | public void SetPidStatus(bool status) |
273 | { | 288 | { |
274 | m_pidControllerActive = status; | 289 | m_pidControllerActive = status; |
275 | } | 290 | } |
276 | 291 | ||
292 | /// <summary> | ||
293 | /// This 'puts' an avatar somewhere in the physics space. | ||
294 | /// Not really a good choice unless you 'know' it's a good | ||
295 | /// spot otherwise you're likely to orbit the avatar. | ||
296 | /// </summary> | ||
277 | public override PhysicsVector Position | 297 | public override PhysicsVector Position |
278 | { | 298 | { |
279 | get { return _position; } | 299 | get { return _position; } |
@@ -293,6 +313,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
293 | set { m_rotationalVelocity = value; } | 313 | set { m_rotationalVelocity = value; } |
294 | } | 314 | } |
295 | 315 | ||
316 | /// <summary> | ||
317 | /// This property sets the height of the avatar only. We use the height to make sure the avatar stands up straight | ||
318 | /// and use it to offset landings properly | ||
319 | /// </summary> | ||
296 | public override PhysicsVector Size | 320 | public override PhysicsVector Size |
297 | { | 321 | { |
298 | get { return new PhysicsVector(CAPSULE_RADIUS*2, CAPSULE_RADIUS*2, CAPSULE_LENGTH); } | 322 | get { return new PhysicsVector(CAPSULE_RADIUS*2, CAPSULE_RADIUS*2, CAPSULE_LENGTH); } |
@@ -301,6 +325,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
301 | m_pidControllerActive = true; | 325 | m_pidControllerActive = true; |
302 | lock (OdeScene.OdeLock) | 326 | lock (OdeScene.OdeLock) |
303 | { | 327 | { |
328 | d.JointDestroy(Amotor); | ||
304 | PhysicsVector SetSize = value; | 329 | PhysicsVector SetSize = value; |
305 | float prevCapsule = CAPSULE_LENGTH; | 330 | float prevCapsule = CAPSULE_LENGTH; |
306 | float capsuleradius = CAPSULE_RADIUS; | 331 | float capsuleradius = CAPSULE_RADIUS; |
@@ -309,20 +334,91 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
309 | CAPSULE_LENGTH = (SetSize.Z - ((SetSize.Z*0.43f))); // subtract 43% of the size | 334 | CAPSULE_LENGTH = (SetSize.Z - ((SetSize.Z*0.43f))); // subtract 43% of the size |
310 | d.BodyDestroy(Body); | 335 | d.BodyDestroy(Body); |
311 | d.GeomDestroy(Shell); | 336 | d.GeomDestroy(Shell); |
312 | //MainLog.Instance.Verbose("PHYSICS", "Set Avatar Height To: " + (CAPSULE_RADIUS + CAPSULE_LENGTH)); | 337 | AvatarGeomAndBodyCreation(_position.X, _position.Y, |
313 | Shell = d.CreateCapsule(_parent_scene.space, capsuleradius, CAPSULE_LENGTH); | 338 | _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule)*2)); |
314 | d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); | 339 | Velocity = new PhysicsVector(0f, 0f, 0f); |
315 | Body = d.BodyCreate(_parent_scene.world); | 340 | |
316 | d.BodySetMass(Body, ref ShellMass); | ||
317 | d.BodySetPosition(Body, _position.X, _position.Y, | ||
318 | _position.Z + Math.Abs(CAPSULE_LENGTH - prevCapsule)); | ||
319 | d.GeomSetBody(Shell, Body); | ||
320 | } | 341 | } |
321 | _parent_scene.geom_name_map[Shell] = m_name; | 342 | _parent_scene.geom_name_map[Shell] = m_name; |
322 | _parent_scene.actor_name_map[Shell] = (PhysicsActor) this; | 343 | _parent_scene.actor_name_map[Shell] = (PhysicsActor) this; |
323 | } | 344 | } |
324 | } | 345 | } |
346 | /// <summary> | ||
347 | /// This creates the Avatar's physical Surrogate at the position supplied | ||
348 | /// </summary> | ||
349 | /// <param name="npositionX"></param> | ||
350 | /// <param name="npositionY"></param> | ||
351 | /// <param name="npositionZ"></param> | ||
352 | private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ) | ||
353 | { | ||
354 | int dAMotorEuler = 1; | ||
355 | Shell = d.CreateCapsule(_parent_scene.space, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
356 | d.MassSetCapsuleTotal(out ShellMass, m_mass, 2, CAPSULE_RADIUS, CAPSULE_LENGTH); | ||
357 | Body = d.BodyCreate(_parent_scene.world); | ||
358 | d.BodySetPosition(Body, npositionX, npositionY, npositionZ); | ||
359 | |||
360 | d.BodySetMass(Body, ref ShellMass); | ||
361 | |||
362 | // 90 Stand up on the cap of the capped cyllinder | ||
363 | d.RFromAxisAndAngle(out m_StandUpRotation, 1, 0, 0, (float)(Math.PI / 2)); | ||
364 | |||
365 | |||
366 | d.GeomSetRotation(Shell, ref m_StandUpRotation); | ||
367 | d.BodySetRotation(Body, ref m_StandUpRotation); | ||
368 | |||
369 | d.GeomSetBody(Shell, Body); | ||
370 | |||
371 | |||
372 | // The purpose of the AMotor here is to keep the avatar's physical | ||
373 | // surrogate from rotating while moving | ||
374 | Amotor = d.JointCreateAMotor(_parent_scene.world, IntPtr.Zero); | ||
375 | d.JointAttach(Amotor, Body, IntPtr.Zero); | ||
376 | d.JointSetAMotorMode(Amotor, dAMotorEuler); | ||
377 | d.JointSetAMotorNumAxes(Amotor, 3); | ||
378 | d.JointSetAMotorAxis(Amotor, 0, 0, 1, 0, 0); | ||
379 | d.JointSetAMotorAxis(Amotor, 1, 0, 0, 1, 0); | ||
380 | d.JointSetAMotorAxis(Amotor, 2, 0, 0, 0, 1); | ||
381 | d.JointSetAMotorAngle(Amotor, 0, 0); | ||
382 | d.JointSetAMotorAngle(Amotor, 1, 0); | ||
383 | d.JointSetAMotorAngle(Amotor, 2, 0); | ||
384 | |||
385 | // These lowstops and high stops are effectively (no wiggle room) | ||
386 | d.JointSetAMotorParam(Amotor, (int)dParam.LowStop, -0.000000000001f); | ||
387 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop3, -0.000000000001f); | ||
388 | d.JointSetAMotorParam(Amotor, (int)dParam.LoStop2, -0.000000000001f); | ||
389 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop, 0.000000000001f); | ||
390 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop3, 0.000000000001f); | ||
391 | d.JointSetAMotorParam(Amotor, (int)dParam.HiStop2, 0.000000000001f); | ||
392 | |||
393 | // Fudge factor is 1f by default, we're setting it to 0. We don't want it to Fudge or the | ||
394 | // capped cyllinder will fall over | ||
395 | d.JointSetAMotorParam(Amotor, (int)dParam.FudgeFactor, 0f); | ||
396 | d.JointSetAMotorParam(Amotor, (int)dParam.FMax, 3800000f); | ||
397 | |||
398 | |||
399 | // The purpose of this routine here is to quickly stabilize the Body while it's popped up in the air. | ||
400 | // The amotor needs a few seconds to stabilize so without it, the avatar shoots up sky high when you | ||
401 | // change appearance and when you enter the simulator | ||
402 | // After this routine is done, the amotor stabilizes much quicker | ||
403 | d.Vector3 feet; | ||
404 | d.Vector3 head; | ||
405 | d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); | ||
406 | d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); | ||
407 | float posture = head.Z - feet.Z; | ||
408 | |||
409 | // restoring force proportional to lack of posture: | ||
410 | float servo = (2.5f - posture) * POSTURE_SERVO; | ||
411 | d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); | ||
412 | d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); | ||
413 | |||
414 | |||
415 | } | ||
325 | 416 | ||
417 | // | ||
418 | /// <summary> | ||
419 | /// Uses the capped cyllinder volume formula to calculate the avatar's mass. | ||
420 | /// This may be used in calculations in the scene/scenepresence | ||
421 | /// </summary> | ||
326 | public override float Mass | 422 | public override float Mass |
327 | { | 423 | { |
328 | get | 424 | get |
@@ -385,6 +481,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
385 | _acceleration = accel; | 481 | _acceleration = accel; |
386 | } | 482 | } |
387 | 483 | ||
484 | /// <summary> | ||
485 | /// Adds the force supplied to the Target Velocity | ||
486 | /// The PID controller takes this target velocity and tries to make it a reality | ||
487 | /// </summary> | ||
488 | /// <param name="force"></param> | ||
388 | public override void AddForce(PhysicsVector force) | 489 | public override void AddForce(PhysicsVector force) |
389 | { | 490 | { |
390 | m_pidControllerActive = true; | 491 | m_pidControllerActive = true; |
@@ -395,29 +496,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
395 | //m_lastUpdateSent = false; | 496 | //m_lastUpdateSent = false; |
396 | } | 497 | } |
397 | 498 | ||
499 | /// <summary> | ||
500 | /// After all of the forces add up with 'add force' we apply them with doForce | ||
501 | /// </summary> | ||
502 | /// <param name="force"></param> | ||
398 | public void doForce(PhysicsVector force) | 503 | public void doForce(PhysicsVector force) |
399 | { | 504 | { |
400 | if (!collidelock) | 505 | if (!collidelock) |
401 | { | 506 | { |
402 | d.BodyAddForce(Body, force.X, force.Y, force.Z); | 507 | d.BodyAddForce(Body, force.X, force.Y, force.Z); |
403 | |||
404 | // ok -- let's stand up straight! | ||
405 | //d.Matrix3 StandUpRotationalMatrix = new d.Matrix3(0.8184158f, -0.5744568f, -0.0139677f, 0.5744615f, 0.8185215f, -0.004074608f, 0.01377355f, -0.004689182f, 0.9998941f); | ||
406 | //d.BodySetRotation(Body, ref StandUpRotationalMatrix); | ||
407 | //d.BodySetRotation(Body, ref m_StandUpRotation); | ||
408 | // The above matrix was generated with the amazing standup routine below by danX0r *cheer* | ||
409 | d.Vector3 feet; | ||
410 | d.Vector3 head; | ||
411 | d.BodyGetRelPointPos(Body, 0.0f, 0.0f, -1.0f, out feet); | ||
412 | d.BodyGetRelPointPos(Body, 0.0f, 0.0f, 1.0f, out head); | ||
413 | float posture = head.Z - feet.Z; | ||
414 | |||
415 | // restoring force proportional to lack of posture: | ||
416 | float servo = (2.5f - posture) * POSTURE_SERVO; | ||
417 | d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, servo, 0.0f, 0.0f, 1.0f); | ||
418 | d.BodyAddForceAtRelPos(Body, 0.0f, 0.0f, -servo, 0.0f, 0.0f, -1.0f); | ||
419 | |||
420 | //m_lastUpdateSent = false; | ||
421 | } | 508 | } |
422 | } | 509 | } |
423 | 510 | ||
@@ -425,9 +512,19 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
425 | { | 512 | { |
426 | } | 513 | } |
427 | 514 | ||
515 | |||
516 | /// <summary> | ||
517 | /// Called from Simulate | ||
518 | /// This is the avatar's movement control + PID Controller | ||
519 | /// </summary> | ||
520 | /// <param name="timeStep"></param> | ||
428 | public void Move(float timeStep) | 521 | public void Move(float timeStep) |
429 | { | 522 | { |
430 | // no lock; for now it's only called from within Simulate() | 523 | // no lock; for now it's only called from within Simulate() |
524 | |||
525 | // If the PID Controller isn't active then we set our force | ||
526 | // calculating base velocity to the current position | ||
527 | |||
431 | if (m_pidControllerActive == false) | 528 | if (m_pidControllerActive == false) |
432 | { | 529 | { |
433 | _zeroPosition = d.BodyGetPosition(Body); | 530 | _zeroPosition = d.BodyGetPosition(Body); |
@@ -458,6 +555,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
458 | } | 555 | } |
459 | if (m_pidControllerActive) | 556 | if (m_pidControllerActive) |
460 | { | 557 | { |
558 | // We only want to deactivate the PID Controller if we think we want to have our surrogate | ||
559 | // react to the physics scene by moving it's position. | ||
560 | // Avatar to Avatar collisions | ||
561 | // Prim to avatar collisions | ||
562 | |||
461 | d.Vector3 pos = d.BodyGetPosition(Body); | 563 | d.Vector3 pos = d.BodyGetPosition(Body); |
462 | vec.X = (_target_velocity.X - vel.X)*PID_D + (_zeroPosition.X - pos.X)*PID_P; | 564 | vec.X = (_target_velocity.X - vel.X)*PID_D + (_zeroPosition.X - pos.X)*PID_P; |
463 | vec.Y = (_target_velocity.Y - vel.Y)*PID_D + (_zeroPosition.Y - pos.Y)*PID_P; | 565 | vec.Y = (_target_velocity.Y - vel.Y)*PID_D + (_zeroPosition.Y - pos.Y)*PID_P; |
@@ -474,11 +576,14 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
474 | _zeroFlag = false; | 576 | _zeroFlag = false; |
475 | if (m_iscolliding || flying) | 577 | if (m_iscolliding || flying) |
476 | { | 578 | { |
579 | // We're flying and colliding with something | ||
477 | vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*PID_D; | 580 | vec.X = ((_target_velocity.X/movementdivisor) - vel.X)*PID_D; |
478 | vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*PID_D; | 581 | vec.Y = ((_target_velocity.Y/movementdivisor) - vel.Y)*PID_D; |
479 | } | 582 | } |
480 | if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) | 583 | if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) |
481 | { | 584 | { |
585 | // We're colliding with something and we're not flying but we're moving | ||
586 | // This means we're walking or running. | ||
482 | d.Vector3 pos = d.BodyGetPosition(Body); | 587 | d.Vector3 pos = d.BodyGetPosition(Body); |
483 | vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P; | 588 | vec.Z = (_target_velocity.Z - vel.Z)*PID_D + (_zeroPosition.Z - pos.Z)*PID_P; |
484 | if (_target_velocity.X > 0) | 589 | if (_target_velocity.X > 0) |
@@ -492,6 +597,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
492 | } | 597 | } |
493 | else if (!m_iscolliding && !flying) | 598 | else if (!m_iscolliding && !flying) |
494 | { | 599 | { |
600 | // we're not colliding and we're not flying so that means we're falling! | ||
601 | // m_iscolliding includes collisions with the ground. | ||
495 | d.Vector3 pos = d.BodyGetPosition(Body); | 602 | d.Vector3 pos = d.BodyGetPosition(Body); |
496 | if (_target_velocity.X > 0) | 603 | if (_target_velocity.X > 0) |
497 | { | 604 | { |
@@ -518,6 +625,9 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
518 | doForce(vec); | 625 | doForce(vec); |
519 | } | 626 | } |
520 | 627 | ||
628 | /// <summary> | ||
629 | /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. | ||
630 | /// </summary> | ||
521 | public void UpdatePositionAndVelocity() | 631 | public void UpdatePositionAndVelocity() |
522 | { | 632 | { |
523 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! | 633 | // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! |
@@ -533,25 +643,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
533 | _position.Y = vec.Y; | 643 | _position.Y = vec.Y; |
534 | _position.Z = vec.Z; | 644 | _position.Z = vec.Z; |
535 | 645 | ||
646 | // Did we move last? = zeroflag | ||
647 | // This helps keep us from sliding all over | ||
648 | |||
536 | if (_zeroFlag) | 649 | if (_zeroFlag) |
537 | { | 650 | { |
538 | _velocity.X = 0.0f; | 651 | _velocity.X = 0.0f; |
539 | _velocity.Y = 0.0f; | 652 | _velocity.Y = 0.0f; |
540 | _velocity.Z = 0.0f; | 653 | _velocity.Z = 0.0f; |
654 | |||
655 | // Did we send out the 'stopped' message? | ||
541 | if (!m_lastUpdateSent) | 656 | if (!m_lastUpdateSent) |
542 | { | 657 | { |
543 | m_lastUpdateSent = true; | 658 | m_lastUpdateSent = true; |
544 | base.RequestPhysicsterseUpdate(); | 659 | base.RequestPhysicsterseUpdate(); |
545 | //string primScenAvatarIn = _parent_scene.whichspaceamIin(_position); | 660 | |
546 | //int[] arrayitem = _parent_scene.calculateSpaceArrayItemFromPos(_position); | ||
547 | //if (primScenAvatarIn == "0") | ||
548 | //{ | ||
549 | //MainLog.Instance.Verbose("Physics", "Avatar " + m_name + " in space with no prim. Arr:':" + arrayitem[0].ToString() + "," + arrayitem[1].ToString()); | ||
550 | //} | ||
551 | //else | ||
552 | //{ | ||
553 | // MainLog.Instance.Verbose("Physics", "Avatar " + m_name + " in Prim space':" + primScenAvatarIn + ". Arr:" + arrayitem[0].ToString() + "," + arrayitem[1].ToString()); | ||
554 | //} | ||
555 | } | 661 | } |
556 | } | 662 | } |
557 | else | 663 | else |
@@ -564,6 +670,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
564 | _velocity.Z = (vec.Z); | 670 | _velocity.Z = (vec.Z); |
565 | if (_velocity.Z < -6 && !m_hackSentFall) | 671 | if (_velocity.Z < -6 && !m_hackSentFall) |
566 | { | 672 | { |
673 | // Collisionupdates will be used in the future, right now the're not being used. | ||
567 | m_hackSentFall = true; | 674 | m_hackSentFall = true; |
568 | //base.SendCollisionUpdate(new CollisionEventUpdate()); | 675 | //base.SendCollisionUpdate(new CollisionEventUpdate()); |
569 | m_pidControllerActive = false; | 676 | m_pidControllerActive = false; |
@@ -581,13 +688,21 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
581 | } | 688 | } |
582 | } | 689 | } |
583 | 690 | ||
691 | /// <summary> | ||
692 | /// Cleanup the things we use in the scene. | ||
693 | /// </summary> | ||
584 | public void Destroy() | 694 | public void Destroy() |
585 | { | 695 | { |
586 | lock (OdeScene.OdeLock) | 696 | lock (OdeScene.OdeLock) |
587 | { | 697 | { |
588 | // d.JointDestroy(Amotor); | 698 | // Kill the Amotor |
699 | d.JointDestroy(Amotor); | ||
700 | |||
701 | //kill the Geometry | ||
589 | d.GeomDestroy(Shell); | 702 | d.GeomDestroy(Shell); |
590 | _parent_scene.geom_name_map.Remove(Shell); | 703 | _parent_scene.geom_name_map.Remove(Shell); |
704 | |||
705 | //kill the body | ||
591 | d.BodyDestroy(Body); | 706 | d.BodyDestroy(Body); |
592 | } | 707 | } |
593 | } | 708 | } |
diff --git a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs index 17dbd0a..366f30b 100644 --- a/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs +++ b/OpenSim/Region/Physics/OdePlugin/OdePlugin.cs | |||
@@ -86,6 +86,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
86 | private IntPtr contactgroup; | 86 | private IntPtr contactgroup; |
87 | private IntPtr LandGeom = (IntPtr) 0; | 87 | private IntPtr LandGeom = (IntPtr) 0; |
88 | private double[] _heightmap; | 88 | private double[] _heightmap; |
89 | private float[] _origheightmap; | ||
89 | private d.NearCallback nearCallback; | 90 | private d.NearCallback nearCallback; |
90 | public d.TriCallback triCallback; | 91 | public d.TriCallback triCallback; |
91 | public d.TriArrayCallback triArrayCallback; | 92 | public d.TriArrayCallback triArrayCallback; |
@@ -115,6 +116,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
115 | 116 | ||
116 | public IMesher mesher; | 117 | public IMesher mesher; |
117 | 118 | ||
119 | |||
120 | /// <summary> | ||
121 | /// Initiailizes the scene | ||
122 | /// Sets many properties that ODE requires to be stable | ||
123 | /// These settings need to be tweaked 'exactly' right or weird stuff happens. | ||
124 | /// </summary> | ||
118 | public OdeScene() | 125 | public OdeScene() |
119 | { | 126 | { |
120 | nearCallback = near; | 127 | nearCallback = near; |
@@ -128,17 +135,27 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
128 | contact.surface.soft_cfm = 0.00003f; | 135 | contact.surface.soft_cfm = 0.00003f; |
129 | */ | 136 | */ |
130 | 137 | ||
138 | // Centeral contact friction and bounce | ||
131 | contact.surface.mu = 250.0f; | 139 | contact.surface.mu = 250.0f; |
132 | contact.surface.bounce = 0.2f; | 140 | contact.surface.bounce = 0.2f; |
133 | 141 | ||
142 | // Terrain contact friction and Bounce | ||
143 | // This is the *non* moving version. Use this when an avatar | ||
144 | // isn't moving to keep it in place better | ||
134 | TerrainContact.surface.mode |= d.ContactFlags.SoftERP; | 145 | TerrainContact.surface.mode |= d.ContactFlags.SoftERP; |
135 | TerrainContact.surface.mu = 550.0f; | 146 | TerrainContact.surface.mu = 550.0f; |
136 | TerrainContact.surface.bounce = 0.1f; | 147 | TerrainContact.surface.bounce = 0.1f; |
137 | TerrainContact.surface.soft_erp = 0.1025f; | 148 | TerrainContact.surface.soft_erp = 0.1025f; |
138 | 149 | ||
150 | // Prim contact friction and bounce | ||
151 | // THis is the *non* moving version of friction and bounce | ||
152 | // Use this when an avatar comes in contact with a prim | ||
153 | // and is moving | ||
139 | AvatarMovementprimContact.surface.mu = 150.0f; | 154 | AvatarMovementprimContact.surface.mu = 150.0f; |
140 | AvatarMovementprimContact.surface.bounce = 0.1f; | 155 | AvatarMovementprimContact.surface.bounce = 0.1f; |
141 | 156 | ||
157 | // Terrain contact friction bounce and various error correcting calculations | ||
158 | // Use this when an avatar is in contact with the terrain and moving. | ||
142 | AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; | 159 | AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP; |
143 | AvatarMovementTerrainContact.surface.mu = 150.0f; | 160 | AvatarMovementTerrainContact.surface.mu = 150.0f; |
144 | AvatarMovementTerrainContact.surface.bounce = 0.1f; | 161 | AvatarMovementTerrainContact.surface.bounce = 0.1f; |
@@ -146,6 +163,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
146 | 163 | ||
147 | lock (OdeLock) | 164 | lock (OdeLock) |
148 | { | 165 | { |
166 | // Creat the world and the first space | ||
149 | world = d.WorldCreate(); | 167 | world = d.WorldCreate(); |
150 | space = d.HashSpaceCreate(IntPtr.Zero); | 168 | space = d.HashSpaceCreate(IntPtr.Zero); |
151 | d.HashSpaceSetLevels(space, -4, 128); | 169 | d.HashSpaceSetLevels(space, -4, 128); |
@@ -153,15 +171,25 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
153 | //contactgroup | 171 | //contactgroup |
154 | 172 | ||
155 | 173 | ||
174 | // Set the gravity,, don't disable things automatically (we set it explicitly on some things) | ||
175 | |||
156 | d.WorldSetGravity(world, 0.0f, 0.0f, -10.0f); | 176 | d.WorldSetGravity(world, 0.0f, 0.0f, -10.0f); |
157 | d.WorldSetAutoDisableFlag(world, false); | 177 | d.WorldSetAutoDisableFlag(world, false); |
158 | d.WorldSetContactSurfaceLayer(world, 0.001f); | 178 | d.WorldSetContactSurfaceLayer(world, 0.001f); |
179 | |||
180 | // Set how many steps we go without running collision testing | ||
181 | // This is in addition to the step size. | ||
182 | // Essentially Steps * m_physicsiterations | ||
159 | d.WorldSetQuickStepNumIterations(world, m_physicsiterations); | 183 | d.WorldSetQuickStepNumIterations(world, m_physicsiterations); |
160 | d.WorldSetContactMaxCorrectingVel(world, 1000.0f); | 184 | ///d.WorldSetContactMaxCorrectingVel(world, 1000.0f); |
161 | } | 185 | } |
162 | 186 | ||
187 | // zero out a heightmap array float array (single dimention [flattened])) | ||
163 | _heightmap = new double[514*514]; | 188 | _heightmap = new double[514*514]; |
164 | 189 | ||
190 | |||
191 | // Zero out the prim spaces array (we split our space into smaller spaces so | ||
192 | // we can hit test less. | ||
165 | for (int i = 0; i < staticPrimspace.GetLength(0); i++) | 193 | for (int i = 0; i < staticPrimspace.GetLength(0); i++) |
166 | { | 194 | { |
167 | for (int j = 0; j < staticPrimspace.GetLength(1); j++) | 195 | for (int j = 0; j < staticPrimspace.GetLength(1); j++) |
@@ -171,19 +199,35 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
171 | } | 199 | } |
172 | } | 200 | } |
173 | 201 | ||
202 | // Initialize the mesh plugin | ||
174 | public override void Initialise(IMesher meshmerizer) | 203 | public override void Initialise(IMesher meshmerizer) |
175 | { | 204 | { |
176 | mesher = meshmerizer; | 205 | mesher = meshmerizer; |
177 | } | 206 | } |
178 | 207 | ||
208 | /// <summary> | ||
209 | /// Debug space message for printing the space that a prim/avatar is in. | ||
210 | /// </summary> | ||
211 | /// <param name="pos"></param> | ||
212 | /// <returns>Returns which split up space the given position is in.</returns> | ||
179 | public string whichspaceamIin(PhysicsVector pos) | 213 | public string whichspaceamIin(PhysicsVector pos) |
180 | { | 214 | { |
181 | return calculateSpaceForGeom(pos).ToString(); | 215 | return calculateSpaceForGeom(pos).ToString(); |
182 | } | 216 | } |
183 | 217 | ||
218 | /// <summary> | ||
219 | /// This is our near callback. A geometry is near a body | ||
220 | /// </summary> | ||
221 | /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param> | ||
222 | /// <param name="g1">a geometry or space</param> | ||
223 | /// <param name="g2">another geometry or space</param> | ||
184 | private void near(IntPtr space, IntPtr g1, IntPtr g2) | 224 | private void near(IntPtr space, IntPtr g1, IntPtr g2) |
185 | { | 225 | { |
186 | // no lock here! It's invoked from within Simulate(), which is thread-locked | 226 | // no lock here! It's invoked from within Simulate(), which is thread-locked |
227 | |||
228 | // Test if we're collidng a geom with a space. | ||
229 | // If so we have to drill down into the space recursively | ||
230 | |||
187 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) | 231 | if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2)) |
188 | { | 232 | { |
189 | // Separating static prim geometry spaces. | 233 | // Separating static prim geometry spaces. |
@@ -192,7 +236,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
192 | // contact points in the space | 236 | // contact points in the space |
193 | 237 | ||
194 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); | 238 | d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback); |
195 | //Colliding a space or a geom with a space or a geom. | 239 | //Colliding a space or a geom with a space or a geom. so drill down |
196 | 240 | ||
197 | //Collide all geoms in each space.. | 241 | //Collide all geoms in each space.. |
198 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); | 242 | //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback); |
@@ -226,12 +270,13 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
226 | name2 = "null"; | 270 | name2 = "null"; |
227 | } | 271 | } |
228 | 272 | ||
229 | if (id == d.GeomClassID.TriMeshClass) | 273 | //if (id == d.GeomClassID.TriMeshClass) |
230 | { | 274 | //{ |
231 | // MainLog.Instance.Verbose("near: A collision was detected between {1} and {2}", 0, name1, name2); | 275 | // MainLog.Instance.Verbose("near: A collision was detected between {1} and {2}", 0, name1, name2); |
232 | //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2); | 276 | //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2); |
233 | } | 277 | //} |
234 | 278 | ||
279 | // Figure out how many contact points we have | ||
235 | int count = 0; | 280 | int count = 0; |
236 | try | 281 | try |
237 | { | 282 | { |
@@ -244,13 +289,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
244 | base.TriggerPhysicsBasedRestart(); | 289 | base.TriggerPhysicsBasedRestart(); |
245 | } | 290 | } |
246 | 291 | ||
292 | PhysicsActor p1; | ||
293 | PhysicsActor p2; | ||
294 | |||
247 | for (int i = 0; i < count; i++) | 295 | for (int i = 0; i < count; i++) |
248 | { | 296 | { |
249 | IntPtr joint; | 297 | IntPtr joint; |
250 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. | 298 | // If we're colliding with terrain, use 'TerrainContact' instead of contact. |
251 | // allows us to have different settings | 299 | // allows us to have different settings |
252 | PhysicsActor p1; | 300 | |
253 | PhysicsActor p2; | ||
254 | 301 | ||
255 | if (!actor_name_map.TryGetValue(g1, out p1)) | 302 | if (!actor_name_map.TryGetValue(g1, out p1)) |
256 | { | 303 | { |
@@ -267,14 +314,14 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
267 | 314 | ||
268 | switch (p1.PhysicsActorType) | 315 | switch (p1.PhysicsActorType) |
269 | { | 316 | { |
270 | case (int) ActorTypes.Agent: | 317 | case (int)ActorTypes.Agent: |
271 | p2.CollidingObj = true; | 318 | p2.CollidingObj = true; |
272 | break; | 319 | break; |
273 | case (int) ActorTypes.Prim: | 320 | case (int)ActorTypes.Prim: |
274 | if (p2.Velocity.X > 0 || p2.Velocity.Y > 0 || p2.Velocity.Z > 0) | 321 | if (p2.Velocity.X > 0 || p2.Velocity.Y > 0 || p2.Velocity.Z > 0) |
275 | p2.CollidingObj = true; | 322 | p2.CollidingObj = true; |
276 | break; | 323 | break; |
277 | case (int) ActorTypes.Unknown: | 324 | case (int)ActorTypes.Unknown: |
278 | p2.CollidingGround = true; | 325 | p2.CollidingGround = true; |
279 | break; | 326 | break; |
280 | default: | 327 | default: |
@@ -288,11 +335,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
288 | 335 | ||
289 | if (contacts[i].depth >= 0.08f) | 336 | if (contacts[i].depth >= 0.08f) |
290 | { | 337 | { |
338 | /* This is disabled at the moment only because it needs more tweaking | ||
339 | It will eventually be uncommented | ||
340 | |||
291 | if (contacts[i].depth >= 1.00f) | 341 | if (contacts[i].depth >= 1.00f) |
292 | { | 342 | { |
293 | //MainLog.Instance.Debug("PHYSICS",contacts[i].depth.ToString()); | 343 | //MainLog.Instance.Debug("PHYSICS",contacts[i].depth.ToString()); |
294 | } | 344 | } |
295 | // If you interpenetrate a prim with an agent | 345 | |
346 | //If you interpenetrate a prim with an agent | ||
296 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | 347 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && |
297 | p1.PhysicsActorType == (int) ActorTypes.Prim) || | 348 | p1.PhysicsActorType == (int) ActorTypes.Prim) || |
298 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | 349 | (p1.PhysicsActorType == (int) ActorTypes.Agent && |
@@ -300,35 +351,37 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
300 | { | 351 | { |
301 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) | 352 | if (p2.PhysicsActorType == (int) ActorTypes.Agent) |
302 | { | 353 | { |
303 | //p2.CollidingObj = true; | 354 | p2.CollidingObj = true; |
304 | //contacts[i].depth = 0.003f; | 355 | contacts[i].depth = 0.003f; |
305 | //p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); | 356 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f); |
306 | //OdeCharacter character = (OdeCharacter) p2; | 357 | OdeCharacter character = (OdeCharacter) p2; |
307 | //character.SetPidStatus(true); | 358 | character.SetPidStatus(true); |
308 | //contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p1.Size.X / 2), contacts[i].pos.Y + (p1.Size.Y / 2), contacts[i].pos.Z + (p1.Size.Z / 2)); | 359 | contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p1.Size.X / 2), contacts[i].pos.Y + (p1.Size.Y / 2), contacts[i].pos.Z + (p1.Size.Z / 2)); |
309 | 360 | ||
310 | } | 361 | } |
311 | else | 362 | else |
312 | { | 363 | { |
313 | 364 | ||
314 | //contacts[i].depth = 0.0000000f; | 365 | contacts[i].depth = 0.0000000f; |
315 | } | 366 | } |
316 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) | 367 | if (p1.PhysicsActorType == (int) ActorTypes.Agent) |
317 | { | 368 | { |
318 | 369 | ||
319 | //p1.CollidingObj = true; | 370 | p1.CollidingObj = true; |
320 | //contacts[i].depth = 0.003f; | 371 | contacts[i].depth = 0.003f; |
321 | //p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); | 372 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f); |
322 | //contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p2.Size.X / 2), contacts[i].pos.Y + (p2.Size.Y / 2), contacts[i].pos.Z + (p2.Size.Z / 2)); | 373 | contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p2.Size.X / 2), contacts[i].pos.Y + (p2.Size.Y / 2), contacts[i].pos.Z + (p2.Size.Z / 2)); |
323 | //OdeCharacter character = (OdeCharacter)p1; | 374 | OdeCharacter character = (OdeCharacter)p1; |
324 | //character.SetPidStatus(true); | 375 | character.SetPidStatus(true); |
325 | } | 376 | } |
326 | else | 377 | else |
327 | { | 378 | { |
328 | 379 | ||
329 | //contacts[i].depth = 0.0000000f; | 380 | contacts[i].depth = 0.0000000f; |
330 | } | 381 | } |
331 | } | 382 | } |
383 | */ | ||
384 | |||
332 | // If you interpenetrate a prim with another prim | 385 | // If you interpenetrate a prim with another prim |
333 | if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim) | 386 | if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim) |
334 | { | 387 | { |
@@ -337,6 +390,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
337 | } | 390 | } |
338 | if (contacts[i].depth >= 1.00f) | 391 | if (contacts[i].depth >= 1.00f) |
339 | { | 392 | { |
393 | OpenSim.Framework.Console.MainLog.Instance.Verbose("P", contacts[i].depth.ToString()); | ||
340 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && | 394 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent && |
341 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || | 395 | p1.PhysicsActorType == (int) ActorTypes.Unknown) || |
342 | (p1.PhysicsActorType == (int) ActorTypes.Agent && | 396 | (p1.PhysicsActorType == (int) ActorTypes.Agent && |
@@ -347,7 +401,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
347 | OdeCharacter character = (OdeCharacter) p2; | 401 | OdeCharacter character = (OdeCharacter) p2; |
348 | 402 | ||
349 | //p2.CollidingObj = true; | 403 | //p2.CollidingObj = true; |
350 | contacts[i].depth = 0.003f; | 404 | contacts[i].depth = 0.00000003f; |
351 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 0.5f); | 405 | p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 0.5f); |
352 | contacts[i].pos = | 406 | contacts[i].pos = |
353 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), | 407 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), |
@@ -363,7 +417,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
363 | OdeCharacter character = (OdeCharacter)p1; | 417 | OdeCharacter character = (OdeCharacter)p1; |
364 | 418 | ||
365 | //p2.CollidingObj = true; | 419 | //p2.CollidingObj = true; |
366 | contacts[i].depth = 0.003f; | 420 | contacts[i].depth = 0.00000003f; |
367 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 0.5f); | 421 | p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 0.5f); |
368 | contacts[i].pos = | 422 | contacts[i].pos = |
369 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), | 423 | new d.Vector3(contacts[i].pos.X + (p1.Size.X/2), |
@@ -383,30 +437,39 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
383 | 437 | ||
384 | if (contacts[i].depth >= 0f) | 438 | if (contacts[i].depth >= 0f) |
385 | { | 439 | { |
440 | // If we're collidng against terrain | ||
386 | if (name1 == "Terrain" || name2 == "Terrain") | 441 | if (name1 == "Terrain" || name2 == "Terrain") |
387 | { | 442 | { |
443 | // If we're moving | ||
388 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && | 444 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && |
389 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | 445 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) |
390 | { | 446 | { |
447 | // Use the movement terrain contact | ||
391 | AvatarMovementTerrainContact.geom = contacts[i]; | 448 | AvatarMovementTerrainContact.geom = contacts[i]; |
392 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); | 449 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact); |
393 | } | 450 | } |
394 | else | 451 | else |
395 | { | 452 | { |
453 | // Use the non moving terrain contact | ||
396 | TerrainContact.geom = contacts[i]; | 454 | TerrainContact.geom = contacts[i]; |
397 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); | 455 | joint = d.JointCreateContact(world, contactgroup, ref TerrainContact); |
398 | } | 456 | } |
399 | } | 457 | } |
400 | else | 458 | else |
401 | { | 459 | { |
460 | // we're colliding with prim or avatar | ||
461 | |||
462 | // check if we're moving | ||
402 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && | 463 | if ((p2.PhysicsActorType == (int) ActorTypes.Agent) && |
403 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) | 464 | (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f)) |
404 | { | 465 | { |
466 | // Use the Movement prim contact | ||
405 | AvatarMovementprimContact.geom = contacts[i]; | 467 | AvatarMovementprimContact.geom = contacts[i]; |
406 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); | 468 | joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact); |
407 | } | 469 | } |
408 | else | 470 | else |
409 | { | 471 | { |
472 | // Use the non movement contact | ||
410 | contact.geom = contacts[i]; | 473 | contact.geom = contacts[i]; |
411 | joint = d.JointCreateContact(world, contactgroup, ref contact); | 474 | joint = d.JointCreateContact(world, contactgroup, ref contact); |
412 | } | 475 | } |
@@ -416,6 +479,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
416 | 479 | ||
417 | if (count > 3) | 480 | if (count > 3) |
418 | { | 481 | { |
482 | // If there are more then 3 contact points, it's likely | ||
483 | // that we've got a pile of objects | ||
484 | // | ||
485 | // We don't want to send out hundreds of terse updates over and over again | ||
486 | // so lets throttle them and send them again after it's somewhat sorted out. | ||
419 | p2.ThrottleUpdates = true; | 487 | p2.ThrottleUpdates = true; |
420 | } | 488 | } |
421 | //System.Console.WriteLine(count.ToString()); | 489 | //System.Console.WriteLine(count.ToString()); |
@@ -423,16 +491,43 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
423 | } | 491 | } |
424 | } | 492 | } |
425 | } | 493 | } |
494 | private float GetTerrainHeightAtXY(float x, float y) | ||
495 | { | ||
496 | return (float)_origheightmap[(int) y*256 + (int) x]; | ||
497 | |||
426 | 498 | ||
499 | } | ||
500 | |||
501 | /// <summary> | ||
502 | /// This is our collision testing routine in ODE | ||
503 | /// </summary> | ||
504 | /// <param name="timeStep"></param> | ||
427 | private void collision_optimized(float timeStep) | 505 | private void collision_optimized(float timeStep) |
428 | { | 506 | { |
429 | foreach (OdeCharacter chr in _characters) | 507 | foreach (OdeCharacter chr in _characters) |
430 | { | 508 | { |
509 | // Reset the collision values to false | ||
510 | // since we don't know if we're colliding yet | ||
511 | |||
431 | chr.IsColliding = false; | 512 | chr.IsColliding = false; |
432 | chr.CollidingGround = false; | 513 | chr.CollidingGround = false; |
433 | chr.CollidingObj = false; | 514 | chr.CollidingObj = false; |
515 | |||
516 | // test the avatar's geometry for collision with the space | ||
517 | // This will return near and the space that they are the closest to | ||
518 | // And we'll run this again against the avatar and the space segment | ||
519 | // This will return with a bunch of possible objects in the space segment | ||
520 | // and we'll run it again on all of them. | ||
521 | |||
434 | d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); | 522 | d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback); |
523 | //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y); | ||
524 | //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10) | ||
525 | //{ | ||
526 | //chr.Position.Z = terrainheight + 10.0f; | ||
527 | //forcedZ = true; | ||
528 | //} | ||
435 | } | 529 | } |
530 | |||
436 | // If the sim is running slow this frame, | 531 | // If the sim is running slow this frame, |
437 | // don't process collision for prim! | 532 | // don't process collision for prim! |
438 | if (timeStep < (m_SkipFramesAtms/3)) | 533 | if (timeStep < (m_SkipFramesAtms/3)) |
@@ -469,6 +564,8 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
469 | // This if may not need to be there.. it might be skipped anyway. | 564 | // This if may not need to be there.. it might be skipped anyway. |
470 | if (d.BodyIsEnabled(chr.Body)) | 565 | if (d.BodyIsEnabled(chr.Body)) |
471 | { | 566 | { |
567 | // Collide test the prims with the terrain.. since if you don't do this, | ||
568 | // next frame, all of the physical prim in the scene will awaken and explode upwards | ||
472 | d.SpaceCollide2(LandGeom, chr.prim_geom, IntPtr.Zero, nearCallback); | 569 | d.SpaceCollide2(LandGeom, chr.prim_geom, IntPtr.Zero, nearCallback); |
473 | } | 570 | } |
474 | } | 571 | } |
@@ -509,6 +606,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
509 | } | 606 | } |
510 | } | 607 | } |
511 | 608 | ||
609 | /// <summary> | ||
610 | /// This is called from within simulate but outside the locked portion | ||
611 | /// We need to do our own locking here | ||
612 | /// Essentially, we need to remove the prim from our space segment, whatever segment it's in. | ||
613 | /// | ||
614 | /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory | ||
615 | /// that the space was using. | ||
616 | /// </summary> | ||
617 | /// <param name="prim"></param> | ||
512 | public void RemovePrimThreadLocked(OdePrim prim) | 618 | public void RemovePrimThreadLocked(OdePrim prim) |
513 | { | 619 | { |
514 | lock (OdeLock) | 620 | lock (OdeLock) |
@@ -567,7 +673,10 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
567 | _prims.Remove(prim); | 673 | _prims.Remove(prim); |
568 | } | 674 | } |
569 | } | 675 | } |
570 | 676 | /// <summary> | |
677 | /// Takes a space pointer and zeros out the array we're using to hold the spaces | ||
678 | /// </summary> | ||
679 | /// <param name="space"></param> | ||
571 | public void resetSpaceArrayItemToZero(IntPtr space) | 680 | public void resetSpaceArrayItemToZero(IntPtr space) |
572 | { | 681 | { |
573 | for (int x = 0; x < staticPrimspace.GetLength(0); x++) | 682 | for (int x = 0; x < staticPrimspace.GetLength(0); x++) |
@@ -585,15 +694,25 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
585 | staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; | 694 | staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero; |
586 | } | 695 | } |
587 | 696 | ||
697 | /// <summary> | ||
698 | /// Called when a static prim moves. Allocates a space for the prim based on it's position | ||
699 | /// </summary> | ||
700 | /// <param name="geom">the pointer to the geom that moved</param> | ||
701 | /// <param name="pos">the position that the geom moved to</param> | ||
702 | /// <param name="currentspace">a pointer to the space it was in before it was moved.</param> | ||
703 | /// <returns>a pointer to the new space it's in</returns> | ||
588 | public IntPtr recalculateSpaceForGeom(IntPtr geom, PhysicsVector pos, IntPtr currentspace) | 704 | public IntPtr recalculateSpaceForGeom(IntPtr geom, PhysicsVector pos, IntPtr currentspace) |
589 | { | 705 | { |
590 | //Todo recalculate space the prim is in. | 706 | |
591 | // Called from setting the Position and Size of an ODEPrim so | 707 | // Called from setting the Position and Size of an ODEPrim so |
592 | // it's already in locked space. | 708 | // it's already in locked space. |
593 | 709 | ||
594 | // we don't want to remove the main space | 710 | // we don't want to remove the main space |
595 | // we don't need to test physical here because this function should | 711 | // we don't need to test physical here because this function should |
596 | // never be called if the prim is physical(active) | 712 | // never be called if the prim is physical(active) |
713 | |||
714 | // All physical prim end up in the root space | ||
715 | |||
597 | if (currentspace != space) | 716 | if (currentspace != space) |
598 | { | 717 | { |
599 | if (d.SpaceQuery(currentspace, geom) && currentspace != (IntPtr) 0) | 718 | if (d.SpaceQuery(currentspace, geom) && currentspace != (IntPtr) 0) |
@@ -707,6 +826,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
707 | return newspace; | 826 | return newspace; |
708 | } | 827 | } |
709 | 828 | ||
829 | /// <summary> | ||
830 | /// Creates a new space at X Y | ||
831 | /// </summary> | ||
832 | /// <param name="iprimspaceArrItemX"></param> | ||
833 | /// <param name="iprimspaceArrItemY"></param> | ||
834 | /// <returns>A pointer to the created space</returns> | ||
710 | public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) | 835 | public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY) |
711 | { | 836 | { |
712 | // creating a new space for prim and inserting it into main space. | 837 | // creating a new space for prim and inserting it into main space. |
@@ -715,6 +840,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
715 | return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; | 840 | return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]; |
716 | } | 841 | } |
717 | 842 | ||
843 | /// <summary> | ||
844 | /// Calculates the space the prim should be in by it's position | ||
845 | /// </summary> | ||
846 | /// <param name="pos"></param> | ||
847 | /// <returns>a pointer to the space. This could be a new space or reused space.</returns> | ||
718 | public IntPtr calculateSpaceForGeom(PhysicsVector pos) | 848 | public IntPtr calculateSpaceForGeom(PhysicsVector pos) |
719 | { | 849 | { |
720 | int[] xyspace = calculateSpaceArrayItemFromPos(pos); | 850 | int[] xyspace = calculateSpaceArrayItemFromPos(pos); |
@@ -725,6 +855,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
725 | return locationbasedspace; | 855 | return locationbasedspace; |
726 | } | 856 | } |
727 | 857 | ||
858 | /// <summary> | ||
859 | /// Holds the space allocation logic | ||
860 | /// </summary> | ||
861 | /// <param name="pos"></param> | ||
862 | /// <returns>an array item based on the position</returns> | ||
728 | public int[] calculateSpaceArrayItemFromPos(PhysicsVector pos) | 863 | public int[] calculateSpaceArrayItemFromPos(PhysicsVector pos) |
729 | { | 864 | { |
730 | int[] returnint = new int[2]; | 865 | int[] returnint = new int[2]; |
@@ -837,7 +972,11 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
837 | return 1; | 972 | return 1; |
838 | } | 973 | } |
839 | 974 | ||
840 | 975 | /// <summary> | |
976 | /// Routine to figure out if we need to mesh this prim with our mesher | ||
977 | /// </summary> | ||
978 | /// <param name="pbs"></param> | ||
979 | /// <returns></returns> | ||
841 | public bool needsMeshing(PrimitiveBaseShape pbs) | 980 | public bool needsMeshing(PrimitiveBaseShape pbs) |
842 | { | 981 | { |
843 | if (pbs.ProfileHollow != 0) | 982 | if (pbs.ProfileHollow != 0) |
@@ -879,6 +1018,12 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
879 | return result; | 1018 | return result; |
880 | } | 1019 | } |
881 | 1020 | ||
1021 | /// <summary> | ||
1022 | /// Called after our prim properties are set Scale, position etc. | ||
1023 | /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex | ||
1024 | /// This assures us that we have no race conditions | ||
1025 | /// </summary> | ||
1026 | /// <param name="prim"></param> | ||
882 | public override void AddPhysicsActorTaint(PhysicsActor prim) | 1027 | public override void AddPhysicsActorTaint(PhysicsActor prim) |
883 | { | 1028 | { |
884 | if (prim is OdePrim) | 1029 | if (prim is OdePrim) |
@@ -889,6 +1034,15 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
889 | } | 1034 | } |
890 | } | 1035 | } |
891 | 1036 | ||
1037 | /// <summary> | ||
1038 | /// This is our main simulate loop | ||
1039 | /// It's thread locked by a Mutex in the scene. | ||
1040 | /// It holds Collisions, it instructs ODE to step through the physical reactions | ||
1041 | /// It moves the objects around in memory | ||
1042 | /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup) | ||
1043 | /// </summary> | ||
1044 | /// <param name="timeStep"></param> | ||
1045 | /// <returns></returns> | ||
892 | public override float Simulate(float timeStep) | 1046 | public override float Simulate(float timeStep) |
893 | { | 1047 | { |
894 | float fps = 0; | 1048 | float fps = 0; |
@@ -904,7 +1058,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
904 | 1058 | ||
905 | if (step_time >= m_SkipFramesAtms) | 1059 | if (step_time >= m_SkipFramesAtms) |
906 | { | 1060 | { |
907 | // Instead of trying to catch up, it'll do one physics frame only | 1061 | // Instead of trying to catch up, it'll do 5 physics frames only |
908 | step_time = ODE_STEPSIZE; | 1062 | step_time = ODE_STEPSIZE; |
909 | m_physicsiterations = 5; | 1063 | m_physicsiterations = 5; |
910 | } | 1064 | } |
@@ -960,6 +1114,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
960 | { | 1114 | { |
961 | actor.UpdatePositionAndVelocity(); | 1115 | actor.UpdatePositionAndVelocity(); |
962 | } | 1116 | } |
1117 | |||
963 | bool processedtaints = false; | 1118 | bool processedtaints = false; |
964 | foreach (OdePrim prim in _taintedPrim) | 1119 | foreach (OdePrim prim in _taintedPrim) |
965 | { | 1120 | { |
@@ -970,6 +1125,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
970 | } | 1125 | } |
971 | processedtaints = true; | 1126 | processedtaints = true; |
972 | } | 1127 | } |
1128 | |||
973 | if (processedtaints) | 1129 | if (processedtaints) |
974 | _taintedPrim = new List<OdePrim>(); | 1130 | _taintedPrim = new List<OdePrim>(); |
975 | 1131 | ||
@@ -1152,7 +1308,7 @@ namespace OpenSim.Region.Physics.OdePlugin | |||
1152 | // this._heightmap[i] = (double)heightMap[i]; | 1308 | // this._heightmap[i] = (double)heightMap[i]; |
1153 | // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...) | 1309 | // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...) |
1154 | // also, creating a buffer zone of one extra sample all around | 1310 | // also, creating a buffer zone of one extra sample all around |
1155 | 1311 | _origheightmap = heightMap; | |
1156 | const uint heightmapWidth = m_regionWidth + 2; | 1312 | const uint heightmapWidth = m_regionWidth + 2; |
1157 | const uint heightmapHeight = m_regionHeight + 2; | 1313 | const uint heightmapHeight = m_regionHeight + 2; |
1158 | const uint heightmapWidthSamples = 2*m_regionWidth + 2; | 1314 | const uint heightmapWidthSamples = 2*m_regionWidth + 2; |