change avatar physics and motion control. Still not that good :(

avinationmerge
UbitUmarov 2014-09-29 20:17:05 +01:00
parent bb019945e8
commit 3052a53889
4 changed files with 495 additions and 202 deletions

View File

@ -58,9 +58,11 @@ namespace OpenSim.Region.Framework.Scenes.Animation
public string CurrentMovementAnimation { get; private set; } public string CurrentMovementAnimation { get; private set; }
private int m_animTickFall; private int m_animTickFall;
public int m_animTickJump; // ScenePresence has to see this to control +Z force private int m_animTickLand;
private int m_animTickJump;
public bool m_jumping = false; public bool m_jumping = false;
public float m_jumpVelocity = 0f;
// private int m_landing = 0; // private int m_landing = 0;
/// <summary> /// <summary>
@ -68,7 +70,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
/// </summary> /// </summary>
public bool Falling { get; private set; } public bool Falling { get; private set; }
private float m_fallHeight; private float m_lastFallVelocity;
/// <value> /// <value>
/// The scene presence that this animator applies to /// The scene presence that this animator applies to
@ -205,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
if (aoSitGndAnim != UUID.Zero) if (aoSitGndAnim != UUID.Zero)
{ {
avnChangeAnim(aoSitGndAnim, false, false); avnChangeAnim(aoSitGndAnim, false, true);
aoSitGndAnim = UUID.Zero; aoSitGndAnim = UUID.Zero;
} }
@ -258,20 +260,38 @@ namespace OpenSim.Region.Framework.Scenes.Animation
return ret; return ret;
} }
public enum motionControlStates : byte
{
sitted = 0,
flying,
falling,
jumping,
landing,
onsurface
}
public motionControlStates currentControlState = motionControlStates.onsurface;
/// <summary> /// <summary>
/// This method determines the proper movement related animation /// This method determines the proper movement related animation
/// </summary> /// </summary>
private string DetermineMovementAnimation() private string DetermineMovementAnimation()
{ {
const float FALL_DELAY = 800f; const int FALL_DELAY = 800;
const float PREJUMP_DELAY = 200f; const int PREJUMP_DELAY = 200;
const float JUMP_PERIOD = 800f; const int JUMP_PERIOD = 800;
#region Inputs #region Inputs
if (m_scenePresence.SitGround) if (m_scenePresence.SitGround)
{
currentControlState = motionControlStates.sitted;
return "SITGROUND"; return "SITGROUND";
}
if (m_scenePresence.ParentID != 0 || m_scenePresence.ParentUUID != UUID.Zero) if (m_scenePresence.ParentID != 0 || m_scenePresence.ParentUUID != UUID.Zero)
{
currentControlState = motionControlStates.sitted;
return "SIT"; return "SIT";
}
AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags; AgentManager.ControlFlags controlFlags = (AgentManager.ControlFlags)m_scenePresence.AgentControlFlags;
PhysicsActor actor = m_scenePresence.PhysicsActor; PhysicsActor actor = m_scenePresence.PhysicsActor;
@ -311,17 +331,31 @@ namespace OpenSim.Region.Framework.Scenes.Animation
// bool moving = (move != Vector3.Zero); // bool moving = (move != Vector3.Zero);
#endregion Inputs #endregion Inputs
// no physics actor case
if (actor == null)
{
// well what to do?
currentControlState = motionControlStates.onsurface;
if (move.X != 0f || move.Y != 0f)
return "WALK";
return "STAND";
}
#region Flying #region Flying
if (actor != null && actor.Flying) bool isColliding = actor.IsColliding;
if (actor.Flying)
{ {
m_animTickFall = 0; m_animTickFall = 0;
m_animTickJump = 0; m_animTickJump = 0;
m_jumping = false; m_jumping = false;
Falling = false; Falling = false;
m_jumpVelocity = 0f;
actor.Selected = false; currentControlState = motionControlStates.flying;
m_fallHeight = actor.Position.Z; // save latest flying height
if (move.X != 0f || move.Y != 0f) if (move.X != 0f || move.Y != 0f)
{ {
@ -333,8 +367,13 @@ namespace OpenSim.Region.Framework.Scenes.Animation
} }
else if (move.Z < 0f) else if (move.Z < 0f)
{ {
if (actor != null && actor.IsColliding) if (isColliding)
{
actor.Flying = false;
currentControlState = motionControlStates.landing;
m_animTickLand = Environment.TickCount;
return "LAND"; return "LAND";
}
else else
return "HOVER_DOWN"; return "HOVER_DOWN";
} }
@ -343,30 +382,42 @@ namespace OpenSim.Region.Framework.Scenes.Animation
return "HOVER"; return "HOVER";
} }
} }
else
{
if (isColliding && currentControlState == motionControlStates.flying)
{
currentControlState = motionControlStates.landing;
m_animTickLand = Environment.TickCount;
return "LAND";
}
}
#endregion Flying #endregion Flying
#region Falling/Floating/Landing #region Falling/Floating/Landing
if ((actor == null || !actor.IsColliding) && !m_jumping) if (!isColliding && currentControlState != motionControlStates.jumping)
{ {
float fallElapsed = (float)(Environment.TickCount - m_animTickFall); float fallVelocity = actor.Velocity.Z;
float fallVelocity = (actor != null) ? actor.Velocity.Z : 0.0f;
if (!m_jumping && (fallVelocity < -3.0f)) if (fallVelocity < -2.5f)
Falling = true; Falling = true;
if (m_animTickFall == 0 || (fallVelocity >= 0.0f)) if (m_animTickFall == 0 || (fallVelocity >= -0.5f))
{ {
// not falling yet, or going up
// reset start of fall time
m_animTickFall = Environment.TickCount; m_animTickFall = Environment.TickCount;
} }
else if (!m_jumping && (fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f) && (m_scenePresence.WasFlying)) else
{ {
int fallElapsed = (Environment.TickCount - m_animTickFall);
if ((fallElapsed > FALL_DELAY) && (fallVelocity < -3.0f))
{
currentControlState = motionControlStates.falling;
m_lastFallVelocity = fallVelocity;
// Falling long enough to trigger the animation // Falling long enough to trigger the animation
return "FALLDOWN"; return "FALLDOWN";
} }
}
// Check if the user has stopped walking just now // Check if the user has stopped walking just now
if (CurrentMovementAnimation == "WALK" && (move == Vector3.Zero)) if (CurrentMovementAnimation == "WALK" && (move == Vector3.Zero))
@ -375,49 +426,44 @@ namespace OpenSim.Region.Framework.Scenes.Animation
return CurrentMovementAnimation; return CurrentMovementAnimation;
} }
#endregion Falling/Floating/Landing m_animTickFall = 0;
#endregion Falling/Floating/Landing
#region Jumping // section added for jumping... #region Jumping // section added for jumping...
int jumptime; if (isColliding && move.Z > 0f && currentControlState != motionControlStates.jumping)
jumptime = Environment.TickCount - m_animTickJump;
if ((move.Z > 0f) && (!m_jumping))
{ {
// Start jumping, prejump // Start jumping, prejump
m_animTickFall = 0; currentControlState = motionControlStates.jumping;
m_jumping = true; m_jumping = true;
Falling = false; Falling = false;
actor.Selected = true; // borrowed for jumping flag
m_animTickJump = Environment.TickCount; m_animTickJump = Environment.TickCount;
m_jumpVelocity = 0.35f;
return "PREJUMP"; return "PREJUMP";
} }
if (m_jumping) if (currentControlState == motionControlStates.jumping)
{ {
int jumptime = Environment.TickCount - m_animTickJump;
if ((jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding) if ((jumptime > (JUMP_PERIOD * 1.5f)) && actor.IsColliding)
{ {
// end jumping // end jumping
m_jumping = false; m_jumping = false;
Falling = false; Falling = false;
actor.Selected = false; // borrowed for jumping flag actor.Selected = false; // borrowed for jumping flag
m_jumpVelocity = 0f; m_animTickLand = Environment.TickCount;
m_animTickFall = Environment.TickCount; currentControlState = motionControlStates.landing;
return "LAND"; return "LAND";
} }
else if (jumptime > JUMP_PERIOD) else if (jumptime > JUMP_PERIOD)
{ {
// jump down // jump down
m_jumpVelocity = 0f;
return "JUMP"; return "JUMP";
} }
else if (jumptime > PREJUMP_DELAY) else if (jumptime > PREJUMP_DELAY)
{ {
// jump up // jump up
m_jumping = true; m_jumping = true;
m_jumpVelocity = 10f;
return "JUMP"; return "JUMP";
} }
} }
@ -426,42 +472,48 @@ namespace OpenSim.Region.Framework.Scenes.Animation
#region Ground Movement #region Ground Movement
if (CurrentMovementAnimation == "FALLDOWN") if (currentControlState == motionControlStates.falling)
{ {
Falling = false; Falling = false;
m_animTickFall = Environment.TickCount; currentControlState = motionControlStates.landing;
m_animTickLand = Environment.TickCount;
// TODO: SOFT_LAND support // TODO: SOFT_LAND support
float fallHeight = m_fallHeight - actor.Position.Z; float fallVsq =m_lastFallVelocity*m_lastFallVelocity;
if (fallHeight > 15.0f) if (fallVsq > 300f) // aprox 20*h
return "STANDUP"; return "STANDUP";
else if (fallHeight > 8.0f) else if (fallVsq > 160f)
return "SOFT_LAND"; return "SOFT_LAND";
else else
return "LAND"; return "LAND";
} }
else if ((CurrentMovementAnimation == "LAND") || (CurrentMovementAnimation == "SOFT_LAND") || (CurrentMovementAnimation == "STANDUP"))
if (currentControlState == motionControlStates.landing)
{ {
int landElapsed = Environment.TickCount - m_animTickFall; Falling = false;
int landElapsed = Environment.TickCount - m_animTickLand;
int limit = 1000; int limit = 1000;
if (CurrentMovementAnimation == "LAND") if (CurrentMovementAnimation == "LAND")
limit = 350; limit = 350;
// NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client // NB if the above is set too long a weird anim reset from some place prevents STAND from being sent to client
if ((m_animTickFall != 0) && (landElapsed <= limit)) if ((m_animTickLand != 0) && (landElapsed <= limit))
{ {
return CurrentMovementAnimation; return CurrentMovementAnimation;
} }
else else
{ {
m_fallHeight = actor.Position.Z; // save latest flying height currentControlState = motionControlStates.onsurface;
m_animTickLand = 0;
return "STAND"; return "STAND";
} }
} }
// next section moved outside paren. and realigned for jumping // next section moved outside paren. and realigned for jumping
if (move.X != 0f || move.Y != 0f) if (move.X != 0f || move.Y != 0f)
{ {
m_fallHeight = actor.Position.Z; // save latest flying height currentControlState = motionControlStates.onsurface;
Falling = false; Falling = false;
// Walking / crouchwalking / running // Walking / crouchwalking / running
if (move.Z < 0f) if (move.Z < 0f)
@ -480,6 +532,7 @@ namespace OpenSim.Region.Framework.Scenes.Animation
} }
else if (!m_jumping) else if (!m_jumping)
{ {
currentControlState = motionControlStates.onsurface;
Falling = false; Falling = false;
// Not walking // Not walking
if (move.Z < 0) if (move.Z < 0)
@ -493,8 +546,6 @@ namespace OpenSim.Region.Framework.Scenes.Animation
} }
#endregion Ground Movement #endregion Ground Movement
Falling = false;
return CurrentMovementAnimation; return CurrentMovementAnimation;
} }

