internal void ProcessTaints() { if (m_taintPosition != _position) { if (Body != IntPtr.Zero) { d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); _position = m_taintPosition; } } if (m_taintForce != Vector3.Zero) { if (Body != IntPtr.Zero) { // FIXME: This is not a good solution since it's subject to a race condition if a force is another // thread sets a new force while we're in this loop (since it could be obliterated by // m_taintForce = Vector3.Zero. Need to lock ProcessTaints() when we set a new tainted force. d.BodyAddForce(Body, m_taintForce.X, m_taintForce.Y, m_taintForce.Z); } m_taintForce = Vector3.Zero; } if (m_taintTargetVelocity != _target_velocity) { _target_velocity = m_taintTargetVelocity; } if (m_tainted_isPhysical != m_isPhysical) { if (m_tainted_isPhysical) { // Create avatar capsule and related ODE data if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) { m_log.Warn("[ODE CHARACTER]: re-creating the following avatar ODE data for " + Name + ", even though it already exists - " + (Shell != IntPtr.Zero ? "Shell ":"") + (Body != IntPtr.Zero ? "Body ":"") + (Amotor != IntPtr.Zero ? "Amotor ":"")); } CreateOdeStructures(_position.X, _position.Y, _position.Z, m_tensor); _parent_scene.AddCharacter(this); } else { _parent_scene.RemoveCharacter(this); DestroyOdeStructures(); } m_isPhysical = m_tainted_isPhysical; } if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) { if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) { // m_log.DebugFormat( // "[ODE CHARACTER]: Changing capsule size from {0} to {1} for {2}", // CAPSULE_LENGTH, m_tainted_CAPSULE_LENGTH, Name); m_pidControllerActive = true; // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() DestroyOdeStructures(); float prevCapsule = CAPSULE_LENGTH; CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; CreateOdeStructures( _position.X, _position.Y, _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); // As with Size, we reset velocity. However, this isn't strictly necessary since it doesn't // appear to stall initial region crossings when done here. Being done for consistency. // Velocity = Vector3.Zero; } else { m_log.Warn("[ODE CHARACTER]: trying to change capsule size for " + Name + ", but the following ODE data is missing - " + (Shell == IntPtr.Zero ? "Shell ":"") + (Body == IntPtr.Zero ? "Body ":"") + (Amotor == IntPtr.Zero ? "Amotor ":"")); } } }
/// <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; } }
public void ProcessTaints(float timestep) { if (m_tainted_isPhysical != m_isPhysical) { if (m_tainted_isPhysical) { // Create avatar capsule and related ODE data if (!(Shell == IntPtr.Zero && Body == IntPtr.Zero && Amotor == IntPtr.Zero)) { m_log.Warn("[PHYSICS]: re-creating the following avatar ODE data, even though it already exists - " + (Shell != IntPtr.Zero ? "Shell ":"") + (Body != IntPtr.Zero ? "Body ":"") + (Amotor != IntPtr.Zero ? "Amotor ":"")); } AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z, m_tensor); _parent_scene.geom_name_map[Shell] = m_name; _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; _parent_scene.AddCharacter(this); } else { _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; } } m_isPhysical = m_tainted_isPhysical; } if (m_tainted_CAPSULE_LENGTH != CAPSULE_LENGTH) { if (Shell != IntPtr.Zero && Body != IntPtr.Zero && Amotor != IntPtr.Zero) { m_pidControllerActive = true; // no lock needed on _parent_scene.OdeLock because we are called from within the thread lock in OdePlugin's simulate() d.JointDestroy(Amotor); float prevCapsule = CAPSULE_LENGTH; CAPSULE_LENGTH = m_tainted_CAPSULE_LENGTH; //m_log.Info("[SIZE]: " + CAPSULE_LENGTH.ToString()); d.BodyDestroy(Body); d.GeomDestroy(Shell); AvatarGeomAndBodyCreation(_position.X, _position.Y, _position.Z + (Math.Abs(CAPSULE_LENGTH - prevCapsule) * 2), m_tensor); Velocity = new PhysicsVector(0f, 0f, 0f); _parent_scene.geom_name_map[Shell] = m_name; _parent_scene.actor_name_map[Shell] = (PhysicsActor)this; } else { m_log.Warn("[PHYSICS]: trying to change capsule size, but the following ODE data is missing - " + (Shell == IntPtr.Zero ? "Shell ":"") + (Body == IntPtr.Zero ? "Body ":"") + (Amotor == IntPtr.Zero ? "Amotor ":"")); } } if (!m_taintPosition.IsIdentical(_position, 0.05f)) { if (Body != IntPtr.Zero) { d.BodySetPosition(Body, m_taintPosition.X, m_taintPosition.Y, m_taintPosition.Z); _position.X = m_taintPosition.X; _position.Y = m_taintPosition.Y; _position.Z = m_taintPosition.Z; } } }