diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs (renamed from OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs) | 572 |
1 files changed, 279 insertions, 293 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs index 103d8fc..83fc3a6 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/BSCharacter.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -30,9 +30,9 @@ using System.Reflection; | |||
30 | using log4net; | 30 | using log4net; |
31 | using OMV = OpenMetaverse; | 31 | using OMV = OpenMetaverse; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Physics.Manager; | 33 | using OpenSim.Region.PhysicsModules.SharedBase; |
34 | 34 | ||
35 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.PhysicsModule.BulletS |
36 | { | 36 | { |
37 | public sealed class BSCharacter : BSPhysObject | 37 | public sealed class BSCharacter : BSPhysObject |
38 | { | 38 | { |
@@ -43,53 +43,52 @@ public sealed class BSCharacter : BSPhysObject | |||
43 | private OMV.Vector3 _size; | 43 | private OMV.Vector3 _size; |
44 | private bool _grabbed; | 44 | private bool _grabbed; |
45 | private bool _selected; | 45 | private bool _selected; |
46 | private OMV.Vector3 _position; | ||
47 | private float _mass; | 46 | private float _mass; |
48 | private float _avatarDensity; | ||
49 | private float _avatarVolume; | 47 | private float _avatarVolume; |
50 | private OMV.Vector3 _force; | ||
51 | private OMV.Vector3 _velocity; | ||
52 | private OMV.Vector3 _torque; | ||
53 | private float _collisionScore; | 48 | private float _collisionScore; |
54 | private OMV.Vector3 _acceleration; | 49 | private OMV.Vector3 _acceleration; |
55 | private OMV.Quaternion _orientation; | ||
56 | private int _physicsActorType; | 50 | private int _physicsActorType; |
57 | private bool _isPhysical; | 51 | private bool _isPhysical; |
58 | private bool _flying; | 52 | private bool _flying; |
59 | private bool _setAlwaysRun; | 53 | private bool _setAlwaysRun; |
60 | private bool _throttleUpdates; | 54 | private bool _throttleUpdates; |
61 | private bool _isColliding; | ||
62 | private bool _collidingObj; | ||
63 | private bool _floatOnWater; | 55 | private bool _floatOnWater; |
64 | private OMV.Vector3 _rotationalVelocity; | 56 | private OMV.Vector3 _rotationalVelocity; |
65 | private bool _kinematic; | 57 | private bool _kinematic; |
66 | private float _buoyancy; | 58 | private float _buoyancy; |
67 | 59 | ||
68 | // The friction and velocity of the avatar is modified depending on whether walking or not. | 60 | private BSActorAvatarMove m_moveActor; |
69 | private float _currentFriction; // the friction currently being used (changed by setVelocity). | 61 | private const string AvatarMoveActorName = "BSCharacter.AvatarMove"; |
70 | |||
71 | private BSVMotor _velocityMotor; | ||
72 | 62 | ||
73 | private OMV.Vector3 _PIDTarget; | 63 | private OMV.Vector3 _PIDTarget; |
74 | private bool _usePID; | ||
75 | private float _PIDTau; | 64 | private float _PIDTau; |
76 | private bool _useHoverPID; | ||
77 | private float _PIDHoverHeight; | ||
78 | private PIDHoverType _PIDHoverType; | ||
79 | private float _PIDHoverTao; | ||
80 | 65 | ||
81 | public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying) | 66 | // public override OMV.Vector3 RawVelocity |
67 | // { get { return base.RawVelocity; } | ||
68 | // set { | ||
69 | // if (value != base.RawVelocity) | ||
70 | // Util.PrintCallStack(); | ||
71 | // Console.WriteLine("Set rawvel to {0}", value); | ||
72 | // base.RawVelocity = value; } | ||
73 | // } | ||
74 | |||
75 | // Avatars are always complete (in the physics engine sense) | ||
76 | public override bool IsIncomplete { get { return false; } } | ||
77 | |||
78 | public BSCharacter( | ||
79 | uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 vel, OMV.Vector3 size, bool isFlying) | ||
80 | |||
82 | : base(parent_scene, localID, avName, "BSCharacter") | 81 | : base(parent_scene, localID, avName, "BSCharacter") |
83 | { | 82 | { |
84 | _physicsActorType = (int)ActorTypes.Agent; | 83 | _physicsActorType = (int)ActorTypes.Agent; |
85 | _position = pos; | 84 | RawPosition = pos; |
86 | 85 | ||
87 | _flying = isFlying; | 86 | _flying = isFlying; |
88 | _orientation = OMV.Quaternion.Identity; | 87 | RawOrientation = OMV.Quaternion.Identity; |
89 | _velocity = OMV.Vector3.Zero; | 88 | RawVelocity = vel; |
90 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); | 89 | _buoyancy = ComputeBuoyancyFromFlying(isFlying); |
91 | _currentFriction = BSParam.AvatarStandingFriction; | 90 | Friction = BSParam.AvatarStandingFriction; |
92 | _avatarDensity = BSParam.AvatarDensity; | 91 | Density = BSParam.AvatarDensity; |
93 | 92 | ||
94 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | 93 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
95 | // replace with the default values. | 94 | // replace with the default values. |
@@ -103,19 +102,28 @@ public sealed class BSCharacter : BSPhysObject | |||
103 | // set _avatarVolume and _mass based on capsule size, _density and Scale | 102 | // set _avatarVolume and _mass based on capsule size, _density and Scale |
104 | ComputeAvatarVolumeAndMass(); | 103 | ComputeAvatarVolumeAndMass(); |
105 | 104 | ||
106 | SetupMovementMotor(); | 105 | DetailLog( |
107 | 106 | "{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5},pos={6},vel={7}", | |
108 | DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", | 107 | LocalID, _size, Scale, Density, _avatarVolume, RawMass, pos, vel); |
109 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | ||
110 | 108 | ||
111 | // do actual creation in taint time | 109 | // do actual creation in taint time |
112 | PhysicsScene.TaintedObject("BSCharacter.create", delegate() | 110 | PhysScene.TaintedObject(LocalID, "BSCharacter.create", delegate() |
113 | { | 111 | { |
114 | DetailLog("{0},BSCharacter.create,taint", LocalID); | 112 | DetailLog("{0},BSCharacter.create,taint", LocalID); |
113 | |||
115 | // New body and shape into PhysBody and PhysShape | 114 | // New body and shape into PhysBody and PhysShape |
116 | PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this); | 115 | PhysScene.Shapes.GetBodyAndShape(true, PhysScene.World, this); |
116 | |||
117 | // The avatar's movement is controlled by this motor that speeds up and slows down | ||
118 | // the avatar seeking to reach the motor's target speed. | ||
119 | // This motor runs as a prestep action for the avatar so it will keep the avatar | ||
120 | // standing as well as moving. Destruction of the avatar will destroy the pre-step action. | ||
121 | m_moveActor = new BSActorAvatarMove(PhysScene, this, AvatarMoveActorName); | ||
122 | PhysicalActors.Add(AvatarMoveActorName, m_moveActor); | ||
117 | 123 | ||
118 | SetPhysicalProperties(); | 124 | SetPhysicalProperties(); |
125 | |||
126 | IsInitialized = true; | ||
119 | }); | 127 | }); |
120 | return; | 128 | return; |
121 | } | 129 | } |
@@ -123,122 +131,77 @@ public sealed class BSCharacter : BSPhysObject | |||
123 | // called when this character is being destroyed and the resources should be released | 131 | // called when this character is being destroyed and the resources should be released |
124 | public override void Destroy() | 132 | public override void Destroy() |
125 | { | 133 | { |
134 | IsInitialized = false; | ||
135 | |||
126 | base.Destroy(); | 136 | base.Destroy(); |
127 | 137 | ||
128 | DetailLog("{0},BSCharacter.Destroy", LocalID); | 138 | DetailLog("{0},BSCharacter.Destroy", LocalID); |
129 | PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() | 139 | PhysScene.TaintedObject(LocalID, "BSCharacter.destroy", delegate() |
130 | { | 140 | { |
131 | PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); | 141 | PhysScene.Shapes.DereferenceBody(PhysBody, null /* bodyCallback */); |
132 | PhysBody.Clear(); | 142 | PhysBody.Clear(); |
133 | PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); | 143 | PhysShape.Dereference(PhysScene); |
134 | PhysShape.Clear(); | 144 | PhysShape = new BSShapeNull(); |
135 | }); | 145 | }); |
136 | } | 146 | } |
137 | 147 | ||
138 | private void SetPhysicalProperties() | 148 | private void SetPhysicalProperties() |
139 | { | 149 | { |
140 | PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody); | 150 | PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody); |
151 | |||
152 | ForcePosition = RawPosition; | ||
141 | 153 | ||
142 | ZeroMotion(true); | 154 | // Set the velocity |
143 | ForcePosition = _position; | 155 | if (m_moveActor != null) |
156 | m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false); | ||
144 | 157 | ||
145 | // Set the velocity and compute the proper friction | 158 | ForceVelocity = RawVelocity; |
146 | _velocityMotor.Reset(); | 159 | TargetVelocity = RawVelocity; |
147 | _velocityMotor.SetTarget(_velocity); | ||
148 | _velocityMotor.SetCurrent(_velocity); | ||
149 | ForceVelocity = _velocity; | ||
150 | 160 | ||
151 | // This will enable or disable the flying buoyancy of the avatar. | 161 | // This will enable or disable the flying buoyancy of the avatar. |
152 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. | 162 | // Needs to be reset especially when an avatar is recreated after crossing a region boundry. |
153 | Flying = _flying; | 163 | Flying = _flying; |
154 | 164 | ||
155 | PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); | 165 | PhysScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution); |
156 | PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin); | 166 | PhysScene.PE.SetMargin(PhysShape.physShapeInfo, PhysScene.Params.collisionMargin); |
157 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 167 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
158 | PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); | 168 | PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold); |
159 | if (BSParam.CcdMotionThreshold > 0f) | 169 | if (BSParam.CcdMotionThreshold > 0f) |
160 | { | 170 | { |
161 | PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); | 171 | PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold); |
162 | PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); | 172 | PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius); |
163 | } | 173 | } |
164 | 174 | ||
165 | UpdatePhysicalMassProperties(RawMass, false); | 175 | UpdatePhysicalMassProperties(RawMass, false); |
166 | 176 | ||
167 | // Make so capsule does not fall over | 177 | // Make so capsule does not fall over |
168 | PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); | 178 | PhysScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); |
169 | 179 | ||
170 | PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); | 180 | // The avatar mover sets some parameters. |
181 | PhysicalActors.Refresh(); | ||
171 | 182 | ||
172 | PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); | 183 | PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); |
184 | |||
185 | PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody); | ||
173 | 186 | ||
174 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); | 187 | // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG); |
175 | PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); | 188 | PhysScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION); |
176 | PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody); | 189 | PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody); |
177 | 190 | ||
178 | // Do this after the object has been added to the world | 191 | // Do this after the object has been added to the world |
179 | PhysBody.collisionType = CollisionType.Avatar; | 192 | if (BSParam.AvatarToAvatarCollisionsByDefault) |
180 | PhysBody.ApplyCollisionMask(PhysicsScene); | 193 | PhysBody.collisionType = CollisionType.Avatar; |
181 | } | 194 | else |
182 | 195 | PhysBody.collisionType = CollisionType.PhantomToOthersAvatar; | |
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}", LocalID, stepVelocity); | ||
214 | } | ||
215 | |||
216 | // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force. | ||
217 | OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass / PhysicsScene.LastTimeStep; | ||
218 | 196 | ||
219 | /* | 197 | PhysBody.ApplyCollisionMask(PhysScene); |
220 | // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user | ||
221 | float moveForceMagnitudeSquared = moveForce.LengthSquared(); | ||
222 | if (moveForceMagnitudeSquared < 0.0001) | ||
223 | { | ||
224 | DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}", | ||
225 | LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce); | ||
226 | ForceVelocity = OMV.Vector3.Zero; | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | AddForce(moveForce, false, true); | ||
231 | } | ||
232 | */ | ||
233 | // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce); | ||
234 | AddForce(moveForce, false, true); | ||
235 | }); | ||
236 | } | 198 | } |
237 | 199 | ||
238 | public override void RequestPhysicsterseUpdate() | 200 | public override void RequestPhysicsterseUpdate() |
239 | { | 201 | { |
240 | base.RequestPhysicsterseUpdate(); | 202 | base.RequestPhysicsterseUpdate(); |
241 | } | 203 | } |
204 | |||
242 | // No one calls this method so I don't know what it could possibly mean | 205 | // No one calls this method so I don't know what it could possibly mean |
243 | public override bool Stopped { get { return false; } } | 206 | public override bool Stopped { get { return false; } } |
244 | 207 | ||
@@ -250,6 +213,10 @@ public sealed class BSCharacter : BSPhysObject | |||
250 | } | 213 | } |
251 | 214 | ||
252 | set { | 215 | set { |
216 | // This is how much the avatar size is changing. Positive means getting bigger. | ||
217 | // The avatar altitude must be adjusted for this change. | ||
218 | float heightChange = value.Z - _size.Z; | ||
219 | |||
253 | _size = value; | 220 | _size = value; |
254 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, | 221 | // Old versions of ScenePresence passed only the height. If width and/or depth are zero, |
255 | // replace with the default values. | 222 | // replace with the default values. |
@@ -259,16 +226,20 @@ public sealed class BSCharacter : BSPhysObject | |||
259 | Scale = ComputeAvatarScale(_size); | 226 | Scale = ComputeAvatarScale(_size); |
260 | ComputeAvatarVolumeAndMass(); | 227 | ComputeAvatarVolumeAndMass(); |
261 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", | 228 | DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", |
262 | LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); | 229 | LocalID, _size, Scale, Density, _avatarVolume, RawMass); |
263 | 230 | ||
264 | PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() | 231 | PhysScene.TaintedObject(LocalID, "BSCharacter.setSize", delegate() |
265 | { | 232 | { |
266 | if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape) | 233 | if (PhysBody.HasPhysicalBody && PhysShape.physShapeInfo.HasPhysicalShape) |
267 | { | 234 | { |
268 | PhysicsScene.PE.SetLocalScaling(PhysShape, Scale); | 235 | PhysScene.PE.SetLocalScaling(PhysShape.physShapeInfo, Scale); |
269 | UpdatePhysicalMassProperties(RawMass, true); | 236 | UpdatePhysicalMassProperties(RawMass, true); |
237 | |||
238 | // Adjust the avatar's position to account for the increase/decrease in size | ||
239 | ForcePosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, RawPosition.Z + heightChange / 2f); | ||
240 | |||
270 | // Make sure this change appears as a property update event | 241 | // Make sure this change appears as a property update event |
271 | PhysicsScene.PE.PushUpdate(PhysBody); | 242 | PhysScene.PE.PushUpdate(PhysBody); |
272 | } | 243 | } |
273 | }); | 244 | }); |
274 | 245 | ||
@@ -279,11 +250,6 @@ public sealed class BSCharacter : BSPhysObject | |||
279 | { | 250 | { |
280 | set { BaseShape = value; } | 251 | set { BaseShape = value; } |
281 | } | 252 | } |
282 | // I want the physics engine to make an avatar capsule | ||
283 | public override BSPhysicsShapeType PreferredPhysicalShape | ||
284 | { | ||
285 | get {return BSPhysicsShapeType.SHAPE_CAPSULE; } | ||
286 | } | ||
287 | 253 | ||
288 | public override bool Grabbed { | 254 | public override bool Grabbed { |
289 | set { _grabbed = value; } | 255 | set { _grabbed = value; } |
@@ -291,6 +257,10 @@ public sealed class BSCharacter : BSPhysObject | |||
291 | public override bool Selected { | 257 | public override bool Selected { |
292 | set { _selected = value; } | 258 | set { _selected = value; } |
293 | } | 259 | } |
260 | public override bool IsSelected | ||
261 | { | ||
262 | get { return _selected; } | ||
263 | } | ||
294 | public override void CrossingFailure() { return; } | 264 | public override void CrossingFailure() { return; } |
295 | public override void link(PhysicsActor obj) { return; } | 265 | public override void link(PhysicsActor obj) { return; } |
296 | public override void delink() { return; } | 266 | public override void delink() { return; } |
@@ -301,29 +271,30 @@ public sealed class BSCharacter : BSPhysObject | |||
301 | // Called at taint time! | 271 | // Called at taint time! |
302 | public override void ZeroMotion(bool inTaintTime) | 272 | public override void ZeroMotion(bool inTaintTime) |
303 | { | 273 | { |
304 | _velocity = OMV.Vector3.Zero; | 274 | RawVelocity = OMV.Vector3.Zero; |
305 | _acceleration = OMV.Vector3.Zero; | 275 | _acceleration = OMV.Vector3.Zero; |
306 | _rotationalVelocity = OMV.Vector3.Zero; | 276 | _rotationalVelocity = OMV.Vector3.Zero; |
307 | 277 | ||
308 | // Zero some other properties directly into the physics engine | 278 | // Zero some other properties directly into the physics engine |
309 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 279 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() |
310 | { | 280 | { |
311 | if (PhysBody.HasPhysicalBody) | 281 | if (PhysBody.HasPhysicalBody) |
312 | PhysicsScene.PE.ClearAllForces(PhysBody); | 282 | PhysScene.PE.ClearAllForces(PhysBody); |
313 | }); | 283 | }); |
314 | } | 284 | } |
285 | |||
315 | public override void ZeroAngularMotion(bool inTaintTime) | 286 | public override void ZeroAngularMotion(bool inTaintTime) |
316 | { | 287 | { |
317 | _rotationalVelocity = OMV.Vector3.Zero; | 288 | _rotationalVelocity = OMV.Vector3.Zero; |
318 | 289 | ||
319 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() | 290 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.ZeroMotion", delegate() |
320 | { | 291 | { |
321 | if (PhysBody.HasPhysicalBody) | 292 | if (PhysBody.HasPhysicalBody) |
322 | { | 293 | { |
323 | PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); | 294 | PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero); |
324 | PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); | 295 | PhysScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero); |
325 | // The next also get rid of applied linear force but the linear velocity is untouched. | 296 | // The next also get rid of applied linear force but the linear velocity is untouched. |
326 | PhysicsScene.PE.ClearForces(PhysBody); | 297 | PhysScene.PE.ClearForces(PhysBody); |
327 | } | 298 | } |
328 | }); | 299 | }); |
329 | } | 300 | } |
@@ -331,38 +302,34 @@ public sealed class BSCharacter : BSPhysObject | |||
331 | 302 | ||
332 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 303 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } |
333 | 304 | ||
334 | public override OMV.Vector3 RawPosition | ||
335 | { | ||
336 | get { return _position; } | ||
337 | set { _position = value; } | ||
338 | } | ||
339 | public override OMV.Vector3 Position { | 305 | public override OMV.Vector3 Position { |
340 | get { | 306 | get { |
341 | // Don't refetch the position because this function is called a zillion times | 307 | // Don't refetch the position because this function is called a zillion times |
342 | // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); | 308 | // RawPosition = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID); |
343 | return _position; | 309 | return RawPosition; |
344 | } | 310 | } |
345 | set { | 311 | set { |
346 | _position = value; | 312 | RawPosition = value; |
347 | PositionSanityCheck(); | ||
348 | 313 | ||
349 | PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() | 314 | PhysScene.TaintedObject(LocalID, "BSCharacter.setPosition", delegate() |
350 | { | 315 | { |
351 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 316 | DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); |
352 | if (PhysBody.HasPhysicalBody) | 317 | PositionSanityCheck(); |
353 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 318 | ForcePosition = RawPosition; |
354 | }); | 319 | }); |
355 | } | 320 | } |
356 | } | 321 | } |
357 | public override OMV.Vector3 ForcePosition { | 322 | public override OMV.Vector3 ForcePosition { |
358 | get { | 323 | get { |
359 | _position = PhysicsScene.PE.GetPosition(PhysBody); | 324 | RawPosition = PhysScene.PE.GetPosition(PhysBody); |
360 | return _position; | 325 | return RawPosition; |
361 | } | 326 | } |
362 | set { | 327 | set { |
363 | _position = value; | 328 | RawPosition = value; |
364 | PositionSanityCheck(); | 329 | if (PhysBody.HasPhysicalBody) |
365 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 330 | { |
331 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); | ||
332 | } | ||
366 | } | 333 | } |
367 | } | 334 | } |
368 | 335 | ||
@@ -375,28 +342,30 @@ public sealed class BSCharacter : BSPhysObject | |||
375 | bool ret = false; | 342 | bool ret = false; |
376 | 343 | ||
377 | // TODO: check for out of bounds | 344 | // TODO: check for out of bounds |
378 | if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position)) | 345 | if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition)) |
379 | { | 346 | { |
380 | // The character is out of the known/simulated area. | 347 | // The character is out of the known/simulated area. |
381 | // Upper levels of code will handle the transition to other areas so, for | 348 | // Force the avatar position to be within known. ScenePresence will use the position |
382 | // the time, we just ignore the position. | 349 | // plus the velocity to decide if the avatar is moving out of the region. |
383 | return ret; | 350 | RawPosition = PhysScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition); |
351 | DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition); | ||
352 | return true; | ||
384 | } | 353 | } |
385 | 354 | ||
386 | // If below the ground, move the avatar up | 355 | // If below the ground, move the avatar up |
387 | float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); | 356 | float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition); |
388 | if (Position.Z < terrainHeight) | 357 | if (Position.Z < terrainHeight) |
389 | { | 358 | { |
390 | DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); | 359 | DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight); |
391 | _position.Z = terrainHeight + 2.0f; | 360 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters); |
392 | ret = true; | 361 | ret = true; |
393 | } | 362 | } |
394 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) | 363 | if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) |
395 | { | 364 | { |
396 | float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position); | 365 | float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition); |
397 | if (Position.Z < waterHeight) | 366 | if (Position.Z < waterHeight) |
398 | { | 367 | { |
399 | _position.Z = waterHeight; | 368 | RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, waterHeight); |
400 | ret = true; | 369 | ret = true; |
401 | } | 370 | } |
402 | } | 371 | } |
@@ -414,11 +383,10 @@ public sealed class BSCharacter : BSPhysObject | |||
414 | { | 383 | { |
415 | // The new position value must be pushed into the physics engine but we can't | 384 | // The new position value must be pushed into the physics engine but we can't |
416 | // just assign to "Position" because of potential call loops. | 385 | // just assign to "Position" because of potential call loops. |
417 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() | 386 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.PositionSanityCheck", delegate() |
418 | { | 387 | { |
419 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); | 388 | DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation); |
420 | if (PhysBody.HasPhysicalBody) | 389 | ForcePosition = RawPosition; |
421 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | ||
422 | }); | 390 | }); |
423 | ret = true; | 391 | ret = true; |
424 | } | 392 | } |
@@ -428,25 +396,25 @@ public sealed class BSCharacter : BSPhysObject | |||
428 | public override float Mass { get { return _mass; } } | 396 | public override float Mass { get { return _mass; } } |
429 | 397 | ||
430 | // used when we only want this prim's mass and not the linkset thing | 398 | // used when we only want this prim's mass and not the linkset thing |
431 | public override float RawMass { | 399 | public override float RawMass { |
432 | get {return _mass; } | 400 | get {return _mass; } |
433 | } | 401 | } |
434 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) | 402 | public override void UpdatePhysicalMassProperties(float physMass, bool inWorld) |
435 | { | 403 | { |
436 | OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass); | 404 | OMV.Vector3 localInertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass); |
437 | PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia); | 405 | PhysScene.PE.SetMassProps(PhysBody, physMass, localInertia); |
438 | } | 406 | } |
439 | 407 | ||
440 | public override OMV.Vector3 Force { | 408 | public override OMV.Vector3 Force { |
441 | get { return _force; } | 409 | get { return RawForce; } |
442 | set { | 410 | set { |
443 | _force = value; | 411 | RawForce = value; |
444 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); | 412 | // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); |
445 | PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() | 413 | PhysScene.TaintedObject(LocalID, "BSCharacter.SetForce", delegate() |
446 | { | 414 | { |
447 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); | 415 | DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce); |
448 | if (PhysBody.HasPhysicalBody) | 416 | if (PhysBody.HasPhysicalBody) |
449 | PhysicsScene.PE.SetObjectForce(PhysBody, _force); | 417 | PhysScene.PE.SetObjectForce(PhysBody, RawForce); |
450 | }); | 418 | }); |
451 | } | 419 | } |
452 | } | 420 | } |
@@ -460,6 +428,7 @@ public sealed class BSCharacter : BSPhysObject | |||
460 | 428 | ||
461 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 429 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
462 | public override void SetVolumeDetect(int param) { return; } | 430 | public override void SetVolumeDetect(int param) { return; } |
431 | public override bool IsVolumeDetect { get { return false; } } | ||
463 | 432 | ||
464 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } | 433 | public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } |
465 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 434 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } |
@@ -469,79 +438,59 @@ public sealed class BSCharacter : BSPhysObject | |||
469 | { | 438 | { |
470 | get | 439 | get |
471 | { | 440 | { |
472 | return _velocityMotor.TargetValue; | 441 | return base.m_targetVelocity; |
473 | } | 442 | } |
474 | set | 443 | set |
475 | { | 444 | { |
476 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); | 445 | DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value); |
446 | m_targetVelocity = value; | ||
477 | OMV.Vector3 targetVel = value; | 447 | OMV.Vector3 targetVel = value; |
478 | if (_setAlwaysRun) | 448 | if (_setAlwaysRun && !_flying) |
479 | targetVel *= BSParam.AvatarAlwaysRunFactor; | 449 | targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 1f); |
480 | 450 | ||
481 | PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() | 451 | if (m_moveActor != null) |
482 | { | 452 | m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */); |
483 | _velocityMotor.Reset(); | ||
484 | _velocityMotor.SetTarget(targetVel); | ||
485 | _velocityMotor.SetCurrent(_velocity); | ||
486 | _velocityMotor.Enabled = true; | ||
487 | }); | ||
488 | } | 453 | } |
489 | } | 454 | } |
490 | // Directly setting velocity means this is what the user really wants now. | 455 | // Directly setting velocity means this is what the user really wants now. |
491 | public override OMV.Vector3 Velocity { | 456 | public override OMV.Vector3 Velocity { |
492 | get { return _velocity; } | 457 | get { return RawVelocity; } |
493 | set { | 458 | set { |
494 | _velocity = value; | 459 | RawVelocity = value; |
495 | // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); | 460 | OMV.Vector3 vel = RawVelocity; |
496 | PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() | 461 | |
462 | DetailLog("{0}: set Velocity = {1}", LocalID, value); | ||
463 | |||
464 | PhysScene.TaintedObject(LocalID, "BSCharacter.setVelocity", delegate() | ||
497 | { | 465 | { |
498 | _velocityMotor.Reset(); | 466 | if (m_moveActor != null) |
499 | _velocityMotor.SetCurrent(_velocity); | 467 | m_moveActor.SetVelocityAndTarget(vel, vel, true /* inTaintTime */); |
500 | _velocityMotor.SetTarget(_velocity); | 468 | |
501 | // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar. | 469 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, vel); |
502 | _velocityMotor.Enabled = false; | 470 | ForceVelocity = vel; |
503 | |||
504 | DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); | ||
505 | ForceVelocity = _velocity; | ||
506 | }); | 471 | }); |
507 | } | 472 | } |
508 | } | 473 | } |
474 | |||
509 | public override OMV.Vector3 ForceVelocity { | 475 | public override OMV.Vector3 ForceVelocity { |
510 | get { return _velocity; } | 476 | get { return RawVelocity; } |
511 | set { | 477 | set { |
512 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); | 478 | PhysScene.AssertInTaintTime("BSCharacter.ForceVelocity"); |
479 | // Util.PrintCallStack(); | ||
480 | DetailLog("{0}: set ForceVelocity = {1}", LocalID, value); | ||
513 | 481 | ||
514 | _velocity = value; | 482 | RawVelocity = value; |
515 | // Depending on whether the avatar is moving or not, change the friction | 483 | PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity); |
516 | // to keep the avatar from slipping around | 484 | PhysScene.PE.Activate(PhysBody, true); |
517 | if (_velocity.Length() == 0) | ||
518 | { | ||
519 | if (_currentFriction != BSParam.AvatarStandingFriction) | ||
520 | { | ||
521 | _currentFriction = BSParam.AvatarStandingFriction; | ||
522 | if (PhysBody.HasPhysicalBody) | ||
523 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
524 | } | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | if (_currentFriction != BSParam.AvatarFriction) | ||
529 | { | ||
530 | _currentFriction = BSParam.AvatarFriction; | ||
531 | if (PhysBody.HasPhysicalBody) | ||
532 | PhysicsScene.PE.SetFriction(PhysBody, _currentFriction); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); | ||
537 | PhysicsScene.PE.Activate(PhysBody, true); | ||
538 | } | 485 | } |
539 | } | 486 | } |
487 | |||
540 | public override OMV.Vector3 Torque { | 488 | public override OMV.Vector3 Torque { |
541 | get { return _torque; } | 489 | get { return RawTorque; } |
542 | set { _torque = value; | 490 | set { RawTorque = value; |
543 | } | 491 | } |
544 | } | 492 | } |
493 | |||
545 | public override float CollisionScore { | 494 | public override float CollisionScore { |
546 | get { return _collisionScore; } | 495 | get { return _collisionScore; } |
547 | set { _collisionScore = value; | 496 | set { _collisionScore = value; |
@@ -551,22 +500,27 @@ public sealed class BSCharacter : BSPhysObject | |||
551 | get { return _acceleration; } | 500 | get { return _acceleration; } |
552 | set { _acceleration = value; } | 501 | set { _acceleration = value; } |
553 | } | 502 | } |
554 | public override OMV.Quaternion RawOrientation | ||
555 | { | ||
556 | get { return _orientation; } | ||
557 | set { _orientation = value; } | ||
558 | } | ||
559 | public override OMV.Quaternion Orientation { | 503 | public override OMV.Quaternion Orientation { |
560 | get { return _orientation; } | 504 | get { return RawOrientation; } |
561 | set { | 505 | set { |
562 | // Orientation is set zillions of times when an avatar is walking. It's like | 506 | // Orientation is set zillions of times when an avatar is walking. It's like |
563 | // the viewer doesn't trust us. | 507 | // the viewer doesn't trust us. |
564 | if (_orientation != value) | 508 | if (RawOrientation != value) |
565 | { | 509 | { |
566 | _orientation = value; | 510 | RawOrientation = value; |
567 | PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() | 511 | PhysScene.TaintedObject(LocalID, "BSCharacter.setOrientation", delegate() |
568 | { | 512 | { |
569 | ForceOrientation = _orientation; | 513 | // Bullet assumes we know what we are doing when forcing orientation |
514 | // so it lets us go against all the rules and just compensates for them later. | ||
515 | // This forces rotation to be only around the Z axis and doesn't change any of the other axis. | ||
516 | // This keeps us from flipping the capsule over which the veiwer does not understand. | ||
517 | float oRoll, oPitch, oYaw; | ||
518 | RawOrientation.GetEulerAngles(out oRoll, out oPitch, out oYaw); | ||
519 | OMV.Quaternion trimmedOrientation = OMV.Quaternion.CreateFromEulers(0f, 0f, oYaw); | ||
520 | // DetailLog("{0},BSCharacter.setOrientation,taint,val={1},valDir={2},conv={3},convDir={4}", | ||
521 | // LocalID, RawOrientation, OMV.Vector3.UnitX * RawOrientation, | ||
522 | // trimmedOrientation, OMV.Vector3.UnitX * trimmedOrientation); | ||
523 | ForceOrientation = trimmedOrientation; | ||
570 | }); | 524 | }); |
571 | } | 525 | } |
572 | } | 526 | } |
@@ -576,16 +530,16 @@ public sealed class BSCharacter : BSPhysObject | |||
576 | { | 530 | { |
577 | get | 531 | get |
578 | { | 532 | { |
579 | _orientation = PhysicsScene.PE.GetOrientation(PhysBody); | 533 | RawOrientation = PhysScene.PE.GetOrientation(PhysBody); |
580 | return _orientation; | 534 | return RawOrientation; |
581 | } | 535 | } |
582 | set | 536 | set |
583 | { | 537 | { |
584 | _orientation = value; | 538 | RawOrientation = value; |
585 | if (PhysBody.HasPhysicalBody) | 539 | if (PhysBody.HasPhysicalBody) |
586 | { | 540 | { |
587 | // _position = PhysicsScene.PE.GetPosition(BSBody); | 541 | // RawPosition = PhysicsScene.PE.GetPosition(BSBody); |
588 | PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation); | 542 | PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation); |
589 | } | 543 | } |
590 | } | 544 | } |
591 | } | 545 | } |
@@ -605,6 +559,9 @@ public sealed class BSCharacter : BSPhysObject | |||
605 | public override bool IsStatic { | 559 | public override bool IsStatic { |
606 | get { return false; } | 560 | get { return false; } |
607 | } | 561 | } |
562 | public override bool IsPhysicallyActive { | ||
563 | get { return true; } | ||
564 | } | ||
608 | public override bool Flying { | 565 | public override bool Flying { |
609 | get { return _flying; } | 566 | get { return _flying; } |
610 | set { | 567 | set { |
@@ -631,14 +588,14 @@ public sealed class BSCharacter : BSPhysObject | |||
631 | public override bool FloatOnWater { | 588 | public override bool FloatOnWater { |
632 | set { | 589 | set { |
633 | _floatOnWater = value; | 590 | _floatOnWater = value; |
634 | PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() | 591 | PhysScene.TaintedObject(LocalID, "BSCharacter.setFloatOnWater", delegate() |
635 | { | 592 | { |
636 | if (PhysBody.HasPhysicalBody) | 593 | if (PhysBody.HasPhysicalBody) |
637 | { | 594 | { |
638 | if (_floatOnWater) | 595 | if (_floatOnWater) |
639 | CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 596 | CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
640 | else | 597 | else |
641 | CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); | 598 | CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER); |
642 | } | 599 | } |
643 | }); | 600 | }); |
644 | } | 601 | } |
@@ -659,7 +616,7 @@ public sealed class BSCharacter : BSPhysObject | |||
659 | public override float Buoyancy { | 616 | public override float Buoyancy { |
660 | get { return _buoyancy; } | 617 | get { return _buoyancy; } |
661 | set { _buoyancy = value; | 618 | set { _buoyancy = value; |
662 | PhysicsScene.TaintedObject("BSCharacter.setBuoyancy", delegate() | 619 | PhysScene.TaintedObject(LocalID, "BSCharacter.setBuoyancy", delegate() |
663 | { | 620 | { |
664 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 621 | DetailLog("{0},BSCharacter.setBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
665 | ForceBuoyancy = _buoyancy; | 622 | ForceBuoyancy = _buoyancy; |
@@ -668,15 +625,16 @@ public sealed class BSCharacter : BSPhysObject | |||
668 | } | 625 | } |
669 | public override float ForceBuoyancy { | 626 | public override float ForceBuoyancy { |
670 | get { return _buoyancy; } | 627 | get { return _buoyancy; } |
671 | set { | 628 | set { |
672 | PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); | 629 | PhysScene.AssertInTaintTime("BSCharacter.ForceBuoyancy"); |
673 | 630 | ||
674 | _buoyancy = value; | 631 | _buoyancy = value; |
675 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); | 632 | DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
676 | // Buoyancy is faked by changing the gravity applied to the object | 633 | // Buoyancy is faked by changing the gravity applied to the object |
677 | float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); | 634 | float grav = BSParam.Gravity * (1f - _buoyancy); |
635 | Gravity = new OMV.Vector3(0f, 0f, grav); | ||
678 | if (PhysBody.HasPhysicalBody) | 636 | if (PhysBody.HasPhysicalBody) |
679 | PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav)); | 637 | PhysScene.PE.SetGravity(PhysBody, Gravity); |
680 | } | 638 | } |
681 | } | 639 | } |
682 | 640 | ||
@@ -684,60 +642,32 @@ public sealed class BSCharacter : BSPhysObject | |||
684 | public override OMV.Vector3 PIDTarget { | 642 | public override OMV.Vector3 PIDTarget { |
685 | set { _PIDTarget = value; } | 643 | set { _PIDTarget = value; } |
686 | } | 644 | } |
687 | public override bool PIDActive { | 645 | |
688 | set { _usePID = value; } | 646 | public override bool PIDActive { get; set; } |
689 | } | 647 | |
690 | public override float PIDTau { | 648 | public override float PIDTau { |
691 | set { _PIDTau = value; } | 649 | set { _PIDTau = value; } |
692 | } | 650 | } |
693 | 651 | ||
694 | // Used for llSetHoverHeight and maybe vehicle height | ||
695 | // Hover Height will override MoveTo target's Z | ||
696 | public override bool PIDHoverActive { | ||
697 | set { _useHoverPID = value; } | ||
698 | } | ||
699 | public override float PIDHoverHeight { | ||
700 | set { _PIDHoverHeight = value; } | ||
701 | } | ||
702 | public override PIDHoverType PIDHoverType { | ||
703 | set { _PIDHoverType = value; } | ||
704 | } | ||
705 | public override float PIDHoverTau { | ||
706 | set { _PIDHoverTao = value; } | ||
707 | } | ||
708 | |||
709 | // For RotLookAt | ||
710 | public override OMV.Quaternion APIDTarget { set { return; } } | ||
711 | public override bool APIDActive { set { return; } } | ||
712 | public override float APIDStrength { set { return; } } | ||
713 | public override float APIDDamping { set { return; } } | ||
714 | |||
715 | public override void AddForce(OMV.Vector3 force, bool pushforce) | 652 | public override void AddForce(OMV.Vector3 force, bool pushforce) |
716 | { | 653 | { |
717 | // Since this force is being applied in only one step, make this a force per second. | 654 | // Since this force is being applied in only one step, make this a force per second. |
718 | OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep; | 655 | OMV.Vector3 addForce = force / PhysScene.LastTimeStep; |
719 | AddForce(addForce, pushforce, false); | 656 | AddForce(addForce, pushforce, false); |
720 | } | 657 | } |
721 | private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { | 658 | public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
722 | if (force.IsFinite()) | 659 | if (force.IsFinite()) |
723 | { | 660 | { |
724 | float magnitude = force.Length(); | 661 | OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude); |
725 | if (magnitude > BSParam.MaxAddForceMagnitude) | ||
726 | { | ||
727 | // Force has a limit | ||
728 | force = force / magnitude * BSParam.MaxAddForceMagnitude; | ||
729 | } | ||
730 | |||
731 | OMV.Vector3 addForce = force; | ||
732 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); | 662 | // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce); |
733 | 663 | ||
734 | PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate() | 664 | PhysScene.TaintedObject(inTaintTime, LocalID, "BSCharacter.AddForce", delegate() |
735 | { | 665 | { |
736 | // Bullet adds this central force to the total force for this tick | 666 | // Bullet adds this central force to the total force for this tick |
737 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); | 667 | // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce); |
738 | if (PhysBody.HasPhysicalBody) | 668 | if (PhysBody.HasPhysicalBody) |
739 | { | 669 | { |
740 | PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce); | 670 | PhysScene.PE.ApplyCentralForce(PhysBody, addForce); |
741 | } | 671 | } |
742 | }); | 672 | }); |
743 | } | 673 | } |
@@ -748,35 +678,66 @@ public sealed class BSCharacter : BSPhysObject | |||
748 | } | 678 | } |
749 | } | 679 | } |
750 | 680 | ||
751 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 681 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { |
752 | } | 682 | } |
753 | public override void SetMomentum(OMV.Vector3 momentum) { | 683 | public override void SetMomentum(OMV.Vector3 momentum) { |
754 | } | 684 | } |
755 | 685 | ||
756 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) | 686 | private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size) |
757 | { | 687 | { |
758 | OMV.Vector3 newScale; | 688 | OMV.Vector3 newScale = size; |
759 | 689 | ||
760 | // Bullet's capsule total height is the "passed height + radius * 2"; | 690 | // Bullet's capsule total height is the "passed height + radius * 2"; |
761 | // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1) | 691 | // The base capsule is 1 unit in diameter and 2 units in height (passed radius=0.5, passed height = 1) |
762 | // The number we pass in for 'scaling' is the multiplier to get that base | 692 | // The number we pass in for 'scaling' is the multiplier to get that base |
763 | // shape to be the size desired. | 693 | // shape to be the size desired. |
764 | // So, when creating the scale for the avatar height, we take the passed height | 694 | // So, when creating the scale for the avatar height, we take the passed height |
765 | // (size.Z) and remove the caps. | 695 | // (size.Z) and remove the caps. |
766 | // Another oddity of the Bullet capsule implementation is that it presumes the Y | 696 | // An oddity of the Bullet capsule implementation is that it presumes the Y |
767 | // dimension is the radius of the capsule. Even though some of the code allows | 697 | // dimension is the radius of the capsule. Even though some of the code allows |
768 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. | 698 | // for a asymmetrical capsule, other parts of the code presume it is cylindrical. |
769 | 699 | ||
770 | // Scale is multiplier of radius with one of "0.5" | 700 | // Scale is multiplier of radius with one of "0.5" |
771 | newScale.X = size.X / 2f; | ||
772 | newScale.Y = size.Y / 2f; | ||
773 | 701 | ||
774 | // The total scale height is the central cylindar plus the caps on the two ends. | 702 | float heightAdjust = BSParam.AvatarHeightMidFudge; |
775 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f; | 703 | if (BSParam.AvatarHeightLowFudge != 0f || BSParam.AvatarHeightHighFudge != 0f) |
704 | { | ||
705 | const float AVATAR_LOW = 1.1f; | ||
706 | const float AVATAR_MID = 1.775f; // 1.87f | ||
707 | const float AVATAR_HI = 2.45f; | ||
708 | // An avatar is between 1.1 and 2.45 meters. Midpoint is 1.775m. | ||
709 | float midHeightOffset = size.Z - AVATAR_MID; | ||
710 | if (midHeightOffset < 0f) | ||
711 | { | ||
712 | // Small avatar. Add the adjustment based on the distance from midheight | ||
713 | heightAdjust += ((-1f * midHeightOffset) / (AVATAR_MID - AVATAR_LOW)) * BSParam.AvatarHeightLowFudge; | ||
714 | } | ||
715 | else | ||
716 | { | ||
717 | // Large avatar. Add the adjustment based on the distance from midheight | ||
718 | heightAdjust += ((midHeightOffset) / (AVATAR_HI - AVATAR_MID)) * BSParam.AvatarHeightHighFudge; | ||
719 | } | ||
720 | } | ||
721 | if (BSParam.AvatarShape == BSShapeCollection.AvatarShapeCapsule) | ||
722 | { | ||
723 | newScale.X = size.X / 2f; | ||
724 | newScale.Y = size.Y / 2f; | ||
725 | // The total scale height is the central cylindar plus the caps on the two ends. | ||
726 | newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2) + heightAdjust) / 2f; | ||
727 | } | ||
728 | else | ||
729 | { | ||
730 | newScale.Z = size.Z + heightAdjust; | ||
731 | } | ||
732 | // m_log.DebugFormat("{0} ComputeAvatarScale: size={1},adj={2},scale={3}", LogHeader, size, heightAdjust, newScale); | ||
733 | |||
776 | // If smaller than the endcaps, just fake like we're almost that small | 734 | // If smaller than the endcaps, just fake like we're almost that small |
777 | if (newScale.Z < 0) | 735 | if (newScale.Z < 0) |
778 | newScale.Z = 0.1f; | 736 | newScale.Z = 0.1f; |
779 | 737 | ||
738 | DetailLog("{0},BSCharacter.ComputerAvatarScale,size={1},lowF={2},midF={3},hiF={4},adj={5},newScale={6}", | ||
739 | LocalID, size, BSParam.AvatarHeightLowFudge, BSParam.AvatarHeightMidFudge, BSParam.AvatarHeightHighFudge, heightAdjust, newScale); | ||
740 | |||
780 | return newScale; | 741 | return newScale; |
781 | } | 742 | } |
782 | 743 | ||
@@ -794,34 +755,59 @@ public sealed class BSCharacter : BSPhysObject | |||
794 | * Math.Min(Size.X, Size.Y) / 2 | 755 | * Math.Min(Size.X, Size.Y) / 2 |
795 | * Size.Y / 2f // plus the volume of the capsule end caps | 756 | * Size.Y / 2f // plus the volume of the capsule end caps |
796 | ); | 757 | ); |
797 | _mass = _avatarDensity * _avatarVolume; | 758 | _mass = Density * BSParam.DensityScaleFactor * _avatarVolume; |
798 | } | 759 | } |
799 | 760 | ||
800 | // The physics engine says that properties have updated. Update same and inform | 761 | // The physics engine says that properties have updated. Update same and inform |
801 | // the world that things have changed. | 762 | // the world that things have changed. |
802 | public override void UpdateProperties(EntityProperties entprop) | 763 | public override void UpdateProperties(EntityProperties entprop) |
803 | { | 764 | { |
804 | _position = entprop.Position; | 765 | // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator. |
805 | _orientation = entprop.Rotation; | 766 | TriggerPreUpdatePropertyAction(ref entprop); |
806 | _velocity = entprop.Velocity; | 767 | |
768 | RawPosition = entprop.Position; | ||
769 | RawOrientation = entprop.Rotation; | ||
770 | |||
771 | // Smooth velocity. OpenSimulator is VERY sensitive to changes in velocity of the avatar | ||
772 | // and will send agent updates to the clients if velocity changes by more than | ||
773 | // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many | ||
774 | // extra updates. | ||
775 | // | ||
776 | // XXX: Contrary to the above comment, setting an update threshold here above 0.4 actually introduces jitter to | ||
777 | // avatar movement rather than removes it. The larger the threshold, the bigger the jitter. | ||
778 | // This is most noticeable in level flight and can be seen with | ||
779 | // the "show updates" option in a viewer. With an update threshold, the RawVelocity cycles between a lower | ||
780 | // bound and an upper bound, where the difference between the two is enough to trigger a large delta v update | ||
781 | // and subsequently trigger an update in ScenePresence.SendTerseUpdateToAllClients(). The cause of this cycle (feedback?) | ||
782 | // has not yet been identified. | ||
783 | // | ||
784 | // If there is a threshold below 0.4 or no threshold check at all (as in ODE), then RawVelocity stays constant and extra | ||
785 | // updates are not triggered in ScenePresence.SendTerseUpdateToAllClients(). | ||
786 | // if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f)) | ||
787 | RawVelocity = entprop.Velocity; | ||
788 | |||
807 | _acceleration = entprop.Acceleration; | 789 | _acceleration = entprop.Acceleration; |
808 | _rotationalVelocity = entprop.RotationalVelocity; | 790 | _rotationalVelocity = entprop.RotationalVelocity; |
809 | 791 | ||
810 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. | 792 | // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. |
811 | PositionSanityCheck(true); | 793 | if (PositionSanityCheck(true)) |
794 | { | ||
795 | DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, RawPosition); | ||
796 | entprop.Position = RawPosition; | ||
797 | } | ||
812 | 798 | ||
813 | // remember the current and last set values | 799 | // remember the current and last set values |
814 | LastEntityProperties = CurrentEntityProperties; | 800 | LastEntityProperties = CurrentEntityProperties; |
815 | CurrentEntityProperties = entprop; | 801 | CurrentEntityProperties = entprop; |
816 | 802 | ||
817 | // Tell the linkset about value changes | 803 | // Tell the linkset about value changes |
818 | Linkset.UpdateProperties(this, true); | 804 | // Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); |
819 | 805 | ||
820 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. | 806 | // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. |
821 | // base.RequestPhysicsterseUpdate(); | 807 | // PhysScene.PostUpdate(this); |
822 | 808 | ||
823 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | 809 | DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", |
824 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | 810 | LocalID, RawPosition, RawOrientation, RawVelocity, _acceleration, _rotationalVelocity); |
825 | } | 811 | } |
826 | } | 812 | } |
827 | } | 813 | } |