// Keyboard callback static void command(int cmd) { IntPtr geom; d.Mass mass; d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); Char ch = Char.ToLower((Char)cmd); switch ((Char)ch) { case 'b': d.MassSetBox(out mass, DENSITY, sides.X, sides.Y, sides.Z); geom = d.CreateBox(space, sides.X, sides.Y, sides.Z); addObject(geom, mass); break; case 'c': sides.X *= 0.5f; d.MassSetCapsule(out mass, DENSITY, 3, sides.X, sides.Y); geom = d.CreateCapsule(space, sides.X, sides.Y); addObject(geom, mass); break; case 'v': d.MassSetBox(out mass, DENSITY, 0.25f, 0.25f, 0.25f); geom = d.CreateConvex(space, planes, planes.Length / 4, points, points.Length / 3, polygons); addObject(geom, mass); break; } }
public void UpdatePosition() { d.Vector3 vec = d.BodyGetPosition(BoundingCapsule); this._position.X = vec.X; this._position.Y = vec.Y; this._position.Z = vec.Z; }
// Keyboard callback public void command(int cmd) { IntPtr geom; d.Mass mass; d.Vector3 sides = new d.Vector3(d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f, d.RandReal() * 0.5f + 0.1f); Char ch = Char.ToLower((Char)cmd); switch ((Char)ch) { case 'w': try { Vector3 rotate = (new Vector3(1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); xyz.X += rotate.X; xyz.Y += rotate.Y; xyz.Z += rotate.Z; ds.SetViewpoint(ref xyz, ref hpr); } catch (ArgumentException) { hpr.X = 0; } break; case 'a': hpr.X++; ds.SetViewpoint(ref xyz, ref hpr); break; case 's': try { Vector3 rotate2 = (new Vector3(-1, 0, 0) * Quaternion.CreateFromEulers(hpr.Z * Utils.DEG_TO_RAD, hpr.Y * Utils.DEG_TO_RAD, hpr.X * Utils.DEG_TO_RAD)); xyz.X += rotate2.X; xyz.Y += rotate2.Y; xyz.Z += rotate2.Z; ds.SetViewpoint(ref xyz, ref hpr); } catch (ArgumentException) { hpr.X = 0; } break; case 'd': hpr.X--; ds.SetViewpoint(ref xyz, ref hpr); break; case 'r': xyz.Z++; ds.SetViewpoint(ref xyz, ref hpr); break; case 'f': xyz.Z--; ds.SetViewpoint(ref xyz, ref hpr); break; case 'e': xyz.Y++; ds.SetViewpoint(ref xyz, ref hpr); break; case 'q': xyz.Y--; ds.SetViewpoint(ref xyz, ref hpr); break; } }
internal void Step() { IntPtr Body = rootPrim.Body; d.Mass dmass; d.BodyGetMass(Body, out dmass); d.Quaternion rot = d.BodyGetQuaternion(Body); Quaternion objrotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object Quaternion rotq = objrotq; // rotq = rotation of object rotq *= m_referenceFrame; // rotq is now rotation in vehicle reference frame Quaternion irotq = Quaternion.Inverse(rotq); d.Vector3 dvtmp; Vector3 tmpV; Vector3 curVel; // velocity in world Vector3 curAngVel; // angular velocity in world Vector3 force = Vector3.Zero; // actually linear aceleration until mult by mass in world frame Vector3 torque = Vector3.Zero; // actually angular aceleration until mult by Inertia in vehicle frame d.Vector3 dtorque = new d.Vector3(); dvtmp = d.BodyGetLinearVel(Body); curVel.X = dvtmp.X; curVel.Y = dvtmp.Y; curVel.Z = dvtmp.Z; Vector3 curLocalVel = curVel * irotq; // current velocity in local dvtmp = d.BodyGetAngularVel(Body); curAngVel.X = dvtmp.X; curAngVel.Y = dvtmp.Y; curAngVel.Z = dvtmp.Z; Vector3 curLocalAngVel = curAngVel * irotq; // current angular velocity in local float ldampZ = 0; // linear motor if (m_lmEfect > 0.01 && m_linearMotorTimescale < 1000) { tmpV = m_linearMotorDirection - curLocalVel; // velocity error tmpV *= m_lmEfect / m_linearMotorTimescale; // error to correct in this timestep tmpV *= rotq; // to world if ((m_flags & VehicleFlag.LIMIT_MOTOR_UP) != 0) { tmpV.Z = 0; } if (m_linearMotorOffset.X != 0 || m_linearMotorOffset.Y != 0 || m_linearMotorOffset.Z != 0) { // have offset, do it now tmpV *= dmass.mass; d.BodyAddForceAtRelPos(Body, tmpV.X, tmpV.Y, tmpV.Z, m_linearMotorOffset.X, m_linearMotorOffset.Y, m_linearMotorOffset.Z); } else { force.X += tmpV.X; force.Y += tmpV.Y; force.Z += tmpV.Z; } m_lmEfect *= m_lmDecay; // m_ffactor = 0.01f + 1e-4f * curVel.LengthSquared(); m_ffactor = 0.0f; } else { m_lmEfect = 0; m_ffactor = 1f; } // hover if (m_VhoverTimescale < 300 && rootPrim.prim_geom != IntPtr.Zero) { // d.Vector3 pos = d.BodyGetPosition(Body); d.Vector3 pos = d.GeomGetPosition(rootPrim.prim_geom); pos.Z -= 0.21f; // minor offset that seems to be always there in sl float t = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); float perr; // default to global but don't go underground perr = m_VhoverHeight - pos.Z; if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) == 0) { if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) { perr += _pParentScene.GetWaterLevel(); } else if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { perr += t; } else { float w = _pParentScene.GetWaterLevel(); if (t > w) { perr += t; } else { perr += w; } } } else if (t > m_VhoverHeight) { perr = t - pos.Z; } ; if ((m_flags & VehicleFlag.HOVER_UP_ONLY) == 0 || perr > -0.1) { ldampZ = m_VhoverEfficiency * m_invtimestep; perr *= (1.0f + ldampZ) / m_VhoverTimescale; // force.Z += perr - curVel.Z * tmp; force.Z += perr; ldampZ *= -curVel.Z; force.Z += _pParentScene.gravityz * m_gravmod * (1f - m_VehicleBuoyancy); } else // no buoyancy { force.Z += _pParentScene.gravityz; } } else { // default gravity and Buoyancy force.Z += _pParentScene.gravityz * m_gravmod * (1f - m_VehicleBuoyancy); } // linear deflection if (m_linearDeflectionEfficiency > 0) { float len = curVel.Length(); if (len > 0.01) // if moving { Vector3 atAxis; atAxis = Xrot(rotq); // where are we pointing to atAxis *= len; // make it same size as world velocity vector tmpV = -atAxis; // oposite direction atAxis -= curVel; // error to one direction len = atAxis.LengthSquared(); tmpV -= curVel; // error to oposite float lens = tmpV.LengthSquared(); if (len > 0.01 || lens > 0.01) // do nothing if close enougth { if (len < lens) { tmpV = atAxis; } tmpV *= (m_linearDeflectionEfficiency / m_linearDeflectionTimescale); // error to correct in this timestep force.X += tmpV.X; force.Y += tmpV.Y; if ((m_flags & VehicleFlag.NO_DEFLECTION_UP) == 0) { force.Z += tmpV.Z; } } } } // linear friction/damping if (curLocalVel.X != 0 || curLocalVel.Y != 0 || curLocalVel.Z != 0) { tmpV.X = -curLocalVel.X / m_linearFrictionTimescale.X; tmpV.Y = -curLocalVel.Y / m_linearFrictionTimescale.Y; tmpV.Z = -curLocalVel.Z / m_linearFrictionTimescale.Z; tmpV *= rotq; // to world if (ldampZ != 0 && Math.Abs(ldampZ) > Math.Abs(tmpV.Z)) { tmpV.Z = ldampZ; } force.X += tmpV.X; force.Y += tmpV.Y; force.Z += tmpV.Z; } // vertical atractor if (m_verticalAttractionTimescale < 300) { float roll; float pitch; float ftmp = m_invtimestep / m_verticalAttractionTimescale / m_verticalAttractionTimescale; float ftmp2; ftmp2 = 0.5f * m_verticalAttractionEfficiency * m_invtimestep; m_amdampX = ftmp2; m_ampwr = 1.0f - 0.8f * m_verticalAttractionEfficiency; GetRollPitch(irotq, out roll, out pitch); if (roll > halfpi) { roll = pi - roll; } else if (roll < -halfpi) { roll = -pi - roll; } float effroll = pitch / halfpi; effroll *= effroll; effroll = 1 - effroll; effroll *= roll; torque.X += effroll * ftmp; if ((m_flags & VehicleFlag.LIMIT_ROLL_ONLY) == 0) { float effpitch = roll / halfpi; effpitch *= effpitch; effpitch = 1 - effpitch; effpitch *= pitch; torque.Y += effpitch * ftmp; } if (m_bankingEfficiency != 0 && Math.Abs(effroll) > 0.01) { float broll = effroll; /* * if (broll > halfpi) * broll = pi - broll; * else if (broll < -halfpi) * broll = -pi - broll; */ broll *= m_bankingEfficiency; if (m_bankingMix != 0) { float vfact = Math.Abs(curLocalVel.X) / 10.0f; if (vfact > 1.0f) { vfact = 1.0f; } if (curLocalVel.X >= 0) { broll *= (1 + (vfact - 1) * m_bankingMix); } else { broll *= -(1 + (vfact - 1) * m_bankingMix); } } // make z rot be in world Z not local as seems to be in sl broll = broll / m_bankingTimescale; tmpV = Zrot(irotq); tmpV *= broll; torque.X += tmpV.X; torque.Y += tmpV.Y; torque.Z += tmpV.Z; m_amdampZ = Math.Abs(m_bankingEfficiency) / m_bankingTimescale; m_amdampY = m_amdampZ; } else { m_amdampZ = 1 / m_angularFrictionTimescale.Z; m_amdampY = m_amdampX; } } else { m_ampwr = 1.0f; m_amdampX = 1 / m_angularFrictionTimescale.X; m_amdampY = 1 / m_angularFrictionTimescale.Y; m_amdampZ = 1 / m_angularFrictionTimescale.Z; } // angular motor if (m_amEfect > 0.01 && m_angularMotorTimescale < 1000) { tmpV = m_angularMotorDirection - curLocalAngVel; // velocity error tmpV *= m_amEfect / m_angularMotorTimescale; // error to correct in this timestep torque.X += tmpV.X * m_ampwr; torque.Y += tmpV.Y * m_ampwr; torque.Z += tmpV.Z; m_amEfect *= m_amDecay; } else { m_amEfect = 0; } // angular deflection if (m_angularDeflectionEfficiency > 0) { Vector3 dirv; if (curLocalVel.X > 0.01f) { dirv = curLocalVel; } else if (curLocalVel.X < -0.01f) { // use oposite dirv = -curLocalVel; } else { // make it fall into small positive x case dirv.X = 0.01f; dirv.Y = curLocalVel.Y; dirv.Z = curLocalVel.Z; } float ftmp = m_angularDeflectionEfficiency / m_angularDeflectionTimescale; if (Math.Abs(dirv.Z) > 0.01) { torque.Y += -(float)Math.Atan2(dirv.Z, dirv.X) * ftmp; } if (Math.Abs(dirv.Y) > 0.01) { torque.Z += (float)Math.Atan2(dirv.Y, dirv.X) * ftmp; } } // angular friction if (curLocalAngVel.X != 0 || curLocalAngVel.Y != 0 || curLocalAngVel.Z != 0) { torque.X -= curLocalAngVel.X * m_amdampX; torque.Y -= curLocalAngVel.Y * m_amdampY; torque.Z -= curLocalAngVel.Z * m_amdampZ; } if (force.X != 0 || force.Y != 0 || force.Z != 0) { force *= dmass.mass; d.BodyAddForce(Body, force.X, force.Y, force.Z); } if (torque.X != 0 || torque.Y != 0 || torque.Z != 0) { torque *= m_referenceFrame; // to object frame dtorque.X = torque.X; dtorque.Y = torque.Y; dtorque.Z = torque.Z; d.MultiplyM3V3(out dvtmp, ref dmass.I, ref dtorque); d.BodyAddRelTorque(Body, dvtmp.X, dvtmp.Y, dvtmp.Z); // add torque in object frame } }
}// end Step private void MoveAngular(float pTimestep) { /* * private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor * private int m_angularMotorApply = 0; // application frame counter * private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) * private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate * private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate * private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate * private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body */ // Get what the body is doing, this includes 'external' influences d.Vector3 angularVelocity = d.BodyGetAngularVel(Body); // Vector3 angularVelocity = Vector3.Zero; if (m_angularMotorApply > 0) { // ramp up to new value // current velocity += error / (time to get there / step interval) // requested speed - last motor speed m_angularMotorVelocity.X += (m_angularMotorDirection.X - m_angularMotorVelocity.X) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected // velocity may still be acheived. } else { // no motor recently applied, keep the body velocity /* m_angularMotorVelocity.X = angularVelocity.X; * m_angularMotorVelocity.Y = angularVelocity.Y; * m_angularMotorVelocity.Z = angularVelocity.Z; */ // and decay the velocity m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); } // end motor section // Vertical attractor section Vector3 vertattr = Vector3.Zero; if (m_verticalAttractionTimescale < 300) { float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); // get present body rotation d.Quaternion rot = d.BodyGetQuaternion(Body); Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // make a vector pointing up Vector3 verterr = Vector3.Zero; verterr.Z = 1.0f; // rotate it to Body Angle verterr = verterr * rotq; // verterr.X and .Y are the World error ammounts. They are 0 when there is no error (Vehicle Body is 'vertical'), and .Z will be 1. // As the body leans to its side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be modulated to prevent a stable inverted body. if (verterr.Z < 0.0f) { verterr.X = 2.0f - verterr.X; verterr.Y = 2.0f - verterr.Y; } // Error is 0 (no error) to +/- 2 (max error) // scale it by VAservo verterr = verterr * VAservo; //if (frcount == 0) Console.WriteLine("VAerr=" + verterr); // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. vertattr.X = verterr.Y; vertattr.Y = -verterr.X; vertattr.Z = 0f; // scaling appears better usingsquare-law float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency); vertattr.X += bounce * angularVelocity.X; vertattr.Y += bounce * angularVelocity.Y; } // else vertical attractor is off // m_lastVertAttractor = vertattr; // Bank section tba // Deflection section tba // Sum velocities m_lastAngularVelocity = m_angularMotorVelocity + vertattr; // + bank + deflection if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) { m_lastAngularVelocity.X = 0; m_lastAngularVelocity.Y = 0; } if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) { if (!d.BodyIsEnabled(Body)) { d.BodyEnable(Body); } } else { m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. } // apply friction Vector3 decayamount = Vector3.One / (m_angularFrictionTimescale / pTimestep); m_lastAngularVelocity -= m_lastAngularVelocity * decayamount; // Apply to the body d.BodySetAngularVel(Body, m_lastAngularVelocity.X, m_lastAngularVelocity.Y, m_lastAngularVelocity.Z); }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="timeStep"></param> public void Move (float timeStep, ref List<AuroraODECharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; if (!m_shouldBePhysical) return; // replace amotor d.Quaternion dtmp; dtmp.W = 1; dtmp.X = 0; dtmp.Y = 0; dtmp.Z = 0; d.BodySetQuaternion (Body, ref dtmp); d.BodySetAngularVel(Body, 0, 0, 0); Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); #region Flight Ceiling // rex, added height check d.Vector3 tempPos = d.BodyGetPosition (Body); if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition (Body); } if (_parent_scene.m_useFlightCeilingHeight && tempPos.Z > _parent_scene.m_flightCeilingHeight) { tempPos.Z = _parent_scene.m_flightCeilingHeight; d.BodySetPosition (Body, tempPos.X, tempPos.Y, tempPos.Z); d.Vector3 tempVel = d.BodyGetLinearVel (Body); if (tempVel.Z > 0.0f) { tempVel.Z = 0.0f; d.BodySetLinearVel (Body, tempVel.X, tempVel.Y, tempVel.Z); } if (_target_velocity.Z > 0.0f) _target_velocity.Z = 0.0f; } // endrex #endregion #region NonFinite Pos Vector3 localPos = new Vector3 ((float)tempPos.X, (float)tempPos.Y, (float)tempPos.Z); if (!localPos.IsFinite ()) { m_log.Warn ("[PHYSICS]: Avatar Position is non-finite!"); defects.Add (this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data /* if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } */ //kill the Geometry _parent_scene.waitForSpaceUnlock (_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy (Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy (Shell); _parent_scene.geom_name_map.Remove (Shell); Shell = IntPtr.Zero; } return; } #endregion #region Check for out of region if (Position.X < 0.25f || Position.Y < 0.25f || Position.X > _parent_scene.Region.RegionSizeX - .25f || Position.Y > _parent_scene.Region.RegionSizeY - .25f) { if (!CheckForRegionCrossing()) { Vector3 newPos = Position; newPos.X = Util.Clip(Position.X, 0.75f, _parent_scene.Region.RegionSizeX - 0.75f); newPos.Y = Util.Clip(Position.Y, 0.75f, _parent_scene.Region.RegionSizeY - 0.75f); Position = newPos; d.BodySetPosition(Body, newPos.X, newPos.Y, newPos.Z); } } #endregion #region Movement Multiplier float movementmult = 1f; if (!m_alwaysRun) movementmult /= _parent_scene.avMovementDivisorWalk; else movementmult /= _parent_scene.avMovementDivisorRun; movementmult *= 10; movementmult *= SpeedModifier; if (flying) movementmult *= _parent_scene.m_AvFlySpeed; #endregion #region Check for underground if (!(Position.X < 0.25f || Position.Y < 0.25f || Position.X > _parent_scene.Region.RegionSizeX - .25f || Position.Y > _parent_scene.Region.RegionSizeY - .25f)) { float groundHeight = _parent_scene.GetTerrainHeightAtXY ( tempPos.X + (tempPos.X == 0 ? tempPos.X : timeStep * 0.75f * vel.X), tempPos.Y + (tempPos.Y == 0 ? tempPos.Y : timeStep * 0.75f * vel.Y)); if ((tempPos.Z - AvatarHalfsize) < groundHeight) { if (!flying) { //if (_target_velocity.Z < 0) _target_velocity.Z = 0; vec.Z = -vel.Z * PID_D * 2f + ((groundHeight - (tempPos.Z - AvatarHalfsize)) * PID_P * 100.0f); } else vec.Z = ((groundHeight - (tempPos.Z - AvatarHalfsize)) * PID_P); } if (tempPos.Z - AvatarHalfsize - groundHeight < 0.12f) { m_iscolliding = true; m_iscollidingGround = true; flying = false; // ground the avatar ContactPoint point = new ContactPoint (); point.PenetrationDepth = vel.Z; point.Position = Position; point.SurfaceNormal = Vector3.Zero; //0 is the ground localID this.AddCollisionEvent (0, point); } else m_iscollidingGround = false; } else m_iscollidingGround = true;//Assume that they are crossing, and keep them from falling down #endregion #region Movement #region Jump code if (IsJumping && (IsColliding && m_preJumpCounter > _parent_scene.m_preJumpTime + 10) || m_preJumpCounter > 50) { m_isJumping = false; m_preJumpCounter = 0; } if (IsJumping) m_preJumpCounter++; if (m_ispreJumping && m_preJumpCounter == _parent_scene.m_preJumpTime) { m_ispreJumping = false; _target_velocity += m_preJumpForce * _parent_scene.m_preJumpForceMultiplier; m_preJumpCounter = 0; m_isJumping = true; } if (m_ispreJumping) { m_preJumpCounter++; TriggerMovementUpdate(); return; } #endregion // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity == Vector3.Zero && Math.Abs (vel.X) < 0.05 && Math.Abs (vel.Y) < 0.05 && Math.Abs (vel.Z) < 0.05 && (this.m_iscollidingGround || this.m_iscollidingObj || this.flying)) //This is so that if we get moved by something else, it will update us in the client { m_isJumping = false; // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = tempPos; } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions // if target vel is zero why was it here ? vec.X = -vel.X * PID_D + (_zeroPosition.X - tempPos.X) * PID_P; vec.Y = -vel.Y * PID_D + (_zeroPosition.Y - tempPos.Y) * PID_P; } } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding) { if (!flying) { if (_target_velocity.Z != 0.0f) vec.Z = (_target_velocity.Z * movementmult - vel.Z) * PID_D;// + (_zeroPosition.Z - tempPos.Z) * PID_P)) _zeropos maybe bad here // We're standing or walking on something vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D * 2; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D * 2; } else { // We're flying and colliding with something vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D * 0.5f; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.5f; } } else { if (flying) { // we're flying vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D * 0.75f; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.75f; } else { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. vec.X = (_target_velocity.X - vel.X) * PID_D * 0.85f; vec.Y = (_target_velocity.Y - vel.Y) * PID_D * 0.85f; } } if (flying) { #region Av gravity if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Should be stop avies from flying upwards { //Decay going up if (_target_velocity.Z > 0) { //How much should we force them down? float Multiplier = (_parent_scene.AllowAvsToEscapeGravity ? .03f : .1f); //How much should we force them down? float fudgeHeight = (_parent_scene.AllowAvsToEscapeGravity ? 80 : 30); //We add the 30 so that gravity is resonably strong once they pass the min height Multiplier *= tempPos.Z + fudgeHeight - _parent_scene.AvGravityHeight; //Limit these so that things don't go wrong if (Multiplier < 1) Multiplier = 1; float maxpower = (_parent_scene.AllowAvsToEscapeGravity ? 1.5f : 3f); if (Multiplier > maxpower) Multiplier = maxpower; _target_velocity.Z /= Multiplier; vel.Z /= Multiplier; } } #endregion vec.Z = (_target_velocity.Z * movementmult - vel.Z) * PID_D * 0.5f; if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Add extra gravity vec.Z += ((10 * _parent_scene.gravityz) * Mass); } } if (flying) { #region Auto Fly Height //Added for auto fly height. Kitto Flora //Changed to only check if the avatar is flying around, // Revolution: If the avatar is going down, they are trying to land (probably), so don't push them up to make it harder // Only if they are moving around sideways do we need to push them up if (_target_velocity.X != 0 || _target_velocity.Y != 0) { Vector3 forwardVel = new Vector3 (_target_velocity.X > 0 ? 2 : (_target_velocity.X < 0 ? -2 : 0), _target_velocity.Y > 0 ? 2 : (_target_velocity.Y < 0 ? -2 : 0), 0); float target_altitude = _parent_scene.GetTerrainHeightAtXY (tempPos.X, tempPos.Y) + MinimumGroundFlightOffset; //We cheat a bit and do a bit lower than normal if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude || (tempPos.Z - CAPSULE_LENGTH) < _parent_scene.GetTerrainHeightAtXY (tempPos.X + forwardVel.X, tempPos.Y + forwardVel.Y) + MinimumGroundFlightOffset) vec.Z += (target_altitude - tempPos.Z) * PID_P * 0.5f; } else { //Straight up and down, only apply when they are very close to the ground float target_altitude = _parent_scene.GetTerrainHeightAtXY (tempPos.X, tempPos.Y); if ((tempPos.Z - CAPSULE_LENGTH + (MinimumGroundFlightOffset / 1.5)) < target_altitude + MinimumGroundFlightOffset) { if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude + 1) { vec.Z += ((target_altitude + 4) - (tempPos.Z - CAPSULE_LENGTH)) * PID_P; } else vec.Z += ((target_altitude + MinimumGroundFlightOffset) - (tempPos.Z - CAPSULE_LENGTH)) * PID_P * 0.5f; } } #endregion } #region Gravity if (!flying && _parent_scene.AllowAvGravity) { if (!_parent_scene.UsePointGravity) { //Add normal gravity vec.X += _parent_scene.gravityx * m_mass; vec.Y += _parent_scene.gravityy * m_mass; vec.Z += _parent_scene.gravityz * m_mass; } else { Vector3 cog = _parent_scene.PointOfGravity; if (cog.X != 0) vec.X += (cog.X - tempPos.X) * m_mass; if (cog.Y != 0) vec.Y += (cog.Y - tempPos.Y) * m_mass; if (cog.Z != 0) vec.Z += (cog.Z - tempPos.Z) * m_mass; } } #endregion #region Under water physics if (_parent_scene.AllowUnderwaterPhysics && (float)tempPos.X < _parent_scene.Region.RegionSizeX && (float)tempPos.Y < _parent_scene.Region.RegionSizeY) { //Position plus height to av's shoulder (aprox) is just above water if ((tempPos.Z + (CAPSULE_LENGTH / 3) - .25f) < _parent_scene.GetWaterLevel ((float)tempPos.X, (float)tempPos.Y)) { if (StartingUnderWater) ShouldBeWalking = Flying == false; StartingUnderWater = false; WasUnderWater = true; Flying = true; lastUnderwaterPush = 0; if (ShouldBeWalking) { lastUnderwaterPush += (float)(_parent_scene.GetWaterLevel ((float)tempPos.X, (float)tempPos.Y) - tempPos.Z) * 33 + 3; vec.Z += lastUnderwaterPush; } else { lastUnderwaterPush += 3500; lastUnderwaterPush += (float)(_parent_scene.GetWaterLevel ((float)tempPos.X, (float)tempPos.Y) - tempPos.Z) * 8; vec.Z += lastUnderwaterPush; } } else { StartingUnderWater = true; if (WasUnderWater) { WasUnderWater = false; Flying = true; } } } #endregion #endregion #region Apply the force if (vec.IsFinite ()) { if (vec.X < 100000000 && vec.Y < 10000000 && vec.Z < 10000000) //Checks for crazy, going to NaN us values { // round small values to zero. those possible are just errors if (Math.Abs (vec.X) < 0.001) vec.X = 0; if (Math.Abs (vec.Y) < 0.001) vec.Y = 0; if (Math.Abs (vec.Z) < 0.001) vec.Z = 0; if (vec == Vector3.Zero) //if we arn't moving, STOP d.BodySetLinearVel(Body, vec.X, vec.Y, vec.Z); else doForce (vec); //When falling, we keep going faster and faster, and eventually, the client blue screens (blue is all you see). // The speed that does this is slightly higher than -30, so we cap it here so we never do that during falling. if (vel.Z < -30) { vel.Z = -30; d.BodySetLinearVel (Body, vel.X, vel.Y, vel.Z); } //Decay out the target velocity _target_velocity *= _parent_scene.m_avDecayTime; if (!_zeroFlag && _target_velocity.ApproxEquals (Vector3.Zero, _parent_scene.m_avStopDecaying)) _target_velocity = Vector3.Zero; } else { //This is a safe guard from going NaN, but it isn't very smooth... which is ok d.BodySetForce (Body, 0, 0, 0); d.BodySetLinearVel (Body, 0, 0, 0); } } else { m_log.Warn ("[PHYSICS]: Got a NaN force vector in Move()"); m_log.Warn ("[PHYSICS]: Avatar Position is non-finite!"); defects.Add (this); //kill the Geometry _parent_scene.waitForSpaceUnlock (_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy (Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy (Shell); _parent_scene.geom_name_map.Remove (Shell); Shell = IntPtr.Zero; } } #endregion }
// normally called from within OnJointMoved, which is called from within a lock (OdeLock) // WARNING: ODE sometimes returns <0,0,0> as the joint axis! Therefore this function // appears to be unreliable. Fortunately we can compute the joint axis ourselves by // keeping track of the joint's original orientation relative to one of the involved bodies. public override Vector3 GetJointAxis(PhysicsJoint joint) { Debug.Assert(joint.IsInPhysicsEngine); d.Vector3 axis = new d.Vector3(); if (!(joint is AuroraODEPhysicsJoint)) { DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); } else { AuroraODEPhysicsJoint odeJoint = (AuroraODEPhysicsJoint)joint; switch (odeJoint.Type) { case PhysicsJointType.Ball: DoJointErrorMessage(joint, "warning - axis requested for ball joint: " + joint.ObjectNameInScene); break; case PhysicsJointType.Hinge: d.JointGetHingeAxis(odeJoint.jointID, out axis); break; } } return new Vector3((float)axis.X, (float)axis.Y, (float)axis.Z); }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> /// <param name="defects">The character will be added to this list if there is something wrong (non-finite /// position or velocity). /// </param> internal void UpdatePositionAndVelocity(List<OdeCharacter> defects) { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 newPos; try { newPos = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; defects.Add(this); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); return; } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) if (newPos.X < 0.0f) newPos.X = 0.0f; if (newPos.Y < 0.0f) newPos.Y = 0.0f; if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f; if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; _position.X = newPos.X; _position.Y = newPos.Y; _position.Z = newPos.Z; // I think we need to update the taintPosition too -- Diva 12/24/10 m_taintPosition = _position; // Did we move last? = zeroflag // This helps keep us from sliding all over if (_zeroFlag) { _velocity = Vector3.Zero; // Did we send out the 'stopped' message? if (!m_lastUpdateSent) { m_lastUpdateSent = true; //base.RequestPhysicsterseUpdate(); } } else { m_lastUpdateSent = false; d.Vector3 newVelocity; try { newVelocity = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { newVelocity.X = _velocity.X; newVelocity.Y = _velocity.Y; newVelocity.Z = _velocity.Z; } _velocity.X = newVelocity.X; _velocity.Y = newVelocity.Y; _velocity.Z = newVelocity.Z; if (_velocity.Z < -6 && !m_hackSentFall) { m_hackSentFall = true; m_pidControllerActive = false; } else if (flying && !m_hackSentFly) { //m_hackSentFly = true; //base.SendCollisionUpdate(new CollisionEventUpdate()); } else { m_hackSentFly = false; m_hackSentFall = false; } } }
} // end Step private void MoveLinear(float pTimestep, AuroraODEPhysicsScene _pParentScene) { d.Vector3 pos = d.BodyGetPosition (Body); d.Vector3 oldPos = pos; if (m_lastPositionVector.X != pos.X || m_lastPositionVector.Y != pos.Y || m_lastPositionVector.Z != pos.Z) { m_lastPositionVector = d.BodyGetPosition (Body); m_lastAngularVelocity = new Vector3 ((float)d.BodyGetAngularVel (Body).X, (float)d.BodyGetAngularVel (Body).Y, (float)d.BodyGetAngularVel (Body).Z); } if (!m_linearMotorDirection.ApproxEquals (Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant { if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // add drive to body Vector3 addAmount = m_linearMotorDirection / (m_linearMotorTimescale * m_linearMotorDecayTimescale / (pTimestep)); m_lastLinearVelocityVector += (addAmount * 10); // lastLinearVelocityVector is the current body velocity vector? // This will work temporarily, but we really need to compare speed on an axis // KF: Limit body velocity to applied velocity? if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; } else { // requested is not significant // if what remains of applied is small, zero it. if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) m_lastLinearVelocityVector = Vector3.Zero; } m_linearMotorDirection = Vector3.Zero; // convert requested object velocity to world-referenced vector m_dir = m_lastLinearVelocityVector; d.Quaternion rot = d.BodyGetQuaternion (Body); Quaternion rotq = new Quaternion (rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object m_dir *= rotq; // Preserve the current Z velocity d.Vector3 vel_now = d.BodyGetLinearVel(Body); m_dir.Z += (float)vel_now.Z; // Preserve the accumulated falling velocity #region Blocking End Points //This makes sure that the vehicle doesn't leave the defined limits of position if (m_BlockingEndPoint != Vector3.Zero) { Vector3 posChange = new Vector3(); posChange.X = (float)(pos.X - m_lastPositionVector.X); posChange.Y = (float)(pos.Y - m_lastPositionVector.Y); posChange.Z = (float)(pos.Z - m_lastPositionVector.Z); if (pos.X >= (m_BlockingEndPoint.X - (float)1)) pos.X -= posChange.X + 1; if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) pos.Y -= posChange.Y + 1; if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) pos.Z -= posChange.Z + 1; if (pos.X <= 0) pos.X += posChange.X + 1; if (pos.Y <= 0) pos.Y += posChange.Y + 1; } #endregion // Check if hovering if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) { // We should hover, get the target height if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) { m_VhoverTargetHeight = (float)_pParentScene.GetWaterLevel((float)pos.X, (float)pos.Y) + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY((float)pos.X, (float)pos.Y) + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) { m_VhoverTargetHeight = m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) { // If body is already heigher, use its height as target height if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = (float)pos.Z; } if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) { if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) { if ((pos.Z - (pos.Z - m_VhoverTargetHeight)) >= _pParentScene.GetTerrainHeightAtXY((float)pos.X, (float)pos.Y)) pos.Z = m_VhoverTargetHeight; } } else { // m_VhoverEfficiency - 0=boucy, 1=Crit.damped // m_VhoverTimescale - time to acheive height float herr0 = (float)pos.Z - m_VhoverTargetHeight; // Replace Vertical speed with correction figure if significant if (Math.Abs(herr0) > 0.01f) { //Note: we use 1.05 because it doesn't disappear completely, only very critically damped m_dir.Z = (float)((-((herr0 * pTimestep * 50.0f) / m_VhoverTimescale)) * (1.05 - m_VhoverEfficiency)); } else //Too small, zero it. m_dir.Z = 0f; } } //Do this here, because it shouldn't clear out gravity or the tainted forces (not part of vehicle physics) if ((m_flags & (VehicleFlag.NO_X)) != 0) m_dir.X = 0; if ((m_flags & (VehicleFlag.NO_Y)) != 0) m_dir.Y = 0; if ((m_flags & (VehicleFlag.NO_Z)) != 0) m_dir.Z = 0; m_lastPositionVector = d.BodyGetPosition(Body); #region Deal with tainted forces // KF: So far I have found no good method to combine a script-requested // .Z velocity and gravity. Therefore only 0g will used script-requested // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; Vector3 TaintedForce = new Vector3(); if (m_forcelist.Count != 0) { try { for (int i = 0; i < m_forcelist.Count; i++) { TaintedForce = TaintedForce + (m_forcelist[i] * 100); } } catch (IndexOutOfRangeException) { TaintedForce = Vector3.Zero; } catch (ArgumentOutOfRangeException) { TaintedForce = Vector3.Zero; } m_forcelist = new List<Vector3>(); } #endregion #region Deflection //Forward is the prefered direction Vector3 PreferredAxisOfMotion = new Vector3 (1 + 1 * (m_linearDeflectionEfficiency / m_linearDeflectionTimescale) * pTimestep * pTimestep * pTimestep, 1, 1); PreferredAxisOfMotion *= m_referenceFrame; //Multiply it so that it scales linearly m_dir *= PreferredAxisOfMotion; #endregion if (Mass == 0) { d.Mass mass; d.BodyGetMass(m_body, out mass); Mass = mass.mass; Mass *= 2; } //No Setting forces, only velocity! Forces are NOT recommended to be used by the ODE manual //d.BodySetForce(Body, _pParentScene.gravityx + TaintedForce.X, // _pParentScene.gravityy + TaintedForce.Y, // (_pParentScene.gravityz * Mass * (1f - m_VehicleBuoyancy)) + TaintedForce.Z); //d.BodySetForce(Body, _pParentScene.gravityx + TaintedForce.X + (m_dir.X * 10000), // _pParentScene.gravityy + TaintedForce.Y + (m_dir.Y * 10000), // (_pParentScene.gravityz * Mass * (1f - m_VehicleBuoyancy)) + TaintedForce.Z + (m_dir.Z * 10000)); m_dir += TaintedForce; //Uses the square to make bouyancy more effective as in SL, as it seems to effect gravity more the higher the value is //This check helps keep things from being pushed into the ground and the consequence of being shoved back out m_dir.Z += ((_pParentScene.gravityz * (float)Mass) * ((((1 - m_VehicleBuoyancy) * (1 - m_VehicleBuoyancy))) * pTimestep)); d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); //Check for changes and only set it once if (pos.X != oldPos.X || pos.Y != oldPos.Y || pos.Z != oldPos.Z) d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); // apply friction // note: seems more effective with how SL does this with the square Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / (pTimestep * pTimestep)); m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; } // end MoveLinear()
public static extern void DrawConvex(ref d.Vector3 pos, ref d.Matrix3 R, dReal[] planes, int planeCount, dReal[] points, int pointCount, int[] polygons);
public static extern void DrawCapsule(ref d.Vector3 pos, ref d.Matrix3 R, dReal length, dReal radius);
public static extern void DrawBox(ref d.Vector3 pos, ref d.Matrix3 R, ref d.Vector3 sides);
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name = "timeStep"></param> public void Move(float timeStep, ref List<AuroraODECharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; if (!m_shouldBePhysical) return; Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); d.Vector3 tempPos; d.BodyCopyPosition(Body, out tempPos); #region Flight Ceiling // rex, added height check if (m_pidControllerActive == false) { _zeroPosition = tempPos; } if (_parent_scene.m_useFlightCeilingHeight && tempPos.Z > _parent_scene.m_flightCeilingHeight) { tempPos.Z = _parent_scene.m_flightCeilingHeight; d.BodySetPosition(Body, tempPos.X, tempPos.Y, tempPos.Z); if (vel.Z > 0.0f) { vel.Z = 0.0f; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } if (_target_velocity.Z > 0.0f) _target_velocity.Z = 0.0f; } // endrex #endregion #region NonFinite Pos Vector3 localPos = new Vector3(tempPos.X, tempPos.Y, tempPos.Z); if (!IsFinite(localPos)) { MainConsole.Instance.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); Shell = IntPtr.Zero; } return; } #endregion #region Check for out of region if (Position.X < 0.25f || Position.Y < 0.25f || Position.X > _parent_scene.Region.RegionSizeX - .25f || Position.Y > _parent_scene.Region.RegionSizeY - .25f) { if (!CheckForRegionCrossing()) { Vector3 newPos = Position; newPos.X = Util.Clip(Position.X, 0.75f, _parent_scene.Region.RegionSizeX - 0.75f); newPos.Y = Util.Clip(Position.Y, 0.75f, _parent_scene.Region.RegionSizeY - 0.75f); Position = newPos; d.BodySetPosition(Body, newPos.X, newPos.Y, newPos.Z); } } #endregion #region Movement Multiplier float movementmult = 1f; if (!m_alwaysRun) movementmult /= _parent_scene.avMovementDivisorWalk; else movementmult /= _parent_scene.avMovementDivisorRun; movementmult *= 10; movementmult *= SpeedModifier; // movementmult *= 1 / _parent_scene.TimeDilation; if (flying) movementmult *= _parent_scene.m_AvFlySpeed; #endregion #region Check for underground d.AABB aabb; d.GeomGetAABB(Shell, out aabb); float chrminZ = aabb.MinZ; Vector3 posch = localPos; float ftmp; if (flying) { ftmp = 0.75f*timeStep; posch.X += vel.X*ftmp; posch.Y += vel.Y*ftmp; } float groundHeight = _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y); if (chrminZ < groundHeight) { float depth = groundHeight - chrminZ; if (_target_velocity.Z < 0) _target_velocity.Z = 0; if (!flying) { if (vel.Z < -10f) vel.Z = -10f; vec.Z = -vel.Z*PID_D*1.5f + depth*PID_P*50.0f; } else { vec.Z = depth*PID_P*50.0f; } if (depth < 0.12f) { m_iscolliding = true; m_colliderfilter = 2; m_iscollidingGround = true; ContactPoint point = new ContactPoint { Type = ActorTypes.Ground, PenetrationDepth = depth, Position = {X = localPos.X, Y = localPos.Y, Z = chrminZ}, SurfaceNormal = new Vector3(0, 0, -1f) }; //0 is the ground localID AddCollisionEvent(0, point); vec.Z *= 0.5f; } else m_iscollidingGround = false; } else m_iscollidingGround = false; /* if(Flying && _target_velocity == Vector3.Zero && Math.Abs(vel.Z) < 0.1) notMoving = true; */ #endregion #region Movement #region Jump code if (IsJumping) { // if ((IsColliding) && m_preJumpCounter > _parent_scene.m_preJumpTime || m_preJumpCounter > 150) if ((IsColliding) && m_preJumpCounter > _parent_scene.m_preJumpTime || m_preJumpCounter > 150) { m_isJumping = false; m_preJumpCounter = 0; _target_velocity.Z = 0; } else m_preJumpCounter++; } else if (m_ispreJumping) { if (m_preJumpCounter == _parent_scene.m_preJumpTime) { m_ispreJumping = false; _target_velocity.X = m_preJumpForce.X*_parent_scene.m_preJumpForceMultiplierX; _target_velocity.Y = m_preJumpForce.Y*_parent_scene.m_preJumpForceMultiplierY; _target_velocity.Z = m_preJumpForce.Z*_parent_scene.m_preJumpForceMultiplierZ; m_preJumpCounter = 0; m_isJumping = true; } else { m_preJumpCounter++; TriggerMovementUpdate(); return; } } //This is for jumping on prims, since otherwise, you don't get off the ground sometimes // if (m_iscolliding && m_isJumping && _target_velocity.Z < 1 && !Flying) // _target_velocity.Z += m_preJumpForce.Z * _parent_scene.m_preJumpForceMultiplier; #endregion Vector3 gravForce = new Vector3(); // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity == Vector3.Zero && Math.Abs(vel.X) < 0.1 && Math.Abs(vel.Y) < 0.1 && Math.Abs(vel.Z) < 0.1 && (this.m_iscolliding || this.flying || (this._zeroFlag && _wasZeroFlagFlying == flying))) //This is so that if we get moved by something else, it will update us in the client { m_isJumping = false; // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _wasZeroFlagFlying = flying; _zeroPosition = tempPos; } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions // if target vel is zero why was it here ? vec.X = -vel.X*PID_D + (_zeroPosition.X - tempPos.X)*PID_P; vec.Y = -vel.Y*PID_D + (_zeroPosition.Y - tempPos.Y)*PID_P; // if (!realFlying) // vec.Z += - vel.Z * PID_D * 5; // else if (flying) vec.Z += -vel.Z*PID_D*0.5f + (_zeroPosition.Z - tempPos.Z)*PID_P; // _parent_scene.CalculateGravity(m_mass, tempPos, true, 0.15f, ref gravForce); // vec += gravForce; } } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding) { if (!flying) //If there is a ground collision, it sets flying to false, so check against real flying { // We're standing or walking on something if (_target_velocity.X != 0.0f) vec.X += (_target_velocity.X * movementmult - vel.X) * PID_D * 2; if (_target_velocity.Y != 0.0f) vec.Y += (_target_velocity.Y * movementmult - vel.Y) * PID_D * 2; if (_target_velocity.Z != 0.0f) vec.Z += (_target_velocity.Z * movementmult - vel.Z) * PID_D; /*// We're standing or walking on something vec.X += (_target_velocity.X*movementmult - vel.X)*PID_D*2; vec.Y += (_target_velocity.Y*movementmult - vel.Y)*PID_D*2; if (_target_velocity.Z > 0.0f) vec.Z += (_target_velocity.Z*movementmult - vel.Z)*PID_D; // + (_zeroPosition.Z - tempPos.Z) * PID_P)) _zeropos maybe bad here*/ } else { // We're flying and colliding with something vec.X += (_target_velocity.X*movementmult - vel.X)*PID_D*0.5f; vec.Y += (_target_velocity.Y*movementmult - vel.Y)*PID_D*0.5f; //if(_target_velocity.Z > 0) vec.Z += (_target_velocity.Z*movementmult - vel.Z)*PID_D*0.5f; } } else { if (flying) { // we're flying vec.X += (_target_velocity.X * movementmult - vel.X) * PID_D * 0.75f; vec.Y += (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.75f; } else { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. vec.X += (_target_velocity.X - vel.X) * PID_D * 0.85f; vec.Y += (_target_velocity.Y - vel.Y) * PID_D * 0.85f; } } if (flying) { #region Av gravity if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Should be stop avies from flying upwards { //Decay going up if (_target_velocity.Z > 0) { //How much should we force them down? float Multiplier = (_parent_scene.AllowAvsToEscapeGravity ? .03f : .1f); //How much should we force them down? float fudgeHeight = (_parent_scene.AllowAvsToEscapeGravity ? 80 : 30); //We add the 30 so that gravity is resonably strong once they pass the min height Multiplier *= tempPos.Z + fudgeHeight - _parent_scene.AvGravityHeight; //Limit these so that things don't go wrong if (Multiplier < 1) Multiplier = 1; float maxpower = (_parent_scene.AllowAvsToEscapeGravity ? 1.5f : 3f); if (Multiplier > maxpower) Multiplier = maxpower; _target_velocity.Z /= Multiplier; vel.Z /= Multiplier; } } #endregion vec.Z = (_target_velocity.Z*movementmult - vel.Z)*PID_D*0.5f; if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Add extra gravity vec.Z += ((10*_parent_scene.gravityz)*Mass); } } if (realFlying) { #region Auto Fly Height //Added for auto fly height. Kitto Flora //Changed to only check if the avatar is flying around, // Revolution: If the avatar is going down, they are trying to land (probably), so don't push them up to make it harder // Only if they are moving around sideways do we need to push them up if (_target_velocity.X != 0 || _target_velocity.Y != 0) { Vector3 forwardVel = new Vector3(_target_velocity.X > 0 ? 2 : (_target_velocity.X < 0 ? -2 : 0), _target_velocity.Y > 0 ? 2 : (_target_velocity.Y < 0 ? -2 : 0), 0); float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y) + MinimumGroundFlightOffset; //We cheat a bit and do a bit lower than normal if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude || (tempPos.Z - CAPSULE_LENGTH) < _parent_scene.GetTerrainHeightAtXY(tempPos.X + forwardVel.X, tempPos.Y + forwardVel.Y) + MinimumGroundFlightOffset) if (_target_velocity.Z < 0) vec.Z += (target_altitude - tempPos.Z)*PID_P*0.5f; //Don't apply so much else vec.Z += (target_altitude - tempPos.Z)*PID_P*1.05f; } else { //Straight up and down, only apply when they are very close to the ground float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y); if ((tempPos.Z - CAPSULE_LENGTH + (MinimumGroundFlightOffset/1.5)) < target_altitude + MinimumGroundFlightOffset) { if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude + 1) { vec.Z += ((target_altitude + 4) - (tempPos.Z - CAPSULE_LENGTH))*PID_P; } else vec.Z += ((target_altitude + MinimumGroundFlightOffset) - (tempPos.Z - CAPSULE_LENGTH))* PID_P*0.5f; } } #endregion } #region Gravity if (!flying) _parent_scene.CalculateGravity(m_mass, tempPos, true, 1.0f, ref gravForce); else _parent_scene.CalculateGravity(m_mass, tempPos, false, 0.65f, ref gravForce); //Allow point gravity and repulsors affect us a bit vec += gravForce; #endregion #region Under water physics if (_parent_scene.AllowUnderwaterPhysics && tempPos.X < _parent_scene.Region.RegionSizeX && tempPos.Y < _parent_scene.Region.RegionSizeY) { //Position plus height to av's shoulder (aprox) is just above water if ((tempPos.Z + (CAPSULE_LENGTH/3) - .25f) < _parent_scene.GetWaterLevel(tempPos.X, tempPos.Y)) { if (StartingUnderWater) ShouldBeWalking = Flying = false; StartingUnderWater = false; WasUnderWater = true; Flying = true; lastUnderwaterPush = 0; if (ShouldBeWalking) { lastUnderwaterPush += (float) (_parent_scene.GetWaterLevel(tempPos.X, tempPos.Y) - tempPos.Z)*33 + 3; vec.Z += lastUnderwaterPush; } else { lastUnderwaterPush += 3500; lastUnderwaterPush += (float) (_parent_scene.GetWaterLevel(tempPos.X, tempPos.Y) - tempPos.Z)*8; vec.Z += lastUnderwaterPush; } } else { StartingUnderWater = true; if (WasUnderWater) { WasUnderWater = false; Flying = true; } } } #endregion #endregion #region Apply the force if (IsFinite(vec)) { if (vec.X < 100000000 && vec.Y < 10000000 && vec.Z < 10000000) //Checks for crazy, going to NaN us values { // round small values to zero. those possible are just errors if (Math.Abs(vec.X) < 0.001) vec.X = 0; if (Math.Abs(vec.Y) < 0.001) vec.Y = 0; if (Math.Abs(vec.Z) < 0.001) vec.Z = 0; //ODE autodisables not moving prims, accept it and reenable when we need to if (!d.BodyIsEnabled(Body)) d.BodyEnable(Body); if (vec == Vector3.Zero) //if we arn't moving, STOP { if (m_lastForceApplied != -1) { m_lastForceApplied = -1; d.BodySetLinearVel(Body, vec.X, vec.Y, vec.Z); } } else { if (m_lastForceApplied < 5) vec *= m_lastForceApplied / 5; doForce(vec); m_lastForceApplied++; } // if (!_zeroFlag && (!flying || m_iscolliding)) // AlignAvatarTiltWithCurrentDirectionOfMovement (vec, gravForce); // the Amotor still lets avatar rotation to drift during colisions // so force it back to identity d.Quaternion qtmp; qtmp.W = 1; qtmp.X = 0; qtmp.Y = 0; qtmp.Z = 0; d.BodySetQuaternion(Body, ref qtmp); d.BodySetAngularVel(Body, 0, 0, 0); //When falling, we keep going faster and faster, and eventually, the client blue screens (blue is all you see). // The speed that does this is slightly higher than -30, so we cap it here so we never do that during falling. if (vel.Z < -30) { vel.Z = -30; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } //Decay out the target velocity DON'T it forces tons of updates _target_velocity *= _parent_scene.m_avDecayTime; if (!_zeroFlag && _target_velocity.ApproxEquals (Vector3.Zero, _parent_scene.m_avStopDecaying)) _target_velocity = Vector3.Zero; } else { //This is a safe guard from going NaN, but it isn't very smooth... which is ok d.BodySetForce(Body, 0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } } else { MainConsole.Instance.Warn("[PHYSICS]: Got a NaN force vector in Move()"); MainConsole.Instance.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); Shell = IntPtr.Zero; } } #endregion }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity(float timestep) { if (!m_shouldBePhysical) return; // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec; try { vec = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! MainConsole.Instance.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } // vec is a ptr into internal ode data better not mess with it _position.X = vec.X; _position.Y = vec.Y; _position.Z = vec.Z; if (!IsFinite(_position)) { _parent_scene.BadCharacter(this); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! return; } try { vec = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { vec.X = _velocity.X; vec.Y = _velocity.Y; vec.Z = _velocity.Z; } d.Vector3 rvec; try { rvec = d.BodyGetAngularVel(Body); } catch (NullReferenceException) { rvec.X = m_rotationalVelocity.X; rvec.Y = m_rotationalVelocity.Y; rvec.Z = m_rotationalVelocity.Z; } m_rotationalVelocity.X = rvec.X; m_rotationalVelocity.Y = rvec.Y; m_rotationalVelocity.Z = rvec.Z; // vec is a ptr into internal ode data better not mess with it _velocity.X = vec.X; _velocity.Y = vec.Y; _velocity.Z = vec.Z; if (!IsFinite(_velocity)) { _parent_scene.BadCharacter(this); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! return; } bool VelIsZero = false; int vcntr = 0; if (Math.Abs(_velocity.X) < 0.01) { vcntr++; _velocity.X = 0; } if (Math.Abs(_velocity.Y) < 0.01) { vcntr++; _velocity.Y = 0; } if (Math.Abs(_velocity.Z) < 0.01) { vcntr++; _velocity.Z = 0; } if (vcntr == 3) VelIsZero = true; // slow down updates, changed y mind: updates should go at physics fps, acording to movement conditions /* m_UpdateTimecntr += timestep; m_UpdateFPScntr = 2.5f * _parent_scene.StepTime; if(m_UpdateTimecntr < m_UpdateFPScntr) return; m_UpdateTimecntr = 0; */ const float VELOCITY_TOLERANCE = 0.025f*0.025f; //const float ANG_VELOCITY_TOLERANCE = 0.05f; const float POSITION_TOLERANCE = 5f*5f; bool needSendUpdate = false; float vlength = (_velocity - m_lastVelocity).LengthSquared(); float plength = (_position - m_lastPosition).LengthSquared(); if ( //!VelIsZero && ( vlength > VELOCITY_TOLERANCE || plength > POSITION_TOLERANCE //(anglength > ANG_VELOCITY_TOLERANCE) || //true // (Math.Abs(_lastorientation.X - _orientation.X) > 0.001) || // (Math.Abs(_lastorientation.Y - _orientation.Y) > 0.001) || // (Math.Abs(_lastorientation.Z - _orientation.Z) > 0.001) || // (Math.Abs(_lastorientation.W - _orientation.W) > 0.001) )) { needSendUpdate = true; m_ZeroUpdateSent = 3; // _lastorientation = Orientation; // base.RequestPhysicsterseUpdate(); // base.TriggerSignificantMovement(); } else if (VelIsZero) { if (m_ZeroUpdateSent > 0) { needSendUpdate = true; m_ZeroUpdateSent--; } } if (needSendUpdate) { m_lastPosition = _position; // m_lastRotationalVelocity = RotationalVelocity; m_lastVelocity = _velocity; m_lastAngVelocity = RotationalVelocity; base.TriggerSignificantMovement(); //Tell any listeners about the new info // This is for animations base.TriggerMovementUpdate(); } }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="timeStep"></param> public void Move(float timeStep, List<AuroraODECharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition(Body); } //PidStatus = true; // rex, added height check d.Vector3 tempPos = d.BodyGetPosition(Body); if (_parent_scene.m_useFlightCeilingHeight && tempPos.Z > _parent_scene.m_flightCeilingHeight) { tempPos.Z = _parent_scene.m_flightCeilingHeight; d.BodySetPosition(Body, tempPos.X, tempPos.Y, tempPos.Z); d.Vector3 tempVel = d.BodyGetLinearVel(Body); if (tempVel.Z > 0.0f) { tempVel.Z = 0.0f; d.BodySetLinearVel(Body, tempVel.X, tempVel.Y, tempVel.Z); } if (_target_velocity.Z > 0.0f) _target_velocity.Z = 0.0f; } // endrex d.Vector3 localpos = d.BodyGetPosition(Body); Vector3 localPos = new Vector3((float)localpos.X, (float)localpos.Y, (float)localpos.Z); if (!localPos.IsFinite()) { m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } return; } Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); float movementdivisor = 1f; if (!m_alwaysRun) movementdivisor = walkDivisor * _parent_scene.TimeDilation; //Dynamically adjust it for slower sims else movementdivisor = runDivisor * _parent_scene.TimeDilation; //Dynamically adjust it for slower sims // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding && Math.Abs(vel.X) < 0.5 && Math.Abs(vel.Y) < 0.5 && Math.Abs(vel.Z) < 0.5) //This is so that if we get moved by something else, it will update us in the client { // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = d.BodyGetPosition(Body); } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions d.Vector3 pos = d.BodyGetPosition(Body); Vector3 velocity = new Vector3((float)vel.X, (float)vel.Y, (float)vel.Z); //NOTE: THIS WILL CAUSE BENDING KNEE //if (!velocity.ApproxEquals(Vector3.Zero, 0.2f)) //{ vec.X = (float)((_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2)); vec.Y = (float)((_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2)); if(!Flying) vec.Z += -(_parent_scene.gravityz * 3f * m_mass); //if (flying) // vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; //} } } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding && !flying) { // We're standing or walking on something vec.X = (float)((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); vec.Y = (float)((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); //Stop pushing down if we are just standing //if (_target_velocity.Z < 0) // _target_velocity.Z = 0; } else if (m_iscolliding && flying) { // We're flying and colliding with something vec.X = (float)((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); vec.Y = (float)((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); } else if (!m_iscolliding && flying) { // we're in mid air suspended vec.X = (float)((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); vec.Y = (float)((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); } if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) { // We're colliding with something and we're not flying but we're moving // This means we're walking or running. d.Vector3 pos = d.BodyGetPosition(Body); vec.Z = (float)((_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P); if (_target_velocity.X > 0) vec.X = (float)((_target_velocity.X - vel.X) / 1.2f) * PID_D; if (_target_velocity.Y > 0) vec.Y = (float)((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } else if (!m_iscolliding && !flying) { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. // d.Vector3 pos = d.BodyGetPosition(Body); if (_target_velocity.X > 0) vec.X = (float)((_target_velocity.X - vel.X) / 1.2f) * PID_D; if (_target_velocity.Y > 0) vec.Y = (float)((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } if (flying) { #region Av gravity float oldVelZ = (float)vel.Z; if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Should be stop avies from flying upwards { //Decay going up if (_target_velocity.Z > 0) { //How much should we force them down? float divisor = (_parent_scene.AllowAvsToEscapeGravity ? 100 : 25); //How much should we force them down? float fudgeHeight = (_parent_scene.AllowAvsToEscapeGravity ? 80 : 30); //We add the 30 so that gravity is resonably strong once they pass the min height float Multiplier = (float)(((tempPos.Z + fudgeHeight) - _parent_scene.AvGravityHeight) / divisor); //Limit these so that things don't go wrong if (Multiplier < 1) Multiplier = 1; float maxpower = (_parent_scene.AllowAvsToEscapeGravity ? 1.5f : 3); if (Multiplier > maxpower) Multiplier = maxpower; _target_velocity.Z /= Multiplier; oldVelZ /= Multiplier; } } vec.Z = (_target_velocity.Z - oldVelZ) * (PID_D); if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Add extra gravity vec.Z += ((25 * _parent_scene.gravityz) * Mass); #endregion } } if (flying) { //Fix grav when flying if (!_parent_scene.AllowAvGravity || (_parent_scene.AllowAvGravity && tempPos.Z < _parent_scene.AvGravityHeight)) { //Cancel out gravity if we are flying vec.X += _parent_scene.gravityx * -3f * m_mass; vec.Y += _parent_scene.gravityy * -3f * m_mass; vec.Z += _parent_scene.gravityz * -3f * m_mass; } #region Auto Fly Height //Added for auto fly height. Kitto Flora //Changed to only check if the avatar is flying around, // Revolution: If the avatar is going down, they are trying to land (probably), so don't push them up to make it harder // Only if they are moving around sideways do we need to push them up if (_target_velocity.X != 0 || _target_velocity.Y != 0) { Vector3 forwardVel = new Vector3(_target_velocity.X > 0 ? 2 : (_target_velocity.X < 0 ? -2 : 0), _target_velocity.Y > 0 ? 2 : (_target_velocity.Y < 0 ? -2 : 0), 0); float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; //We cheat a bit and do a bit lower than normal if ((_position.Z - CAPSULE_LENGTH) < target_altitude) vec.Z += (target_altitude - _position.Z) * PID_D; //Check in the direction we are going as well target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X + forwardVel.X, _position.Y + forwardVel.Y) + MinimumGroundFlightOffset; if ((_position.Z - CAPSULE_LENGTH) < target_altitude) vec.Z += (target_altitude - _position.Z) * PID_D / 2; } else { //Straight up and down, only apply when they are very close to the ground float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y); if ((_position.Z - CAPSULE_LENGTH + (MinimumGroundFlightOffset / 1.5)) < target_altitude + MinimumGroundFlightOffset) { if ((_position.Z - CAPSULE_LENGTH) < target_altitude + 1) { vec.Z += ((target_altitude+4) - (_position.Z - CAPSULE_LENGTH)) * PID_D; } else vec.Z += ((target_altitude + MinimumGroundFlightOffset) - (_position.Z - CAPSULE_LENGTH)) * PID_D / 2; } } #endregion } #region Gravity //The '3' is since the gravity isn't exactly what people would expect... maybe should be a config option someday if (!_parent_scene.UsePointGravity) { //Add normal gravity vec.X += _parent_scene.gravityx * 3f * m_mass; vec.Y += _parent_scene.gravityy * 3f * m_mass; vec.Z += _parent_scene.gravityz * 3f * m_mass; } else { Vector3 cog = _parent_scene.PointOfGravity; if (cog.X != 0) vec.X += (cog.X - Position.X) * m_mass; if (cog.Y != 0) vec.Y += (cog.Y - Position.Y) * m_mass; if (cog.Z != 0) vec.Z += (cog.Z - Position.Z) * m_mass; } #endregion #region Under water physics if (_parent_scene.AllowUnderwaterPhysics) { //Position plus height to av's shoulder (aprox) is just above water if ((_position.Z + (CAPSULE_LENGTH / 3) - .25f) < _parent_scene.waterlevel) { if (StartingUnderWater) ShouldBeWalking = Flying == false; StartingUnderWater = false; WasUnderWater = true; Flying = true; lastUnderwaterPush = 0; if (ShouldBeWalking) { lastUnderwaterPush += (_parent_scene.waterlevel - _position.Z) * 100 + 10; vec.Z += lastUnderwaterPush; } else { lastUnderwaterPush += 8000; lastUnderwaterPush += (_parent_scene.waterlevel - _position.Z) * 25; vec.Z += lastUnderwaterPush; } } else { StartingUnderWater = true; if (WasUnderWater) { WasUnderWater = false; Flying = true; } } } #endregion #region Check for underground if (!flying || (flying && _target_velocity.X == 0 || _target_velocity.Y == 0)) //Don't duplicate the ground check for flying from above, it will already have given us a good shove { if (m_WaitGroundCheck >= 10 && vel.Z != 0) { float groundHeight = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y); if (_position.Z - (CAPSULE_LENGTH / 2) < groundHeight) vec.Z += ((groundHeight - (_position.Z - (CAPSULE_LENGTH / 2))) * 100); m_WaitGroundCheck = -1; } m_WaitGroundCheck++; } #endregion if (vec.IsFinite()) { if (vec.X < 100000 && vec.Y < 100000 && vec.Z < 100000) //Checks for crazy, going to NaN us values { //Stop us from fidgiting if we have a small velocity if (Math.Abs(vec.X) < 0.05 && Math.Abs(vec.Y) < 0.05 && Math.Abs(vec.Z) < 0.05) { vec = new Vector3(0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } //Reduce insanely small values to 0 if (Math.Abs(vec.Z) < 0.01) vec.Z = 0; doForce(vec); //When falling, we keep going faster and faster, and eventually, the client blue screens (blue is all you see). // The speed that does this is slightly higher than -30, so we cap it here so we never do that during falling. if (vel.Z < -30) { vel.Z = -30; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } //Check if the capsule is tilted before changing it if (!_zeroFlag && !_parent_scene.IsAvCapsuleTilted) AlignAvatarTiltWithCurrentDirectionOfMovement(vec); } else { //This is a safe guard from going NaN, but it isn't very smooth... which is ok d.BodySetForce(Body, 0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } } else { m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } } }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="timeStep"></param> public void Move(float timeStep) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) { return; } if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition(Body); } //PidStatus = true; d.Vector3 localpos = d.BodyGetPosition(Body); PhysicsVector localPos = new PhysicsVector(localpos.X, localpos.Y, localpos.Z); if (!PhysicsVector.isFinite(localPos)) { m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } return; } PhysicsVector vec = new PhysicsVector(); d.Vector3 vel = d.BodyGetLinearVel(Body); float movementdivisor = 1f; if (!m_alwaysRun) { movementdivisor = walkDivisor; } else { movementdivisor = runDivisor; } // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) { // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = d.BodyGetPosition(Body); } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions d.Vector3 pos = d.BodyGetPosition(Body); vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); if (flying) { vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; } } //PidStatus = true; } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding && !flying) { // We're standing on something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); } else if (m_iscolliding && flying) { // We're flying and colliding with something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); } else if (!m_iscolliding && flying) { // we're in mid air suspended vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); } if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) { // We're colliding with something and we're not flying but we're moving // This means we're walking or running. d.Vector3 pos = d.BodyGetPosition(Body); vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; if (_target_velocity.X > 0) { vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; } if (_target_velocity.Y > 0) { vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } } else if (!m_iscolliding && !flying) { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. // d.Vector3 pos = d.BodyGetPosition(Body); if (_target_velocity.X > 0) { vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; } if (_target_velocity.Y > 0) { vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } } if (flying) { vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); } } if (flying) { vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); //Added for auto fly height. Kitto Flora //d.Vector3 pos = d.BodyGetPosition(Body); float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; if (_position.Z < target_altitude) { vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; } // end add Kitto Flora } if (PhysicsVector.isFinite(vec)) { doForce(vec); } else { m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } return; } }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity() { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec; try { vec = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) if (vec.X < 0.0f) vec.X = 0.0f; if (vec.Y < 0.0f) vec.Y = 0.0f; if (vec.X > (int)_parent_scene.WorldExtents.X - 0.05f) vec.X = (int)_parent_scene.WorldExtents.X - 0.05f; if (vec.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) vec.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; _position.X = (float)vec.X; _position.Y = (float)vec.Y; _position.Z = (float)vec.Z; // Did we move last? = zeroflag // This helps keep us from sliding all over if (_zeroFlag) { /*if (CollisionEventsThisFrame != null) { base.SendCollisionUpdate(CollisionEventsThisFrame); } CollisionEventsThisFrame = new CollisionEventUpdate(); m_eventsubscription = 0;*/ _velocity.X = 0.0f; _velocity.Y = 0.0f; _velocity.Z = 0.0f; // Did we send out the 'stopped' message? if (!m_lastUpdateSent) { m_lastUpdateSent = true; //base.RequestPhysicsterseUpdate(); } } else { m_lastUpdateSent = false; try { vec = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { vec.X = _velocity.X; vec.Y = _velocity.Y; vec.Z = _velocity.Z; } _velocity.X = (float)(vec.X); _velocity.Y = (float)(vec.Y); _velocity.Z = (float)(vec.Z); if (_velocity.Z < -6 && !m_hackSentFall) { //m_hackSentFall = true; //m_pidControllerActive = false; } else if (flying && !m_hackSentFly) { //m_hackSentFly = true; //base.SendCollisionUpdate(new CollisionEventUpdate()); } else { m_hackSentFly = false; m_hackSentFall = false; } } }
public static extern void SetViewpoint(ref d.Vector3 xyz, ref d.Vector3 hpr);
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="defects">The character will be added to this list if there is something wrong (non-finite /// position or velocity). /// </param> internal void Move(List<OdeCharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition(Body); } //PidStatus = true; d.Vector3 localpos = d.BodyGetPosition(Body); Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); if (!localPos.IsFinite()) { m_log.WarnFormat( "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", localPos, Name); defects.Add(this); return; } Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); // m_log.DebugFormat( // "[ODE CHARACTER]: Current velocity in Move() is <{0},{1},{2}>, target {3} for {4}", // vel.X, vel.Y, vel.Z, _target_velocity, Name); float movementdivisor = 1f; if (!m_alwaysRun) { movementdivisor = walkDivisor; } else { movementdivisor = runDivisor; } // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) { // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = d.BodyGetPosition(Body); } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions d.Vector3 pos = d.BodyGetPosition(Body); vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y)* (PID_P * 2); if (flying) { vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; } } //PidStatus = true; } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding && !flying) { // We're standing on something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); } else if (m_iscolliding && flying) { // We're flying and colliding with something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); } else if (!m_iscolliding && flying) { // we're in mid air suspended vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); // m_log.DebugFormat( // "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}", // vec, _target_velocity, movementdivisor, vel); } if (flying) { // This also acts as anti-gravity so that we hover when flying rather than fall. vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); } else { if (m_iscolliding && _target_velocity.Z > 0.0f) { // We're colliding with something and we're not flying but we're moving // This means we're walking or running. d.Vector3 pos = d.BodyGetPosition(Body); vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } else if (!m_iscolliding) { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } } } if (flying) { // Anti-gravity so that we hover when flying rather than fall. vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); //Added for auto fly height. Kitto Flora //d.Vector3 pos = d.BodyGetPosition(Body); float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; if (_position.Z < target_altitude) { vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; } // end add Kitto Flora } if (vec.IsFinite()) { // Apply the total force acting on this avatar d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); if (!_zeroFlag) AlignAvatarTiltWithCurrentDirectionOfMovement(vec); } else { m_log.WarnFormat( "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", vec, Name); defects.Add(this); return; } d.Vector3 newVel = d.BodyGetLinearVel(Body); if (newVel.X >= 256 || newVel.X <= 256 || newVel.Y >= 256 || newVel.Y <= 256 || newVel.Z >= 256 || newVel.Z <= 256) { // m_log.DebugFormat( // "[ODE CHARACTER]: Limiting falling velocity from {0} to {1} for {2}", newVel.Z, -9.8, Name); newVel.X = Util.Clamp<float>(newVel.X, -255f, 255f); newVel.Y = Util.Clamp<float>(newVel.Y, -255f, 255f); if (!flying) newVel.Z = Util.Clamp<float>( newVel.Z, -_parent_scene.AvatarTerminalVelocity, _parent_scene.AvatarTerminalVelocity); else newVel.Z = Util.Clamp<float>(newVel.Z, -255f, 255f); d.BodySetLinearVel(Body, newVel.X, newVel.Y, newVel.Z); } }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="defects">The character will be added to this list if there is something wrong (non-finite /// position or velocity). /// </param> internal void Move(List <OdeCharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) { return; } if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition(Body); } //PidStatus = true; d.Vector3 localpos = d.BodyGetPosition(Body); Vector3 localPos = new Vector3(localpos.X, localpos.Y, localpos.Z); if (!localPos.IsFinite()) { m_log.WarnFormat( "[ODE CHARACTER]: Avatar position of {0} for {1} is non-finite! Removing from physics scene.", localPos, Name); defects.Add(this); return; } Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); float movementdivisor = 1f; if (!m_alwaysRun) { movementdivisor = walkDivisor; } else { movementdivisor = runDivisor; } // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f && m_iscolliding) { // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = d.BodyGetPosition(Body); } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions d.Vector3 pos = d.BodyGetPosition(Body); vec.X = (_target_velocity.X - vel.X) * (PID_D) + (_zeroPosition.X - pos.X) * (PID_P * 2); vec.Y = (_target_velocity.Y - vel.Y) * (PID_D) + (_zeroPosition.Y - pos.Y) * (PID_P * 2); if (flying) { vec.Z = (_target_velocity.Z - vel.Z) * (PID_D) + (_zeroPosition.Z - pos.Z) * PID_P; } } //PidStatus = true; } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding && !flying) { // We're standing on something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D); } else if (m_iscolliding && flying) { // We're flying and colliding with something vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 16); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 16); } else if (!m_iscolliding && flying) { // we're in mid air suspended vec.X = ((_target_velocity.X / movementdivisor) - vel.X) * (PID_D / 6); vec.Y = ((_target_velocity.Y / movementdivisor) - vel.Y) * (PID_D / 6); // m_log.DebugFormat( // "[ODE CHARACTER]: !m_iscolliding && flying, vec {0}, _target_velocity {1}, movementdivisor {2}, vel {3}", // vec, _target_velocity, movementdivisor, vel); } if (m_iscolliding && !flying && _target_velocity.Z > 0.0f) { // We're colliding with something and we're not flying but we're moving // This means we're walking or running. d.Vector3 pos = d.BodyGetPosition(Body); vec.Z = (_target_velocity.Z - vel.Z) * PID_D + (_zeroPosition.Z - pos.Z) * PID_P; if (_target_velocity.X > 0) { vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; } if (_target_velocity.Y > 0) { vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } } else if (!m_iscolliding && !flying) { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. // d.Vector3 pos = d.BodyGetPosition(Body); if (_target_velocity.X > 0) { vec.X = ((_target_velocity.X - vel.X) / 1.2f) * PID_D; } if (_target_velocity.Y > 0) { vec.Y = ((_target_velocity.Y - vel.Y) / 1.2f) * PID_D; } } if (flying) { vec.Z = (_target_velocity.Z - vel.Z) * (PID_D); } } if (flying) { vec.Z += ((-1 * _parent_scene.gravityz) * m_mass); //Added for auto fly height. Kitto Flora //d.Vector3 pos = d.BodyGetPosition(Body); float target_altitude = _parent_scene.GetTerrainHeightAtXY(_position.X, _position.Y) + MinimumGroundFlightOffset; if (_position.Z < target_altitude) { vec.Z += (target_altitude - _position.Z) * PID_P * 5.0f; } // end add Kitto Flora } if (vec.IsFinite()) { // Apply the total force acting on this avatar d.BodyAddForce(Body, vec.X, vec.Y, vec.Z); if (!_zeroFlag) { AlignAvatarTiltWithCurrentDirectionOfMovement(vec); } } else { m_log.WarnFormat( "[ODE CHARACTER]: Got a NaN force vector {0} in Move() for {1}. Removing character from physics scene.", vec, Name); defects.Add(this); return; } }
internal void Stop() { m_lastLinearVelocityVector = Vector3.Zero; m_lastAngularVelocity = Vector3.Zero; m_lastPositionVector = d.BodyGetPosition(Body); }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> /// <param name="defects">The character will be added to this list if there is something wrong (non-finite /// position or velocity). /// </param> internal void UpdatePositionAndVelocity(List <OdeCharacter> defects) { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 newPos; try { newPos = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; defects.Add(this); newPos = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODE CHARACTER]: Avatar Null reference for Avatar {0}, physical actor {1}", Name, m_uuid); return; } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) if (newPos.X < 0.0f) { newPos.X = 0.0f; } if (newPos.Y < 0.0f) { newPos.Y = 0.0f; } if (newPos.X > (int)_parent_scene.WorldExtents.X - 0.05f) { newPos.X = (int)_parent_scene.WorldExtents.X - 0.05f; } if (newPos.Y > (int)_parent_scene.WorldExtents.Y - 0.05f) { newPos.Y = (int)_parent_scene.WorldExtents.Y - 0.05f; } _position.X = newPos.X; _position.Y = newPos.Y; _position.Z = newPos.Z; // I think we need to update the taintPosition too -- Diva 12/24/10 m_taintPosition = _position; // Did we move last? = zeroflag // This helps keep us from sliding all over if (_zeroFlag) { _velocity = Vector3.Zero; // Did we send out the 'stopped' message? if (!m_lastUpdateSent) { m_lastUpdateSent = true; //base.RequestPhysicsterseUpdate(); } } else { m_lastUpdateSent = false; d.Vector3 newVelocity; try { newVelocity = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { newVelocity.X = _velocity.X; newVelocity.Y = _velocity.Y; newVelocity.Z = _velocity.Z; } _velocity.X = newVelocity.X; _velocity.Y = newVelocity.Y; _velocity.Z = newVelocity.Z; if (_velocity.Z < -6 && !m_hackSentFall) { m_hackSentFall = true; m_pidControllerActive = false; } else if (flying && !m_hackSentFly) { //m_hackSentFly = true; //base.SendCollisionUpdate(new CollisionEventUpdate()); } else { m_hackSentFly = false; m_hackSentFall = false; } } }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity(float timestep) { if (!m_shouldBePhysical) return; // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec; try { vec = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } // vec is a ptr into internal ode data better not mess with it _position.X = (float)vec.X; _position.Y = (float)vec.Y; _position.Z = (float)vec.Z; // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) bool needfixbody = false; /*if (_position.X < 0.0f) { needfixbody = true; _position.X = 0.1f; } else if (_position.X > (int)_parent_scene.Region.RegionSizeX - 0.1f) { needfixbody = true; _position.X = (int)_parent_scene.Region.RegionSizeX - 0.1f; } if (_position.Y < 0.0f) { needfixbody = true; _position.Y = 0.1f; } else if (_position.Y > (int)_parent_scene.Region.RegionSizeY - 0.1) { needfixbody = true; _position.Y = (int)_parent_scene.Region.RegionSizeY - 0.1f; }*/ if (needfixbody) d.BodySetPosition(Body, _position.X, _position.Y, _position.Z); try { vec = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { vec.X = _velocity.X; vec.Y = _velocity.Y; vec.Z = _velocity.Z; } // vec is a ptr into internal ode data better not mess with it _velocity.X = vec.X; _velocity.Y = vec.Y; _velocity.Z = vec.Z; bool VelIsZero = false; int vcntr = 0; if (Math.Abs(_velocity.X) < 0.01) { vcntr++; _velocity.X = 0; } if (Math.Abs(_velocity.Y) < 0.01) { vcntr++; _velocity.Y = 0; } if (Math.Abs(_velocity.Z) < 0.01) { vcntr++; _velocity.Z = 0; } if (vcntr == 3) VelIsZero = true; // slow down updates m_UpdateTimecntr += timestep; if (m_UpdateTimecntr < m_UpdateFPScntr) return; m_UpdateTimecntr = 0; const float VELOCITY_TOLERANCE = 0.01f; const float POSITION_TOLERANCE = 0.05f; bool needSendUpdate = false; //Check to see whether we need to trigger the significant movement method in the presence // avas don't rotate for now if (!RotationalVelocity.ApproxEquals(m_lastRotationalVelocity, VELOCITY_TOLERANCE) || // but simulator does not process rotation changes if (//!VelIsZero && // (!Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || ( (Math.Abs(Velocity.X - m_lastVelocity.X) > VELOCITY_TOLERANCE) || (Math.Abs(Velocity.Y - m_lastVelocity.Y) > VELOCITY_TOLERANCE) || (Math.Abs(Velocity.Z - m_lastVelocity.Z) > VELOCITY_TOLERANCE) || (Math.Abs(_position.X - m_lastPosition.X) > POSITION_TOLERANCE) || (Math.Abs(_position.Y - m_lastPosition.Y) > POSITION_TOLERANCE) || (Math.Abs(_position.Z - m_lastPosition.Z) > POSITION_TOLERANCE)// || // (Math.Abs(_lastorientation.X - _orientation.X) > 0.001) || // (Math.Abs(_lastorientation.Y - _orientation.Y) > 0.001) || // (Math.Abs(_lastorientation.Z - _orientation.Z) > 0.001) || // (Math.Abs(_lastorientation.W - _orientation.W) > 0.001) )) { // Update the "last" values needSendUpdate = true; m_ZeroUpdateSent = false; m_lastPosition = _position; // m_lastRotationalVelocity = RotationalVelocity; m_lastVelocity = Velocity; // _lastorientation = Orientation; // base.RequestPhysicsterseUpdate(); // base.TriggerSignificantMovement(); } else if (VelIsZero) { if (!m_ZeroUpdateSent) { needSendUpdate = true; m_ZeroUpdateSent = true; } } if (needSendUpdate) { base.RequestPhysicsterseUpdate(); base.TriggerSignificantMovement(); } //Tell any listeners about the new info // This is for animations base.TriggerMovementUpdate (); }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity (float timestep) { if(!m_shouldBePhysical) return; // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec; try { vec = d.BodyGetPosition(Body); } catch(NullReferenceException) { bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } // vec is a ptr into internal ode data better not mess with it _position.X = (float)vec.X; _position.Y = (float)vec.Y; _position.Z = (float)vec.Z; if (!IsFinite(_position)) { _parent_scene.BadCharacter(this); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! return; } try { vec = d.BodyGetLinearVel(Body); } catch(NullReferenceException) { vec.X = _velocity.X; vec.Y = _velocity.Y; vec.Z = _velocity.Z; } d.Vector3 rvec; try { rvec = d.BodyGetAngularVel(Body); } catch(NullReferenceException) { rvec.X = m_rotationalVelocity.X; rvec.Y = m_rotationalVelocity.Y; rvec.Z = m_rotationalVelocity.Z; } m_rotationalVelocity.X = rvec.X; m_rotationalVelocity.Y = rvec.Y; m_rotationalVelocity.Z = rvec.Z; // vec is a ptr into internal ode data better not mess with it _velocity.X = vec.X; _velocity.Y = vec.Y; _velocity.Z = vec.Z; if (!IsFinite(_velocity)) { _parent_scene.BadCharacter(this); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! return; } bool VelIsZero = false; int vcntr = 0; if(Math.Abs(_velocity.X) < 0.01) { vcntr++; _velocity.X = 0; } if(Math.Abs(_velocity.Y) < 0.01) { vcntr++; _velocity.Y = 0; } if(Math.Abs(_velocity.Z) < 0.01) { vcntr++; _velocity.Z = 0; } if(vcntr == 3) VelIsZero = true; // slow down updates m_UpdateTimecntr += timestep; m_UpdateFPScntr = 2.5f * _parent_scene.StepTime * 10 * (6 - (_parent_scene.TimeDilation * 5)); if(m_UpdateTimecntr < m_UpdateFPScntr) return; m_UpdateTimecntr = 0; const float VELOCITY_TOLERANCE = 0.025f; //const float ANG_VELOCITY_TOLERANCE = 0.05f; const float POSITION_TOLERANCE = 5f; bool needSendUpdate = false; //Check to see whether we need to trigger the significant movement method in the presence // avas don't rotate for now if (!RotationalVelocity.ApproxEquals(m_lastRotationalVelocity, VELOCITY_TOLERANCE) || // but simulator does not process rotation changes float length = (Velocity - m_lastVelocity).LengthSquared(); //The rotational velocity check... is odd and doesn't work right, so ignore it here // Velocity (when turning) will change enough to trigger the updates //float anglength = (m_rotationalVelocity - m_lastAngVelocity).LengthSquared(); if(//!VelIsZero && // (!Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || ( (length > VELOCITY_TOLERANCE)// || //(anglength > ANG_VELOCITY_TOLERANCE) || //true // (Math.Abs(_lastorientation.X - _orientation.X) > 0.001) || // (Math.Abs(_lastorientation.Y - _orientation.Y) > 0.001) || // (Math.Abs(_lastorientation.Z - _orientation.Z) > 0.001) || // (Math.Abs(_lastorientation.W - _orientation.W) > 0.001) )) { //m_log.Warn("Vel change - " + length); // Update the "last" values needSendUpdate = true; m_ZeroUpdateSent = 10; m_lastPosition = _position; // m_lastRotationalVelocity = RotationalVelocity; m_lastVelocity = Velocity; m_lastAngVelocity = RotationalVelocity; // _lastorientation = Orientation; // base.RequestPhysicsterseUpdate(); // base.TriggerSignificantMovement(); } else if(VelIsZero) { if(m_ZeroUpdateSent > 0) { needSendUpdate = true; m_ZeroUpdateSent--; } } if((Math.Abs(_position.X - m_lastPosition.X) > POSITION_TOLERANCE) || (Math.Abs(_position.Y - m_lastPosition.Y) > POSITION_TOLERANCE) || (Math.Abs(_position.Z - m_lastPosition.Z) > POSITION_TOLERANCE)) { m_lastPosition = _position; needSendUpdate = true; } if(needSendUpdate) { base.TriggerSignificantMovement(); //Tell any listeners about the new info // This is for animations base.TriggerMovementUpdate(); } }
}// end Step private void MoveLinear(float pTimestep, OdeScene _pParentScene) { if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant { if (!d.BodyIsEnabled(Body)) d.BodyEnable(Body); // add drive to body Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? // This will work temporarily, but we really need to compare speed on an axis // KF: Limit body velocity to applied velocity? if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; // decay applied velocity Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); //Console.WriteLine("decay: " + decayfraction); m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; //Console.WriteLine("actual: " + m_linearMotorDirection); } else { // requested is not significant // if what remains of applied is small, zero it. if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) m_lastLinearVelocityVector = Vector3.Zero; } // convert requested object velocity to world-referenced vector m_dir = m_lastLinearVelocityVector; d.Quaternion rot = d.BodyGetQuaternion(Body); Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object m_dir *= rotq; // apply obj rotation to velocity vector // add Gravity andBuoyancy // KF: So far I have found no good method to combine a script-requested // .Z velocity and gravity. Therefore only 0g will used script-requested // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. Vector3 grav = Vector3.Zero; // There is some gravity, make a gravity force vector // that is applied after object velocity. d.Mass objMass; d.BodyGetMass(Body, out objMass); // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Preserve the current Z velocity d.Vector3 vel_now = d.BodyGetLinearVel(Body); m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity d.Vector3 pos = d.BodyGetPosition(Body); // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); Vector3 posChange = new Vector3(); posChange.X = pos.X - m_lastPositionVector.X; posChange.Y = pos.Y - m_lastPositionVector.Y; posChange.Z = pos.Z - m_lastPositionVector.Z; double Zchange = Math.Abs(posChange.Z); if (m_BlockingEndPoint != Vector3.Zero) { if (pos.X >= (m_BlockingEndPoint.X - (float)1)) { pos.X -= posChange.X + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) { pos.Y -= posChange.Y + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) { pos.Z -= posChange.Z + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.X <= 0) { pos.X += posChange.X + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Y <= 0) { pos.Y += posChange.Y + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } } if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) { pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } // Check if hovering if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) { // We should hover, get the target height if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) { m_VhoverTargetHeight = m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) { // If body is aready heigher, use its height as target height if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; } if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) { if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) { d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight); } } else { float herr0 = pos.Z - m_VhoverTargetHeight; // Replace Vertical speed with correction figure if significant if (Math.Abs(herr0) > 0.01f) { m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); //KF: m_VhoverEfficiency is not yet implemented } else { m_dir.Z = 0f; } } // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped // m_VhoverTimescale = 0f; // time to acheive height // pTimestep is time since last frame,in secs } if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) { //Start Experimental Values if (Zchange > .3) { grav.Z = (float)(grav.Z * 3); } if (Zchange > .15) { grav.Z = (float)(grav.Z * 2); } if (Zchange > .75) { grav.Z = (float)(grav.Z * 1.5); } if (Zchange > .05) { grav.Z = (float)(grav.Z * 1.25); } if (Zchange > .025) { grav.Z = (float)(grav.Z * 1.125); } float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); float postemp = (pos.Z - terraintemp); if (postemp > 2.5f) { grav.Z = (float)(grav.Z * 1.037125); } //End Experimental Values } if ((m_flags & (VehicleFlag.NO_X)) != 0) { m_dir.X = 0; } if ((m_flags & (VehicleFlag.NO_Y)) != 0) { m_dir.Y = 0; } if ((m_flags & (VehicleFlag.NO_Z)) != 0) { m_dir.Z = 0; } m_lastPositionVector = d.BodyGetPosition(Body); // Apply velocity d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); // apply gravity force d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); // apply friction Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; } // end MoveLinear()
private int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) { // String name1 = null; // String name2 = null; // // if (!geom_name_map.TryGetValue(trimesh, out name1)) // { // name1 = "null"; // } // // if (!geom_name_map.TryGetValue(refObject, out name2)) // { // name2 = "null"; // } // m_log.InfoFormat("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex); d.Vector3 v0 = new d.Vector3(); d.Vector3 v1 = new d.Vector3(); d.Vector3 v2 = new d.Vector3(); d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); // m_log.DebugFormat("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z); return 1; }
private void MoveLinear(float pTimestep, OdeScene _pParentScene) { if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant { if (!d.BodyIsEnabled(Body)) { d.BodyEnable(Body); } // add drive to body Vector3 addAmount = m_linearMotorDirection / (m_linearMotorTimescale / pTimestep); m_lastLinearVelocityVector += (addAmount * 10); // lastLinearVelocityVector is the current body velocity vector? // This will work temporarily, but we really need to compare speed on an axis // KF: Limit body velocity to applied velocity? if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) { m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; } if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) { m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; } if (Math.Abs(m_lastLinearVelocityVector.Z) > Math.Abs(m_linearMotorDirectionLASTSET.Z)) { m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; } // decay applied velocity Vector3 decayfraction = ((Vector3.One / (m_linearMotorDecayTimescale / pTimestep))); //Console.WriteLine("decay: " + decayfraction); m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; //Console.WriteLine("actual: " + m_linearMotorDirection); } else { // requested is not significant // if what remains of applied is small, zero it. if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) { m_lastLinearVelocityVector = Vector3.Zero; } } // convert requested object velocity to world-referenced vector m_dir = m_lastLinearVelocityVector; d.Quaternion rot = d.BodyGetQuaternion(Body); Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object m_dir *= rotq; // apply obj rotation to velocity vector // add Gravity andBuoyancy // KF: So far I have found no good method to combine a script-requested // .Z velocity and gravity. Therefore only 0g will used script-requested // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. Vector3 grav = Vector3.Zero; // There is some gravity, make a gravity force vector // that is applied after object velocity. d.Mass objMass; d.BodyGetMass(Body, out objMass); // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; grav.Z = _pParentScene.gravityz * objMass.mass * (1f - m_VehicleBuoyancy); // Preserve the current Z velocity d.Vector3 vel_now = d.BodyGetLinearVel(Body); m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity d.Vector3 pos = d.BodyGetPosition(Body); // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); Vector3 posChange = new Vector3(); posChange.X = pos.X - m_lastPositionVector.X; posChange.Y = pos.Y - m_lastPositionVector.Y; posChange.Z = pos.Z - m_lastPositionVector.Z; double Zchange = Math.Abs(posChange.Z); if (m_BlockingEndPoint != Vector3.Zero) { if (pos.X >= (m_BlockingEndPoint.X - (float)1)) { pos.X -= posChange.X + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) { pos.Y -= posChange.Y + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) { pos.Z -= posChange.Z + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.X <= 0) { pos.X += posChange.X + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } if (pos.Y <= 0) { pos.Y += posChange.Y + 1; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } } if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) { pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; d.BodySetPosition(Body, pos.X, pos.Y, pos.Z); } // Check if hovering if ((m_Hoverflags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) { // We should hover, get the target height if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) { m_VhoverTargetHeight = m_VhoverHeight; } if ((m_Hoverflags & VehicleFlag.HOVER_UP_ONLY) != 0) { // If body is aready heigher, use its height as target height if (pos.Z > m_VhoverTargetHeight) { m_VhoverTargetHeight = pos.Z; } } if ((m_Hoverflags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) { if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) { d.BodySetPosition(Body, pos.X, pos.Y, m_VhoverTargetHeight); } } else { float herr0 = pos.Z - m_VhoverTargetHeight; // Replace Vertical speed with correction figure if significant if (Math.Abs(herr0) > 0.01f) { m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); //KF: m_VhoverEfficiency is not yet implemented } else { m_dir.Z = 0f; } } // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped // m_VhoverTimescale = 0f; // time to acheive height // pTimestep is time since last frame,in secs } if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) { //Start Experimental Values if (Zchange > .3) { grav.Z = (float)(grav.Z * 3); } if (Zchange > .15) { grav.Z = (float)(grav.Z * 2); } if (Zchange > .75) { grav.Z = (float)(grav.Z * 1.5); } if (Zchange > .05) { grav.Z = (float)(grav.Z * 1.25); } if (Zchange > .025) { grav.Z = (float)(grav.Z * 1.125); } float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); float postemp = (pos.Z - terraintemp); if (postemp > 2.5f) { grav.Z = (float)(grav.Z * 1.037125); } //End Experimental Values } if ((m_flags & (VehicleFlag.NO_X)) != 0) { m_dir.X = 0; } if ((m_flags & (VehicleFlag.NO_Y)) != 0) { m_dir.Y = 0; } if ((m_flags & (VehicleFlag.NO_Z)) != 0) { m_dir.Z = 0; } m_lastPositionVector = d.BodyGetPosition(Body); // Apply velocity d.BodySetLinearVel(Body, m_dir.X, m_dir.Y, m_dir.Z); // apply gravity force d.BodyAddForce(Body, grav.X, grav.Y, grav.Z); // apply friction Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; } // end MoveLinear()
// normally called from within OnJointMoved, which is called from within a lock (OdeLock) public override Vector3 GetJointAnchor(PhysicsJoint joint) { Debug.Assert(joint.IsInPhysicsEngine); d.Vector3 pos = new d.Vector3(); if (!(joint is OdePhysicsJoint)) { DoJointErrorMessage(joint, "warning: non-ODE joint requesting anchor: " + joint.ObjectNameInScene); } else { OdePhysicsJoint odeJoint = (OdePhysicsJoint)joint; switch (odeJoint.Type) { case PhysicsJointType.Ball: d.JointGetBallAnchor(odeJoint.jointID, out pos); break; case PhysicsJointType.Hinge: d.JointGetHingeAnchor(odeJoint.jointID, out pos); break; } } return new Vector3(pos.X, pos.Y, pos.Z); }
public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex) { d.Vector3 v0 = new d.Vector3(); d.Vector3 v1 = new d.Vector3(); d.Vector3 v2 = new d.Vector3(); d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2); return 1; }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity(float timestep) { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec; try { vec = d.BodyGetPosition(Body); } catch (NullReferenceException) { bad = true; _parent_scene.BadCharacter(this); vec = new d.Vector3(_position.X, _position.Y, _position.Z); base.RaiseOutOfBounds(_position); // Tells ScenePresence that there's a problem! m_log.WarnFormat("[ODEPLUGIN]: Avatar Null reference for Avatar {0}, physical actor {1}", m_name, m_uuid); } // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) bool needfixbody = false; if (vec.X < 0.0f) { needfixbody = true; vec.X = CAPSULE_RADIUS; } else if (vec.X > (int)_parent_scene.WorldExtents.X - CAPSULE_RADIUS) { needfixbody = true; vec.X = (int)_parent_scene.WorldExtents.X - CAPSULE_RADIUS; } if (vec.Y < 0.0f) { needfixbody = true; vec.Y = CAPSULE_RADIUS; } else if (vec.Y > (int)_parent_scene.WorldExtents.Y - CAPSULE_RADIUS) { needfixbody = true; vec.Y = (int)_parent_scene.WorldExtents.Y - CAPSULE_RADIUS; } if (needfixbody) d.BodySetPosition(Body, vec.X, vec.Y, vec.Z); _position.X = (float)vec.X; _position.Y = (float)vec.Y; _position.Z = (float)vec.Z; // Did we move last? = zeroflag // This helps keep us from sliding all over if (_zeroFlag) { /*if (CollisionEventsThisFrame != null) { base.SendCollisionUpdate(CollisionEventsThisFrame); } CollisionEventsThisFrame = new CollisionEventUpdate(); m_eventsubscription = 0;*/ _velocity = Vector3.Zero; // Did we send out the 'stopped' message? if (!m_lastUpdateSent) { m_lastUpdateSent = true; base.RequestPhysicsterseUpdate(); } //Tell any listeners that we've stopped base.TriggerMovementUpdate(); } else { m_lastUpdateSent = false; try { vec = d.BodyGetLinearVel(Body); } catch (NullReferenceException) { vec.X = _velocity.X; vec.Y = _velocity.Y; vec.Z = _velocity.Z; } /* if (vec.X == 0 && vec.Y == 0 && vec.Z == 0) { m_log.Warn("[AODECharacter]: We have a malformed Velocity, ignoring..."); } else */ needfixbody = false; if (Math.Abs(vec.X) < 0.001 && vec.X != 0) { needfixbody = true; vec.X = 0; } if (Math.Abs(vec.Y) < 0.001 && vec.Y != 0) { needfixbody = true; vec.Y = 0; } if (Math.Abs(vec.Z) < 0.001 && vec.Z != 0) { needfixbody = true; vec.Z = 0; } if (needfixbody) d.BodySetLinearVel(Body, vec.X, vec.Y, vec.Z); _velocity = new Vector3((float)(vec.X), (float)(vec.Y), (float)(vec.Z)); const float VELOCITY_TOLERANCE = 0.001f; const float POSITION_TOLERANCE = 0.05f; //Check to see whether we need to trigger the significant movement method in the presence if (!RotationalVelocity.ApproxEquals(m_lastRotationalVelocity, VELOCITY_TOLERANCE) || !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) || !Position.ApproxEquals(m_lastPosition, POSITION_TOLERANCE)) { // Update the "last" values m_lastPosition = Position; m_lastRotationalVelocity = RotationalVelocity; m_lastVelocity = Velocity; base.RequestPhysicsterseUpdate(); base.TriggerSignificantMovement(); } //Tell any listeners about the new info base.TriggerMovementUpdate(); } }
public void step(int pause) { ds.SetColor(1.0f, 1.0f, 0.0f); ds.SetTexture(ds.Texture.Wood); lock (_prims) { foreach (OdePrim prm in _prims) { //IntPtr body = d.GeomGetBody(prm.prim_geom); if (prm.prim_geom != IntPtr.Zero) { d.Vector3 pos; d.GeomCopyPosition(prm.prim_geom, out pos); //d.BodyCopyPosition(body, out pos); d.Matrix3 R; d.GeomCopyRotation(prm.prim_geom, out R); //d.BodyCopyRotation(body, out R); d.Vector3 sides = new d.Vector3(); sides.X = prm.Size.X; sides.Y = prm.Size.Y; sides.Z = prm.Size.Z; ds.DrawBox(ref pos, ref R, ref sides); } } } ds.SetColor(1.0f, 0.0f, 0.0f); lock (_characters) { foreach (OdeCharacter chr in _characters) { if (chr.Shell != IntPtr.Zero) { IntPtr body = d.GeomGetBody(chr.Shell); d.Vector3 pos; d.GeomCopyPosition(chr.Shell, out pos); //d.BodyCopyPosition(body, out pos); d.Matrix3 R; d.GeomCopyRotation(chr.Shell, out R); //d.BodyCopyRotation(body, out R); ds.DrawCapsule(ref pos, ref R, chr.Size.Z, 0.35f); d.Vector3 sides = new d.Vector3(); sides.X = 0.5f; sides.Y = 0.5f; sides.Z = 0.5f; ds.DrawBox(ref pos, ref R, ref sides); } } } }
/// <summary> /// Called from Simulate /// This is the avatar's movement control + PID Controller /// </summary> /// <param name="timeStep"></param> public void Move(float timeStep, List<AuroraODECharacter> defects) { // no lock; for now it's only called from within Simulate() // If the PID Controller isn't active then we set our force // calculating base velocity to the current position if (Body == IntPtr.Zero) return; // replace amotor d.Quaternion dtmp; dtmp.W =1; dtmp.X=0; dtmp.Y=0; dtmp.Z=0; d.BodySetQuaternion(Body, ref dtmp); d.BodySetAngularVel(Body, 0, 0, 0); if (m_pidControllerActive == false) { _zeroPosition = d.BodyGetPosition(Body); } //PidStatus = true; // rex, added height check d.Vector3 tempPos = d.BodyGetPosition(Body); if (_parent_scene.m_useFlightCeilingHeight && tempPos.Z > _parent_scene.m_flightCeilingHeight) { tempPos.Z = _parent_scene.m_flightCeilingHeight; d.BodySetPosition(Body, tempPos.X, tempPos.Y, tempPos.Z); d.Vector3 tempVel = d.BodyGetLinearVel(Body); if (tempVel.Z > 0.0f) { tempVel.Z = 0.0f; d.BodySetLinearVel(Body, tempVel.X, tempVel.Y, tempVel.Z); } if (_target_velocity.Z > 0.0f) _target_velocity.Z = 0.0f; } // endrex Vector3 localPos = new Vector3((float)tempPos.X, (float)tempPos.Y, (float)tempPos.Z); if (!localPos.IsFinite()) { m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } return; } Vector3 vec = Vector3.Zero; d.Vector3 vel = d.BodyGetLinearVel(Body); #region Check for underground // _parent_scene.CheckTerrainColisionAABB(Shell); // if (!flying || (flying && _target_velocity.X == 0 || _target_velocity.Y == 0)) // if (!m_iscollidingGround) //Don't duplicate the ground check for flying from above, it will already have given us a good shove { // if (m_WaitGroundCheck >= 10 && vel.Z != 0) { float groundHeight = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y); if ((tempPos.Z - AvatarHalfsize) < groundHeight) { if (!flying) { if (_target_velocity.Z < 0) _target_velocity.Z = 0; vec.Z = -vel.Z * PID_D + ((groundHeight - (tempPos.Z - AvatarHalfsize)) * PID_P * 20.0f); } else vec.Z = ((groundHeight - (tempPos.Z - AvatarHalfsize)) * PID_P); } if (tempPos.Z - AvatarHalfsize - groundHeight < 0.1) { m_iscolliding = true; m_iscollidingGround = true; flying = false; // gound the avatar } else m_iscollidingGround = false; // m_WaitGroundCheck = -1; } // m_WaitGroundCheck++; } /* if (!m_alwaysRun) movementdivisor = _parent_scene.avMovementDivisorWalk * (_parent_scene.TimeDilation < 0.3 ? 0.6f : _parent_scene.TimeDilation); //Dynamically adjust it for slower sims else movementdivisor = _parent_scene.avMovementDivisorRun * (_parent_scene.TimeDilation < 0.3 ? 0.6f : _parent_scene.TimeDilation); //Dynamically adjust it for slower sims */ // no dinamic messing here float movementmult = 1f; if (!m_alwaysRun) movementmult /= _parent_scene.avMovementDivisorWalk; else movementmult /= _parent_scene.avMovementDivisorRun; // if velocity is zero, use position control; otherwise, velocity control if (_target_velocity == Vector3.Zero && Math.Abs(vel.X) < 0.05 && Math.Abs(vel.Y) < 0.05 && Math.Abs(vel.Z) < 0.05 && (this.m_iscollidingGround || this.m_iscollidingObj || this.flying)) //This is so that if we get moved by something else, it will update us in the client { // keep track of where we stopped. No more slippin' & slidin' if (!_zeroFlag) { _zeroFlag = true; _zeroPosition = tempPos; } if (m_pidControllerActive) { // We only want to deactivate the PID Controller if we think we want to have our surrogate // react to the physics scene by moving it's position. // Avatar to Avatar collisions // Prim to avatar collisions // if target vel is zero why was it here ? //vec.X = -vel.X * PID_D + (_zeroPosition.X - tempPos.X) * PID_P * 2f; //vec.Y = -vel.Y * PID_D + (_zeroPosition.Y - tempPos.Y) * PID_P * 2f; } } else { m_pidControllerActive = true; _zeroFlag = false; if (m_iscolliding) { if(!flying) { if (_target_velocity.Z != 0.0f) vec.Z = (_target_velocity.Z - vel.Z) * PID_D;// + (_zeroPosition.Z - tempPos.Z) * PID_P)) _zeropos maybe bad here // We're standing or walking on something vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D*2; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D*2; } else { // We're flying and colliding with something vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D * 0.5f; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.5f; } } else { if (flying) { // we're flyind vec.X = (_target_velocity.X * movementmult - vel.X) * PID_D * 0.75f; vec.Y = (_target_velocity.Y * movementmult - vel.Y) * PID_D * 0.75f; } else { // we're not colliding and we're not flying so that means we're falling! // m_iscolliding includes collisions with the ground. vec.X = (_target_velocity.X - vel.X) * PID_D * 0.85f; vec.Y = (_target_velocity.Y - vel.Y) * PID_D * 0.85f; } } if (flying) { #region Av gravity if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Should be stop avies from flying upwards { //Decay going up if (_target_velocity.Z > 0) { //How much should we force them down? float Multiplier = (_parent_scene.AllowAvsToEscapeGravity ? .03f : .1f); //How much should we force them down? float fudgeHeight = (_parent_scene.AllowAvsToEscapeGravity ? 80 : 30); //We add the 30 so that gravity is resonably strong once they pass the min height Multiplier *= tempPos.Z + fudgeHeight - _parent_scene.AvGravityHeight; //Limit these so that things don't go wrong if (Multiplier < 1) Multiplier = 1; float maxpower = (_parent_scene.AllowAvsToEscapeGravity ? 1.5f : 3f); if (Multiplier > maxpower) Multiplier = maxpower; _target_velocity.Z /= Multiplier; vel.Z /= Multiplier; } } #endregion vec.Z = (_target_velocity.Z - vel.Z) * PID_D * 0.5f; if (_parent_scene.AllowAvGravity && tempPos.Z > _parent_scene.AvGravityHeight) //Add extra gravity vec.Z += ((10 * _parent_scene.gravityz) * Mass); } } if (flying) { #region Auto Fly Height //Added for auto fly height. Kitto Flora //Changed to only check if the avatar is flying around, // Revolution: If the avatar is going down, they are trying to land (probably), so don't push them up to make it harder // Only if they are moving around sideways do we need to push them up if (_target_velocity.X != 0 || _target_velocity.Y != 0) { Vector3 forwardVel = new Vector3(_target_velocity.X > 0 ? 2 : (_target_velocity.X < 0 ? -2 : 0), _target_velocity.Y > 0 ? 2 : (_target_velocity.Y < 0 ? -2 : 0), 0); float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y) + MinimumGroundFlightOffset; //We cheat a bit and do a bit lower than normal if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude || (tempPos.Z - CAPSULE_LENGTH) < _parent_scene.GetTerrainHeightAtXY(tempPos.X + forwardVel.X, tempPos.Y + forwardVel.Y) + MinimumGroundFlightOffset) vec.Z += (target_altitude - tempPos.Z) * PID_P * 0.5f; } else { //Straight up and down, only apply when they are very close to the ground float target_altitude = _parent_scene.GetTerrainHeightAtXY(tempPos.X, tempPos.Y); if ((tempPos.Z - CAPSULE_LENGTH + (MinimumGroundFlightOffset / 1.5)) < target_altitude + MinimumGroundFlightOffset) { if ((tempPos.Z - CAPSULE_LENGTH) < target_altitude + 1) { vec.Z += ((target_altitude + 4) - (tempPos.Z - CAPSULE_LENGTH)) * PID_P; } else vec.Z += ((target_altitude + MinimumGroundFlightOffset) - (tempPos.Z - CAPSULE_LENGTH)) * PID_P * 0.5f; } } #endregion } #region Gravity if (!flying && _parent_scene.AllowAvGravity) { if (!_parent_scene.UsePointGravity) { //Add normal gravity vec.X += _parent_scene.gravityx * m_mass; vec.Y += _parent_scene.gravityy * m_mass; vec.Z += _parent_scene.gravityz * m_mass; } else { Vector3 cog = _parent_scene.PointOfGravity; if (cog.X != 0) vec.X += (cog.X - tempPos.X) * m_mass; if (cog.Y != 0) vec.Y += (cog.Y - tempPos.Y) * m_mass; if (cog.Z != 0) vec.Z += (cog.Z - tempPos.Z) * m_mass; } } #endregion #region Under water physics if (_parent_scene.AllowUnderwaterPhysics) { //Position plus height to av's shoulder (aprox) is just above water if ((tempPos.Z + (CAPSULE_LENGTH / 3) - .25f) < _parent_scene.GetWaterLevel((float)tempPos.X, (float)tempPos.Y)) { if (StartingUnderWater) ShouldBeWalking = Flying == false; StartingUnderWater = false; WasUnderWater = true; Flying = true; lastUnderwaterPush = 0; if (ShouldBeWalking) { lastUnderwaterPush += (float)(_parent_scene.GetWaterLevel((float)tempPos.X, (float)tempPos.Y) - tempPos.Z) * 33 + 3; vec.Z += lastUnderwaterPush; } else { lastUnderwaterPush += 3500; lastUnderwaterPush += (float)(_parent_scene.GetWaterLevel((float)tempPos.X, (float)tempPos.Y) - tempPos.Z) * 8; vec.Z += lastUnderwaterPush; } } else { StartingUnderWater = true; if (WasUnderWater) { WasUnderWater = false; Flying = true; } } } #endregion #endregion if (vec.IsFinite()) { if (vec.X < 100000000 && vec.Y < 10000000 && vec.Z < 10000000) //Checks for crazy, going to NaN us values { d.Vector3 veloc = d.BodyGetLinearVel(Body); //Stop us from fidgiting if we have a small velocity /* if (_zeroFlag && ((Math.Abs(vec.X) < 0.09 && Math.Abs(vec.Y) < 0.09 && Math.Abs(vec.Z) < 0.03) && !flying && vec.Z != 0)) { //m_log.Warn("Nulling Velo: " + vec.ToString()); vec = new Vector3(0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } //Reduce insanely small values to 0 if the velocity isn't going up if (Math.Abs(vec.Z) < 0.01 && veloc.Z < 0.6 && _zeroFlag) { if (veloc.Z != 0) { if (-veloc.Z > 0) vec.Z = 0; else vec.Z = -veloc.Z * 5; d.BodySetLinearVel(Body, veloc.X, veloc.Y, vec.Z); } } */ // round small values to zero. those possible are just errors if (Math.Abs(vec.X) < 0.001) vec.X = 0; if (Math.Abs(vec.Y) < 0.001) vec.Y = 0; if (Math.Abs(vec.Z) < 0.001) vec.Z = 0; doForce(vec); //When falling, we keep going faster and faster, and eventually, the client blue screens (blue is all you see). // The speed that does this is slightly higher than -30, so we cap it here so we never do that during falling. if (vel.Z < -30) { vel.Z = -30; d.BodySetLinearVel(Body, vel.X, vel.Y, vel.Z); } //Decay out the target velocity _target_velocity *= _parent_scene.m_avDecayTime; if (!_zeroFlag && _target_velocity.ApproxEquals(Vector3.Zero, _parent_scene.m_avStopDecaying)) _target_velocity = Vector3.Zero; //Check if the capsule is tilted before changing it // if (!_zeroFlag && !_parent_scene.IsAvCapsuleTilted) // AlignAvatarTiltWithCurrentDirectionOfMovement(vec); } else { //This is a safe guard from going NaN, but it isn't very smooth... which is ok d.BodySetForce(Body, 0, 0, 0); d.BodySetLinearVel(Body, 0, 0, 0); } } else { m_log.Warn("[PHYSICS]: Got a NaN force vector in Move()"); m_log.Warn("[PHYSICS]: Avatar Position is non-finite!"); defects.Add(this); // _parent_scene.RemoveCharacter(this); // destroy avatar capsule and related ODE data if (Amotor != IntPtr.Zero) { // Kill the Amotor d.JointDestroy(Amotor); Amotor = IntPtr.Zero; } //kill the Geometry _parent_scene.waitForSpaceUnlock(_parent_scene.space); if (Body != IntPtr.Zero) { //kill the body d.BodyDestroy(Body); Body = IntPtr.Zero; } if (Shell != IntPtr.Zero) { d.GeomDestroy(Shell); _parent_scene.geom_name_map.Remove(Shell); Shell = IntPtr.Zero; } } }
/// <summary> /// Updates the reported position and velocity. This essentially sends the data up to ScenePresence. /// </summary> public void UpdatePositionAndVelocity() { // no lock; called from Simulate() -- if you call this from elsewhere, gotta lock or do Monitor.Enter/Exit! d.Vector3 vec = d.BodyGetPosition(Body); // kluge to keep things in bounds. ODE lets dead avatars drift away (they should be removed!) if (vec.X < 0.0f) { vec.X = 0.0f; } if (vec.Y < 0.0f) { vec.Y = 0.0f; } if (vec.X > 255.95f) { vec.X = 255.95f; } if (vec.Y > 255.95f) { vec.Y = 255.95f; } _position.X = vec.X; _position.Y = vec.Y; _position.Z = vec.Z; // Did we move last? = zeroflag // This helps keep us from sliding all over if (_zeroFlag) { _velocity.X = 0.0f; _velocity.Y = 0.0f; _velocity.Z = 0.0f; // Did we send out the 'stopped' message? if (!m_lastUpdateSent) { m_lastUpdateSent = true; //base.RequestPhysicsterseUpdate(); } } else { m_lastUpdateSent = false; vec = d.BodyGetLinearVel(Body); _velocity.X = (vec.X); _velocity.Y = (vec.Y); _velocity.Z = (vec.Z); if (_velocity.Z < -6 && !m_hackSentFall) { m_hackSentFall = true; m_pidControllerActive = false; } else if (flying && !m_hackSentFly) { //m_hackSentFly = true; //base.SendCollisionUpdate(new CollisionEventUpdate()); } else { m_hackSentFly = false; m_hackSentFall = false; } } }
} // end Step private void MoveLinear (float pTimestep, AuroraODEPhysicsScene _pParentScene, AuroraODEPrim parent) { if (!m_linearMotorDirection.ApproxEquals (Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant { if (!d.BodyIsEnabled (Body)) d.BodyEnable (Body); // add drive to body Vector3 addAmount = m_linearMotorDirection / ((m_linearMotorTimescale) / pTimestep); m_lastLinearVelocityVector += (addAmount); // lastLinearVelocityVector is the current body velocity vector? // This will work temporarily, but we really need to compare speed on an axis // KF: Limit body velocity to applied velocity? if (Math.Abs (m_lastLinearVelocityVector.X) > Math.Abs (m_linearMotorDirectionLASTSET.X)) m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; if (Math.Abs (m_lastLinearVelocityVector.Y) > Math.Abs (m_linearMotorDirectionLASTSET.Y)) m_lastLinearVelocityVector.Y = m_linearMotorDirectionLASTSET.Y; if (Math.Abs (m_lastLinearVelocityVector.Z) > Math.Abs (m_linearMotorDirectionLASTSET.Z)) m_lastLinearVelocityVector.Z = m_linearMotorDirectionLASTSET.Z; // decay applied velocity Vector3 decayfraction = ((Vector3.One / (m_linearMotorDecayTimescale / (pTimestep)))); decayfraction.Z = ((1 / (m_linearMotorDecayTimescale / (pTimestep * pTimestep)))); //Console.WriteLine("decay: " + decayfraction); Vector3 decayAmt = (m_linearMotorDirection * decayfraction); m_linearMotorDirection -= decayAmt; //Console.WriteLine("actual: " + m_linearMotorDirection); } else { // requested is not significant // if what remains of applied is small, zero it. if (m_lastLinearVelocityVector.ApproxEquals (Vector3.Zero, 0.01f)) m_lastLinearVelocityVector = Vector3.Zero; } // convert requested object velocity to world-referenced vector m_dir = m_lastLinearVelocityVector; d.Quaternion rot = d.BodyGetQuaternion (Body); Quaternion rotq = new Quaternion (rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object m_dir *= rotq; // apply obj rotation to velocity vector // add Gravity andBuoyancy // KF: So far I have found no good method to combine a script-requested // .Z velocity and gravity. Therefore only 0g will used script-requested // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. Vector3 grav = Vector3.Zero; // There is some gravity, make a gravity force vector // that is applied after object velocity. // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; grav.Z = _pParentScene.gravityz * Mass * (float)parent.ParentEntity.GravityMultiplier * (1f - m_VehicleBuoyancy); // Preserve the current Z velocity d.Vector3 vel_now = d.BodyGetLinearVel (Body); if(m_lastLinearVelocityVector.Z == 0 && m_verticalAttractionTimescale == 0) m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity else if(Type != Vehicle.TYPE_AIRPLANE && Type != Vehicle.TYPE_BALLOON) m_dir.Z += vel_now.Z; d.Vector3 pos = d.BodyGetPosition (Body); // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); Vector3 posChange = new Vector3 (); posChange.X = pos.X - m_lastPositionVector.X; posChange.Y = pos.Y - m_lastPositionVector.Y; posChange.Z = pos.Z - m_lastPositionVector.Z; double Zchange = Math.Abs (posChange.Z); if (m_BlockingEndPoint != Vector3.Zero) { if (pos.X >= (m_BlockingEndPoint.X - (float)1)) { pos.X -= posChange.X + 1; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) { pos.Y -= posChange.Y + 1; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) { pos.Z -= posChange.Z + 1; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } if (pos.X <= 0) { pos.X += posChange.X + 1; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } if (pos.Y <= 0) { pos.Y += posChange.Y + 1; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } } if (pos.Z < _pParentScene.GetTerrainHeightAtXY (pos.X, pos.Y)) { pos.Z = _pParentScene.GetTerrainHeightAtXY (pos.X, pos.Y) + 2; d.BodySetPosition (Body, pos.X, pos.Y, pos.Z); } // Check if hovering if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) { // We should hover, get the target height if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) { m_VhoverTargetHeight = (float)_pParentScene.GetWaterLevel (pos.X, pos.Y) + m_VhoverHeight; } if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) { m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY (pos.X, pos.Y) + m_VhoverHeight; } if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) { m_VhoverTargetHeight = m_VhoverHeight; } if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) { // If body is aready heigher, use its height as target height if (pos.Z > m_VhoverTargetHeight) m_VhoverTargetHeight = pos.Z; } if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) { if ((pos.Z - m_VhoverTargetHeight) > .2 || (pos.Z - m_VhoverTargetHeight) < -.2) { d.BodySetPosition (Body, pos.X, pos.Y, m_VhoverTargetHeight); } } else { float herr0 = pos.Z - m_VhoverTargetHeight; // Replace Vertical speed with correction figure if significant if (Math.Abs (herr0) > 0.01f) { m_dir.Z = -((herr0 * pTimestep * 50.0f) / m_VhoverTimescale); //KF: m_VhoverEfficiency is not yet implemented } else { m_dir.Z = 0f; } } // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped // m_VhoverTimescale = 0f; // time to acheive height // pTimestep is time since last frame,in secs } if ((m_flags & (VehicleFlag.NO_X)) != 0) m_dir.X = 0; if ((m_flags & (VehicleFlag.NO_Y)) != 0) m_dir.Y = 0; if ((m_flags & (VehicleFlag.NO_Z)) != 0) m_dir.Z = 0; #region Limit Motor Up if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) //if it isn't going up, don't apply the limiting force { if (Zchange > -0.1f) { //Requires idea of 'up', so use reference frame to rotate it //Add to the X, because that will normally tilt the vehicle downward (if its rotated, it'll be rotated by the ref. frame grav += (new Vector3 (0, 0, ((float)Math.Abs (Zchange) * (pTimestep * -_pParentScene.PID_D * _pParentScene.PID_D)))); } } #endregion #region Deal with tainted forces // KF: So far I have found no good method to combine a script-requested // .Z velocity and gravity. Therefore only 0g will used script-requested // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; Vector3 TaintedForce = new Vector3 (); if (m_forcelist.Count != 0) { try { for (int i = 0; i < m_forcelist.Count; i++) { TaintedForce = TaintedForce + (m_forcelist[i] * 100); } } catch (IndexOutOfRangeException) { TaintedForce = Vector3.Zero; } catch (ArgumentOutOfRangeException) { TaintedForce = Vector3.Zero; } m_forcelist = new List<Vector3> (); } #endregion #region Deflection //Forward is the prefered direction /*Vector3 deflectionamount = m_dir / (m_linearDeflectionTimescale / pTimestep); //deflectionamount *= m_linearDeflectionEfficiency; if (deflectionamount != Vector3.Zero) { } Vector3 deflection = Vector3.One / deflectionamount; m_dir /= deflection;*/ #endregion m_lastPositionVector = d.BodyGetPosition (Body); #region limitations if (Math.Abs (m_dir.X) > 1000 || Math.Abs (m_dir.Y) > 1000 || Math.Abs (m_dir.Z) > 1000) { //This vehicle is f***ed parent.RaiseOutOfBounds (parent.Position); parent._zeroFlag = true; parent.m_disabled = true; parent.m_frozen = true; return; } #endregion // Apply velocity d.BodySetLinearVel (Body, m_dir.X, m_dir.Y, m_dir.Z); // apply gravity force d.BodyAddForce (Body, grav.X, grav.Y, grav.Z); // apply friction Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; } // end MoveLinear()