View File

@ -287,13 +287,6 @@ namespace OpenSim.Region.Framework.Scenes
set { PhysicsActor.Flying = value; } set { PhysicsActor.Flying = value; }
} }
// add for fly velocity control
private bool FlyingOld {get; set;}
public bool WasFlying
{
get; private set;
}
public bool IsColliding public bool IsColliding
{ {
get { return PhysicsActor != null && PhysicsActor.IsColliding; } get { return PhysicsActor != null && PhysicsActor.IsColliding; }
@ -936,7 +929,7 @@ namespace OpenSim.Region.Framework.Scenes
/// <remarks> /// <remarks>
/// AGENT_CONTRL_STOP comes about if user holds down space key on viewers. /// AGENT_CONTRL_STOP comes about if user holds down space key on viewers.
/// </remarks> /// </remarks>
private float AgentControlStopSlowWhilstMoving = 0.5f; private float AgentControlStopSlowWhilstMoving = 0.2f;
private bool m_forceFly; private bool m_forceFly;
@ -2174,7 +2167,7 @@ namespace OpenSim.Region.Framework.Scenes
bool DCFlagKeyPressed = false; bool DCFlagKeyPressed = false;
Vector3 agent_control_v3 = Vector3.Zero; Vector3 agent_control_v3 = Vector3.Zero;
bool newFlying = actor.Flying; bool newFlying = false;
if (ForceFly) if (ForceFly)
newFlying = true; newFlying = true;
@ -2286,11 +2279,11 @@ namespace OpenSim.Region.Framework.Scenes
if (Flying && !ForceFly) if (Flying && !ForceFly)
{ {
// Need to stop in mid air if user holds down AGENT_CONTROL_STOP // Need to stop in mid air if user holds down AGENT_CONTROL_STOP
if (AgentControlStopActive) // if (AgentControlStopActive)
{ // {
agent_control_v3 = Vector3.Zero; // agent_control_v3 = Vector3.Zero;
} // }
else // else
{ {
// Landing detection code // Landing detection code
@ -2321,6 +2314,7 @@ namespace OpenSim.Region.Framework.Scenes
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE); m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
} }
/*
if (Flying && IsColliding && controlland) if (Flying && IsColliding && controlland)
{ {
// nesting this check because LengthSquared() is expensive and we don't // nesting this check because LengthSquared() is expensive and we don't
@ -2328,8 +2322,13 @@ namespace OpenSim.Region.Framework.Scenes
if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX)) if ((Velocity.LengthSquared() <= LAND_VELOCITYMAG_MAX))
StopFlying(); StopFlying();
} }
*/
} }
} }
else if (IsColliding && agent_control_v3.Z < 0f)
agent_control_v3.Z = 0;
// else if(AgentControlStopActive %% Velocity.Z <0.01f)
// m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name); // m_log.DebugFormat("[SCENE PRESENCE]: MovementFlag {0} for {1}", MovementFlag, Name);
@ -2342,32 +2341,22 @@ namespace OpenSim.Region.Framework.Scenes
if (update_movementflag if (update_movementflag
|| (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0))) || (update_rotation && DCFlagKeyPressed && (!AgentControlStopActive || MovementFlag != 0)))
{ {
// if (update_movementflag || !AgentControlStopActive || MovementFlag != 0)
// {
// m_log.DebugFormat(
// "[SCENE PRESENCE]: In {0} adding velocity of {1} to {2}, umf = {3}, mf = {4}, ur = {5}",
// m_scene.RegionInfo.RegionName, agent_control_v3, Name,
// update_movementflag, MovementFlag, update_rotation);
float speedModifier;
if (AgentControlStopActive) if (AgentControlStopActive)
speedModifier = AgentControlStopSlowWhilstMoving; {
else // if (MovementFlag == 0 && Animator.Falling)
speedModifier = 1; if (MovementFlag == 0 && Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling)
{
AddNewMovement(agent_control_v3, speedModifier); AddNewMovement(agent_control_v3, AgentControlStopSlowWhilstMoving, true);
// } }
else
AddNewMovement(agent_control_v3, AgentControlStopSlowWhilstMoving);
}
else
AddNewMovement(agent_control_v3);
} }
// else
// {
// if (!update_movementflag)
// {
// m_log.DebugFormat(
// "[SCENE PRESENCE]: In {0} ignoring requested update of {1} for {2} as update_movementflag = false",
// m_scene.RegionInfo.RegionName, agent_control_v3, Name);
// }
// }
if (update_movementflag && ParentID == 0) if (update_movementflag && ParentID == 0)
{ {
@ -3246,68 +3235,58 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="vec">The vector in which to move. This is relative to the rotation argument</param> /// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
/// <param name="thisAddSpeedModifier"> /// <param name="thisAddSpeedModifier">
/// Optional additional speed modifier for this particular add. Default is 1</param> /// Optional additional speed modifier for this particular add. Default is 1</param>
public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1) public void AddNewMovement(Vector3 vec, float thisAddSpeedModifier = 1, bool breaking = false)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}", // "[SCENE PRESENCE]: Adding new movement {0} with rotation {1}, thisAddSpeedModifier {2} for {3}",
// vec, Rotation, thisAddSpeedModifier, Name); // vec, Rotation, thisAddSpeedModifier, Name);
Vector3 direc = vec * Rotation; Vector3 direc = vec * Rotation;
direc.Normalize(); direc.Normalize();
if (Flying != FlyingOld) // add for fly velocity control
{
FlyingOld = Flying; // add for fly velocity control
if (!Flying)
WasFlying = true; // add for fly velocity control
}
if (IsColliding)
WasFlying = false; // add for fly velocity control
if ((vec.Z == 0f) && !Flying) if ((vec.Z == 0f) && !Flying)
direc.Z = 0f; // Prevent camera WASD up. direc.Z = 0f; // Prevent camera WASD up.
direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier; direc *= 0.03f * 128f * SpeedModifier * thisAddSpeedModifier;
// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name); // m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
if (PhysicsActor != null) if (Animator.currentControlState == ScenePresenceAnimator.motionControlStates.falling)
{ {
if (Flying) if (breaking)
direc.Z = -9999f; //hack
else
direc = Vector3.Zero;
}
else if (Flying)
{ {
if(IsColliding)
direc = Vector3.Zero;
else
direc *= 4.0f; direc *= 4.0f;
//bool controlland = (((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) || ((m_AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
//if (controlland)
// m_log.Info("[AGENT]: landCommand");
//if (IsColliding)
// m_log.Info("[AGENT]: colliding");
//if (Flying && IsColliding && controlland)
//{
// StopFlying();
// m_log.Info("[AGENT]: Stop Flying");
//}
} }
if (Animator.Falling && WasFlying) // if falling from flying, disable motion add else if (IsColliding)
{
direc *= 0.0f;
}
else if (!Flying && IsColliding)
{ {
if (direc.Z > 2.0f) if (direc.Z > 2.0f)
{ {
direc.Z *= 2.6f; direc.Z *= 2.6f;
// TODO: PreJump and jump happen too quickly. Many times prejump gets ignored.
// Animator.TrySetMovementAnimation("PREJUMP");
// Animator.TrySetMovementAnimation("JUMP");
} }
else if (direc.Z < 0)
direc.Z = 0;
/*
float c = CollisionPlane.Z;
if (c > 0.2f && c < 0.94f && (direc.X != 0 || direc.Y != 0))
{
float p = direc.X * CollisionPlane.X + direc.Y * CollisionPlane.Y;
direc.X -= p * CollisionPlane.X;
direc.Y -= p * CollisionPlane.Y;
direc.Z -= p * c;
} }
*/
} }
// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name); // m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
// TODO: Add the force instead of only setting it to support multiple forces per frame?
m_forceToApply = direc; m_forceToApply = direc;
Animator.UpdateMovementAnimations(); Animator.UpdateMovementAnimations();
} }

