aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs')
-rw-r--r--OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs710
1 files changed, 581 insertions, 129 deletions
diff --git a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
index f5bf05d..bb04ea7 100644
--- a/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
+++ b/OpenSim/Region/Physics/UbitOdePlugin/ODECharacter.cs
@@ -74,19 +74,32 @@ namespace OpenSim.Region.Physics.OdePlugin
74 74
75 private Vector3 _position; 75 private Vector3 _position;
76 private Vector3 _zeroPosition; 76 private Vector3 _zeroPosition;
77 private bool _zeroFlag = false;
78 private Vector3 _velocity; 77 private Vector3 _velocity;
79 private Vector3 _target_velocity; 78 private Vector3 _target_velocity;
80 private Vector3 _acceleration; 79 private Vector3 _acceleration;
81 private Vector3 m_rotationalVelocity; 80 private Vector3 m_rotationalVelocity;
81 private Vector3 m_size;
82 private Quaternion m_orientation;
83 private Quaternion m_orientation2D;
82 private float m_mass = 80f; 84 private float m_mass = 80f;
83 public float m_density = 60f; 85 public float m_density = 60f;
84 private bool m_pidControllerActive = true; 86 private bool m_pidControllerActive = true;
85 public float PID_D = 800.0f; 87
86 public float PID_P = 900.0f; 88 const float basePID_D = 0.55f; // scaled for unit mass unit time (2200 /(50*80))
87 //private static float POSTURE_SERVO = 10000.0f; 89 const float basePID_P = 0.225f; // scaled for unit mass unit time (900 /(50*80))
88 public float CAPSULE_RADIUS = 0.37f; 90 public float PID_D;
89 public float CAPSULE_LENGTH = 2.140599f; 91 public float PID_P;
92
93 private float timeStep;
94 private float invtimeStep;
95
96 private float m_feetOffset = 0;
97 private float feetOff = 0;
98 private float feetSZ = 0.5f;
99 const float feetScale = 0.8f;
100 private float boneOff = 0;
101 private float m_lastVelocitySqr = 0;
102
90 public float walkDivisor = 1.3f; 103 public float walkDivisor = 1.3f;
91 public float runDivisor = 0.8f; 104 public float runDivisor = 0.8f;
92 private bool flying = false; 105 private bool flying = false;
@@ -94,6 +107,9 @@ namespace OpenSim.Region.Physics.OdePlugin
94 private bool m_iscollidingGround = false; 107 private bool m_iscollidingGround = false;
95 private bool m_iscollidingObj = false; 108 private bool m_iscollidingObj = false;
96 private bool m_alwaysRun = false; 109 private bool m_alwaysRun = false;
110
111 private bool _zeroFlag = false;
112
97 private int m_requestedUpdateFrequency = 0; 113 private int m_requestedUpdateFrequency = 0;
98 private uint m_localID = 0; 114 private uint m_localID = 0;
99 public bool m_returnCollisions = false; 115 public bool m_returnCollisions = false;
@@ -111,6 +127,7 @@ namespace OpenSim.Region.Physics.OdePlugin
111 int m_colliderfilter = 0; 127 int m_colliderfilter = 0;
112 int m_colliderGroundfilter = 0; 128 int m_colliderGroundfilter = 0;
113 int m_colliderObjectfilter = 0; 129 int m_colliderObjectfilter = 0;
130 bool m_collisionException = false;
114 131
115 // Default we're a Character 132 // Default we're a Character
116 private CollisionCategories m_collisionCategories = (CollisionCategories.Character); 133 private CollisionCategories m_collisionCategories = (CollisionCategories.Character);
@@ -123,10 +140,18 @@ namespace OpenSim.Region.Physics.OdePlugin
123 // we do land collisions not ode | CollisionCategories.Land); 140 // we do land collisions not ode | CollisionCategories.Land);
124 public IntPtr Body = IntPtr.Zero; 141 public IntPtr Body = IntPtr.Zero;
125 private OdeScene _parent_scene; 142 private OdeScene _parent_scene;
126 public IntPtr Shell = IntPtr.Zero; 143 private IntPtr topbox = IntPtr.Zero;
144 private IntPtr midbox = IntPtr.Zero;
145 private IntPtr feetbox = IntPtr.Zero;
146 private IntPtr bbox = IntPtr.Zero;
147 public IntPtr collider = IntPtr.Zero;
148
127 public IntPtr Amotor = IntPtr.Zero; 149 public IntPtr Amotor = IntPtr.Zero;
150
128 public d.Mass ShellMass; 151 public d.Mass ShellMass;
129// public bool collidelock = false; 152
153
154
130 155
131 public int m_eventsubscription = 0; 156 public int m_eventsubscription = 0;
132 private int m_cureventsubscription = 0; 157 private int m_cureventsubscription = 0;
@@ -139,9 +164,15 @@ namespace OpenSim.Region.Physics.OdePlugin
139 164
140 float mu; 165 float mu;
141 166
142 public OdeCharacter(String avName, OdeScene parent_scene, Vector3 pos, Vector3 size, float pid_d, float pid_p, float capsule_radius, float density, float walk_divisor, float rundivisor) 167
168
169 public OdeCharacter(uint localID, String avName, OdeScene parent_scene, Vector3 pos, Vector3 pSize, float pfeetOffset, float density, float walk_divisor, float rundivisor)
143 { 170 {
144 m_uuid = UUID.Random(); 171 m_uuid = UUID.Random();
172 m_localID = localID;
173
174 timeStep = parent_scene.ODE_STEPSIZE;
175 invtimeStep = 1 / timeStep;
145 176
146 if (pos.IsFinite()) 177 if (pos.IsFinite())
147 { 178 {
@@ -163,22 +194,37 @@ namespace OpenSim.Region.Physics.OdePlugin
163 194
164 _parent_scene = parent_scene; 195 _parent_scene = parent_scene;
165 196
166 PID_D = pid_d; 197
167 PID_P = pid_p; 198 m_size.X = pSize.X;
168 CAPSULE_RADIUS = capsule_radius; 199 m_size.Y = pSize.Y;
200 m_size.Z = pSize.Z;
201
202 if(m_size.X <0.01f)
203 m_size.X = 0.01f;
204 if(m_size.Y <0.01f)
205 m_size.Y = 0.01f;
206 if(m_size.Z <0.01f)
207 m_size.Z = 0.01f;
208
209 m_feetOffset = pfeetOffset;
210 m_orientation = Quaternion.Identity;
211 m_orientation2D = Quaternion.Identity;
169 m_density = density; 212 m_density = density;
170 m_mass = 80f; // sure we have a default
171 213
172 // force lower density for testing 214 // force lower density for testing
173 m_density = 3.0f; 215 m_density = 3.0f;
174 216
217 m_density *= 1.4f; // scale to have mass similar to capsule
218
175 mu = parent_scene.AvatarFriction; 219 mu = parent_scene.AvatarFriction;
176 220
177 walkDivisor = walk_divisor; 221 walkDivisor = walk_divisor;
178 runDivisor = rundivisor; 222 runDivisor = rundivisor;
179 223
180 CAPSULE_LENGTH = size.Z * 1.15f - CAPSULE_RADIUS * 2.0f; 224 m_mass = m_density * m_size.X * m_size.Y * m_size.Z; ; // sure we have a default
181 //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); 225
226 PID_D = basePID_D * m_mass * invtimeStep;
227 PID_P = basePID_P * m_mass * invtimeStep;
182 228
183 m_isPhysical = false; // current status: no ODE information exists 229 m_isPhysical = false; // current status: no ODE information exists
184 230
@@ -261,7 +307,7 @@ namespace OpenSim.Region.Physics.OdePlugin
261 set 307 set
262 { 308 {
263 flying = value; 309 flying = value;
264 // m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying); 310// m_log.DebugFormat("[PHYSICS]: Set OdeCharacter Flying to {0}", flying);
265 } 311 }
266 } 312 }
267 313
@@ -305,25 +351,25 @@ namespace OpenSim.Region.Physics.OdePlugin
305 get { return m_iscollidingGround; } 351 get { return m_iscollidingGround; }
306 set 352 set
307 { 353 {
308 /* we now control this 354/* we now control this
309 if (value) 355 if (value)
310 { 356 {
311 m_colliderGroundfilter += 2; 357 m_colliderGroundfilter += 2;
312 if (m_colliderGroundfilter > 2) 358 if (m_colliderGroundfilter > 2)
313 m_colliderGroundfilter = 2; 359 m_colliderGroundfilter = 2;
314 } 360 }
315 else 361 else
316 { 362 {
317 m_colliderGroundfilter--; 363 m_colliderGroundfilter--;
318 if (m_colliderGroundfilter < 0) 364 if (m_colliderGroundfilter < 0)
319 m_colliderGroundfilter = 0; 365 m_colliderGroundfilter = 0;
320 } 366 }
321 367
322 if (m_colliderGroundfilter == 0) 368 if (m_colliderGroundfilter == 0)
323 m_iscollidingGround = false; 369 m_iscollidingGround = false;
324 else 370 else
325 m_iscollidingGround = true; 371 m_iscollidingGround = true;
326 */ 372 */
327 } 373 }
328 374
329 } 375 }
@@ -355,7 +401,7 @@ namespace OpenSim.Region.Physics.OdePlugin
355 else 401 else
356 m_iscollidingObj = true; 402 m_iscollidingObj = true;
357 403
358 // m_iscollidingObj = value; 404// m_iscollidingObj = value;
359 405
360 if (m_iscollidingObj) 406 if (m_iscollidingObj)
361 m_pidControllerActive = false; 407 m_pidControllerActive = false;
@@ -420,13 +466,21 @@ namespace OpenSim.Region.Physics.OdePlugin
420 /// </summary> 466 /// </summary>
421 public override Vector3 Size 467 public override Vector3 Size
422 { 468 {
423 get { 469 get
424 float d = CAPSULE_RADIUS * 2; 470 {
425 return new Vector3(d, d, (CAPSULE_LENGTH +d)/1.15f); } 471 return m_size;
472 }
426 set 473 set
427 { 474 {
428 if (value.IsFinite()) 475 if (value.IsFinite())
429 { 476 {
477 if(value.X <0.01f)
478 value.X = 0.01f;
479 if(value.Y <0.01f)
480 value.Y = 0.01f;
481 if(value.Z <0.01f)
482 value.Z = 0.01f;
483
430 AddChange(changes.Size, value); 484 AddChange(changes.Size, value);
431 } 485 }
432 else 486 else
@@ -436,6 +490,28 @@ namespace OpenSim.Region.Physics.OdePlugin
436 } 490 }
437 } 491 }
438 492
493 public override void setAvatarSize(Vector3 size, float feetOffset)
494 {
495 if (size.IsFinite())
496 {
497 if (size.X < 0.01f)
498 size.X = 0.01f;
499 if (size.Y < 0.01f)
500 size.Y = 0.01f;
501 if (size.Z < 0.01f)
502 size.Z = 0.01f;
503
504 strAvatarSize st = new strAvatarSize();
505 st.size = size;
506 st.offset = feetOffset;
507 AddChange(changes.AvatarSize, st);
508 }
509 else
510 {
511 m_log.Warn("[PHYSICS]: Got a NaN AvatarSize from Scene on a Character");
512 }
513
514 }
439 /// <summary> 515 /// <summary>
440 /// This creates the Avatar's physical Surrogate at the position supplied 516 /// This creates the Avatar's physical Surrogate at the position supplied
441 /// </summary> 517 /// </summary>
@@ -452,8 +528,7 @@ namespace OpenSim.Region.Physics.OdePlugin
452 { 528 {
453 get 529 get
454 { 530 {
455 float AVvolume = (float)(Math.PI * CAPSULE_RADIUS * CAPSULE_RADIUS * (1.3333333333f * CAPSULE_RADIUS + CAPSULE_LENGTH)); 531 return m_mass;
456 return m_density * AVvolume;
457 } 532 }
458 } 533 }
459 public override void link(PhysicsActor obj) 534 public override void link(PhysicsActor obj)
@@ -571,9 +646,13 @@ namespace OpenSim.Region.Physics.OdePlugin
571 646
572 public override Quaternion Orientation 647 public override Quaternion Orientation
573 { 648 {
574 get { return Quaternion.Identity; } 649 get { return m_orientation; }
575 set 650 set
576 { 651 {
652// fakeori = value;
653// givefakeori++;
654 value.Normalize();
655 AddChange(changes.Orientation, value);
577 } 656 }
578 } 657 }
579 658
@@ -625,54 +704,116 @@ namespace OpenSim.Region.Physics.OdePlugin
625 AddChange(changes.Momentum, momentum); 704 AddChange(changes.Momentum, momentum);
626 } 705 }
627 706
707 private void ajustCollider()
708 {
709 float vq = _velocity.LengthSquared();
710 if (m_lastVelocitySqr != vq)
711 {
712 m_lastVelocitySqr = vq;
713 if (vq > 100.0f)
714 {
715 Vector3 off = _velocity;
716 float t = 0.5f * timeStep;
717 off = off * t;
718 d.GeomSetOffsetPosition(bbox, off.X, off.Y, off.Z);
719 off.X = 2.0f * (m_size.X + Math.Abs(off.X));
720 off.Y = 2.0f * (m_size.Y + Math.Abs(off.Y));
721 off.Z = m_size.Z + 2.0f * Math.Abs(off.Z);
722 d.GeomBoxSetLengths(bbox, off.X, off.Y, off.Z);
723
724 d.GeomSetCategoryBits(bbox, (uint)m_collisionCategories);
725 d.GeomSetCollideBits(bbox, (uint)m_collisionFlags);
726 d.GeomSetCategoryBits(topbox, 0);
727 d.GeomSetCollideBits(topbox, 0);
728 d.GeomSetCategoryBits(midbox, 0);
729 d.GeomSetCollideBits(midbox, 0);
730 d.GeomSetCategoryBits(feetbox, 0);
731 d.GeomSetCollideBits(feetbox, 0);
732 }
733 else
734 {
735 d.GeomSetCategoryBits(bbox, 0);
736 d.GeomSetCollideBits(bbox, 0);
737 d.GeomSetCategoryBits(topbox, (uint)m_collisionCategories);
738 d.GeomSetCollideBits(topbox, (uint)m_collisionFlags);
739 d.GeomSetCategoryBits(midbox, (uint)m_collisionCategories);
740 d.GeomSetCollideBits(midbox, (uint)m_collisionFlags);
741 d.GeomSetCategoryBits(feetbox, (uint)m_collisionCategories);
742 d.GeomSetCollideBits(feetbox, (uint)m_collisionFlags);
743 }
744 }
745 }
628 746
629 // WARNING: This MUST NOT be called outside of ProcessTaints, else we can have unsynchronized access
630 // to ODE internals. ProcessTaints is called from within thread-locked Simulate(), so it is the only
631 // place that is safe to call this routine AvatarGeomAndBodyCreation.
632 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ) 747 private void AvatarGeomAndBodyCreation(float npositionX, float npositionY, float npositionZ)
633 { 748 {
634 _parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace); 749 // sizes one day should came from visual parameters
635 if (CAPSULE_LENGTH <= 0) 750 float sx = m_size.X;
636 { 751 float sy = m_size.Y;
637 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); 752 float sz = m_size.Z;
638 CAPSULE_LENGTH = 0.01f;
639 753
640 } 754 float topsx = sx * 0.9f;
755 float midsx = sx;
756 float feetsx = sx * feetScale;
757 float bonesx = sx * 0.2f;
641 758
642 if (CAPSULE_RADIUS <= 0) 759 float topsy = sy * 0.4f;
643 { 760 float midsy = sy;
644 m_log.Warn("[PHYSICS]: The capsule size you specified in opensim.ini is invalid! Setting it to the smallest possible size!"); 761 float feetsy = sy * feetScale * 0.8f;
645 CAPSULE_RADIUS = 0.01f; 762 float bonesy = feetsy * 0.2f;
646 763
647 } 764 float topsz = sz * 0.15f;
648 Shell = d.CreateCapsule(_parent_scene.ActiveSpace, CAPSULE_RADIUS, CAPSULE_LENGTH); 765 float feetsz = sz * 0.45f;
766 if (feetsz > 0.6f)
767 feetsz = 0.6f;
768
769 float midsz = sz - topsz - feetsz;
770 float bonesz = sz;
771
772 float bot = -sz * 0.5f + m_feetOffset;
773
774 boneOff = bot + 0.3f;
775
776 float feetz = bot + feetsz * 0.5f;
777 bot += feetsz;
649 778
650 d.GeomSetCategoryBits(Shell, (uint)m_collisionCategories); 779 feetOff = bot;
651 d.GeomSetCollideBits(Shell, (uint)m_collisionFlags); 780 feetSZ = feetsz;
652 781
653 d.MassSetCapsule(out ShellMass, m_density, 3, CAPSULE_RADIUS, CAPSULE_LENGTH); 782 float midz = bot + midsz * 0.5f;
783 bot += midsz;
784 float topz = bot + topsz * 0.5f;
654 785
655 m_mass = ShellMass.mass; // update mass 786 _parent_scene.waitForSpaceUnlock(_parent_scene.CharsSpace);
656 787
657 // rescale PID parameters 788 collider = d.HashSpaceCreate(_parent_scene.CharsSpace);
658 PID_D = _parent_scene.avPIDD; 789 d.HashSpaceSetLevels(collider, -4, 3);
659 PID_P = _parent_scene.avPIDP; 790 d.SpaceSetSublevel(collider, 3);
791 d.SpaceSetCleanup(collider, false);
792 d.GeomSetCategoryBits(collider, (uint)m_collisionCategories);
793 d.GeomSetCollideBits(collider, (uint)m_collisionFlags);
660 794
661 // rescale PID parameters so that this aren't affected by mass 795 feetbox = d.CreateBox(collider, feetsx, feetsy, feetsz);
662 // and so don't get unstable for some masses 796 midbox = d.CreateBox(collider, midsx, midsy, midsz);
663 // also scale by ode time step so you don't need to refix them 797 topbox = d.CreateBox(collider, topsx, topsy, topsz);
798 bbox = d.CreateBox(collider, m_size.X, m_size.Y, m_size.Z);
664 799
665 PID_D /= 50 * 80; //scale to original mass of around 80 and 50 ODE fps 800 m_mass = m_density * m_size.X * m_size.Y * m_size.Z; // update mass
666 PID_D *= m_mass / _parent_scene.ODE_STEPSIZE; 801
667 PID_P /= 50 * 80; 802 d.MassSetBoxTotal(out ShellMass, m_mass, m_size.X, m_size.Y, m_size.Z);
668 PID_P *= m_mass / _parent_scene.ODE_STEPSIZE; 803
804 PID_D = basePID_D * m_mass / _parent_scene.ODE_STEPSIZE;
805 PID_P = basePID_P * m_mass / _parent_scene.ODE_STEPSIZE;
669 806
670 Body = d.BodyCreate(_parent_scene.world); 807 Body = d.BodyCreate(_parent_scene.world);
671 808
672 _zeroFlag = false; 809 _zeroFlag = false;
810 m_collisionException = false;
673 m_pidControllerActive = true; 811 m_pidControllerActive = true;
674 m_freemove = false; 812 m_freemove = false;
675 813
814 _velocity = Vector3.Zero;
815 m_lastVelocitySqr = 0;
816
676 d.BodySetAutoDisableFlag(Body, false); 817 d.BodySetAutoDisableFlag(Body, false);
677 d.BodySetPosition(Body, npositionX, npositionY, npositionZ); 818 d.BodySetPosition(Body, npositionX, npositionY, npositionZ);
678 819
@@ -681,7 +822,17 @@ namespace OpenSim.Region.Physics.OdePlugin
681 _position.Z = npositionZ; 822 _position.Z = npositionZ;
682 823
683 d.BodySetMass(Body, ref ShellMass); 824 d.BodySetMass(Body, ref ShellMass);
684 d.GeomSetBody(Shell, Body); 825 d.GeomSetBody(feetbox, Body);
826 d.GeomSetBody(midbox, Body);
827 d.GeomSetBody(topbox, Body);
828 d.GeomSetBody(bbox, Body);
829
830 d.GeomSetOffsetPosition(feetbox, 0, 0, feetz);
831 d.GeomSetOffsetPosition(midbox, 0, 0, midz);
832 d.GeomSetOffsetPosition(topbox, 0, 0, topz);
833
834 ajustCollider();
835
685 836
686 // The purpose of the AMotor here is to keep the avatar's physical 837 // The purpose of the AMotor here is to keep the avatar's physical
687 // surrogate from rotating while moving 838 // surrogate from rotating while moving
@@ -741,15 +892,222 @@ namespace OpenSim.Region.Physics.OdePlugin
741 Body = IntPtr.Zero; 892 Body = IntPtr.Zero;
742 } 893 }
743 894
744 //kill the Geometry 895 //kill the Geoms
745 if (Shell != IntPtr.Zero) 896 if (topbox != IntPtr.Zero)
746 { 897 {
747// _parent_scene.geom_name_map.Remove(Shell); 898 _parent_scene.actor_name_map.Remove(topbox);
748 _parent_scene.actor_name_map.Remove(Shell); 899 _parent_scene.waitForSpaceUnlock(collider);
749 _parent_scene.waitForSpaceUnlock(_parent_scene.ActiveSpace); 900 d.GeomDestroy(topbox);
750 d.GeomDestroy(Shell); 901 topbox = IntPtr.Zero;
751 Shell = IntPtr.Zero;
752 } 902 }
903 if (midbox != IntPtr.Zero)
904 {
905 _parent_scene.actor_name_map.Remove(midbox);
906 _parent_scene.waitForSpaceUnlock(collider);
907 d.GeomDestroy(midbox);
908 midbox = IntPtr.Zero;
909 }
910 if (feetbox != IntPtr.Zero)
911 {
912 _parent_scene.actor_name_map.Remove(feetbox);
913 _parent_scene.waitForSpaceUnlock(collider);
914 d.GeomDestroy(feetbox);
915 feetbox = IntPtr.Zero;
916 }
917
918 if (bbox != IntPtr.Zero)
919 {
920 _parent_scene.actor_name_map.Remove(bbox);
921 _parent_scene.waitForSpaceUnlock(collider);
922 d.GeomDestroy(bbox);
923 bbox = IntPtr.Zero;
924 }
925
926 if (collider != IntPtr.Zero)
927 {
928 d.SpaceDestroy(collider);
929 collider = IntPtr.Zero;
930 }
931
932 }
933
934 //in place 2D rotation around Z assuming rot is normalised and is a rotation around Z
935 public void RotateXYonZ(ref float x, ref float y, ref Quaternion rot)
936 {
937 float sin = 2.0f * rot.Z * rot.W;
938 float cos = rot.W * rot.W - rot.Z * rot.Z;
939 float tx = x;
940
941 x = tx * cos - y * sin;
942 y = tx * sin + y * cos;
943 }
944 public void RotateXYonZ(ref float x, ref float y, ref float sin, ref float cos)
945 {
946 float tx = x;
947 x = tx * cos - y * sin;
948 y = tx * sin + y * cos;
949 }
950 public void invRotateXYonZ(ref float x, ref float y, ref float sin, ref float cos)
951 {
952 float tx = x;
953 x = tx * cos + y * sin;
954 y = -tx * sin + y * cos;
955 }
956
957 public void invRotateXYonZ(ref float x, ref float y, ref Quaternion rot)
958 {
959 float sin = - 2.0f * rot.Z * rot.W;
960 float cos = rot.W * rot.W - rot.Z * rot.Z;
961 float tx = x;
962
963 x = tx * cos - y * sin;
964 y = tx * sin + y * cos;
965 }
966
967
968 public bool Collide(IntPtr me, bool reverse, ref d.ContactGeom contact, ref bool feetcollision)
969 {
970 feetcollision = false;
971 if (m_collisionException)
972 return false;
973
974 Vector3 offset;
975
976 if (me == bbox) // if moving fast
977 {
978 // force a full inelastic collision
979 m_collisionException = true;
980
981 offset = m_size * m_orientation2D;
982
983 offset.X = (float)Math.Abs(offset.X) * 0.5f + contact.depth;
984 offset.Y = (float)Math.Abs(offset.Y) * 0.5f + contact.depth;
985 offset.Z = (float)Math.Abs(offset.Z) * 0.5f + contact.depth;
986
987 if (reverse)
988 {
989 offset.X *= -contact.normal.X;
990 offset.Y *= -contact.normal.Y;
991 offset.Z *= -contact.normal.Z;
992 }
993 else
994 {
995 offset.X *= contact.normal.X;
996 offset.Y *= contact.normal.Y;
997 offset.Z *= contact.normal.Z;
998 }
999
1000 offset.X += contact.pos.X;
1001 offset.Y += contact.pos.Y;
1002 offset.Z += contact.pos.Z;
1003
1004 _position = offset;
1005 return false;
1006 }
1007
1008 offset.X = contact.pos.X - _position.X;
1009 offset.Y = contact.pos.Y - _position.Y;
1010
1011 if (me == topbox)
1012 {
1013 offset.Z = contact.pos.Z - _position.Z;
1014
1015 offset.Normalize();
1016
1017 if (reverse)
1018 {
1019 contact.normal.X = offset.X;
1020 contact.normal.Y = offset.Y;
1021 contact.normal.Z = offset.Z;
1022 }
1023 else
1024 {
1025 contact.normal.X = -offset.X;
1026 contact.normal.Y = -offset.Y;
1027 contact.normal.Z = -offset.Z;
1028 }
1029 return true;
1030 }
1031
1032 if (me == midbox)
1033 {
1034 if (Math.Abs(contact.normal.Z) > 0.95f)
1035 offset.Z = contact.pos.Z - _position.Z;
1036 else
1037 offset.Z = contact.normal.Z;
1038
1039 offset.Normalize();
1040
1041 if (reverse)
1042 {
1043 contact.normal.X = offset.X;
1044 contact.normal.Y = offset.Y;
1045 contact.normal.Z = offset.Z;
1046 }
1047 else
1048 {
1049 contact.normal.X = -offset.X;
1050 contact.normal.Y = -offset.Y;
1051 contact.normal.Z = -offset.Z;
1052 }
1053
1054 return true;
1055 }
1056
1057 else if (me == feetbox)
1058 {
1059 float h = contact.pos.Z - _position.Z;
1060
1061 if (Math.Abs(contact.normal.Z) > 0.95f)
1062 {
1063 if (contact.normal.Z > 0)
1064 contact.normal.Z = 1.0f;
1065 else
1066 contact.normal.Z = -1.0f;
1067 contact.normal.X = 0.0f;
1068 contact.normal.Y = 0.0f;
1069 feetcollision = true;
1070 if (h < boneOff)
1071 IsColliding = true;
1072 return true;
1073 }
1074
1075 offset.Z = h - feetOff; // distance from top of feetbox
1076
1077 if (offset.Z > 0)
1078 return false;
1079
1080 if (offset.Z > -0.01)
1081 {
1082 offset.X = 0;
1083 offset.Y = 0;
1084 offset.Z = -1.0f;
1085 }
1086 else
1087 {
1088 offset.Normalize();
1089 }
1090
1091 if (reverse)
1092 {
1093 contact.normal.X = offset.X;
1094 contact.normal.Y = offset.Y;
1095 contact.normal.Z = offset.Z;
1096 }
1097 else
1098 {
1099 contact.normal.X = -offset.X;
1100 contact.normal.Y = -offset.Y;
1101 contact.normal.Z = -offset.Z;
1102 }
1103 feetcollision = true;
1104 if (h < boneOff)
1105 IsColliding = true;
1106 }
1107 else
1108 return false;
1109
1110 return true;
753 } 1111 }
754 1112
755 /// <summary> 1113 /// <summary>
@@ -757,11 +1115,28 @@ namespace OpenSim.Region.Physics.OdePlugin
757 /// This is the avatar's movement control + PID Controller 1115 /// This is the avatar's movement control + PID Controller
758 /// </summary> 1116 /// </summary>
759 /// <param name="timeStep"></param> 1117 /// <param name="timeStep"></param>
760 public void Move(float timeStep, List<OdeCharacter> defects) 1118 public void Move(List<OdeCharacter> defects)
761 { 1119 {
762 if (Body == IntPtr.Zero) 1120 if (Body == IntPtr.Zero)
763 return; 1121 return;
764 1122
1123 if (m_collisionException)
1124 {
1125 d.BodySetPosition(Body,_position.X, _position.Y, _position.Z);
1126 d.BodySetLinearVel(Body, 0, 0, 0);
1127
1128 float v = _velocity.Length();
1129 if (v != 0)
1130 {
1131 v = 5.0f / v;
1132 _velocity = _velocity * v;
1133 d.BodySetLinearVel(Body, _velocity.X, _velocity.Y, _velocity.Z);
1134 }
1135 ajustCollider();
1136 m_collisionException = false;
1137 return;
1138 }
1139
765 d.Vector3 dtmp = d.BodyGetPosition(Body); 1140 d.Vector3 dtmp = d.BodyGetPosition(Body);
766 Vector3 localpos = new Vector3(dtmp.X, dtmp.Y, dtmp.Z); 1141 Vector3 localpos = new Vector3(dtmp.X, dtmp.Y, dtmp.Z);
767 1142
@@ -769,10 +1144,10 @@ namespace OpenSim.Region.Physics.OdePlugin
769 // so force it back to identity 1144 // so force it back to identity
770 1145
771 d.Quaternion qtmp; 1146 d.Quaternion qtmp;
772 qtmp.W = 1; 1147 qtmp.W = m_orientation2D.W;
773 qtmp.X = 0; 1148 qtmp.X = m_orientation2D.X;
774 qtmp.Y = 0; 1149 qtmp.Y = m_orientation2D.Y;
775 qtmp.Z = 0; 1150 qtmp.Z = m_orientation2D.Z;
776 d.BodySetQuaternion(Body, ref qtmp); 1151 d.BodySetQuaternion(Body, ref qtmp);
777 1152
778 if (m_pidControllerActive == false) 1153 if (m_pidControllerActive == false)
@@ -835,10 +1210,10 @@ namespace OpenSim.Region.Physics.OdePlugin
835 1210
836 //****************************************** 1211 //******************************************
837 // colide with land 1212 // colide with land
838 d.AABB aabb;
839 d.GeomGetAABB(Shell, out aabb);
840 float chrminZ = aabb.MinZ;
841 1213
1214 d.AABB aabb;
1215 d.GeomGetAABB(feetbox, out aabb);
1216 float chrminZ = aabb.MinZ; ; // move up a bit
842 Vector3 posch = localpos; 1217 Vector3 posch = localpos;
843 1218
844 float ftmp; 1219 float ftmp;
@@ -881,11 +1256,12 @@ namespace OpenSim.Region.Physics.OdePlugin
881 contact.PenetrationDepth = depth; 1256 contact.PenetrationDepth = depth;
882 contact.Position.X = localpos.X; 1257 contact.Position.X = localpos.X;
883 contact.Position.Y = localpos.Y; 1258 contact.Position.Y = localpos.Y;
884 contact.Position.Z = chrminZ; 1259 contact.Position.Z = terrainheight;
885 contact.SurfaceNormal.X = 0f; 1260 contact.SurfaceNormal.X = 0.0f;
886 contact.SurfaceNormal.Y = 0f; 1261 contact.SurfaceNormal.Y = 0.0f;
887 contact.SurfaceNormal.Z = -1f; 1262 contact.SurfaceNormal.Z = -1f;
888 contact.RelativeSpeed = -vel.Z; 1263 contact.RelativeSpeed = -vel.Z;
1264 contact.CharacterFeet = true;
889 AddCollisionEvent(0, contact); 1265 AddCollisionEvent(0, contact);
890 1266
891 vec.Z *= 0.5f; 1267 vec.Z *= 0.5f;
@@ -904,6 +1280,7 @@ namespace OpenSim.Region.Physics.OdePlugin
904 m_iscollidingGround = false; 1280 m_iscollidingGround = false;
905 } 1281 }
906 1282
1283
907 //****************************************** 1284 //******************************************
908 1285
909 bool tviszero = (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f); 1286 bool tviszero = (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f);
@@ -1039,21 +1416,58 @@ namespace OpenSim.Region.Physics.OdePlugin
1039 } 1416 }
1040 1417
1041 // update our local ideia of position velocity and aceleration 1418 // update our local ideia of position velocity and aceleration
1419 // _position = localpos;
1042 _position = localpos; 1420 _position = localpos;
1421
1043 if (_zeroFlag) 1422 if (_zeroFlag)
1044 { 1423 {
1045 _velocity = Vector3.Zero; 1424 _velocity = Vector3.Zero;
1046 _acceleration = Vector3.Zero; 1425 _acceleration = Vector3.Zero;
1426 m_rotationalVelocity = Vector3.Zero;
1047 } 1427 }
1048 else 1428 else
1049 { 1429 {
1050 _acceleration = _velocity; // previus velocity 1430 Vector3 a =_velocity; // previus velocity
1051 _velocity = vel; 1431 SetSmooth(ref _velocity, ref vel, 2);
1052 _acceleration = (vel - _acceleration) / timeStep; 1432 a = (_velocity - a) * invtimeStep;
1433 SetSmooth(ref _acceleration, ref a, 2);
1434
1435 dtmp = d.BodyGetAngularVel(Body);
1436 m_rotationalVelocity.X = 0f;
1437 m_rotationalVelocity.Y = 0f;
1438 m_rotationalVelocity.Z = dtmp.Z;
1439 Math.Round(m_rotationalVelocity.Z,3);
1053 } 1440 }
1054 1441 ajustCollider();
1442 }
1443
1444 public void round(ref Vector3 v, int digits)
1445 {
1446 v.X = (float)Math.Round(v.X, digits);
1447 v.Y = (float)Math.Round(v.Y, digits);
1448 v.Z = (float)Math.Round(v.Z, digits);
1449 }
1450
1451 public void SetSmooth(ref Vector3 dst, ref Vector3 value)
1452 {
1453 dst.X = 0.1f * dst.X + 0.9f * value.X;
1454 dst.Y = 0.1f * dst.Y + 0.9f * value.Y;
1455 dst.Z = 0.1f * dst.Z + 0.9f * value.Z;
1055 } 1456 }
1056 1457
1458 public void SetSmooth(ref Vector3 dst, ref Vector3 value, int rounddigits)
1459 {
1460 dst.X = 0.4f * dst.X + 0.6f * value.X;
1461 dst.X = (float)Math.Round(dst.X, rounddigits);
1462
1463 dst.Y = 0.4f * dst.Y + 0.6f * value.Y;
1464 dst.Y = (float)Math.Round(dst.Y, rounddigits);
1465
1466 dst.Z = 0.4f * dst.Z + 0.6f * value.Z;
1467 dst.Z = (float)Math.Round(dst.Z, rounddigits);
1468 }
1469
1470
1057 /// <summary> 1471 /// <summary>
1058 /// Updates the reported position and velocity. 1472 /// Updates the reported position and velocity.
1059 /// Used to copy variables from unmanaged space at heartbeat rate and also trigger scene updates acording 1473 /// Used to copy variables from unmanaged space at heartbeat rate and also trigger scene updates acording
@@ -1176,20 +1590,15 @@ namespace OpenSim.Region.Physics.OdePlugin
1176 { 1590 {
1177 if (NewStatus) 1591 if (NewStatus)
1178 { 1592 {
1179 // Create avatar capsule and related ODE data 1593 AvatarGeomAndBodyDestroy();
1180 if ((Shell != IntPtr.Zero))
1181 {
1182 // a lost shell ?
1183 m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - "
1184 + (Shell != IntPtr.Zero ? "Shell " : "")
1185 + (Body != IntPtr.Zero ? "Body " : "")
1186 + (Amotor != IntPtr.Zero ? "Amotor " : ""));
1187 AvatarGeomAndBodyDestroy();
1188 }
1189 1594
1190 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z); 1595 AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z);
1191 1596
1192 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; 1597 _parent_scene.actor_name_map[collider] = (PhysicsActor)this;
1598 _parent_scene.actor_name_map[feetbox] = (PhysicsActor)this;
1599 _parent_scene.actor_name_map[midbox] = (PhysicsActor)this;
1600 _parent_scene.actor_name_map[topbox] = (PhysicsActor)this;
1601 _parent_scene.actor_name_map[bbox] = (PhysicsActor)this;
1193 _parent_scene.AddCharacter(this); 1602 _parent_scene.AddCharacter(this);
1194 } 1603 }
1195 else 1604 else
@@ -1218,39 +1627,40 @@ namespace OpenSim.Region.Physics.OdePlugin
1218 { 1627 {
1219 } 1628 }
1220 1629
1221 private void changeSize(Vector3 Size) 1630 private void changeAvatarSize(strAvatarSize st)
1222 { 1631 {
1223 if (Size.IsFinite()) 1632 m_feetOffset = st.offset;
1633 changeSize(st.size);
1634 }
1635
1636 private void changeSize(Vector3 pSize)
1637 {
1638 if (pSize.IsFinite())
1224 { 1639 {
1225 float caplen = Size.Z; 1640 // for now only look to Z changes since viewers also don't change X and Y
1641 if (pSize.Z != m_size.Z)
1642 {
1643 AvatarGeomAndBodyDestroy();
1226 1644
1227 caplen = caplen * 1.15f - CAPSULE_RADIUS * 2.0f;
1228 1645
1229 if (caplen != CAPSULE_LENGTH) 1646 float oldsz = m_size.Z;
1230 { 1647 m_size = pSize;
1231 if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero)
1232 {
1233 AvatarGeomAndBodyDestroy();
1234 1648
1235 float prevCapsule = CAPSULE_LENGTH;
1236 CAPSULE_LENGTH = caplen;
1237 1649
1238 AvatarGeomAndBodyCreation(_position.X, _position.Y, 1650 AvatarGeomAndBodyCreation(_position.X, _position.Y,
1239 _position.Z + (CAPSULE_LENGTH - prevCapsule) * 0.5f); 1651 _position.Z + (m_size.Z - oldsz) * 0.5f);
1240 1652
1241 Velocity = Vector3.Zero; 1653 Velocity = Vector3.Zero;
1654
1242 1655
1243 _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; 1656 _parent_scene.actor_name_map[collider] = (PhysicsActor)this;
1244 } 1657 _parent_scene.actor_name_map[feetbox] = (PhysicsActor)this;
1245 else 1658 _parent_scene.actor_name_map[midbox] = (PhysicsActor)this;
1246 { 1659 _parent_scene.actor_name_map[topbox] = (PhysicsActor)this;
1247 m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - " 1660 _parent_scene.actor_name_map[bbox] = (PhysicsActor)this;
1248 + (Shell == IntPtr.Zero ? "Shell " : "")
1249 + (Body == IntPtr.Zero ? "Body " : "")
1250 + (Amotor == IntPtr.Zero ? "Amotor " : ""));
1251 }
1252 } 1661 }
1253 m_freemove = false; 1662 m_freemove = false;
1663 m_collisionException = false;
1254 m_pidControllerActive = true; 1664 m_pidControllerActive = true;
1255 } 1665 }
1256 else 1666 else
@@ -1270,6 +1680,36 @@ namespace OpenSim.Region.Physics.OdePlugin
1270 1680
1271 private void changeOrientation(Quaternion newOri) 1681 private void changeOrientation(Quaternion newOri)
1272 { 1682 {
1683 if (m_orientation != newOri)
1684 {
1685 m_orientation = newOri; // keep a copy for core use
1686 // but only use rotations around Z
1687
1688 m_orientation2D.W = newOri.W;
1689 m_orientation2D.Z = newOri.Z;
1690
1691 float t = m_orientation2D.W * m_orientation2D.W + m_orientation2D.Z * m_orientation2D.Z;
1692 if (t > 0)
1693 {
1694 t = 1.0f / (float)Math.Sqrt(t);
1695 m_orientation2D.W *= t;
1696 m_orientation2D.Z *= t;
1697 }
1698 else
1699 {
1700 m_orientation2D.W = 1.0f;
1701 m_orientation2D.Z = 0f;
1702 }
1703 m_orientation2D.Y = 0f;
1704 m_orientation2D.X = 0f;
1705
1706 d.Quaternion myrot = new d.Quaternion();
1707 myrot.X = m_orientation2D.X;
1708 myrot.Y = m_orientation2D.Y;
1709 myrot.Z = m_orientation2D.Z;
1710 myrot.W = m_orientation2D.W;
1711 d.BodySetQuaternion(Body, ref myrot);
1712 }
1273 } 1713 }
1274 1714
1275 private void changeVelocity(Vector3 newVel) 1715 private void changeVelocity(Vector3 newVel)
@@ -1351,6 +1791,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1351 1791
1352 if (Body != IntPtr.Zero) 1792 if (Body != IntPtr.Zero)
1353 d.BodySetLinearVel(Body, newmomentum.X, newmomentum.Y, newmomentum.Z); 1793 d.BodySetLinearVel(Body, newmomentum.X, newmomentum.Y, newmomentum.Z);
1794 ajustCollider();
1354 } 1795 }
1355 1796
1356 private void donullchange() 1797 private void donullchange()
@@ -1359,7 +1800,7 @@ namespace OpenSim.Region.Physics.OdePlugin
1359 1800
1360 public bool DoAChange(changes what, object arg) 1801 public bool DoAChange(changes what, object arg)
1361 { 1802 {
1362 if (Shell == IntPtr.Zero && what != changes.Add && what != changes.Remove) 1803 if (collider == IntPtr.Zero && what != changes.Add && what != changes.Remove)
1363 { 1804 {
1364 return false; 1805 return false;
1365 } 1806 }
@@ -1425,6 +1866,10 @@ namespace OpenSim.Region.Physics.OdePlugin
1425 changeSize((Vector3)arg); 1866 changeSize((Vector3)arg);
1426 break; 1867 break;
1427 1868
1869 case changes.AvatarSize:
1870 changeAvatarSize((strAvatarSize)arg);
1871 break;
1872
1428 case changes.Momentum: 1873 case changes.Momentum:
1429 changeMomentum((Vector3)arg); 1874 changeMomentum((Vector3)arg);
1430 break; 1875 break;
@@ -1472,5 +1917,12 @@ namespace OpenSim.Region.Physics.OdePlugin
1472 { 1917 {
1473 _parent_scene.AddChange((PhysicsActor)this, what, arg); 1918 _parent_scene.AddChange((PhysicsActor)this, what, arg);
1474 } 1919 }
1920
1921 private struct strAvatarSize
1922 {
1923 public Vector3 size;
1924 public float offset;
1925 }
1926
1475 } 1927 }
1476} 1928}