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
Robert Adams 2013-04-07 08:27:49 -07:00
parent c7cd077e55
commit fe16dc09da
11 changed files with 1078 additions and 636 deletions

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -40,7 +40,7 @@ public class BSActorLockAxis : BSActor
BSConstraint LockAxisConstraint = null; BSConstraint LockAxisConstraint = null;
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName) 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); m_physicsScene.DetailLog("{0},BSActorLockAxis,constructor", m_controllingPrim.LocalID);
LockAxisConstraint = null; LockAxisConstraint = null;
@ -99,7 +99,7 @@ public class BSActorLockAxis : BSActor
// If a constraint is set up, remove it from the physical scene // If a constraint is set up, remove it from the physical scene
RemoveAxisLockConstraint(); RemoveAxisLockConstraint();
// Schedule a call before the next simulation step to restore the constraint. // 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(); Refresh();
}); });

View File

@ -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);
}
}
}

View File

@ -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:
}
}
}

View File

@ -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:
}
}
}

View File

@ -32,12 +32,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSActorCollection public class BSActorCollection
{ {
private BSScene PhysicsScene { get; set; } private BSScene m_physicsScene { get; set; }
private Dictionary<string, BSActor> m_actors; private Dictionary<string, BSActor> m_actors;
public BSActorCollection(BSScene physicsScene) public BSActorCollection(BSScene physicsScene)
{ {
PhysicsScene = physicsScene; m_physicsScene = physicsScene;
m_actors = new Dictionary<string, BSActor>(); m_actors = new Dictionary<string, BSActor>();
} }
public void Add(string name, BSActor actor) public void Add(string name, BSActor actor)
@ -61,6 +61,10 @@ public class BSActorCollection
Release(); Release();
m_actors.Clear(); m_actors.Clear();
} }
public void Dispose()
{
Clear();
}
public bool HasActor(string name) public bool HasActor(string name)
{ {
return m_actors.ContainsKey(name); return m_actors.ContainsKey(name);
@ -71,6 +75,10 @@ public class BSActorCollection
act(kvp.Value); act(kvp.Value);
} }
public void Enable(bool enabl)
{
ForEachActor(a => a.Enable(enabl));
}
public void Release() public void Release()
{ {
ForEachActor(a => a.Dispose()); ForEachActor(a => a.Dispose());

View File

@ -46,9 +46,6 @@ public sealed class BSCharacter : BSPhysObject
private OMV.Vector3 _position; private OMV.Vector3 _position;
private float _mass; private float _mass;
private float _avatarVolume; private float _avatarVolume;
private OMV.Vector3 _force;
private OMV.Vector3 _velocity;
private OMV.Vector3 _torque;
private float _collisionScore; private float _collisionScore;
private OMV.Vector3 _acceleration; private OMV.Vector3 _acceleration;
private OMV.Quaternion _orientation; private OMV.Quaternion _orientation;
@ -61,17 +58,13 @@ public sealed class BSCharacter : BSPhysObject
private OMV.Vector3 _rotationalVelocity; private OMV.Vector3 _rotationalVelocity;
private bool _kinematic; private bool _kinematic;
private float _buoyancy; 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 OMV.Vector3 _PIDTarget;
private bool _usePID; private bool _usePID;
private float _PIDTau; 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) public BSCharacter(uint localID, String avName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, bool isFlying)
: base(parent_scene, localID, avName, "BSCharacter") : base(parent_scene, localID, avName, "BSCharacter")
@ -81,11 +74,10 @@ public sealed class BSCharacter : BSPhysObject
_flying = isFlying; _flying = isFlying;
_orientation = OMV.Quaternion.Identity; _orientation = OMV.Quaternion.Identity;
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_buoyancy = ComputeBuoyancyFromFlying(isFlying); _buoyancy = ComputeBuoyancyFromFlying(isFlying);
Friction = BSParam.AvatarStandingFriction; Friction = BSParam.AvatarStandingFriction;
Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor; Density = BSParam.AvatarDensity / BSParam.DensityScaleFactor;
_isStationaryStanding = false;
// Old versions of ScenePresence passed only the height. If width and/or depth are zero, // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
// replace with the default values. // 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 // set _avatarVolume and _mass based on capsule size, _density and Scale
ComputeAvatarVolumeAndMass(); 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}", DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
LocalID, _size, Scale, Density, _avatarVolume, RawMass); LocalID, _size, Scale, Density, _avatarVolume, RawMass);
@ -139,10 +136,10 @@ public sealed class BSCharacter : BSPhysObject
ForcePosition = _position; ForcePosition = _position;
// Set the velocity // Set the velocity
_velocityMotor.Reset(); if (m_moveActor != null)
_velocityMotor.SetTarget(_velocity); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, false);
_velocityMotor.SetCurrent(_velocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
// This will enable or disable the flying buoyancy of the avatar. // 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. // 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); 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() public override void RequestPhysicsterseUpdate()
{ {
@ -403,7 +244,7 @@ public sealed class BSCharacter : BSPhysObject
// Called at taint time! // Called at taint time!
public override void ZeroMotion(bool inTaintTime) public override void ZeroMotion(bool inTaintTime)
{ {
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
@ -542,15 +383,15 @@ public sealed class BSCharacter : BSPhysObject
} }
public override OMV.Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return RawForce; }
set { set {
_force = value; RawForce = value;
// m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force); // m_log.DebugFormat("{0}: Force = {1}", LogHeader, _force);
PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 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) if (PhysBody.HasPhysicalBody)
PhysicsScene.PE.SetObjectForce(PhysBody, _force); PhysicsScene.PE.SetObjectForce(PhysBody, RawForce);
}); });
} }
} }
@ -573,7 +414,7 @@ public sealed class BSCharacter : BSPhysObject
{ {
get get
{ {
return m_targetVelocity; return base.m_targetVelocity;
} }
set set
{ {
@ -583,51 +424,39 @@ public sealed class BSCharacter : BSPhysObject
if (_setAlwaysRun) if (_setAlwaysRun)
targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f); targetVel *= new OMV.Vector3(BSParam.AvatarAlwaysRunFactor, BSParam.AvatarAlwaysRunFactor, 0f);
PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate() if (m_moveActor != null)
{ m_moveActor.SetVelocityAndTarget(RawVelocity, targetVel, false /* inTaintTime */);
_velocityMotor.Reset();
_velocityMotor.SetTarget(targetVel);
_velocityMotor.SetCurrent(_velocity);
_velocityMotor.Enabled = true;
});
} }
} }
public override OMV.Vector3 RawVelocity
{
get { return _velocity; }
set { _velocity = value; }
}
// Directly setting velocity means this is what the user really wants now. // Directly setting velocity means this is what the user really wants now.
public override OMV.Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
_velocity = value; RawVelocity = value;
// m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, RawVelocity);
PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
{ {
_velocityMotor.Reset(); if (m_moveActor != null)
_velocityMotor.SetCurrent(_velocity); m_moveActor.SetVelocityAndTarget(RawVelocity, RawVelocity, true /* inTaintTime */);
_velocityMotor.SetTarget(_velocity);
_velocityMotor.Enabled = false;
DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, RawVelocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
}); });
} }
} }
public override OMV.Vector3 ForceVelocity { public override OMV.Vector3 ForceVelocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity"); PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
_velocity = value; RawVelocity = value;
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
PhysicsScene.PE.Activate(PhysBody, true); PhysicsScene.PE.Activate(PhysBody, true);
} }
} }
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return RawTorque; }
set { _torque = value; set { RawTorque = value;
} }
} }
public override float CollisionScore { public override float CollisionScore {
@ -783,27 +612,6 @@ public sealed class BSCharacter : BSPhysObject
set { _PIDTau = value; } 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) 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. // 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) { public override void SetMomentum(OMV.Vector3 momentum) {
} }
@ -887,7 +695,7 @@ public sealed class BSCharacter : BSPhysObject
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
// Don't change position if standing on a stationary object. // Don't change position if standing on a stationary object.
if (!_isStationaryStanding) if (!IsStationary)
_position = entprop.Position; _position = entprop.Position;
_orientation = entprop.Rotation; _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 // 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 // 0.001m/s. Bullet introduces a lot of jitter in the velocity which causes many
// extra updates. // extra updates.
if (!entprop.Velocity.ApproxEquals(_velocity, 0.1f)) if (!entprop.Velocity.ApproxEquals(RawVelocity, 0.1f))
_velocity = entprop.Velocity; RawVelocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
@ -920,7 +728,7 @@ public sealed class BSCharacter : BSPhysObject
// base.RequestPhysicsterseUpdate(); // base.RequestPhysicsterseUpdate();
DetailLog("{0},BSCharacter.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", 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);
} }
} }
} }

