BulletSim: complete movement of physical object action code out of the
physical object and into actors for setForce, setTorque, hover, lock axis and avatar move.user_profiles
parent
c7cd077e55
commit
fe16dc09da
|
@ -0,0 +1,287 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OMV = OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public class BSActorAvatarMove : BSActor
|
||||
{
|
||||
BSVMotor m_velocityMotor;
|
||||
|
||||
public BSActorAvatarMove(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_velocityMotor = null;
|
||||
m_physicsScene.DetailLog("{0},BSActorAvatarMove,constructor", m_controllingPrim.LocalID);
|
||||
}
|
||||
|
||||
// BSActor.isActive
|
||||
public override bool isActive
|
||||
{
|
||||
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||
}
|
||||
|
||||
// Release any connections and resources used by the actor.
|
||||
// BSActor.Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||
// Called at taint-time.
|
||||
// BSActor.Refresh()
|
||||
public override void Refresh()
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh", m_controllingPrim.LocalID);
|
||||
|
||||
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||
if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorAvatarMove,refresh,notAvatarMove,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the object is physically active, add the hoverer prestep action
|
||||
if (isActive)
|
||||
{
|
||||
ActivateAvatarMove();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateAvatarMove();
|
||||
}
|
||||
}
|
||||
|
||||
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||
// Called at taint-time.
|
||||
// BSActor.RemoveBodyDependencies()
|
||||
public override void RemoveBodyDependencies()
|
||||
{
|
||||
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||
}
|
||||
|
||||
public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
|
||||
{
|
||||
m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
|
||||
{
|
||||
m_velocityMotor.Reset();
|
||||
m_velocityMotor.SetTarget(targ);
|
||||
m_velocityMotor.SetCurrent(vel);
|
||||
m_velocityMotor.Enabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
// If a hover motor has not been created, create one and start the hovering.
|
||||
private void ActivateAvatarMove()
|
||||
{
|
||||
if (m_velocityMotor == null)
|
||||
{
|
||||
// Infinite decay and timescale values so motor only changes current to target values.
|
||||
m_velocityMotor = new BSVMotor("BSCharacter.Velocity",
|
||||
0.2f, // time scale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.InfiniteVector, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
|
||||
m_physicsScene.BeforeStep += Mover;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateAvatarMove()
|
||||
{
|
||||
if (m_velocityMotor != null)
|
||||
{
|
||||
m_physicsScene.BeforeStep -= Mover;
|
||||
m_velocityMotor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||
private void Mover(float timeStep)
|
||||
{
|
||||
// Don't do movement while the object is selected.
|
||||
if (!isActive)
|
||||
return;
|
||||
|
||||
// TODO: Decide if the step parameters should be changed depending on the avatar's
|
||||
// state (flying, colliding, ...). There is code in ODE to do this.
|
||||
|
||||
// COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
|
||||
// specified for the avatar is the one that should be used. For falling, if the avatar
|
||||
// is not flying and is not colliding then it is presumed to be falling and the Z
|
||||
// component is not fooled with (thus allowing gravity to do its thing).
|
||||
// When the avatar is standing, though, the user has specified a velocity of zero and
|
||||
// the avatar should be standing. But if the avatar is pushed by something in the world
|
||||
// (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
|
||||
// move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
|
||||
// errors can creap in and the avatar will slowly float off in some direction.
|
||||
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
|
||||
// from real pushing.
|
||||
// The code below uses whether the collider is static or moving to decide whether to zero motion.
|
||||
|
||||
m_velocityMotor.Step(timeStep);
|
||||
m_controllingPrim.IsStationary = false;
|
||||
|
||||
// If we're not supposed to be moving, make sure things are zero.
|
||||
if (m_velocityMotor.ErrorIsZero() && m_velocityMotor.TargetValue == OMV.Vector3.Zero)
|
||||
{
|
||||
// The avatar shouldn't be moving
|
||||
m_velocityMotor.Zero();
|
||||
|
||||
if (m_controllingPrim.IsColliding)
|
||||
{
|
||||
// If we are colliding with a stationary object, presume we're standing and don't move around
|
||||
if (!m_controllingPrim.ColliderIsMoving)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", m_controllingPrim.LocalID);
|
||||
m_controllingPrim.IsStationary = true;
|
||||
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
||||
}
|
||||
|
||||
// Standing has more friction on the ground
|
||||
if (m_controllingPrim.Friction != BSParam.AvatarStandingFriction)
|
||||
{
|
||||
m_controllingPrim.Friction = BSParam.AvatarStandingFriction;
|
||||
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_controllingPrim.Flying)
|
||||
{
|
||||
// Flying and not collising and velocity nearly zero.
|
||||
m_controllingPrim.ZeroMotion(true /* inTaintTime */);
|
||||
}
|
||||
}
|
||||
|
||||
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}",
|
||||
m_controllingPrim.LocalID, m_velocityMotor.TargetValue, m_controllingPrim.IsColliding);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Supposed to be moving.
|
||||
OMV.Vector3 stepVelocity = m_velocityMotor.CurrentValue;
|
||||
|
||||
if (m_controllingPrim.Friction != BSParam.AvatarFriction)
|
||||
{
|
||||
// Probably starting up walking. Set friction to moving friction.
|
||||
m_controllingPrim.Friction = BSParam.AvatarFriction;
|
||||
m_physicsScene.PE.SetFriction(m_controllingPrim.PhysBody, m_controllingPrim.Friction);
|
||||
}
|
||||
|
||||
// If falling, we keep the world's downward vector no matter what the other axis specify.
|
||||
// The check for RawVelocity.Z < 0 makes jumping work (temporary upward force).
|
||||
if (!m_controllingPrim.Flying && !m_controllingPrim.IsColliding)
|
||||
{
|
||||
if (m_controllingPrim.RawVelocity.Z < 0)
|
||||
stepVelocity.Z = m_controllingPrim.RawVelocity.Z;
|
||||
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
|
||||
}
|
||||
|
||||
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
|
||||
OMV.Vector3 moveForce = (stepVelocity - m_controllingPrim.RawVelocity) * m_controllingPrim.Mass;
|
||||
|
||||
// Should we check for move force being small and forcing velocity to zero?
|
||||
|
||||
// Add special movement force to allow avatars to walk up stepped surfaces.
|
||||
moveForce += WalkUpStairs();
|
||||
|
||||
m_physicsScene.DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}",
|
||||
m_controllingPrim.LocalID, stepVelocity, m_controllingPrim.RawVelocity, m_controllingPrim.Mass, moveForce);
|
||||
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, moveForce);
|
||||
}
|
||||
}
|
||||
|
||||
// Decide if the character is colliding with a low object and compute a force to pop the
|
||||
// avatar up so it can walk up and over the low objects.
|
||||
private OMV.Vector3 WalkUpStairs()
|
||||
{
|
||||
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||
|
||||
// This test is done if moving forward, not flying and is colliding with something.
|
||||
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
|
||||
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
|
||||
if (m_controllingPrim.IsColliding && !m_controllingPrim.Flying && m_controllingPrim.TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
|
||||
{
|
||||
// The range near the character's feet where we will consider stairs
|
||||
float nearFeetHeightMin = m_controllingPrim.RawPosition.Z - (m_controllingPrim.Size.Z / 2f) + 0.05f;
|
||||
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
|
||||
|
||||
// Look for a collision point that is near the character's feet and is oriented the same as the charactor is
|
||||
foreach (KeyValuePair<uint, ContactPoint> kvp in m_controllingPrim.CollisionsLastTick.m_objCollisionList)
|
||||
{
|
||||
// Don't care about collisions with the terrain
|
||||
if (kvp.Key > m_physicsScene.TerrainManager.HighestTerrainID)
|
||||
{
|
||||
OMV.Vector3 touchPosition = kvp.Value.Position;
|
||||
// DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
|
||||
// LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
|
||||
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
|
||||
{
|
||||
// This contact is within the 'near the feet' range.
|
||||
// The normal should be our contact point to the object so it is pointing away
|
||||
// thus the difference between our facing orientation and the normal should be small.
|
||||
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * m_controllingPrim.RawOrientation;
|
||||
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
|
||||
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
|
||||
if (diff < BSParam.AvatarStepApproachFactor)
|
||||
{
|
||||
// Found the stairs contact point. Push up a little to raise the character.
|
||||
float upForce = (touchPosition.Z - nearFeetHeightMin) * m_controllingPrim.Mass * BSParam.AvatarStepForceFactor;
|
||||
ret = new OMV.Vector3(0f, 0f, upForce);
|
||||
|
||||
// Also move the avatar up for the new height
|
||||
OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
|
||||
m_controllingPrim.ForcePosition = m_controllingPrim.RawPosition + displacement;
|
||||
}
|
||||
m_physicsScene.DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
|
||||
m_controllingPrim.LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OMV = OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public class BSActorHover : BSActor
|
||||
{
|
||||
private BSFMotor m_hoverMotor;
|
||||
|
||||
public BSActorHover(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_hoverMotor = null;
|
||||
m_physicsScene.DetailLog("{0},BSActorHover,constructor", m_controllingPrim.LocalID);
|
||||
}
|
||||
|
||||
// BSActor.isActive
|
||||
public override bool isActive
|
||||
{
|
||||
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||
}
|
||||
|
||||
// Release any connections and resources used by the actor.
|
||||
// BSActor.Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||
// Called at taint-time.
|
||||
// BSActor.Refresh()
|
||||
public override void Refresh()
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorHover,refresh", m_controllingPrim.LocalID);
|
||||
|
||||
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||
if (!m_controllingPrim.HoverActive)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorHover,refresh,notHovering,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the object is physically active, add the hoverer prestep action
|
||||
if (isActive)
|
||||
{
|
||||
ActivateHover();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateHover();
|
||||
}
|
||||
}
|
||||
|
||||
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||
// Called at taint-time.
|
||||
// BSActor.RemoveBodyDependencies()
|
||||
public override void RemoveBodyDependencies()
|
||||
{
|
||||
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||
}
|
||||
|
||||
// If a hover motor has not been created, create one and start the hovering.
|
||||
private void ActivateHover()
|
||||
{
|
||||
if (m_hoverMotor == null)
|
||||
{
|
||||
// Turning the target on
|
||||
m_hoverMotor = new BSFMotor("BSActorHover",
|
||||
m_controllingPrim.HoverTau, // timeScale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.Infinite, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
|
||||
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
|
||||
m_hoverMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
|
||||
m_physicsScene.BeforeStep += Hoverer;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateHover()
|
||||
{
|
||||
if (m_hoverMotor != null)
|
||||
{
|
||||
m_physicsScene.BeforeStep -= Hoverer;
|
||||
m_hoverMotor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||
private void Hoverer(float timeStep)
|
||||
{
|
||||
// Don't do hovering while the object is selected.
|
||||
if (!isActive)
|
||||
return;
|
||||
|
||||
m_hoverMotor.SetCurrent(m_controllingPrim.RawPosition.Z);
|
||||
m_hoverMotor.SetTarget(ComputeCurrentHoverHeight());
|
||||
float targetHeight = m_hoverMotor.Step(timeStep);
|
||||
|
||||
// 'targetHeight' is where we'd like the Z of the prim to be at this moment.
|
||||
// Compute the amount of force to push us there.
|
||||
float moveForce = (targetHeight - m_controllingPrim.RawPosition.Z) * m_controllingPrim.RawMass;
|
||||
// Undo anything the object thinks it's doing at the moment
|
||||
moveForce = -m_controllingPrim.RawVelocity.Z * m_controllingPrim.Mass;
|
||||
|
||||
m_physicsScene.PE.ApplyCentralImpulse(m_controllingPrim.PhysBody, new OMV.Vector3(0f, 0f, moveForce));
|
||||
m_physicsScene.DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}",
|
||||
m_controllingPrim.LocalID, targetHeight, moveForce, m_controllingPrim.RawMass);
|
||||
}
|
||||
|
||||
// Based on current position, determine what we should be hovering at now.
|
||||
// Must recompute often. What if we walked offa cliff>
|
||||
private float ComputeCurrentHoverHeight()
|
||||
{
|
||||
float ret = m_controllingPrim.HoverHeight;
|
||||
float groundHeight = m_physicsScene.TerrainManager.GetTerrainHeightAtXYZ(m_controllingPrim.RawPosition);
|
||||
|
||||
switch (m_controllingPrim.HoverType)
|
||||
{
|
||||
case PIDHoverType.Ground:
|
||||
ret = groundHeight + m_controllingPrim.HoverHeight;
|
||||
break;
|
||||
case PIDHoverType.GroundAndWater:
|
||||
float waterHeight = m_physicsScene.TerrainManager.GetWaterLevelAtXYZ(m_controllingPrim.RawPosition);
|
||||
if (groundHeight > waterHeight)
|
||||
{
|
||||
ret = groundHeight + m_controllingPrim.HoverHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = waterHeight + m_controllingPrim.HoverHeight;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public class BSActorLockAxis : BSActor
|
|||
BSConstraint LockAxisConstraint = null;
|
||||
|
||||
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj,actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
|
||||
LockAxisConstraint = null;
|
||||
|
@ -99,7 +99,7 @@ public class BSActorLockAxis : BSActor
|
|||
// If a constraint is set up, remove it from the physical scene
|
||||
RemoveAxisLockConstraint();
|
||||
// Schedule a call before the next simulation step to restore the constraint.
|
||||
m_physicsScene.PostTaintObject(m_controllingPrim.LockedAxisActorName, m_controllingPrim.LocalID, delegate()
|
||||
m_physicsScene.PostTaintObject("BSActorLockAxis:" + ActorName, m_controllingPrim.LocalID, delegate()
|
||||
{
|
||||
Refresh();
|
||||
});
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OMV = OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public class BSActorMoveToTarget : BSActor
|
||||
{
|
||||
private BSVMotor m_targetMotor;
|
||||
|
||||
public BSActorMoveToTarget(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_targetMotor = null;
|
||||
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,constructor", m_controllingPrim.LocalID);
|
||||
}
|
||||
|
||||
// BSActor.isActive
|
||||
public override bool isActive
|
||||
{
|
||||
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||
}
|
||||
|
||||
// Release any connections and resources used by the actor.
|
||||
// BSActor.Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||
// Called at taint-time.
|
||||
// BSActor.Refresh()
|
||||
public override void Refresh()
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh", m_controllingPrim.LocalID);
|
||||
|
||||
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||
if (!m_controllingPrim.HoverActive)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorMoveToTarget,refresh,notMoveToTarget,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the object is physically active, add the hoverer prestep action
|
||||
if (isActive)
|
||||
{
|
||||
ActivateMoveToTarget();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateMoveToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||
// Called at taint-time.
|
||||
// BSActor.RemoveBodyDependencies()
|
||||
public override void RemoveBodyDependencies()
|
||||
{
|
||||
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||
}
|
||||
|
||||
// If a hover motor has not been created, create one and start the hovering.
|
||||
private void ActivateMoveToTarget()
|
||||
{
|
||||
if (m_targetMotor == null)
|
||||
{
|
||||
// We're taking over after this.
|
||||
m_controllingPrim.ZeroMotion(true);
|
||||
|
||||
m_targetMotor = new BSVMotor("BSPrim.PIDTarget",
|
||||
m_controllingPrim.MoveToTargetTau, // timeScale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.InfiniteVector, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
m_targetMotor.PhysicsScene = m_physicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
m_targetMotor.SetTarget(m_controllingPrim.MoveToTargetTarget);
|
||||
m_targetMotor.SetCurrent(m_controllingPrim.RawPosition);
|
||||
|
||||
m_physicsScene.BeforeStep += Mover;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateMoveToTarget()
|
||||
{
|
||||
if (m_targetMotor != null)
|
||||
{
|
||||
m_physicsScene.BeforeStep -= Mover;
|
||||
m_targetMotor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||
private void Mover(float timeStep)
|
||||
{
|
||||
// Don't do hovering while the object is selected.
|
||||
if (!isActive)
|
||||
return;
|
||||
|
||||
OMV.Vector3 origPosition = m_controllingPrim.RawPosition; // DEBUG DEBUG (for printout below)
|
||||
|
||||
// 'movePosition' is where we'd like the prim to be at this moment.
|
||||
OMV.Vector3 movePosition = m_controllingPrim.RawPosition + m_targetMotor.Step(timeStep);
|
||||
|
||||
// If we are very close to our target, turn off the movement motor.
|
||||
if (m_targetMotor.ErrorIsZero())
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
|
||||
m_controllingPrim.LocalID, movePosition, m_controllingPrim.RawPosition, m_controllingPrim.Mass);
|
||||
m_controllingPrim.ForcePosition = m_targetMotor.TargetValue;
|
||||
m_targetMotor.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_controllingPrim.ForcePosition = movePosition;
|
||||
}
|
||||
m_physicsScene.DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", m_controllingPrim.LocalID, origPosition, movePosition);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OMV = OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public class BSActorSetForce : BSActor
|
||||
{
|
||||
BSFMotor m_forceMotor;
|
||||
|
||||
public BSActorSetForce(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_forceMotor = null;
|
||||
m_physicsScene.DetailLog("{0},BSActorSetForce,constructor", m_controllingPrim.LocalID);
|
||||
}
|
||||
|
||||
// BSActor.isActive
|
||||
public override bool isActive
|
||||
{
|
||||
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||
}
|
||||
|
||||
// Release any connections and resources used by the actor.
|
||||
// BSActor.Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||
// Called at taint-time.
|
||||
// BSActor.Refresh()
|
||||
public override void Refresh()
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh", m_controllingPrim.LocalID);
|
||||
|
||||
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||
if (m_controllingPrim.RawForce == OMV.Vector3.Zero)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorSetForce,refresh,notSetForce,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the object is physically active, add the hoverer prestep action
|
||||
if (isActive)
|
||||
{
|
||||
ActivateSetForce();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateSetForce();
|
||||
}
|
||||
}
|
||||
|
||||
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||
// Called at taint-time.
|
||||
// BSActor.RemoveBodyDependencies()
|
||||
public override void RemoveBodyDependencies()
|
||||
{
|
||||
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||
}
|
||||
|
||||
// If a hover motor has not been created, create one and start the hovering.
|
||||
private void ActivateSetForce()
|
||||
{
|
||||
if (m_forceMotor == null)
|
||||
{
|
||||
// A fake motor that might be used someday
|
||||
m_forceMotor = new BSFMotor("setForce", 1f, 1f, 1f, 1f);
|
||||
|
||||
m_physicsScene.BeforeStep += Mover;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateSetForce()
|
||||
{
|
||||
if (m_forceMotor != null)
|
||||
{
|
||||
m_physicsScene.BeforeStep -= Mover;
|
||||
m_forceMotor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||
private void Mover(float timeStep)
|
||||
{
|
||||
// Don't do force while the object is selected.
|
||||
if (!isActive)
|
||||
return;
|
||||
|
||||
m_physicsScene.DetailLog("{0},BSActorSetForce,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawForce);
|
||||
if (m_controllingPrim.PhysBody.HasPhysicalBody)
|
||||
{
|
||||
m_physicsScene.PE.ApplyCentralForce(m_controllingPrim.PhysBody, m_controllingPrim.RawForce);
|
||||
m_controllingPrim.ActivateIfPhysical(false);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyrightD
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
|
||||
using OMV = OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
{
|
||||
public class BSActorSetTorque : BSActor
|
||||
{
|
||||
BSFMotor m_torqueMotor;
|
||||
|
||||
public BSActorSetTorque(BSScene physicsScene, BSPhysObject pObj, string actorName)
|
||||
: base(physicsScene, pObj, actorName)
|
||||
{
|
||||
m_torqueMotor = null;
|
||||
m_physicsScene.DetailLog("{0},BSActorSetTorque,constructor", m_controllingPrim.LocalID);
|
||||
}
|
||||
|
||||
// BSActor.isActive
|
||||
public override bool isActive
|
||||
{
|
||||
get { return Enabled && m_controllingPrim.IsPhysicallyActive; }
|
||||
}
|
||||
|
||||
// Release any connections and resources used by the actor.
|
||||
// BSActor.Dispose()
|
||||
public override void Dispose()
|
||||
{
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
// Called when physical parameters (properties set in Bullet) need to be re-applied.
|
||||
// Called at taint-time.
|
||||
// BSActor.Refresh()
|
||||
public override void Refresh()
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh", m_controllingPrim.LocalID);
|
||||
|
||||
// If not active any more, get rid of me (shouldn't ever happen, but just to be safe)
|
||||
if (m_controllingPrim.RawTorque == OMV.Vector3.Zero)
|
||||
{
|
||||
m_physicsScene.DetailLog("{0},BSActorSetTorque,refresh,notSetTorque,removing={1}", m_controllingPrim.LocalID, ActorName);
|
||||
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
|
||||
return;
|
||||
}
|
||||
|
||||
// If the object is physically active, add the hoverer prestep action
|
||||
if (isActive)
|
||||
{
|
||||
ActivateSetTorque();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeactivateSetTorque();
|
||||
}
|
||||
}
|
||||
|
||||
// The object's physical representation is being rebuilt so pick up any physical dependencies (constraints, ...).
|
||||
// Register a prestep action to restore physical requirements before the next simulation step.
|
||||
// Called at taint-time.
|
||||
// BSActor.RemoveBodyDependencies()
|
||||
public override void RemoveBodyDependencies()
|
||||
{
|
||||
// Nothing to do for the hoverer since it is all software at pre-step action time.
|
||||
}
|
||||
|
||||
// If a hover motor has not been created, create one and start the hovering.
|
||||
private void ActivateSetTorque()
|
||||
{
|
||||
if (m_torqueMotor == null)
|
||||
{
|
||||
// A fake motor that might be used someday
|
||||
m_torqueMotor = new BSFMotor("setTorque", 1f, 1f, 1f, 1f);
|
||||
|
||||
m_physicsScene.BeforeStep += Mover;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeactivateSetTorque()
|
||||
{
|
||||
if (m_torqueMotor != null)
|
||||
{
|
||||
m_physicsScene.BeforeStep -= Mover;
|
||||
m_torqueMotor = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Called just before the simulation step. Update the vertical position for hoverness.
|
||||
private void Mover(float timeStep)
|
||||
{
|
||||
// Don't do force while the object is selected.
|
||||
if (!isActive)
|
||||
return;
|
||||
|
||||
m_physicsScene.DetailLog("{0},BSActorSetTorque,preStep,force={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
|
||||
if (m_controllingPrim.PhysBody.HasPhysicalBody)
|
||||
{
|
||||
m_controllingPrim.AddAngularForce(m_controllingPrim.RawTorque, false, true);
|
||||
m_controllingPrim.ActivateIfPhysical(false);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -32,12 +32,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
{
|
||||
public class BSActorCollection
|
||||
{
|
||||
private BSScene PhysicsScene { get; set; }
|
||||
private BSScene m_physicsScene { get; set; }
|
||||
private Dictionary<string, BSActor> m_actors;
|
||||
|
||||
public BSActorCollection(BSScene physicsScene)
|
||||
{
|
||||
PhysicsScene = physicsScene;
|
||||
m_physicsScene = physicsScene;
|
||||
m_actors = new Dictionary<string, BSActor>();
|
||||
}
|
||||
public void Add(string name, BSActor actor)
|
||||
|
@ -61,6 +61,10 @@ public class BSActorCollection
|
|||
Release();
|
||||
m_actors.Clear();
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
public bool HasActor(string name)
|
||||
{
|
||||
return m_actors.ContainsKey(name);
|
||||
|
@ -71,6 +75,10 @@ public class BSActorCollection
|
|||
act(kvp.Value);
|
||||
}
|
||||
|
||||
public void Enable(bool enabl)
|
||||
{
|
||||
ForEachActor(a => a.Enable(enabl));
|
||||
}
|
||||
public void Release()
|
||||
{
|
||||
ForEachActor(a => a.Dispose());
|
||||
|
|
|
@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject
|
|||
private OMV.Vector3 _position;
|
||||
private float _mass;
|
||||
private float _avatarVolume;
|
||||
private OMV.Vector3 _force;
|
||||
private OMV.Vector3 _velocity;
|
||||
private OMV.Vector3 _torque;
|
||||
private float _collisionScore;
|
||||
private OMV.Vector3 _acceleration;
|
||||
private OMV.Quaternion _orientation;
|
||||
|
@ -61,17 +58,13 @@ public sealed class BSCharacter : BSPhysObject
|
|||
private OMV.Vector3 _rotationalVelocity;
|
||||
private bool _kinematic;
|
||||
private float _buoyancy;
|
||||
private bool _isStationaryStanding; // true is standing on a stationary object
|
||||
|
||||
private BSVMotor _velocityMotor;
|
||||
private BSActorAvatarMove m_moveActor;
|
||||
private const string AvatarMoveActorName = "BSCharacter.AvatarMove";
|
||||
|
||||
private OMV.Vector3 _PIDTarget;
|
||||
private bool _usePID;
|
||||
private float _PIDTau;
|
||||
private bool _useHoverPID;
|
||||
private float _PIDHoverHeight;
|
||||
private PIDHoverType _PIDHoverType;
|
||||
private float _PIDHoverTao;
|
||||
|
||||
public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
|
||||
: base(parent_scene, localID, avName, "BSCharacter")
|
||||
|
@ -81,11 +74,10 @@ public sealed class BSCharacter : BSPhysObject
|
|||
|
||||
_flying = isFlying;
|
||||
_orientation = OMV.Quaternion.Identity;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
RawVelocity = OMV.Vector3.Zero;
|
||||
_buoyancy = ComputeBuoyancyFromFlying(isFlying);
|
||||
Friction = BSParam.AvatarStandingFriction;
|
||||
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
|
||||
_isStationaryStanding = false;
|
||||
|
||||
// Old versions of ScenePresence passed only the height. If width and/or depth are zero,
|
||||
// replace with the default values.
|
||||
|
@ -99,7 +91,12 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// set _avatarVolume and _mass based on capsule size, _density and Scale
|
||||
ComputeAvatarVolumeAndMass();
|
||||
|
||||
SetupMovementMotor();
|
||||
// The avatar's movement is controlled by this motor that speeds up and slows down
|
||||
// the avatar seeking to reach the motor's target speed.
|
||||
// This motor runs as a prestep action for the avatar so it will keep the avatar
|
||||
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
|
||||
m_moveActor = new BSActorAvatarMove(PhysicsScene, this, AvatarMoveActorName);
|
||||
PhysicalActors.Add(AvatarMoveActorName, m_moveActor);
|
||||
|
||||
DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
|
||||
LocalID, _size, Scale, Density, _avatarVolume, RawMass);
|
||||
|
@ -139,10 +136,10 @@ public sealed class BSCharacter : BSPhysObject
|
|||
ForcePosition = _position;
|
||||
|
||||
// Set the velocity
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetTarget(_velocity);
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
ForceVelocity = _velocity;
|
||||
if (m_moveActor != null)
|
||||
m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
|
||||
|
||||
ForceVelocity = RawVelocity;
|
||||
|
||||
// This will enable or disable the flying buoyancy of the avatar.
|
||||
// Needs to be reset especially when an avatar is recreated after crossing a region boundry.
|
||||
|
@ -176,162 +173,6 @@ public sealed class BSCharacter : BSPhysObject
|
|||
PhysBody.ApplyCollisionMask(PhysicsScene);
|
||||
}
|
||||
|
||||
// The avatar's movement is controlled by this motor that speeds up and slows down
|
||||
// the avatar seeking to reach the motor's target speed.
|
||||
// This motor runs as a prestep action for the avatar so it will keep the avatar
|
||||
// standing as well as moving. Destruction of the avatar will destroy the pre-step action.
|
||||
private void SetupMovementMotor()
|
||||
{
|
||||
// Infinite decay and timescale values so motor only changes current to target values.
|
||||
_velocityMotor = new BSVMotor("BSCharacter.Velocity",
|
||||
0.2f, // time scale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.InfiniteVector, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
// _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
|
||||
RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
|
||||
{
|
||||
// TODO: Decide if the step parameters should be changed depending on the avatar's
|
||||
// state (flying, colliding, ...). There is code in ODE to do this.
|
||||
|
||||
// COMMENTARY: when the user is making the avatar walk, except for falling, the velocity
|
||||
// specified for the avatar is the one that should be used. For falling, if the avatar
|
||||
// is not flying and is not colliding then it is presumed to be falling and the Z
|
||||
// component is not fooled with (thus allowing gravity to do its thing).
|
||||
// When the avatar is standing, though, the user has specified a velocity of zero and
|
||||
// the avatar should be standing. But if the avatar is pushed by something in the world
|
||||
// (raising elevator platform, moving vehicle, ...) the avatar should be allowed to
|
||||
// move. Thus, the velocity cannot be forced to zero. The problem is that small velocity
|
||||
// errors can creap in and the avatar will slowly float off in some direction.
|
||||
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
|
||||
// from real pushing.
|
||||
// The code below uses whether the collider is static or moving to decide whether to zero motion.
|
||||
|
||||
_velocityMotor.Step(timeStep);
|
||||
_isStationaryStanding = false;
|
||||
|
||||
// If we're not supposed to be moving, make sure things are zero.
|
||||
if (_velocityMotor.ErrorIsZero() && _velocityMotor.TargetValue == OMV.Vector3.Zero)
|
||||
{
|
||||
// The avatar shouldn't be moving
|
||||
_velocityMotor.Zero();
|
||||
|
||||
if (IsColliding)
|
||||
{
|
||||
// If we are colliding with a stationary object, presume we're standing and don't move around
|
||||
if (!ColliderIsMoving)
|
||||
{
|
||||
DetailLog("{0},BSCharacter.MoveMotor,collidingWithStationary,zeroingMotion", LocalID);
|
||||
_isStationaryStanding = true;
|
||||
ZeroMotion(true /* inTaintTime */);
|
||||
}
|
||||
|
||||
// Standing has more friction on the ground
|
||||
if (Friction != BSParam.AvatarStandingFriction)
|
||||
{
|
||||
Friction = BSParam.AvatarStandingFriction;
|
||||
PhysicsScene.PE.SetFriction(PhysBody, Friction);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Flying)
|
||||
{
|
||||
// Flying and not collising and velocity nearly zero.
|
||||
ZeroMotion(true /* inTaintTime */);
|
||||
}
|
||||
}
|
||||
|
||||
DetailLog("{0},BSCharacter.MoveMotor,taint,stopping,target={1},colliding={2}", LocalID, _velocityMotor.TargetValue, IsColliding);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Supposed to be moving.
|
||||
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
|
||||
|
||||
if (Friction != BSParam.AvatarFriction)
|
||||
{
|
||||
// Probably starting up walking. Set friction to moving friction.
|
||||
Friction = BSParam.AvatarFriction;
|
||||
PhysicsScene.PE.SetFriction(PhysBody, Friction);
|
||||
}
|
||||
|
||||
// If falling, we keep the world's downward vector no matter what the other axis specify.
|
||||
// The check for _velocity.Z < 0 makes jumping work (temporary upward force).
|
||||
if (!Flying && !IsColliding)
|
||||
{
|
||||
if (_velocity.Z < 0)
|
||||
stepVelocity.Z = _velocity.Z;
|
||||
// DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
|
||||
}
|
||||
|
||||
// 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
|
||||
OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
|
||||
|
||||
// Should we check for move force being small and forcing velocity to zero?
|
||||
|
||||
// Add special movement force to allow avatars to walk up stepped surfaces.
|
||||
moveForce += WalkUpStairs();
|
||||
|
||||
DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
|
||||
PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Decide if the character is colliding with a low object and compute a force to pop the
|
||||
// avatar up so it can walk up and over the low objects.
|
||||
private OMV.Vector3 WalkUpStairs()
|
||||
{
|
||||
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||
|
||||
// This test is done if moving forward, not flying and is colliding with something.
|
||||
// DetailLog("{0},BSCharacter.WalkUpStairs,IsColliding={1},flying={2},targSpeed={3},collisions={4}",
|
||||
// LocalID, IsColliding, Flying, TargetSpeed, CollisionsLastTick.Count);
|
||||
if (IsColliding && !Flying && TargetVelocitySpeed > 0.1f /* && ForwardSpeed < 0.1f */)
|
||||
{
|
||||
// The range near the character's feet where we will consider stairs
|
||||
float nearFeetHeightMin = RawPosition.Z - (Size.Z / 2f) + 0.05f;
|
||||
float nearFeetHeightMax = nearFeetHeightMin + BSParam.AvatarStepHeight;
|
||||
|
||||
// Look for a collision point that is near the character's feet and is oriented the same as the charactor is
|
||||
foreach (KeyValuePair<uint, ContactPoint> kvp in CollisionsLastTick.m_objCollisionList)
|
||||
{
|
||||
// Don't care about collisions with the terrain
|
||||
if (kvp.Key > PhysicsScene.TerrainManager.HighestTerrainID)
|
||||
{
|
||||
OMV.Vector3 touchPosition = kvp.Value.Position;
|
||||
// DetailLog("{0},BSCharacter.WalkUpStairs,min={1},max={2},touch={3}",
|
||||
// LocalID, nearFeetHeightMin, nearFeetHeightMax, touchPosition);
|
||||
if (touchPosition.Z >= nearFeetHeightMin && touchPosition.Z <= nearFeetHeightMax)
|
||||
{
|
||||
// This contact is within the 'near the feet' range.
|
||||
// The normal should be our contact point to the object so it is pointing away
|
||||
// thus the difference between our facing orientation and the normal should be small.
|
||||
OMV.Vector3 directionFacing = OMV.Vector3.UnitX * RawOrientation;
|
||||
OMV.Vector3 touchNormal = OMV.Vector3.Normalize(kvp.Value.SurfaceNormal);
|
||||
float diff = Math.Abs(OMV.Vector3.Distance(directionFacing, touchNormal));
|
||||
if (diff < BSParam.AvatarStepApproachFactor)
|
||||
{
|
||||
// Found the stairs contact point. Push up a little to raise the character.
|
||||
float upForce = (touchPosition.Z - nearFeetHeightMin) * Mass * BSParam.AvatarStepForceFactor;
|
||||
ret = new OMV.Vector3(0f, 0f, upForce);
|
||||
|
||||
// Also move the avatar up for the new height
|
||||
OMV.Vector3 displacement = new OMV.Vector3(0f, 0f, BSParam.AvatarStepHeight / 2f);
|
||||
ForcePosition = RawPosition + displacement;
|
||||
}
|
||||
DetailLog("{0},BSCharacter.WalkUpStairs,touchPos={1},nearFeetMin={2},faceDir={3},norm={4},diff={5},ret={6}",
|
||||
LocalID, touchPosition, nearFeetHeightMin, directionFacing, touchNormal, diff, ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void RequestPhysicsterseUpdate()
|
||||
{
|
||||
|
@ -403,7 +244,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// Called at taint time!
|
||||
public override void ZeroMotion(bool inTaintTime)
|
||||
{
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
RawVelocity = OMV.Vector3.Zero;
|
||||
_acceleration = OMV.Vector3.Zero;
|
||||
_rotationalVelocity = OMV.Vector3.Zero;
|
||||
|
||||
|
@ -542,15 +383,15 @@ public sealed class BSCharacter : BSPhysObject
|
|||
}
|
||||
|
||||
public override OMV.Vector3 Force {
|
||||
get { return _force; }
|
||||
get { return RawForce; }
|
||||
set {
|
||||
_force = value;
|
||||
RawForce = value;
|
||||
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
|
||||
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
|
||||
{
|
||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
|
||||
DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, RawForce);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
PhysicsScene.PE.SetObjectForce(PhysBody, _force);
|
||||
PhysicsScene.PE.SetObjectForce(PhysBody, RawForce);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +414,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
{
|
||||
get
|
||||
{
|
||||
return m_targetVelocity;
|
||||
return base.m_targetVelocity;
|
||||
}
|
||||
set
|
||||
{
|
||||
|
@ -583,51 +424,39 @@ public sealed class BSCharacter : BSPhysObject
|
|||
if (_setAlwaysRun)
|
||||
targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
|
||||
|
||||
PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
|
||||
{
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetTarget(targetVel);
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
_velocityMotor.Enabled = true;
|
||||
});
|
||||
if (m_moveActor != null)
|
||||
m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 RawVelocity
|
||||
{
|
||||
get { return _velocity; }
|
||||
set { _velocity = value; }
|
||||
}
|
||||
// Directly setting velocity means this is what the user really wants now.
|
||||
public override OMV.Vector3 Velocity {
|
||||
get { return _velocity; }
|
||||
get { return RawVelocity; }
|
||||
set {
|
||||
_velocity = value;
|
||||
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
|
||||
RawVelocity = value;
|
||||
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
|
||||
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
|
||||
{
|
||||
_velocityMotor.Reset();
|
||||
_velocityMotor.SetCurrent(_velocity);
|
||||
_velocityMotor.SetTarget(_velocity);
|
||||
_velocityMotor.Enabled = false;
|
||||
if (m_moveActor != null)
|
||||
m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
|
||||
|
||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
ForceVelocity = _velocity;
|
||||
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
|
||||
ForceVelocity = RawVelocity;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 ForceVelocity {
|
||||
get { return _velocity; }
|
||||
get { return RawVelocity; }
|
||||
set {
|
||||
PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
|
||||
|
||||
_velocity = value;
|
||||
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
|
||||
RawVelocity = value;
|
||||
PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
|
||||
PhysicsScene.PE.Activate(PhysBody, true);
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 Torque {
|
||||
get { return _torque; }
|
||||
set { _torque = value;
|
||||
get { return RawTorque; }
|
||||
set { RawTorque = value;
|
||||
}
|
||||
}
|
||||
public override float CollisionScore {
|
||||
|
@ -783,27 +612,6 @@ public sealed class BSCharacter : BSPhysObject
|
|||
set { _PIDTau = value; }
|
||||
}
|
||||
|
||||
// Used for llSetHoverHeight and maybe vehicle height
|
||||
// Hover Height will override MoveTo target's Z
|
||||
public override bool PIDHoverActive {
|
||||
set { _useHoverPID = value; }
|
||||
}
|
||||
public override float PIDHoverHeight {
|
||||
set { _PIDHoverHeight = value; }
|
||||
}
|
||||
public override PIDHoverType PIDHoverType {
|
||||
set { _PIDHoverType = value; }
|
||||
}
|
||||
public override float PIDHoverTau {
|
||||
set { _PIDHoverTao = value; }
|
||||
}
|
||||
|
||||
// For RotLookAt
|
||||
public override OMV.Quaternion APIDTarget { set { return; } }
|
||||
public override bool APIDActive { set { return; } }
|
||||
public override float APIDStrength { set { return; } }
|
||||
public override float APIDDamping { set { return; } }
|
||||
|
||||
public override void AddForce(OMV.Vector3 force, bool pushforce)
|
||||
{
|
||||
// Since this force is being applied in only one step, make this a force per second.
|
||||
|
@ -833,7 +641,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||
}
|
||||
public override void SetMomentum(OMV.Vector3 momentum) {
|
||||
}
|
||||
|
@ -887,7 +695,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
public override void UpdateProperties(EntityProperties entprop)
|
||||
{
|
||||
// Don't change position if standing on a stationary object.
|
||||
if (!_isStationaryStanding)
|
||||
if (!IsStationary)
|
||||
_position = entprop.Position;
|
||||
|
||||
_orientation = entprop.Rotation;
|
||||
|
@ -896,8 +704,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// and will send agent updates to the clients if velocity changes by more than
|
||||
// 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
|
||||
// extra updates.
|
||||
if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f))
|
||||
_velocity = entprop.Velocity;
|
||||
if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
|
||||
RawVelocity = entprop.Velocity;
|
||||
|
||||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
|
@ -920,7 +728,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// base.RequestPhysicsterseUpdate();
|
||||
|
||||
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
|
||||
LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
|
||||
LocalID, _position, _orientation, RawVelocity, _acceleration, _rotationalVelocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
* VariableName: used by the simulator and performs taint operations, etc
|
||||
* RawVariableName: direct reference to the BulletSim storage for the variable value
|
||||
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
|
||||
* The last two (and certainly the last one) should be referenced only in taint-time.
|
||||
* The last one should only be referenced in taint-time.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -84,6 +84,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Initialize variables kept in base.
|
||||
GravModifier = 1.0f;
|
||||
Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
|
||||
HoverActive = false;
|
||||
|
||||
// We don't have any physical representation yet.
|
||||
PhysBody = new BulletBody(localID);
|
||||
|
@ -110,11 +111,10 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
// Tell the object to clean up.
|
||||
public virtual void Destroy()
|
||||
{
|
||||
UnRegisterAllPreStepActions();
|
||||
UnRegisterAllPostStepActions();
|
||||
PhysicalActors.Enable(false);
|
||||
PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate()
|
||||
{
|
||||
PhysicalActors.Release();
|
||||
PhysicalActors.Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -203,15 +203,48 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
public abstract OMV.Quaternion RawOrientation { get; set; }
|
||||
public abstract OMV.Quaternion ForceOrientation { get; set; }
|
||||
|
||||
public abstract OMV.Vector3 RawVelocity { get; set; }
|
||||
public OMV.Vector3 RawVelocity { get; set; }
|
||||
public abstract OMV.Vector3 ForceVelocity { get; set; }
|
||||
|
||||
public OMV.Vector3 RawForce { get; set; }
|
||||
public OMV.Vector3 RawTorque { get; set; }
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce)
|
||||
{
|
||||
AddAngularForce(force, pushforce, false);
|
||||
}
|
||||
public abstract void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime);
|
||||
|
||||
public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
|
||||
|
||||
public abstract float ForceBuoyancy { get; set; }
|
||||
|
||||
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; }
|
||||
|
||||
public override bool PIDActive { set { MoveToTargetActive = value; } }
|
||||
public override OMV.Vector3 PIDTarget { set { MoveToTargetTarget = value; } }
|
||||
public override float PIDTau { set { MoveToTargetTau = value; } }
|
||||
|
||||
public bool MoveToTargetActive { get; set; }
|
||||
public OMV.Vector3 MoveToTargetTarget { get; set; }
|
||||
public float MoveToTargetTau { get; set; }
|
||||
|
||||
// Used for llSetHoverHeight and maybe vehicle height. Hover Height will override MoveTo target's Z
|
||||
public override bool PIDHoverActive { set { HoverActive = value; } }
|
||||
public override float PIDHoverHeight { set { HoverHeight = value; } }
|
||||
public override PIDHoverType PIDHoverType { set { HoverType = value; } }
|
||||
public override float PIDHoverTau { set { HoverTau = value; } }
|
||||
|
||||
public bool HoverActive { get; set; }
|
||||
public float HoverHeight { get; set; }
|
||||
public PIDHoverType HoverType { get; set; }
|
||||
public float HoverTau { get; set; }
|
||||
|
||||
// For RotLookAt
|
||||
public override OMV.Quaternion APIDTarget { set { return; } }
|
||||
public override bool APIDActive { set { return; } }
|
||||
public override float APIDStrength { set { return; } }
|
||||
public override float APIDDamping { set { return; } }
|
||||
|
||||
// The current velocity forward
|
||||
public virtual float ForwardSpeed
|
||||
{
|
||||
|
@ -237,7 +270,44 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
|
||||
public OMV.Vector3 LockedAxis { get; set; } // zero means locked. one means free.
|
||||
public readonly OMV.Vector3 LockedAxisFree = new OMV.Vector3(1f, 1f, 1f); // All axis are free
|
||||
public readonly String LockedAxisActorName = "BSPrim.LockedAxis";
|
||||
|
||||
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
|
||||
// they need waking up when parameters are changed.
|
||||
// Called in taint-time!!
|
||||
public void ActivateIfPhysical(bool forceIt)
|
||||
{
|
||||
if (IsPhysical && PhysBody.HasPhysicalBody)
|
||||
PhysicsScene.PE.Activate(PhysBody, forceIt);
|
||||
}
|
||||
|
||||
// 'actors' act on the physical object to change or constrain its motion. These can range from
|
||||
// hovering to complex vehicle motion.
|
||||
public delegate BSActor CreateActor();
|
||||
public void CreateRemoveActor(bool createRemove, string actorName, bool inTaintTime, CreateActor creator)
|
||||
{
|
||||
if (createRemove)
|
||||
{
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate()
|
||||
{
|
||||
if (!PhysicalActors.HasActor(actorName))
|
||||
{
|
||||
DetailLog("{0},BSPrim.CreateRemoveActor,taint,registerActor,a={1}", LocalID, actorName);
|
||||
PhysicalActors.Add(actorName, creator());
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CreateRemoveActor:" + actorName, delegate()
|
||||
{
|
||||
if (PhysicalActors.HasActor(actorName))
|
||||
{
|
||||
DetailLog("{0},BSPrim.CreateRemoveActor,taint,unregisterActor,a={1}", LocalID, actorName);
|
||||
PhysicalActors.RemoveAndRelease(actorName);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#region Collisions
|
||||
|
||||
|
@ -255,7 +325,9 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
protected CollisionFlags CurrentCollisionFlags { get; set; }
|
||||
// On a collision, check the collider and remember if the last collider was moving
|
||||
// Used to modify the standing of avatars (avatars on stationary things stand still)
|
||||
protected bool ColliderIsMoving;
|
||||
public bool ColliderIsMoving;
|
||||
// Used by BSCharacter to manage standing (and not slipping)
|
||||
public bool IsStationary;
|
||||
|
||||
// Count of collisions for this object
|
||||
protected long CollisionAccumulation { get; set; }
|
||||
|
@ -293,7 +365,7 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
protected CollisionEventUpdate CollisionCollection;
|
||||
// Remember collisions from last tick for fancy collision based actions
|
||||
// (like a BSCharacter walking up stairs).
|
||||
protected CollisionEventUpdate CollisionsLastTick;
|
||||
public CollisionEventUpdate CollisionsLastTick;
|
||||
|
||||
// The simulation step is telling this object about a collision.
|
||||
// Return 'true' if a collision was processed and should be sent up.
|
||||
|
@ -424,104 +496,6 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
|
||||
public BSActorCollection PhysicalActors;
|
||||
|
||||
// There are some actions that must be performed for a physical object before each simulation step.
|
||||
// These actions are optional so, rather than scanning all the physical objects and asking them
|
||||
// if they have anything to do, a physical object registers for an event call before the step is performed.
|
||||
// This bookkeeping makes it easy to add, remove and clean up after all these registrations.
|
||||
private Dictionary<string, BSScene.PreStepAction> RegisteredPrestepActions = new Dictionary<string, BSScene.PreStepAction>();
|
||||
private Dictionary<string, BSScene.PostStepAction> RegisteredPoststepActions = new Dictionary<string, BSScene.PostStepAction>();
|
||||
protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
|
||||
lock (RegisteredPrestepActions)
|
||||
{
|
||||
// Clean out any existing action
|
||||
UnRegisterPreStepAction(op, id);
|
||||
RegisteredPrestepActions[identifier] = actn;
|
||||
PhysicsScene.BeforeStep += actn;
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
|
||||
}
|
||||
|
||||
// Unregister a pre step action. Safe to call if the action has not been registered.
|
||||
// Returns 'true' if an action was actually removed
|
||||
protected bool UnRegisterPreStepAction(string op, uint id)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
bool removed = false;
|
||||
lock (RegisteredPrestepActions)
|
||||
{
|
||||
if (RegisteredPrestepActions.ContainsKey(identifier))
|
||||
{
|
||||
PhysicsScene.BeforeStep -= RegisteredPrestepActions[identifier];
|
||||
RegisteredPrestepActions.Remove(identifier);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
|
||||
return removed;
|
||||
}
|
||||
|
||||
protected void UnRegisterAllPreStepActions()
|
||||
{
|
||||
lock (RegisteredPrestepActions)
|
||||
{
|
||||
foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredPrestepActions)
|
||||
{
|
||||
PhysicsScene.BeforeStep -= kvp.Value;
|
||||
}
|
||||
RegisteredPrestepActions.Clear();
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
|
||||
}
|
||||
|
||||
protected void RegisterPostStepAction(string op, uint id, BSScene.PostStepAction actn)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
|
||||
lock (RegisteredPoststepActions)
|
||||
{
|
||||
// Clean out any existing action
|
||||
UnRegisterPostStepAction(op, id);
|
||||
RegisteredPoststepActions[identifier] = actn;
|
||||
PhysicsScene.AfterStep += actn;
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.RegisterPostStepAction,id={1}", LocalID, identifier);
|
||||
}
|
||||
|
||||
// Unregister a pre step action. Safe to call if the action has not been registered.
|
||||
// Returns 'true' if an action was actually removed.
|
||||
protected bool UnRegisterPostStepAction(string op, uint id)
|
||||
{
|
||||
string identifier = op + "-" + id.ToString();
|
||||
bool removed = false;
|
||||
lock (RegisteredPoststepActions)
|
||||
{
|
||||
if (RegisteredPoststepActions.ContainsKey(identifier))
|
||||
{
|
||||
PhysicsScene.AfterStep -= RegisteredPoststepActions[identifier];
|
||||
RegisteredPoststepActions.Remove(identifier);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterPostStepAction,id={1},removed={2}", LocalID, identifier, removed);
|
||||
return removed;
|
||||
}
|
||||
|
||||
protected void UnRegisterAllPostStepActions()
|
||||
{
|
||||
lock (RegisteredPoststepActions)
|
||||
{
|
||||
foreach (KeyValuePair<string, BSScene.PostStepAction> kvp in RegisteredPoststepActions)
|
||||
{
|
||||
PhysicsScene.AfterStep -= kvp.Value;
|
||||
}
|
||||
RegisteredPoststepActions.Clear();
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterAllPostStepActions,", LocalID);
|
||||
}
|
||||
|
||||
// When an update to the physical properties happens, this event is fired to let
|
||||
// different actors to modify the update before it is passed around
|
||||
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
|
||||
|
@ -533,46 +507,6 @@ public abstract class BSPhysObject : PhysicsActor
|
|||
actions(ref entprop);
|
||||
}
|
||||
|
||||
private Dictionary<string, PreUpdatePropertyAction> RegisteredPreUpdatePropertyActions = new Dictionary<string, PreUpdatePropertyAction>();
|
||||
public void RegisterPreUpdatePropertyAction(string identifier, PreUpdatePropertyAction actn)
|
||||
{
|
||||
lock (RegisteredPreUpdatePropertyActions)
|
||||
{
|
||||
// Clean out any existing action
|
||||
UnRegisterPreUpdatePropertyAction(identifier);
|
||||
RegisteredPreUpdatePropertyActions[identifier] = actn;
|
||||
OnPreUpdateProperty += actn;
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.RegisterPreUpdatePropertyAction,id={1}", LocalID, identifier);
|
||||
}
|
||||
public bool UnRegisterPreUpdatePropertyAction(string identifier)
|
||||
{
|
||||
bool removed = false;
|
||||
lock (RegisteredPreUpdatePropertyActions)
|
||||
{
|
||||
if (RegisteredPreUpdatePropertyActions.ContainsKey(identifier))
|
||||
{
|
||||
OnPreUpdateProperty -= RegisteredPreUpdatePropertyActions[identifier];
|
||||
RegisteredPreUpdatePropertyActions.Remove(identifier);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterPreUpdatePropertyAction,id={1},removed={2}", LocalID, identifier, removed);
|
||||
return removed;
|
||||
}
|
||||
public void UnRegisterAllPreUpdatePropertyActions()
|
||||
{
|
||||
lock (RegisteredPreUpdatePropertyActions)
|
||||
{
|
||||
foreach (KeyValuePair<string, PreUpdatePropertyAction> kvp in RegisteredPreUpdatePropertyActions)
|
||||
{
|
||||
OnPreUpdateProperty -= kvp.Value;
|
||||
}
|
||||
RegisteredPreUpdatePropertyActions.Clear();
|
||||
}
|
||||
DetailLog("{0},BSPhysObject.UnRegisterAllPreUpdatePropertyAction,", LocalID);
|
||||
}
|
||||
|
||||
#endregion // Per Simulation Step actions
|
||||
|
||||
// High performance detailed logging routine used by the physical objects.
|
||||
|
|
|
@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject
|
|||
private OMV.Vector3 _position;
|
||||
|
||||
private float _mass; // the mass of this object
|
||||
private OMV.Vector3 _force;
|
||||
private OMV.Vector3 _velocity;
|
||||
private OMV.Vector3 _torque;
|
||||
private OMV.Vector3 _acceleration;
|
||||
private OMV.Quaternion _orientation;
|
||||
private int _physicsActorType;
|
||||
|
@ -73,16 +70,13 @@ public class BSPrim : BSPhysObject
|
|||
private int CrossingFailures { get; set; }
|
||||
|
||||
public BSDynamics VehicleActor;
|
||||
public string VehicleActorName = "BasicVehicle";
|
||||
public const string VehicleActorName = "BasicVehicle";
|
||||
|
||||
private BSVMotor _targetMotor;
|
||||
private OMV.Vector3 _PIDTarget;
|
||||
private float _PIDTau;
|
||||
|
||||
private BSFMotor _hoverMotor;
|
||||
private float _PIDHoverHeight;
|
||||
private PIDHoverType _PIDHoverType;
|
||||
private float _PIDHoverTau;
|
||||
public const string HoverActorName = "HoverActor";
|
||||
public const String LockedAxisActorName = "BSPrim.LockedAxis";
|
||||
public const string MoveToTargetActorName = "MoveToTargetActor";
|
||||
public const string SetForceActorName = "SetForceActor";
|
||||
public const string SetTorqueActorName = "SetTorqueActor";
|
||||
|
||||
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
|
||||
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
|
||||
|
@ -95,7 +89,7 @@ public class BSPrim : BSPhysObject
|
|||
Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
|
||||
_orientation = rotation;
|
||||
_buoyancy = 0f;
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
RawVelocity = OMV.Vector3.Zero;
|
||||
_rotationalVelocity = OMV.Vector3.Zero;
|
||||
BaseShape = pbs;
|
||||
_isPhysical = pisPhysical;
|
||||
|
@ -233,7 +227,7 @@ public class BSPrim : BSPhysObject
|
|||
// Called at taint time!
|
||||
public override void ZeroMotion(bool inTaintTime)
|
||||
{
|
||||
_velocity = OMV.Vector3.Zero;
|
||||
RawVelocity = OMV.Vector3.Zero;
|
||||
_acceleration = OMV.Vector3.Zero;
|
||||
_rotationalVelocity = OMV.Vector3.Zero;
|
||||
|
||||
|
@ -270,19 +264,17 @@ public class BSPrim : BSPhysObject
|
|||
if (axis.Z != 1) locking.Z = 0f;
|
||||
LockedAxis = locking;
|
||||
|
||||
if (LockedAxis != LockedAxisFree)
|
||||
CreateRemoveActor(LockedAxis != LockedAxisFree /* creatActor */, LockedAxisActorName, false /* inTaintTime */, delegate()
|
||||
{
|
||||
return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName);
|
||||
});
|
||||
|
||||
// Update parameters so the new actor's Refresh() action is called at the right time.
|
||||
PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
|
||||
{
|
||||
// If there is not already an axis locker, make one
|
||||
if (!PhysicalActors.HasActor(LockedAxisActorName))
|
||||
{
|
||||
DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID);
|
||||
PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName));
|
||||
}
|
||||
UpdatePhysicalParameters();
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -407,9 +399,9 @@ public class BSPrim : BSPhysObject
|
|||
ZeroMotion(inTaintTime);
|
||||
ret = true;
|
||||
}
|
||||
if (_velocity.LengthSquared() > BSParam.MaxLinearVelocity)
|
||||
if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
|
||||
{
|
||||
_velocity = Util.ClampV(_velocity, BSParam.MaxLinearVelocity);
|
||||
RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
|
||||
ret = true;
|
||||
}
|
||||
if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
|
||||
|
@ -506,35 +498,13 @@ public class BSPrim : BSPhysObject
|
|||
}
|
||||
|
||||
public override OMV.Vector3 Force {
|
||||
get { return _force; }
|
||||
get { return RawForce; }
|
||||
set {
|
||||
_force = value;
|
||||
if (_force != OMV.Vector3.Zero)
|
||||
RawForce = value;
|
||||
CreateRemoveActor(RawForce == OMV.Vector3.Zero, SetForceActorName, false /* inTaintTime */, delegate()
|
||||
{
|
||||
// If the force is non-zero, it must be reapplied each tick because
|
||||
// Bullet clears the forces applied last frame.
|
||||
RegisterPreStepAction("BSPrim.setForce", LocalID,
|
||||
delegate(float timeStep)
|
||||
{
|
||||
if (!IsPhysicallyActive || _force == OMV.Vector3.Zero)
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
|
||||
return;
|
||||
}
|
||||
|
||||
DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setForce", LocalID);
|
||||
}
|
||||
return new BSActorSetForce(PhysicsScene, this, SetForceActorName);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,62 +640,39 @@ public class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 RawVelocity
|
||||
{
|
||||
get { return _velocity; }
|
||||
set { _velocity = value; }
|
||||
}
|
||||
public override OMV.Vector3 Velocity {
|
||||
get { return _velocity; }
|
||||
get { return RawVelocity; }
|
||||
set {
|
||||
_velocity = value;
|
||||
RawVelocity = value;
|
||||
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
|
||||
{
|
||||
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
ForceVelocity = _velocity;
|
||||
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
|
||||
ForceVelocity = RawVelocity;
|
||||
});
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 ForceVelocity {
|
||||
get { return _velocity; }
|
||||
get { return RawVelocity; }
|
||||
set {
|
||||
PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
|
||||
|
||||
_velocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
|
||||
RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
{
|
||||
DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity);
|
||||
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
|
||||
DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
|
||||
PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
|
||||
ActivateIfPhysical(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override OMV.Vector3 Torque {
|
||||
get { return _torque; }
|
||||
get { return RawTorque; }
|
||||
set {
|
||||
_torque = value;
|
||||
if (_torque != OMV.Vector3.Zero)
|
||||
RawTorque = value;
|
||||
CreateRemoveActor(RawTorque == OMV.Vector3.Zero, SetTorqueActorName, false /* inTaintTime */, delegate()
|
||||
{
|
||||
// If the torque is non-zero, it must be reapplied each tick because
|
||||
// Bullet clears the forces applied last frame.
|
||||
RegisterPreStepAction("BSPrim.setTorque", LocalID,
|
||||
delegate(float timeStep)
|
||||
{
|
||||
if (!IsPhysicallyActive || _torque == OMV.Vector3.Zero)
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (PhysBody.HasPhysicalBody)
|
||||
AddAngularForce(_torque, false, true);
|
||||
}
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
|
||||
}
|
||||
return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName);
|
||||
});
|
||||
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
|
||||
}
|
||||
}
|
||||
|
@ -909,7 +856,7 @@ public class BSPrim : BSPhysObject
|
|||
|
||||
// For good measure, make sure the transform is set through to the motion state
|
||||
ForcePosition = _position;
|
||||
ForceVelocity = _velocity;
|
||||
ForceVelocity = RawVelocity;
|
||||
ForceRotationalVelocity = _rotationalVelocity;
|
||||
|
||||
// A dynamic object has mass
|
||||
|
@ -966,15 +913,6 @@ public class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
// Enable physical actions. Bullet will keep sleeping non-moving physical objects so
|
||||
// they need waking up when parameters are changed.
|
||||
// Called in taint-time!!
|
||||
private void ActivateIfPhysical(bool forceIt)
|
||||
{
|
||||
if (IsPhysical && PhysBody.HasPhysicalBody)
|
||||
PhysicsScene.PE.Activate(PhysBody, forceIt);
|
||||
}
|
||||
|
||||
// Turn on or off the flag controlling whether collision events are returned to the simulator.
|
||||
private void EnableCollisions(bool wantsCollisionEvents)
|
||||
{
|
||||
|
@ -1096,166 +1034,27 @@ public class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
// Used for MoveTo
|
||||
public override OMV.Vector3 PIDTarget {
|
||||
set
|
||||
{
|
||||
// TODO: add a sanity check -- don't move more than a region or something like that.
|
||||
_PIDTarget = value;
|
||||
}
|
||||
}
|
||||
public override float PIDTau {
|
||||
set { _PIDTau = value; }
|
||||
}
|
||||
public override bool PIDActive {
|
||||
set {
|
||||
if (value)
|
||||
base.MoveToTargetActive = value;
|
||||
CreateRemoveActor(MoveToTargetActive, MoveToTargetActorName, false /* inTaintTime */, delegate()
|
||||
{
|
||||
// We're taking over after this.
|
||||
ZeroMotion(true);
|
||||
|
||||
_targetMotor = new BSVMotor("BSPrim.PIDTarget",
|
||||
_PIDTau, // timeScale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.InfiniteVector, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
_targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
_targetMotor.SetTarget(_PIDTarget);
|
||||
_targetMotor.SetCurrent(RawPosition);
|
||||
/*
|
||||
_targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
|
||||
_targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
|
||||
_targetMotor.SetTarget(_PIDTarget);
|
||||
_targetMotor.SetCurrent(RawPosition);
|
||||
_targetMotor.TimeScale = _PIDTau;
|
||||
_targetMotor.Efficiency = 1f;
|
||||
*/
|
||||
|
||||
RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
|
||||
{
|
||||
if (!IsPhysicallyActive)
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
|
||||
return;
|
||||
}
|
||||
|
||||
OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
|
||||
|
||||
// 'movePosition' is where we'd like the prim to be at this moment.
|
||||
OMV.Vector3 movePosition = RawPosition + _targetMotor.Step(timeStep);
|
||||
|
||||
// If we are very close to our target, turn off the movement motor.
|
||||
if (_targetMotor.ErrorIsZero())
|
||||
{
|
||||
DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
|
||||
LocalID, movePosition, RawPosition, Mass);
|
||||
ForcePosition = _targetMotor.TargetValue;
|
||||
_targetMotor.Enabled = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
_position = movePosition;
|
||||
PositionSanityCheck(true /* intaintTime */);
|
||||
ForcePosition = _position;
|
||||
}
|
||||
DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
|
||||
return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// Stop any targetting
|
||||
UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used for llSetHoverHeight and maybe vehicle height
|
||||
// Hover Height will override MoveTo target's Z
|
||||
public override bool PIDHoverActive {
|
||||
set {
|
||||
if (value)
|
||||
base.HoverActive = value;
|
||||
CreateRemoveActor(HoverActive /* creatActor */, HoverActorName, false /* inTaintTime */, delegate()
|
||||
{
|
||||
// Turning the target on
|
||||
_hoverMotor = new BSFMotor("BSPrim.Hover",
|
||||
_PIDHoverTau, // timeScale
|
||||
BSMotor.Infinite, // decay time scale
|
||||
BSMotor.Infinite, // friction timescale
|
||||
1f // efficiency
|
||||
);
|
||||
_hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
|
||||
_hoverMotor.SetCurrent(RawPosition.Z);
|
||||
_hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
|
||||
|
||||
RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
|
||||
{
|
||||
// Don't do hovering while the object is selected.
|
||||
if (!IsPhysicallyActive)
|
||||
return;
|
||||
|
||||
_hoverMotor.SetCurrent(RawPosition.Z);
|
||||
_hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
|
||||
float targetHeight = _hoverMotor.Step(timeStep);
|
||||
|
||||
// 'targetHeight' is where we'd like the Z of the prim to be at this moment.
|
||||
// Compute the amount of force to push us there.
|
||||
float moveForce = (targetHeight - RawPosition.Z) * Mass;
|
||||
// Undo anything the object thinks it's doing at the moment
|
||||
moveForce = -RawVelocity.Z * Mass;
|
||||
|
||||
PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
|
||||
DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
|
||||
return new BSActorHover(PhysicsScene, this, HoverActorName);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterPreStepAction("BSPrim.Hover", LocalID);
|
||||
}
|
||||
}
|
||||
}
|
||||
public override float PIDHoverHeight {
|
||||
set { _PIDHoverHeight = value; }
|
||||
}
|
||||
public override PIDHoverType PIDHoverType {
|
||||
set { _PIDHoverType = value; }
|
||||
}
|
||||
public override float PIDHoverTau {
|
||||
set { _PIDHoverTau = value; }
|
||||
}
|
||||
// Based on current position, determine what we should be hovering at now.
|
||||
// Must recompute often. What if we walked offa cliff>
|
||||
private float ComputeCurrentPIDHoverHeight()
|
||||
{
|
||||
float ret = _PIDHoverHeight;
|
||||
float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
|
||||
|
||||
switch (_PIDHoverType)
|
||||
{
|
||||
case PIDHoverType.Ground:
|
||||
ret = groundHeight + _PIDHoverHeight;
|
||||
break;
|
||||
case PIDHoverType.GroundAndWater:
|
||||
float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
|
||||
if (groundHeight > waterHeight)
|
||||
{
|
||||
ret = groundHeight + _PIDHoverHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = waterHeight + _PIDHoverHeight;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// For RotLookAt
|
||||
public override OMV.Quaternion APIDTarget { set { return; } }
|
||||
public override bool APIDActive { set { return; } }
|
||||
public override float APIDStrength { set { return; } }
|
||||
public override float APIDDamping { set { return; } }
|
||||
|
||||
public override void AddForce(OMV.Vector3 force, bool pushforce) {
|
||||
// Per documentation, max force is limited.
|
||||
|
@ -1324,10 +1123,8 @@ public class BSPrim : BSPhysObject
|
|||
}
|
||||
}
|
||||
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
|
||||
AddAngularForce(force, pushforce, false);
|
||||
}
|
||||
public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
|
||||
// BSPhysObject.AddAngularForce()
|
||||
public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
|
||||
{
|
||||
if (force.IsFinite())
|
||||
{
|
||||
|
@ -1694,8 +1491,8 @@ public class BSPrim : BSPhysObject
|
|||
_orientation = entprop.Rotation;
|
||||
// DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
|
||||
// very sensitive to velocity changes.
|
||||
if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold))
|
||||
_velocity = entprop.Velocity;
|
||||
if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
|
||||
RawVelocity = entprop.Velocity;
|
||||
_acceleration = entprop.Acceleration;
|
||||
_rotationalVelocity = entprop.RotationalVelocity;
|
||||
|
||||
|
@ -1705,7 +1502,7 @@ public class BSPrim : BSPhysObject
|
|||
if (PositionSanityCheck(true /* inTaintTime */ ))
|
||||
{
|
||||
entprop.Position = _position;
|
||||
entprop.Velocity = _velocity;
|
||||
entprop.Velocity = RawVelocity;
|
||||
entprop.RotationalVelocity = _rotationalVelocity;
|
||||
entprop.Acceleration = _acceleration;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ Enable vehicle border crossings (at least as poorly as ODE)
|
|||
Terrain skirts
|
||||
Avatar created in previous region and not new region when crossing border
|
||||
Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
|
||||
Lock axis
|
||||
Deleting a linkset while standing on the root will leave the physical shape of the root behind.
|
||||
Not sure if it is because standing on it. Done with large prim linksets.
|
||||
Linkset child rotations.
|
||||
|
@ -344,3 +343,5 @@ Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
|
|||
Verify that angular motion specified around Z moves in the vehicle coordinates.
|
||||
DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
|
||||
Nebadon vehicles turning funny in arena (DONE)
|
||||
Lock axis (DONE 20130401)
|
||||
|
||||
|
|
Loading…
Reference in New Issue