View File

@ -79,6 +79,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private Vector3 _acceleration; private Vector3 _acceleration;
private Vector3 m_rotationalVelocity; private Vector3 m_rotationalVelocity;
private Vector3 m_size; private Vector3 m_size;
private Vector3 m_collideNormal;
private Quaternion m_orientation; private Quaternion m_orientation;
private Quaternion m_orientation2D; private Quaternion m_orientation2D;
private float m_mass = 80f; private float m_mass = 80f;
@ -109,6 +110,7 @@ namespace OpenSim.Region.Physics.OdePlugin
private bool _zeroFlag = false; private bool _zeroFlag = false;
private uint m_localID = 0; private uint m_localID = 0;
public bool m_returnCollisions = false; public bool m_returnCollisions = false;
// taints and their non-tainted counterparts // taints and their non-tainted counterparts
@ -155,8 +157,6 @@ namespace OpenSim.Region.Physics.OdePlugin
float mu; float mu;
public OdeCharacter(uint localID, String avName, OdeScene parent_scene, Vector3 pos, Vector3 pSize, float pfeetOffset, float density, float walk_divisor, float rundivisor) public OdeCharacter(uint localID, String avName, OdeScene parent_scene, Vector3 pos, Vector3 pSize, float pfeetOffset, float density, float walk_divisor, float rundivisor)
{ {
m_uuid = UUID.Random(); m_uuid = UUID.Random();
@ -865,10 +865,11 @@ namespace OpenSim.Region.Physics.OdePlugin
y = tx * sin + y * cos; y = tx * sin + y * cos;
} }
public bool Collide(IntPtr me, IntPtr other, bool reverse, ref d.ContactGeom contact,
public bool Collide(IntPtr me,IntPtr other, bool reverse, ref d.ContactGeom contact, ref bool feetcollision) ref d.ContactGeom altContact , ref bool useAltcontact, ref bool feetcollision)
{ {
feetcollision = false; feetcollision = false;
useAltcontact = false;
if (me == capsule) if (me == capsule)
{ {
@ -899,31 +900,77 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
feetcollision = true; feetcollision = true;
if (h < boneOff) if (h < boneOff)
{
m_collideNormal.X = contact.normal.X;
m_collideNormal.Y = contact.normal.Y;
m_collideNormal.Z = contact.normal.Z;
IsColliding = true; IsColliding = true;
} }
}
return true; return true;
} }
if (offset.Z > 0) d.AABB aabb;
d.GeomGetAABB(other,out aabb);
float othertop = aabb.MaxZ - _position.Z;
if (offset.Z > 0 || othertop > -feetOff || contact.normal.Z > 0.35f)
{
if (offset.Z <= 0)
{
feetcollision = true;
if (h < boneOff)
{
m_collideNormal.X = contact.normal.X;
m_collideNormal.Y = contact.normal.Y;
m_collideNormal.Z = contact.normal.Z;
IsColliding = true;
}
}
if (contact.normal.Z < 0.2f)
{
contact.normal.Z = 0;
float t = contact.normal.X * contact.normal.X + contact.normal.Y * contact.normal.Y;
if (t > 0)
{
t = 1.0f / t;
contact.normal.X *= t;
contact.normal.Y *= t;
}
}
return true; return true;
}
altContact = contact;
useAltcontact = true;
offset.Normalize(); offset.Normalize();
if (contact.depth > 0.1f)
contact.depth = 0.1f;
if (reverse) if (reverse)
{ {
contact.normal.X = offset.X; altContact.normal.X = offset.X;
contact.normal.Y = offset.Y; altContact.normal.Y = offset.Y;
contact.normal.Z = offset.Z; altContact.normal.Z = offset.Z;
} }
else else
{ {
contact.normal.X = -offset.X; altContact.normal.X = -offset.X;
contact.normal.Y = -offset.Y; altContact.normal.Y = -offset.Y;
contact.normal.Z = -offset.Z; altContact.normal.Z = -offset.Z;
} }
feetcollision = true; feetcollision = true;
if (h < boneOff) if (h < boneOff)
{
m_collideNormal.X = contact.normal.X;
m_collideNormal.Y = contact.normal.Y;
m_collideNormal.Z = contact.normal.Z;
IsColliding = true; IsColliding = true;
}
return true; return true;
} }
return false; return false;
@ -1003,6 +1050,9 @@ namespace OpenSim.Region.Physics.OdePlugin
Vector3 vel = new Vector3(dtmp.X, dtmp.Y, dtmp.Z); Vector3 vel = new Vector3(dtmp.X, dtmp.Y, dtmp.Z);
float velLengthSquared = vel.LengthSquared(); float velLengthSquared = vel.LengthSquared();
Vector3 ctz = _target_velocity;
float movementdivisor = 1f; float movementdivisor = 1f;
//Ubit change divisions into multiplications below //Ubit change divisions into multiplications below
if (!m_alwaysRun) if (!m_alwaysRun)
@ -1010,13 +1060,16 @@ namespace OpenSim.Region.Physics.OdePlugin
else else
movementdivisor = 1 / runDivisor; movementdivisor = 1 / runDivisor;
ctz.X *= movementdivisor;
ctz.Y *= movementdivisor;
//****************************************** //******************************************
// colide with land // colide with land
d.AABB aabb; d.AABB aabb;
// d.GeomGetAABB(feetbox, out aabb); // d.GeomGetAABB(feetbox, out aabb);
d.GeomGetAABB(capsule, out aabb); d.GeomGetAABB(capsule, out aabb);
float chrminZ = aabb.MinZ; ; // move up a bit float chrminZ = aabb.MinZ; // move up a bit
Vector3 posch = localpos; Vector3 posch = localpos;
float ftmp; float ftmp;
@ -1031,15 +1084,18 @@ namespace OpenSim.Region.Physics.OdePlugin
float terrainheight = _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y); float terrainheight = _parent_scene.GetTerrainHeightAtXY(posch.X, posch.Y);
if (chrminZ < terrainheight) if (chrminZ < terrainheight)
{ {
if (ctz.Z < 0)
ctz.Z = 0;
Vector3 n = _parent_scene.GetTerrainNormalAtXY(posch.X, posch.Y);
float depth = terrainheight - chrminZ; float depth = terrainheight - chrminZ;
if (!flying)
{
vec.Z = -vel.Z * PID_D * 1.5f + depth * PID_P * 50;
}
else
vec.Z = depth * PID_P * 50; vec.Z = depth * PID_P * 50;
if (depth < 0.1f) if (!flying)
vec.Z += -vel.Z * PID_D;
if (depth < 0.2f)
{ {
m_colliderGroundfilter++; m_colliderGroundfilter++;
if (m_colliderGroundfilter > 2) if (m_colliderGroundfilter > 2)
@ -1053,50 +1109,83 @@ namespace OpenSim.Region.Physics.OdePlugin
m_freemove = false; m_freemove = false;
} }
m_collideNormal.X = n.X;
m_collideNormal.Y = n.Y;
m_collideNormal.Z = n.Z;
m_iscollidingGround = true; m_iscollidingGround = true;
ContactPoint contact = new ContactPoint(); ContactPoint contact = new ContactPoint();
contact.PenetrationDepth = depth; contact.PenetrationDepth = depth;
contact.Position.X = localpos.X; contact.Position.X = localpos.X;
contact.Position.Y = localpos.Y; contact.Position.Y = localpos.Y;
contact.Position.Z = terrainheight; contact.Position.Z = terrainheight;
contact.SurfaceNormal.X = 0.0f; contact.SurfaceNormal.X = -n.X;
contact.SurfaceNormal.Y = 0.0f; contact.SurfaceNormal.Y = -n.Y;
contact.SurfaceNormal.Z = -1f; contact.SurfaceNormal.Z = -n.Z;
contact.RelativeSpeed = -vel.Z; contact.RelativeSpeed = -vel.Z;
contact.CharacterFeet = true; contact.CharacterFeet = true;
AddCollisionEvent(0, contact); AddCollisionEvent(0, contact);
vec.Z *= 0.5f; // vec.Z *= 0.5f;
} }
} }
else else
{
m_colliderGroundfilter -= 5;
if (m_colliderGroundfilter <= 0)
{ {
m_colliderGroundfilter = 0; m_colliderGroundfilter = 0;
m_iscollidingGround = false; m_iscollidingGround = false;
} }
} }
}
else else
{
m_colliderGroundfilter -= 5;
if (m_colliderGroundfilter <= 0)
{ {
m_colliderGroundfilter = 0; m_colliderGroundfilter = 0;
m_iscollidingGround = false; m_iscollidingGround = false;
} }
}
//****************************************** //******************************************
if (!m_iscolliding)
m_collideNormal.Z = 0;
bool tviszero = (ctz.X == 0.0f && ctz.Y == 0.0f && ctz.Z == 0.0f);
bool tviszero = (_target_velocity.X == 0.0f && _target_velocity.Y == 0.0f && _target_velocity.Z == 0.0f);
// if (!tviszero || m_iscolliding || velLengthSquared <0.01)
if (!tviszero) if (!tviszero)
{
m_freemove = false; m_freemove = false;
// movement relative to surface if moving on it
// dont disturbe vertical movement, ie jumps
if (m_iscolliding && !flying && ctz.Z == 0 && m_collideNormal.Z > 0.2f && m_collideNormal.Z < 0.94f)
{
float p = ctz.X * m_collideNormal.X + ctz.Y * m_collideNormal.Y;
ctz.X *= (float)Math.Sqrt(1 - m_collideNormal.X * m_collideNormal.X);
ctz.Y *= (float)Math.Sqrt(1 - m_collideNormal.Y * m_collideNormal.Y);
ctz.Z -= p;
if (ctz.Z < 0)
ctz.Z *= 2;
}
}
if (!m_freemove) if (!m_freemove)
{ {
// if velocity is zero, use position control; otherwise, velocity control // if velocity is zero, use position control; otherwise, velocity control
if (tviszero && m_iscolliding) if (tviszero && m_iscolliding && !flying)
{ {
// keep track of where we stopped. No more slippin' & slidin' // keep track of where we stopped. No more slippin' & slidin'
if (!_zeroFlag) if (!_zeroFlag)
@ -1129,22 +1218,48 @@ namespace OpenSim.Region.Physics.OdePlugin
{ {
if (!flying) if (!flying)
{ {
if (_target_velocity.Z > 0.0f) // we are on a surface
if (ctz.Z > 0f)
{ {
// We're colliding with something and we're not flying but we're moving // moving up or JUMPING
// This means we're walking or running. JUMPING vec.Z += (ctz.Z - vel.Z) * PID_D * 1.2f;// +(_zeroPosition.Z - localpos.Z) * PID_P;
vec.Z += (_target_velocity.Z - vel.Z) * PID_D * 1.2f;// +(_zeroPosition.Z - localpos.Z) * PID_P; vec.X += (ctz.X - vel.X) * (PID_D);
vec.Y += (ctz.Y - vel.Y) * (PID_D);
} }
else
{
// we are moving down on a surface
if (ctz.Z == 0)
{
if (vel.Z > 0)
vec.Z -= vel.Z * PID_D * 2.0f;
vec.X += (ctz.X - vel.X) * (PID_D);
vec.Y += (ctz.Y - vel.Y) * (PID_D);
}
// intencionally going down
else
{
if (ctz.Z < vel.Z)
vec.Z += (ctz.Z - vel.Z) * PID_D * 2.0f;
else
{
}
if (Math.Abs(ctz.X) > Math.Abs(vel.X))
vec.X += (ctz.X - vel.X) * (PID_D);
if (Math.Abs(ctz.Y) > Math.Abs(vel.Y))
vec.Y += (ctz.Y - vel.Y) * (PID_D);
}
}
// We're standing on something // 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 else
{ {
// We're flying and colliding with something // We're flying and colliding with something
vec.X = ((_target_velocity.X * movementdivisor) - vel.X) * (PID_D * 0.0625f); vec.X += (ctz.X - vel.X) * (PID_D * 0.0625f);
vec.Y = ((_target_velocity.Y * movementdivisor) - vel.Y) * (PID_D * 0.0625f); vec.Y += (ctz.Y - vel.Y) * (PID_D * 0.0625f);
vec.Z += (_target_velocity.Z - vel.Z) * (PID_D); vec.Z += (ctz.Z - vel.Z) * (PID_D);
} }
} }
else // ie not colliding else // ie not colliding
@ -1152,9 +1267,9 @@ namespace OpenSim.Region.Physics.OdePlugin
if (flying) //(!m_iscolliding && flying) if (flying) //(!m_iscolliding && flying)
{ {
// we're in mid air suspended // we're in mid air suspended
vec.X = ((_target_velocity.X * movementdivisor) - vel.X) * (PID_D * 1.667f); vec.X += (ctz.X - vel.X) * (PID_D * 1.667f);
vec.Y = ((_target_velocity.Y * movementdivisor) - vel.Y) * (PID_D * 1.667f); vec.Y += (ctz.Y - vel.Y) * (PID_D * 1.667f);
vec.Z += (_target_velocity.Z - vel.Z) * (PID_D); vec.Z += (ctz.Z - vel.Z) * (PID_D);
} }
else else
@ -1163,8 +1278,11 @@ namespace OpenSim.Region.Physics.OdePlugin
// m_iscolliding includes collisions with the ground. // m_iscolliding includes collisions with the ground.
// d.Vector3 pos = d.BodyGetPosition(Body); // d.Vector3 pos = d.BodyGetPosition(Body);
vec.X = (_target_velocity.X - vel.X) * PID_D * 0.833f; vec.X += (ctz.X - vel.X) * PID_D * 0.833f;
vec.Y = (_target_velocity.Y - vel.Y) * PID_D * 0.833f; vec.Y += (ctz.Y - vel.Y) * PID_D * 0.833f;
// hack for breaking on fall
if (ctz.Z == -9999f)
vec.Z += -vel.Z * PID_D - _parent_scene.gravityz * m_mass;
} }
} }
} }