View File

@ -43,7 +43,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
* VariableName: used by the simulator and performs taint operations, etc * VariableName: used by the simulator and performs taint operations, etc
* RawVariableName: direct reference to the BulletSim storage for the variable value * RawVariableName: direct reference to the BulletSim storage for the variable value
* ForceVariableName: direct reference (store and fetch) to the value in the physics engine. * 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. // Initialize variables kept in base.
GravModifier = 1.0f; GravModifier = 1.0f;
Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity); Gravity = new OMV.Vector3(0f, 0f, BSParam.Gravity);
HoverActive = false;
// We don't have any physical representation yet. // We don't have any physical representation yet.
PhysBody = new BulletBody(localID); PhysBody = new BulletBody(localID);
@ -110,11 +111,10 @@ public abstract class BSPhysObject : PhysicsActor
// Tell the object to clean up. // Tell the object to clean up.
public virtual void Destroy() public virtual void Destroy()
{ {
UnRegisterAllPreStepActions(); PhysicalActors.Enable(false);
UnRegisterAllPostStepActions();
PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate() 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 RawOrientation { get; set; }
public abstract OMV.Quaternion ForceOrientation { 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 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 OMV.Vector3 ForceRotationalVelocity { get; set; }
public abstract float ForceBuoyancy { get; set; } public abstract float ForceBuoyancy { get; set; }
public virtual bool ForceBodyShapeRebuild(bool inTaintTime) { return false; } 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 // The current velocity forward
public virtual float ForwardSpeed 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 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 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 #region Collisions
@ -255,7 +325,9 @@ public abstract class BSPhysObject : PhysicsActor
protected CollisionFlags CurrentCollisionFlags { get; set; } protected CollisionFlags CurrentCollisionFlags { get; set; }
// On a collision, check the collider and remember if the last collider was moving // 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) // 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 // Count of collisions for this object
protected long CollisionAccumulation { get; set; } protected long CollisionAccumulation { get; set; }
@ -293,7 +365,7 @@ public abstract class BSPhysObject : PhysicsActor
protected CollisionEventUpdate CollisionCollection; protected CollisionEventUpdate CollisionCollection;
// Remember collisions from last tick for fancy collision based actions // Remember collisions from last tick for fancy collision based actions
// (like a BSCharacter walking up stairs). // (like a BSCharacter walking up stairs).
protected CollisionEventUpdate CollisionsLastTick; public CollisionEventUpdate CollisionsLastTick;
// The simulation step is telling this object about a collision. // The simulation step is telling this object about a collision.
// Return 'true' if a collision was processed and should be sent up. // Return 'true' if a collision was processed and should be sent up.
@ -424,104 +496,6 @@ public abstract class BSPhysObject : PhysicsActor
public BSActorCollection PhysicalActors; 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 // 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 // different actors to modify the update before it is passed around
public delegate void PreUpdatePropertyAction(ref EntityProperties entprop); public delegate void PreUpdatePropertyAction(ref EntityProperties entprop);
@ -533,46 +507,6 @@ public abstract class BSPhysObject : PhysicsActor
actions(ref entprop); 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 #endregion // Per Simulation Step actions
// High performance detailed logging routine used by the physical objects. // High performance detailed logging routine used by the physical objects.

View File

@ -55,9 +55,6 @@ public class BSPrim : BSPhysObject
private OMV.Vector3 _position; private OMV.Vector3 _position;
private float _mass; // the mass of this object 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.Vector3 _acceleration;
private OMV.Quaternion _orientation; private OMV.Quaternion _orientation;
private int _physicsActorType; private int _physicsActorType;
@ -73,16 +70,13 @@ public class BSPrim : BSPhysObject
private int CrossingFailures { get; set; } private int CrossingFailures { get; set; }
public BSDynamics VehicleActor; public BSDynamics VehicleActor;
public string VehicleActorName = "BasicVehicle"; public const string VehicleActorName = "BasicVehicle";
private BSVMotor _targetMotor; public const string HoverActorName = "HoverActor";
private OMV.Vector3 _PIDTarget; public const String LockedAxisActorName = "BSPrim.LockedAxis";
private float _PIDTau; public const string MoveToTargetActorName = "MoveToTargetActor";
public const string SetForceActorName = "SetForceActor";
private BSFMotor _hoverMotor; public const string SetTorqueActorName = "SetTorqueActor";
private float _PIDHoverHeight;
private PIDHoverType _PIDHoverType;
private float _PIDHoverTau;
public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 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). Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
_orientation = rotation; _orientation = rotation;
_buoyancy = 0f; _buoyancy = 0f;
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
BaseShape = pbs; BaseShape = pbs;
_isPhysical = pisPhysical; _isPhysical = pisPhysical;
@ -233,7 +227,7 @@ public class BSPrim : BSPhysObject
// Called at taint time! // Called at taint time!
public override void ZeroMotion(bool inTaintTime) public override void ZeroMotion(bool inTaintTime)
{ {
_velocity = OMV.Vector3.Zero; RawVelocity = OMV.Vector3.Zero;
_acceleration = OMV.Vector3.Zero; _acceleration = OMV.Vector3.Zero;
_rotationalVelocity = OMV.Vector3.Zero; _rotationalVelocity = OMV.Vector3.Zero;
@ -270,19 +264,17 @@ public class BSPrim : BSPhysObject
if (axis.Z != 1) locking.Z = 0f; if (axis.Z != 1) locking.Z = 0f;
LockedAxis = locking; LockedAxis = locking;
if (LockedAxis != LockedAxisFree) CreateRemoveActor(LockedAxis != LockedAxisFree /* creatActor */, LockedAxisActorName, false /* inTaintTime */, delegate()
{ {
PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() return new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName);
{ });
// If there is not already an axis locker, make one
if (!PhysicalActors.HasActor(LockedAxisActorName)) // Update parameters so the new actor's Refresh() action is called at the right time.
{ PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
DetailLog("{0},BSPrim.LockAngularMotion,taint,registeringLockAxisActor", LocalID); {
PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName)); UpdatePhysicalParameters();
} });
UpdatePhysicalParameters();
});
}
return; return;
} }
@ -407,9 +399,9 @@ public class BSPrim : BSPhysObject
ZeroMotion(inTaintTime); ZeroMotion(inTaintTime);
ret = true; 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; ret = true;
} }
if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared) if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
@ -506,35 +498,13 @@ public class BSPrim : BSPhysObject
} }
public override OMV.Vector3 Force { public override OMV.Vector3 Force {
get { return _force; } get { return RawForce; }
set { set {
_force = value; RawForce = value;
if (_force != OMV.Vector3.Zero) CreateRemoveActor(RawForce == OMV.Vector3.Zero, SetForceActorName, false /* inTaintTime */, delegate()
{ {
// If the force is non-zero, it must be reapplied each tick because return new BSActorSetForce(PhysicsScene, this, SetForceActorName);
// 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);
}
} }
} }
@ -670,62 +640,39 @@ public class BSPrim : BSPhysObject
} }
} }
} }
public override OMV.Vector3 RawVelocity
{
get { return _velocity; }
set { _velocity = value; }
}
public override OMV.Vector3 Velocity { public override OMV.Vector3 Velocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
_velocity = value; RawVelocity = value;
PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
{ {
// DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
}); });
} }
} }
public override OMV.Vector3 ForceVelocity { public override OMV.Vector3 ForceVelocity {
get { return _velocity; } get { return RawVelocity; }
set { set {
PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity"); PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
_velocity = Util.ClampV(value, BSParam.MaxLinearVelocity); RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
if (PhysBody.HasPhysicalBody) if (PhysBody.HasPhysicalBody)
{ {
DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, _velocity); DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity); PhysicsScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
ActivateIfPhysical(false); ActivateIfPhysical(false);
} }
} }
} }
public override OMV.Vector3 Torque { public override OMV.Vector3 Torque {
get { return _torque; } get { return RawTorque; }
set { set {
_torque = value; RawTorque = value;
if (_torque != OMV.Vector3.Zero) CreateRemoveActor(RawTorque == OMV.Vector3.Zero, SetTorqueActorName, false /* inTaintTime */, delegate()
{ {
// If the torque is non-zero, it must be reapplied each tick because return new BSActorSetTorque(PhysicsScene, this, SetTorqueActorName);
// 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);
}
// DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); // 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 // For good measure, make sure the transform is set through to the motion state
ForcePosition = _position; ForcePosition = _position;
ForceVelocity = _velocity; ForceVelocity = RawVelocity;
ForceRotationalVelocity = _rotationalVelocity; ForceRotationalVelocity = _rotationalVelocity;
// A dynamic object has mass // 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. // Turn on or off the flag controlling whether collision events are returned to the simulator.
private void EnableCollisions(bool wantsCollisionEvents) private void EnableCollisions(bool wantsCollisionEvents)
{ {
@ -1096,78 +1034,13 @@ 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 { public override bool PIDActive {
set { set {
if (value) base.MoveToTargetActive = value;
CreateRemoveActor(MoveToTargetActive, MoveToTargetActorName, false /* inTaintTime */, delegate()
{ {
// We're taking over after this. return new BSActorMoveToTarget(PhysicsScene, this, MoveToTargetActorName);
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);
});
}
else
{
// Stop any targetting
UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
}
} }
} }
@ -1175,87 +1048,13 @@ public class BSPrim : BSPhysObject
// Hover Height will override MoveTo target's Z // Hover Height will override MoveTo target's Z
public override bool PIDHoverActive { public override bool PIDHoverActive {
set { set {
if (value) base.HoverActive = value;
CreateRemoveActor(HoverActive /* creatActor */, HoverActorName, false /* inTaintTime */, delegate()
{ {
// Turning the target on return new BSActorHover(PhysicsScene, this, HoverActorName);
_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);
});
}
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) { public override void AddForce(OMV.Vector3 force, bool pushforce) {
// Per documentation, max force is limited. // Per documentation, max force is limited.
@ -1324,10 +1123,8 @@ public class BSPrim : BSPhysObject
} }
} }
public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { // BSPhysObject.AddAngularForce()
AddAngularForce(force, pushforce, false); public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
}
public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
{ {
if (force.IsFinite()) if (force.IsFinite())
{ {
@ -1694,8 +1491,8 @@ public class BSPrim : BSPhysObject
_orientation = entprop.Rotation; _orientation = entprop.Rotation;
// DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
// very sensitive to velocity changes. // very sensitive to velocity changes.
if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(_velocity, BSParam.UpdateVelocityChangeThreshold)) if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
_velocity = entprop.Velocity; RawVelocity = entprop.Velocity;
_acceleration = entprop.Acceleration; _acceleration = entprop.Acceleration;
_rotationalVelocity = entprop.RotationalVelocity; _rotationalVelocity = entprop.RotationalVelocity;
@ -1705,7 +1502,7 @@ public class BSPrim : BSPhysObject
if (PositionSanityCheck(true /* inTaintTime */ )) if (PositionSanityCheck(true /* inTaintTime */ ))
{ {
entprop.Position = _position; entprop.Position = _position;
entprop.Velocity = _velocity; entprop.Velocity = RawVelocity;
entprop.RotationalVelocity = _rotationalVelocity; entprop.RotationalVelocity = _rotationalVelocity;
entprop.Acceleration = _acceleration; entprop.Acceleration = _acceleration;
} }

View File

@ -6,7 +6,6 @@ Enable vehicle border crossings (at least as poorly as ODE)
Terrain skirts Terrain skirts
Avatar created in previous region and not new region when crossing border 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) 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. 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. Not sure if it is because standing on it. Done with large prim linksets.
Linkset child rotations. 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. Verify that angular motion specified around Z moves in the vehicle coordinates.
DONE 20130120: BulletSim properly applies force in vehicle relative coordinates. DONE 20130120: BulletSim properly applies force in vehicle relative coordinates.
Nebadon vehicles turning funny in arena (DONE) Nebadon vehicles turning funny in arena (DONE)
Lock axis (DONE 20130401)