aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs351
1 files changed, 351 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
new file mode 100755
index 0000000..ac8c30c
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSActorAvatarMove.cs
@@ -0,0 +1,351 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenSim.Region.Physics.Manager;
34
35using OMV = OpenMetaverse;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39public class BSActorAvatarMove : BSActor
40{
41 BSVMotor m_velocityMotor;
42
43 // Set to true if we think we're going up stairs.
44 // This state is remembered because collisions will turn on and off as we go up stairs.
45 int m_walkingUpStairs;
46 float m_lastStepUp;
47
48 public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
49 : base(physicsScene, pObj, actorName)
50 {
51 m_velocityMotor = null;
52 m_walkingUpStairs = 0;
53 m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
54 }
55
56 // BSActor.isActive
57 public override bool isActive
58 {
59 get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
60 }
61
62 // Release any connections and resources used by the actor.
63 // BSActor.Dispose()
64 public override void Dispose()
65 {
66 Enabled = false;
67 }
68
69 // Called when physical parameters (properties set in Bullet) need to be re-applied.
70 // Called at taint-time.
71 // BSActor.Refresh()
72 public override void Refresh()
73 {
74 m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
75
76 // If the object is physically active, add the hoverer prestep action
77 if (isActive)
78 {
79 ActivateAvatarMove();
80 }
81 else
82 {
83 DeactivateAvatarMove();
84 }
85 }
86
87 // The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
88 // Register a prestep action to restore physical requirements before the next simulation step.
89 // Called at taint-time.
90 // BSActor.RemoveDependencies()
91 public override void RemoveDependencies()
92 {
93 // Nothing to do for the hoverer since it is all software at pre-step action time.
94 }
95
96 // Usually called when target velocity changes to set the current velocity and the target
97 // into the movement motor.
98 public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
99 {
100 m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
101 {
102 if (m_velocityMotor != null)
103 {
104 m_velocityMotor.Reset();
105 m_velocityMotor.SetTarget(targ);
106 m_velocityMotor.SetCurrent(vel);
107 m_velocityMotor.Enabled = true;
108 }
109 });
110 }
111
112 // If a hover motor has not been created, create one and start the hovering.
113 private void ActivateAvatarMove()
114 {
115 if (m_velocityMotor == null)
116 {
117 // Infinite decay and timescale values so motor only changes current to target values.
118 m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
119 0.2f, // time scale
120 BSMotor.Infinite, // decay time scale
121 1f // efficiency
122 );
123 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
124 SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
125
126 m_physicsScene.BeforeStep += Mover;
127
128 m_walkingUpStairs = 0;
129 }
130 }
131
132 private void DeactivateAvatarMove()
133 {
134 if (m_velocityMotor != null)
135 {
136 m_physicsScene.BeforeStep -= Mover;
137 m_velocityMotor = null;
138 }
139 }
140
141 // Called just before the simulation step. Update the vertical position for hoverness.
142 private void Mover(float timeStep)
143 {
144 // Don't do movement while the object is selected.
145 if (!isActive)
146 return;
147
148 // TODO: Decide if the step parameters should be changed depending on the avatar's
149 // state (flying, colliding, ...). There is code in ODE to do this.
150
151 // COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
152 // specified for the avatar is the one that should be used. For falling, if the avatar
153 // is not flying and is not colliding then it is presumed to be falling and the Z
154 // component is not fooled with (thus allowing gravity to do its thing).
155 // When the avatar is standing, though, the user has specified a velocity of zero and
156 // the avatar should be standing. But if the avatar is pushed by something in the world
157 // (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
158 // move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
159 // errors can creap in and the avatar will slowly float off in some direction.
160 // So, the problem is that, when an avatar is standing, we cannot tell creaping error
161 // from real pushing.
162 // The code below uses whether the collider is static or moving to decide whether to zero motion.
163
164 m_velocityMotor.Step(timeStep);
165 m_controllingPrim.IsStationary = false;
166
167 // If we're not supposed to be moving, make sure things are zero.
168 if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
169 {
170 // The avatar shouldn't be moving
171 m_velocityMotor.Zero();
172
173 if (m_controllingPrim.IsColliding)
174 {
175 // If we are colliding with a stationary object, presume we're standing and don't move around
176 if (!m_controllingPrim.ColliderIsMoving)
177 {
178 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
179 m_controllingPrim.IsStationary = true;
180 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
181 }
182
183 // Standing has more friction on the ground
184 if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
185 {
186 m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
187 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
188 }
189 }
190 else
191 {
192 if (m_controllingPrim.Flying)
193 {
194 // Flying and not collising and velocity nearly zero.
195 m_controllingPrim.ZeroMotion(true /* inTaintTime */);
196 }
197 }
198
199 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
200 m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
201 }
202 else
203 {
204 // Supposed to be moving.
205 OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
206
207 if (m_controllingPrim.Friction != BSParam.AvatarFriction)
208 {
209 // Probably starting up walking. Set friction to moving friction.
210 m_controllingPrim.Friction = BSParam.AvatarFriction;
211 m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
212 }
213
214 // If falling, we keep the world's downward vector no matter what the other axis specify.
215 // The check for RawVelocity.Z < 0 makes jumping work (temporary upward force).
216 if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
217 {
218 if (m_controllingPrim.RawVelocity.Z < 0)
219 stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
220 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
221 }
222
223 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
224 OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
225
226 // Add special movement force to allow avatars to walk up stepped surfaces.
227 moveForce += WalkUpStairs();
228
229 m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
230 m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
231 m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
232 }
233 }
234
235 // Decide if the character is colliding with a low object and compute a force to pop the
236 // avatar up so it can walk up and over the low objects.
237 private OMV.Vector3 WalkUpStairs()
238 {
239 OMV.Vector3 ret = OMV.Vector3.Zero;
240
241 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4},avHeight={5}",
242 m_controllingPrim.LocalID, m_controllingPrim.IsColliding, m_controllingPrim.Flying,
243 m_controllingPrim.TargetVelocitySpeed, m_controllingPrim.CollisionsLastTick.Count, m_controllingPrim.Size.Z);
244 // This test is done if moving forward, not flying and is colliding with something.
245 // Check for stairs climbing if colliding, not flying and moving forward
246 if ( m_controllingPrim.IsColliding
247 && !m_controllingPrim.Flying
248 && m_controllingPrim.TargetVelocitySpeed > 0.1f )
249 {
250 // The range near the character's feet where we will consider stairs
251 // float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
252 // Note: there is a problem with the computation of the capsule height. Thus RawPosition is off
253 // from the height. Revisit size and this computation when height is scaled properly.
254 float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) - 0.05f;
255 float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
256
257 // Look for a collision point that is near the character's feet and is oriented the same as the charactor is.
258 // Find the highest 'good' collision.
259 OMV.Vector3 highestTouchPosition = OMV.Vector3.Zero;
260 foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
261 {
262 // Don't care about collisions with the terrain
263 if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
264 {
265 OMV.Vector3 touchPosition = kvp.Value.Position;
266 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
267 m_controllingPrim.LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
268 if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
269 {
270 // This contact is within the 'near the feet' range.
271 // The normal should be our contact point to the object so it is pointing away
272 // thus the difference between our facing orientation and the normal should be small.
273 OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
274 OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
275 float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
276 if (diff < BSParam.AvatarStepApproachFactor)
277 {
278 if (highestTouchPosition.Z < touchPosition.Z)
279 highestTouchPosition = touchPosition;
280 }
281 }
282 }
283 }
284 m_walkingUpStairs = 0;
285 // If there is a good step sensing, move the avatar over the step.
286 if (highestTouchPosition != OMV.Vector3.Zero)
287 {
288 // Remember that we are going up stairs. This is needed because collisions
289 // will stop when we move up so this smoothes out that effect.
290 m_walkingUpStairs = BSParam.AvatarStepSmoothingSteps;
291
292 m_lastStepUp = highestTouchPosition.Z - nearFeetHeightMin;
293 ret = ComputeStairCorrection(m_lastStepUp);
294 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},ret={3}",
295 m_controllingPrim.LocalID, highestTouchPosition, nearFeetHeightMin, ret);
296 }
297 }
298 else
299 {
300 // If we used to be going up stairs but are not now, smooth the case where collision goes away while
301 // we are bouncing up the stairs.
302 if (m_walkingUpStairs > 0)
303 {
304 m_walkingUpStairs--;
305 ret = ComputeStairCorrection(m_lastStepUp);
306 }
307 }
308
309 return ret;
310 }
311
312 private OMV.Vector3 ComputeStairCorrection(float stepUp)
313 {
314 OMV.Vector3 ret = OMV.Vector3.Zero;
315 OMV.Vector3 displacement = OMV.Vector3.Zero;
316
317 if (stepUp > 0f)
318 {
319 // Found the stairs contact point. Push up a little to raise the character.
320 if (BSParam.AvatarStepForceFactor > 0f)
321 {
322 float upForce = stepUp * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
323 ret = new OMV.Vector3(0f, 0f, upForce);
324 }
325
326 // Also move the avatar up for the new height
327 if (BSParam.AvatarStepUpCorrectionFactor > 0f)
328 {
329 // Move the avatar up related to the height of the collision
330 displacement = new OMV.Vector3(0f, 0f, stepUp * BSParam.AvatarStepUpCorrectionFactor);
331 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
332 }
333 else
334 {
335 if (BSParam.AvatarStepUpCorrectionFactor < 0f)
336 {
337 // Move the avatar up about the specified step height
338 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight);
339 m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
340 }
341 }
342 m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs.ComputeStairCorrection,disp={1},force={2}",
343 m_controllingPrim.LocalID, displacement, ret);
344
345 }
346 return ret;
347 }
348}
349}
350
351