View File

@ -935,18 +935,22 @@ namespace OpenSim.Region.Physics.OdePlugin
SharedTmpcontact.surface.mu = mu; SharedTmpcontact.surface.mu = mu;
SharedTmpcontact.surface.bounce = bounce; SharedTmpcontact.surface.bounce = bounce;
d.ContactGeom altContact = new d.ContactGeom();
bool useAltcontact = false;
bool noskip = true;
while (true) while (true)
{ {
// if (!(IgnoreNegSides && curContact.side1 < 0)) // if (!(IgnoreNegSides && curContact.side1 < 0))
{ {
bool noskip = true; noskip = true;
useAltcontact = false;
if (dop1ava) if (dop1ava)
{ {
if (!(((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref FeetCollision))) if ((((OdeCharacter)p1).Collide(g1, g2, false, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
noskip = false;
else
{ {
if(p2.PhysicsActorType == (int)ActorTypes.Agent) if (p2.PhysicsActorType == (int)ActorTypes.Agent)
{ {
p1.CollidingObj = true; p1.CollidingObj = true;
p2.CollidingObj = true; p2.CollidingObj = true;
@ -954,18 +958,32 @@ namespace OpenSim.Region.Physics.OdePlugin
else if (p2.Velocity.LengthSquared() > 0.0f) else if (p2.Velocity.LengthSquared() > 0.0f)
p2.CollidingObj = true; p2.CollidingObj = true;
} }
else
noskip = false;
} }
else if (dop2ava) else if (dop2ava)
{ {
if (!(((OdeCharacter)p2).Collide(g2,g1, true, ref curContact, ref FeetCollision))) if ((((OdeCharacter)p2).Collide(g2, g1, true, ref curContact, ref altContact , ref useAltcontact, ref FeetCollision)))
noskip = false; {
else if (p1.Velocity.LengthSquared() > 0.0f) if (p1.PhysicsActorType == (int)ActorTypes.Agent)
{
p1.CollidingObj = true; p1.CollidingObj = true;
p2.CollidingObj = true;
}
else if (p2.Velocity.LengthSquared() > 0.0f)
p1.CollidingObj = true;
}
else
noskip = false;
} }
if (noskip) if (noskip)
{ {
if(useAltcontact)
Joint = CreateContacJoint(ref altContact);
else
Joint = CreateContacJoint(ref curContact); Joint = CreateContacJoint(ref curContact);
if (Joint == IntPtr.Zero) if (Joint == IntPtr.Zero)
break; break;
@ -1924,12 +1942,12 @@ namespace OpenSim.Region.Physics.OdePlugin
dy = 0; dy = 0;
} }
} }
else else
{ {
// we still have square fixed size regions // we still have square fixed size regions
// also flip x and y because of how map is done for ODE fliped axis // also flip x and y because of how map is done for ODE fliped axis
// so ix,iy,dx and dy are inter exchanged // so ix,iy,dx and dy are inter exchanged
if (x < regsize - 1) if (x < regsize - 1)
{ {
iy = (int)x; iy = (int)x;
@ -1976,7 +1994,7 @@ namespace OpenSim.Region.Physics.OdePlugin
*/ */
h0 = ((float)heights[iy]); // 0,0 vertice h0 = ((float)heights[iy]); // 0,0 vertice
if ((dy > dx)) if (dy>dx)
{ {
iy += regsize; iy += regsize;
h2 = (float)heights[iy]; // 0,1 vertice h2 = (float)heights[iy]; // 0,1 vertice
@ -1994,6 +2012,133 @@ namespace OpenSim.Region.Physics.OdePlugin
return h0 + h1 + h2; return h0 + h1 + h2;
} }
public Vector3 GetTerrainNormalAtXY(float x, float y)
{
int offsetX = ((int)(x / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
int offsetY = ((int)(y / (int)Constants.RegionSize)) * (int)Constants.RegionSize;
IntPtr heightFieldGeom = IntPtr.Zero;
Vector3 norm = new Vector3(0, 0, 1);
// get region map
if (!RegionTerrain.TryGetValue(new Vector3(offsetX, offsetY, 0), out heightFieldGeom))
return norm;
if (heightFieldGeom == IntPtr.Zero)
return norm;
if (!TerrainHeightFieldHeights.ContainsKey(heightFieldGeom))
return norm;
// TerrainHeightField for ODE as offset 1m
x += 1f - offsetX;
y += 1f - offsetY;
// make position fit into array
if (x < 0)
x = 0;
if (y < 0)
y = 0;
// integer indexs
int ix;
int iy;
// interpolators offset
float dx;
float dy;
int regsize = (int)Constants.RegionSize + 3; // map size see setterrain number of samples
int xstep = 1;
int ystep = regsize;
bool firstTri = false;
if (OdeUbitLib)
{
if (x < regsize - 1)
{
ix = (int)x;
dx = x - (float)ix;
}
else // out world use external height
{
ix = regsize - 2;
dx = 0;
}
if (y < regsize - 1)
{
iy = (int)y;
dy = y - (float)iy;
}
else
{
iy = regsize - 2;
dy = 0;
}
firstTri = dy > dx;
}
else
{
xstep = regsize;
ystep = 1;
// we still have square fixed size regions
// also flip x and y because of how map is done for ODE fliped axis
// so ix,iy,dx and dy are inter exchanged
if (x < regsize - 1)
{
iy = (int)x;
dy = x - (float)iy;
}
else // out world use external height
{
iy = regsize - 2;
dy = 0;
}
if (y < regsize - 1)
{
ix = (int)y;
dx = y - (float)ix;
}
else
{
ix = regsize - 2;
dx = 0;
}
firstTri = dx > dy;
}
float h0;
float h1;
float h2;
iy *= regsize;
iy += ix; // all indexes have iy + ix
float[] heights = TerrainHeightFieldHeights[heightFieldGeom];
if (firstTri)
{
h1 = ((float)heights[iy]); // 0,0 vertice
iy += ystep;
h0 = (float)heights[iy]; // 0,1
h2 = (float)heights[iy+xstep]; // 1,1 vertice
norm.X = h0 - h2;
norm.Y = h1 - h0;
}
else
{
h2 = ((float)heights[iy]); // 0,0 vertice
iy += xstep;
h0 = ((float)heights[iy]); // 1,0 vertice
h1 = (float)heights[iy+ystep]; // vertice 1,1
norm.X = h2 - h0;
norm.Y = h0 - h1;
}
norm.Z = 1;
norm.Normalize();
return norm;
}
public override void SetTerrain(float[] heightMap) public override void SetTerrain(float[] heightMap)
{ {