aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs221
1 files changed, 125 insertions, 96 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 3f7b5e1..3b77e49 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -66,7 +66,6 @@ public sealed class BSCharacter : BSPhysObject
66 private float _buoyancy; 66 private float _buoyancy;
67 67
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity). 69 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 70
72 private BSVMotor _velocityMotor; 71 private BSVMotor _velocityMotor;
@@ -85,37 +84,27 @@ public sealed class BSCharacter : BSPhysObject
85 _physicsActorType = (int)ActorTypes.Agent; 84 _physicsActorType = (int)ActorTypes.Agent;
86 _position = pos; 85 _position = pos;
87 86
88 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
89 // replace with the default values.
90 _size = size;
91 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
92 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
93
94 // A motor to control the acceleration and deceleration of the avatar movement.
95 // _velocityMotor = new BSVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
96 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
97 // Infinite decay and timescale values so motor only changes current to target values.
98 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
99 0.2f, // time scale
100 BSMotor.Infinite, // decay time scale
101 BSMotor.InfiniteVector, // friction timescale
102 1f // efficiency
103 );
104 _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
105
106 _flying = isFlying; 87 _flying = isFlying;
107 _orientation = OMV.Quaternion.Identity; 88 _orientation = OMV.Quaternion.Identity;
108 _velocity = OMV.Vector3.Zero; 89 _velocity = OMV.Vector3.Zero;
109 _appliedVelocity = OMV.Vector3.Zero;
110 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
111 _currentFriction = BSParam.AvatarStandingFriction; 91 _currentFriction = BSParam.AvatarStandingFriction;
112 _avatarDensity = BSParam.AvatarDensity; 92 _avatarDensity = BSParam.AvatarDensity;
113 93
114 // The dimensions of the avatar capsule are kept in the scale. 94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values.
96 _size = size;
97 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
98 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99
100 // The dimensions of the physical capsule are kept in the scale.
115 // Physics creates a unit capsule which is scaled by the physics engine. 101 // Physics creates a unit capsule which is scaled by the physics engine.
116 ComputeAvatarScale(_size); 102 Scale = ComputeAvatarScale(_size);
117 // set _avatarVolume and _mass based on capsule size, _density and Scale 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
118 ComputeAvatarVolumeAndMass(); 104 ComputeAvatarVolumeAndMass();
105
106 SetupMovementMotor();
107
119 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
120 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
121 110
@@ -152,13 +141,12 @@ public sealed class BSCharacter : BSPhysObject
152 141
153 ZeroMotion(true); 142 ZeroMotion(true);
154 ForcePosition = _position; 143 ForcePosition = _position;
144
155 // Set the velocity and compute the proper friction 145 // Set the velocity and compute the proper friction
156 ForceVelocity = _velocity;
157 // Setting the current and target in the motor will cause it to start computing any deceleration.
158 _velocityMotor.Reset(); 146 _velocityMotor.Reset();
159 _velocityMotor.SetCurrent(_velocity);
160 _velocityMotor.SetTarget(_velocity); 147 _velocityMotor.SetTarget(_velocity);
161 _velocityMotor.Enabled = false; 148 _velocityMotor.SetCurrent(_velocity);
149 ForceVelocity = _velocity;
162 150
163 // This will enable or disable the flying buoyancy of the avatar. 151 // This will enable or disable the flying buoyancy of the avatar.
164 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
@@ -192,6 +180,63 @@ public sealed class BSCharacter : BSPhysObject
192 PhysBody.ApplyCollisionMask(); 180 PhysBody.ApplyCollisionMask();
193 } 181 }
194 182
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}",
214 LocalID, stepVelocity);
215 }
216
217 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
218 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep;
219
220 /*
221 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
222 float moveForceMagnitudeSquared = moveForce.LengthSquared();
223 if (moveForceMagnitudeSquared < 0.0001)
224 {
225 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
226 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
227 ForceVelocity = OMV.Vector3.Zero;
228 }
229 else
230 {
231 AddForce(moveForce, false, true);
232 }
233 */
234 DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
235 LocalID, stepVelocity, _velocity, Mass, moveForce);
236 AddForce(moveForce, false, true);
237 });
238 }
239
195 public override void RequestPhysicsterseUpdate() 240 public override void RequestPhysicsterseUpdate()
196 { 241 {
197 base.RequestPhysicsterseUpdate(); 242 base.RequestPhysicsterseUpdate();
@@ -207,14 +252,13 @@ public sealed class BSCharacter : BSPhysObject
207 } 252 }
208 253
209 set { 254 set {
210 // When an avatar's size is set, only the height is changed.
211 _size = value; 255 _size = value;
212 // Old versions of ScenePresence passed only the height. If width and/or depth are zero, 256 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
213 // replace with the default values. 257 // replace with the default values.
214 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth; 258 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
215 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth; 259 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
216 260
217 ComputeAvatarScale(_size); 261 Scale = ComputeAvatarScale(_size);
218 ComputeAvatarVolumeAndMass(); 262 ComputeAvatarVolumeAndMass();
219 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 263 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
220 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 264 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
@@ -433,15 +477,15 @@ public sealed class BSCharacter : BSPhysObject
433 { 477 {
434 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); 478 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
435 OMV.Vector3 targetVel = value; 479 OMV.Vector3 targetVel = value;
480 if (_setAlwaysRun)
481 targetVel *= BSParam.AvatarAlwaysRunFactor;
482
436 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() 483 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
437 { 484 {
438 _velocityMotor.Reset(); 485 _velocityMotor.Reset();
439 _velocityMotor.SetTarget(targetVel); 486 _velocityMotor.SetTarget(targetVel);
440 _velocityMotor.SetCurrent(_velocity); 487 _velocityMotor.SetCurrent(_velocity);
441 _velocityMotor.Enabled = true; 488 _velocityMotor.Enabled = true;
442
443 // Make sure a property update happens next step so the motor gets incorporated.
444 BulletSimAPI.PushUpdate2(PhysBody.ptr);
445 }); 489 });
446 } 490 }
447 } 491 }
@@ -490,8 +534,6 @@ public sealed class BSCharacter : BSPhysObject
490 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 534 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction);
491 } 535 }
492 } 536 }
493 // Remember the set velocity so we can suppress the reduction by friction, ...
494 _appliedVelocity = value;
495 537
496 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 538 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
497 BulletSimAPI.Activate2(PhysBody.ptr, true); 539 BulletSimAPI.Activate2(PhysBody.ptr, true);
@@ -519,16 +561,16 @@ public sealed class BSCharacter : BSPhysObject
519 public override OMV.Quaternion Orientation { 561 public override OMV.Quaternion Orientation {
520 get { return _orientation; } 562 get { return _orientation; }
521 set { 563 set {
522 _orientation = value; 564 // Orientation is set zillions of times when an avatar is walking. It's like
523 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 565 // the viewer doesn't trust us.
524 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 566 if (_orientation != value)
525 { 567 {
526 if (PhysBody.HasPhysicalBody) 568 _orientation = value;
569 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
527 { 570 {
528 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 571 ForceOrientation = _orientation;
529 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 572 });
530 } 573 }
531 });
532 } 574 }
533 } 575 }
534 // Go directly to Bullet to get/set the value. 576 // Go directly to Bullet to get/set the value.
@@ -542,7 +584,11 @@ public sealed class BSCharacter : BSPhysObject
542 set 584 set
543 { 585 {
544 _orientation = value; 586 _orientation = value;
545 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 587 if (PhysBody.HasPhysicalBody)
588 {
589 // _position = BulletSimAPI.GetPosition2(BSBody.ptr);
590 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
591 }
546 } 592 }
547 } 593 }
548 public override int PhysicsActorType { 594 public override int PhysicsActorType {
@@ -668,7 +714,13 @@ public sealed class BSCharacter : BSPhysObject
668 public override float APIDStrength { set { return; } } 714 public override float APIDStrength { set { return; } }
669 public override float APIDDamping { set { return; } } 715 public override float APIDDamping { set { return; } }
670 716
671 public override void AddForce(OMV.Vector3 force, bool pushforce) { 717 public override void AddForce(OMV.Vector3 force, bool pushforce)
718 {
719 // Since this force is being applied in only one step, make this a force per second.
720 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
721 AddForce(addForce, pushforce, false);
722 }
723 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
672 if (force.IsFinite()) 724 if (force.IsFinite())
673 { 725 {
674 float magnitude = force.Length(); 726 float magnitude = force.Length();
@@ -678,10 +730,10 @@ public sealed class BSCharacter : BSPhysObject
678 force = force / magnitude * BSParam.MaxAddForceMagnitude; 730 force = force / magnitude * BSParam.MaxAddForceMagnitude;
679 } 731 }
680 732
681 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; 733 OMV.Vector3 addForce = force;
682 DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); 734 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
683 735
684 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate() 736 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
685 { 737 {
686 // Bullet adds this central force to the total force for this tick 738 // Bullet adds this central force to the total force for this tick
687 DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); 739 DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
@@ -703,21 +755,31 @@ public sealed class BSCharacter : BSPhysObject
703 public override void SetMomentum(OMV.Vector3 momentum) { 755 public override void SetMomentum(OMV.Vector3 momentum) {
704 } 756 }
705 757
706 private void ComputeAvatarScale(OMV.Vector3 size) 758 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
707 { 759 {
708 OMV.Vector3 newScale = size; 760 OMV.Vector3 newScale;
709 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 761
710 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 762 // Bullet's capsule total height is the "passed height + radius * 2";
711 763 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
712 // From the total height, remove the capsule half spheres that are at each end 764 // The number we pass in for 'scaling' is the multiplier to get that base
713 // The 1.15f came from ODE. Not sure what this factors in. 765 // shape to be the size desired.
714 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 766 // So, when creating the scale for the avatar height, we take the passed height
767 // (size.Z) and remove the caps.
768 // Another oddity of the Bullet capsule implementation is that it presumes the Y
769 // dimension is the radius of the capsule. Even though some of the code allows
770 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
771
772 // Scale is multiplier of radius with one of "0.5"
773 newScale.X = size.X / 2f;
774 newScale.Y = size.Y / 2f;
715 775
716 // The total scale height is the central cylindar plus the caps on the two ends. 776 // The total scale height is the central cylindar plus the caps on the two ends.
717 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); 777 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
778 // If smaller than the endcaps, just fake like we're almost that small
779 if (newScale.Z < 0)
780 newScale.Z = 0.1f;
718 781
719 // Convert diameters to radii and height to half height -- the way Bullet expects it. 782 return newScale;
720 Scale = newScale / 2f;
721 } 783 }
722 784
723 // set _avatarVolume and _mass based on capsule size, _density and Scale 785 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -725,14 +787,14 @@ public sealed class BSCharacter : BSPhysObject
725 { 787 {
726 _avatarVolume = (float)( 788 _avatarVolume = (float)(
727 Math.PI 789 Math.PI
728 * Scale.X 790 * Size.X / 2f
729 * Scale.Y // the area of capsule cylinder 791 * Size.Y / 2f // the area of capsule cylinder
730 * Scale.Z // times height of capsule cylinder 792 * Size.Z // times height of capsule cylinder
731 + 1.33333333f 793 + 1.33333333f
732 * Math.PI 794 * Math.PI
733 * Scale.X 795 * Size.X / 2f
734 * Math.Min(Scale.X, Scale.Y) 796 * Math.Min(Size.X, Size.Y) / 2
735 * Scale.Y // plus the volume of the capsule end caps 797 * Size.Y / 2f // plus the volume of the capsule end caps
736 ); 798 );
737 _mass = _avatarDensity * _avatarVolume; 799 _mass = _avatarDensity * _avatarVolume;
738 } 800 }
@@ -750,39 +812,6 @@ public sealed class BSCharacter : BSPhysObject
750 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 812 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
751 PositionSanityCheck(true); 813 PositionSanityCheck(true);
752 814
753 if (_velocityMotor.Enabled)
754 {
755 // TODO: Decide if the step parameters should be changed depending on the avatar's
756 // state (flying, colliding, ...).
757
758 OMV.Vector3 stepVelocity = _velocityMotor.Step(PhysicsScene.LastTimeStep);
759
760 // Check for cases to turn off the motor.
761 if (
762 // If the walking motor is all done, turn it off
763 (_velocityMotor.TargetValue.ApproxEquals(OMV.Vector3.Zero, 0.01f) && _velocityMotor.ErrorIsZero) )
764 {
765 ZeroMotion(true);
766 stepVelocity = OMV.Vector3.Zero;
767 _velocityMotor.Enabled = false;
768 DetailLog("{0},BSCharacter.UpdateProperties,taint,disableVelocityMotor,m={1}", LocalID, _velocityMotor);
769 }
770 else
771 {
772 // If the motor is not being turned off...
773 // If falling, we keep the world's downward vector no matter what the other axis specify.
774 if (!Flying && !IsColliding)
775 {
776 stepVelocity.Z = entprop.Velocity.Z;
777 DetailLog("{0},BSCharacter.UpdateProperties,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
778 }
779 }
780
781 _velocity = stepVelocity;
782 entprop.Velocity = _velocity;
783 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
784 }
785
786 // remember the current and last set values 815 // remember the current and last set values
787 LastEntityProperties = CurrentEntityProperties; 816 LastEntityProperties = CurrentEntityProperties;
788 CurrentEntityProperties = entprop; 817 CurrentEntityProperties = entprop;