Merge branch 'master' of ssh://opensimulator.org/var/git/opensim

user_profiles
Justin Clark-Casey (justincc) 2013-04-09 22:45:00 +01:00
commit aab2b032aa
16 changed files with 1265 additions and 832 deletions

View File

@ -101,6 +101,7 @@ what it is today.
* jhurliman * jhurliman
* John R Sohn (XenReborn) * John R Sohn (XenReborn)
* jonc * jonc
* Jon Cundill
* Junta Kohime * Junta Kohime
* Kayne * Kayne
* Kevin Cozens * Kevin Cozens

View File

@ -0,0 +1,285 @@
/*
* 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 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.
}
// Usually called when target velocity changes to set the current velocity and the target
// into the movement motor.
public void SetVelocityAndTarget(OMV.Vector3 vel, OMV.Vector3 targ, bool inTaintTime)
{
m_physicsScene.TaintedObject(inTaintTime, "BSActorAvatarMove.setVelocityAndTarget", delegate()
{
if (m_velocityMotor != null)
{
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.
SetVelocityAndTarget(m_controllingPrim.RawVelocity, m_controllingPrim.TargetVelocity, true /* inTaintTime */);
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,174 @@
/*
* 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, turn me off
if (!m_controllingPrim.HoverActive)
{
SetEnabled(false);
}
// 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

@ -36,11 +36,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{ {
public class BSActorLockAxis : BSActor public class BSActorLockAxis : BSActor
{ {
bool TryExperimentalLockAxisCode = true;
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;
@ -69,18 +68,13 @@ public class BSActorLockAxis : BSActor
// If all the axis are free, we don't need to exist // If all the axis are free, we don't need to exist
if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree) if (m_controllingPrim.LockedAxis == m_controllingPrim.LockedAxisFree)
{ {
m_physicsScene.DetailLog("{0},BSActorLockAxis,refresh,allAxisFree,removing={1}", m_controllingPrim.LocalID, ActorName); Enabled = false;
m_controllingPrim.PhysicalActors.RemoveAndRelease(ActorName);
return;
} }
// If the object is physically active, add the axis locking constraint // If the object is physically active, add the axis locking constraint
if (Enabled if (isActive)
&& m_controllingPrim.IsPhysicallyActive
&& TryExperimentalLockAxisCode
&& m_controllingPrim.LockedAxis != m_controllingPrim.LockedAxisFree)
{ {
if (LockAxisConstraint == null) AddAxisLockConstraint();
AddAxisLockConstraint();
} }
else else
{ {
@ -99,7 +93,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();
}); });
@ -108,58 +102,61 @@ public class BSActorLockAxis : BSActor
private void AddAxisLockConstraint() private void AddAxisLockConstraint()
{ {
// Lock that axis by creating a 6DOF constraint that has one end in the world and if (LockAxisConstraint == null)
// the other in the object.
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
// http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
// Remove any existing axis constraint (just to be sure)
RemoveAxisLockConstraint();
BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
OMV.Vector3.Zero, OMV.Quaternion.Identity,
false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
// The constraint is tied to the world and oriented to the prim.
// Free to move linearly in the region
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float fPI = (float)Math.PI;
OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
if (m_controllingPrim.LockedAxis.X != 1f)
{ {
angularLow.X = 0f; // Lock that axis by creating a 6DOF constraint that has one end in the world and
angularHigh.X = 0f; // the other in the object.
} // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=20817
if (m_controllingPrim.LockedAxis.Y != 1f) // http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?p=26380
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (m_controllingPrim.LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
{
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
}
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}", // Remove any existing axis constraint (just to be sure)
m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh); RemoveAxisLockConstraint();
// Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo. BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(m_physicsScene.World, m_controllingPrim.PhysBody,
axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f); OMV.Vector3.Zero, OMV.Quaternion.Identity,
false /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
m_physicsScene.Constraints.AddConstraint(LockAxisConstraint);
axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass); // The constraint is tied to the world and oriented to the prim.
// Free to move linearly in the region
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = m_physicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float fPI = (float)Math.PI;
OMV.Vector3 angularLow = new OMV.Vector3(-fPI, -fPI, -fPI);
OMV.Vector3 angularHigh = new OMV.Vector3(fPI, fPI, fPI);
if (m_controllingPrim.LockedAxis.X != 1f)
{
angularLow.X = 0f;
angularHigh.X = 0f;
}
if (m_controllingPrim.LockedAxis.Y != 1f)
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (m_controllingPrim.LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
if (!axisConstrainer.SetAngularLimits(angularLow, angularHigh))
{
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,failedSetAngularLimits", m_controllingPrim.LocalID);
}
m_physicsScene.DetailLog("{0},BSActorLockAxis.AddAxisLockConstraint,create,linLow={1},linHi={2},angLow={3},angHi={4}",
m_controllingPrim.LocalID, linearLow, linearHigh, angularLow, angularHigh);
// Constants from one of the posts mentioned above and used in Bullet's ConstraintDemo.
axisConstrainer.TranslationalLimitMotor(true /* enable */, 5.0f, 0.1f);
axisConstrainer.RecomputeConstraintVariables(m_controllingPrim.RawMass);
}
} }
private void RemoveAxisLockConstraint() private void RemoveAxisLockConstraint()

View File

@ -0,0 +1,152 @@
/*
* 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...
if (!m_controllingPrim.MoveToTargetActive)
{
Enabled = false;
}
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 moveToTarget 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;
}
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);
Enabled = false;
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,torque={1}", m_controllingPrim.LocalID, m_controllingPrim.RawTorque);
// 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,disabling={1}", m_controllingPrim.LocalID, ActorName);
Enabled = false;
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,45 +32,72 @@ 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)
{ {
m_actors[name] = actor; lock (m_actors)
{
if (!m_actors.ContainsKey(name))
{
m_actors[name] = actor;
}
}
} }
public bool RemoveAndRelease(string name) public bool RemoveAndRelease(string name)
{ {
bool ret = false; bool ret = false;
if (m_actors.ContainsKey(name)) lock (m_actors)
{ {
BSActor beingRemoved = m_actors[name]; if (m_actors.ContainsKey(name))
beingRemoved.Dispose(); {
m_actors.Remove(name); BSActor beingRemoved = m_actors[name];
ret = true; m_actors.Remove(name);
beingRemoved.Dispose();
ret = true;
}
} }
return ret; return ret;
} }
public void Clear() public void Clear()
{ {
Release(); lock (m_actors)
m_actors.Clear(); {
Release();
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);
} }
public bool TryGetActor(string actorName, out BSActor theActor)
{
return m_actors.TryGetValue(actorName, out theActor);
}
public void ForEachActor(Action<BSActor> act) public void ForEachActor(Action<BSActor> act)
{ {
foreach (KeyValuePair<string, BSActor> kvp in m_actors) lock (m_actors)
act(kvp.Value); {
foreach (KeyValuePair<string, BSActor> kvp in m_actors)
act(kvp.Value);
}
} }
public void Enable(bool enabl)
{
ForEachActor(a => a.SetEnabled(enabl));
}
public void Release() public void Release()
{ {
ForEachActor(a => a.Dispose()); ForEachActor(a => a.Dispose());
@ -98,7 +125,7 @@ public abstract class BSActor
{ {
protected BSScene m_physicsScene { get; private set; } protected BSScene m_physicsScene { get; private set; }
protected BSPhysObject m_controllingPrim { get; private set; } protected BSPhysObject m_controllingPrim { get; private set; }
protected bool Enabled { get; set; } public virtual bool Enabled { get; set; }
public string ActorName { get; private set; } public string ActorName { get; private set; }
public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName) public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
@ -114,8 +141,10 @@ public abstract class BSActor
{ {
get { return Enabled; } get { return Enabled; }
} }
// Turn the actor on an off.
public virtual void Enable(bool setEnabled) // Turn the actor on an off. Only used by ActorCollection to set all enabled/disabled.
// Anyone else should assign true/false to 'Enabled'.
public void SetEnabled(bool setEnabled)
{ {
Enabled = setEnabled; Enabled = setEnabled;
} }

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.
@ -163,6 +160,9 @@ public sealed class BSCharacter : BSPhysObject
// Make so capsule does not fall over // Make so capsule does not fall over
PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero); PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
// The avatar mover sets some parameters.
PhysicalActors.Refresh();
PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT); PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody); PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
@ -176,162 +176,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 +247,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 +386,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 +417,7 @@ public sealed class BSCharacter : BSPhysObject
{ {
get get
{ {
return m_targetVelocity; return base.m_targetVelocity;
} }
set set
{ {
@ -583,51 +427,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 +615,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 +644,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 +698,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 +707,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 +731,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,45 @@ 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.
// May be called at non-taint time as this just adds the actor to the action list and the real
// work is done during the simulation step.
// Note that, if the actor is already in the list and we are disabling same, the actor is just left
// in the list disabled.
public delegate BSActor CreateActor();
public void EnableActor(bool enableActor, string actorName, CreateActor creator)
{
lock (PhysicalActors)
{
BSActor theActor;
if (PhysicalActors.TryGetActor(actorName, out theActor))
{
// The actor already exists so just turn it on or off
theActor.Enabled = enableActor;
}
else
{
// The actor does not exist. If it should, create it.
if (enableActor)
{
theActor = creator();
PhysicalActors.Add(actorName, theActor);
theActor.Enabled = true;
}
}
}
}
#region Collisions #region Collisions
@ -255,7 +326,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 +366,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 +497,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 +508,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,12 +89,13 @@ 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;
_isVolumeDetect = false; _isVolumeDetect = false;
// We keep a handle to the vehicle actor so we can set vehicle parameters later.
VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName); VehicleActor = new BSDynamics(PhysicsScene, this, VehicleActorName);
PhysicalActors.Add(VehicleActorName, VehicleActor); PhysicalActors.Add(VehicleActorName, VehicleActor);
@ -233,7 +228,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 +265,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) EnableActor(LockedAxis != LockedAxisFree, LockedAxisActorName, 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 +400,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,48 +499,25 @@ 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) EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, 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);
}
} }
} }
public override int VehicleType { public override int VehicleType {
get { get {
return (int)VehicleActor.Type; // if we are a vehicle, return that type return (int)VehicleActor.Type;
} }
set { set {
Vehicle type = (Vehicle)value; Vehicle type = (Vehicle)value;
PhysicsScene.TaintedObject("setVehicleType", delegate() PhysicsScene.TaintedObject("setVehicleType", delegate()
{ {
// Done at taint time so we're sure the physics engine is not using the variables
// Vehicle code changes the parameters for this vehicle type. // Vehicle code changes the parameters for this vehicle type.
VehicleActor.ProcessTypeChange(type); VehicleActor.ProcessTypeChange(type);
ActivateIfPhysical(false); ActivateIfPhysical(false);
@ -670,63 +640,40 @@ 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) EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, 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, DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
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);
} }
} }
public override OMV.Vector3 Acceleration { public override OMV.Vector3 Acceleration {
@ -839,7 +786,6 @@ public class BSPrim : BSPhysObject
MakeDynamic(IsStatic); MakeDynamic(IsStatic);
// Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
VehicleActor.Refresh();
PhysicalActors.Refresh(); PhysicalActors.Refresh();
// Arrange for collision events if the simulator wants them // Arrange for collision events if the simulator wants them
@ -909,7 +855,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 +912,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 +1033,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;
EnableActor(MoveToTargetActive, MoveToTargetActorName, 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 +1047,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;
EnableActor(HoverActive, HoverActorName, 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 +1122,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())
{ {
@ -1661,7 +1457,7 @@ public class BSPrim : BSPhysObject
{ {
// Create the correct physical representation for this type of object. // Create the correct physical representation for this type of object.
// Updates base.PhysBody and base.PhysShape with the new information. // Updates base.PhysBody and base.PhysShape with the new information.
// Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody) PhysicsScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysicsScene.World, this, null, delegate(BulletBody dBody)
{ {
// Called if the current prim body is about to be destroyed. // Called if the current prim body is about to be destroyed.
@ -1675,9 +1471,9 @@ public class BSPrim : BSPhysObject
return; return;
} }
// Called at taint-time
protected virtual void RemoveBodyDependencies() protected virtual void RemoveBodyDependencies()
{ {
VehicleActor.RemoveBodyDependencies();
PhysicalActors.RemoveBodyDependencies(); PhysicalActors.RemoveBodyDependencies();
} }
@ -1685,6 +1481,7 @@ public class BSPrim : BSPhysObject
// the world that things have changed. // the world that things have changed.
public override void UpdateProperties(EntityProperties entprop) public override void UpdateProperties(EntityProperties entprop)
{ {
// Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
TriggerPreUpdatePropertyAction(ref entprop); TriggerPreUpdatePropertyAction(ref entprop);
// DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
@ -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;
} }
@ -1717,16 +1514,8 @@ public class BSPrim : BSPhysObject
LastEntityProperties = CurrentEntityProperties; LastEntityProperties = CurrentEntityProperties;
CurrentEntityProperties = entprop; CurrentEntityProperties = entprop;
// Note that BSPrim can be overloaded by BSPrimLinkable which controls updates from root and children prims.
base.RequestPhysicsterseUpdate(); base.RequestPhysicsterseUpdate();
/*
else
{
// For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
} }
} }
} }

View File

@ -163,6 +163,15 @@ public class BSPrimLinkable : BSPrimDisplaced
// TODO: this will have to change when linksets are articulated. // TODO: this will have to change when linksets are articulated.
base.UpdateProperties(entprop); base.UpdateProperties(entprop);
} }
/*
else
{
// For debugging, report the movement of children
DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
entprop.Acceleration, entprop.RotationalVelocity);
}
*/
// The linkset might like to know about changing locations // The linkset might like to know about changing locations
Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this); Linkset.UpdateProperties(UpdatedProperties.EntPropUpdates, this);
} }

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)

View File

@ -137,10 +137,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
userID, sessionID, secureSessionID); userID, sessionID, secureSessionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddSession" }, { "RequestMethod", "AddSession" },
{ "UserID", userID.ToString() } { "UserID", userID.ToString() }
}; };
if (sessionID != UUID.Zero) if (sessionID != UUID.Zero)
{ {
requestArgs["SessionID"] = sessionID.ToString(); requestArgs["SessionID"] = sessionID.ToString();
@ -158,13 +159,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LogoutAgent(UUID sessionID) public bool LogoutAgent(UUID sessionID)
{ {
// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "RemoveSession" }, { "RequestMethod", "RemoveSession" },
{ "SessionID", sessionID.ToString() } { "SessionID", sessionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -177,13 +178,13 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LogoutRegionAgents(UUID regionID) public bool LogoutRegionAgents(UUID regionID)
{ {
// m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "RemoveSessions" }, { "RequestMethod", "RemoveSessions" },
{ "SceneID", regionID.ToString() } { "SceneID", regionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -202,49 +203,46 @@ namespace OpenSim.Services.Connectors.SimianGrid
public PresenceInfo GetAgent(UUID sessionID) public PresenceInfo GetAgent(UUID sessionID)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); OSDMap sessionResponse = GetSessionDataFromSessionID(sessionID);
if (sessionResponse == null)
NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetSession" }, m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session {0}: {1}",sessionID.ToString(),sessionResponse["Message"].AsString());
{ "SessionID", sessionID.ToString() } return null;
};
OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (sessionResponse["Success"].AsBoolean())
{
UUID userID = sessionResponse["UserID"].AsUUID();
m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() }
};
OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (userResponse["Success"].AsBoolean())
return ResponseToPresenceInfo(sessionResponse, userResponse);
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
}
else
{
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString());
} }
return null; UUID userID = sessionResponse["UserID"].AsUUID();
OSDMap userResponse = GetUserData(userID);
if (userResponse == null)
{
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID.ToString(),userResponse["Message"].AsString());
return null;
}
return ResponseToPresenceInfo(sessionResponse);
} }
public PresenceInfo[] GetAgents(string[] userIDs) public PresenceInfo[] GetAgents(string[] userIDs)
{ {
List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length); List<PresenceInfo> presences = new List<PresenceInfo>();
for (int i = 0; i < userIDs.Length; i++) NameValueCollection requestArgs = new NameValueCollection
{ {
UUID userID; { "RequestMethod", "GetSessions" },
if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) { "UserIDList", String.Join(",",userIDs) }
presences.AddRange(GetSessions(userID)); };
OSDMap sessionListResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (! sessionListResponse["Success"].AsBoolean())
{
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve sessions: {0}",sessionListResponse["Message"].AsString());
return null;
}
OSDArray sessionList = sessionListResponse["Sessions"] as OSDArray;
for (int i = 0; i < sessionList.Count; i++)
{
OSDMap sessionInfo = sessionList[i] as OSDMap;
presences.Add(ResponseToPresenceInfo(sessionInfo));
} }
return presences.ToArray(); return presences.ToArray();
@ -262,7 +260,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID);
// Remove the session to mark this user offline // Remove the session to mark this user offline
if (!LogoutAgent(sessionID)) if (!LogoutAgent(sessionID))
@ -270,11 +268,11 @@ namespace OpenSim.Services.Connectors.SimianGrid
// Save our last position as user data // Save our last position as user data
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddUserData" }, { "RequestMethod", "AddUserData" },
{ "UserID", userID.ToString() }, { "UserID", userID.ToString() },
{ "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -287,14 +285,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "AddUserData" }, { "RequestMethod", "AddUserData" },
{ "UserID", userID.ToString() }, { "UserID", userID.ToString() },
{ "HomeLocation", SerializeLocation(regionID, position, lookAt) } { "HomeLocation", SerializeLocation(regionID, position, lookAt) }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -312,23 +310,14 @@ namespace OpenSim.Services.Connectors.SimianGrid
public GridUserInfo GetGridUserInfo(string user) public GridUserInfo GetGridUserInfo(string user)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user);
UUID userID = new UUID(user); UUID userID = new UUID(user);
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); OSDMap userResponse = GetUserData(userID);
if (userResponse != null)
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() }
};
OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs);
if (userResponse["Success"].AsBoolean())
return ResponseToGridUserInfo(userResponse); return ResponseToGridUserInfo(userResponse);
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString());
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}: {1}",userID,userResponse["Message"].AsString());
return null; return null;
} }
@ -338,65 +327,49 @@ namespace OpenSim.Services.Connectors.SimianGrid
private OSDMap GetUserData(UUID userID) private OSDMap GetUserData(UUID userID)
{ {
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID);
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetUser" }, { "RequestMethod", "GetUser" },
{ "UserID", userID.ToString() } { "UserID", userID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
if (response["Success"].AsBoolean() && response["User"] is OSDMap) if (response["Success"].AsBoolean() && response["User"] is OSDMap)
return response; return response;
else
m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString());
m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for {0}; {1}",userID.ToString(),response["Message"].AsString());
return null; return null;
} }
private List<PresenceInfo> GetSessions(UUID userID) private OSDMap GetSessionDataFromSessionID(UUID sessionID)
{ {
List<PresenceInfo> presences = new List<PresenceInfo>(1); NameValueCollection requestArgs = new NameValueCollection
OSDMap userResponse = GetUserData(userID);
if (userResponse != null)
{
// m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID);
NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "GetSession" }, { "RequestMethod", "GetSession" },
{ "UserID", userID.ToString() } { "SessionID", sessionID.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
if (response["Success"].AsBoolean()) if (response["Success"].AsBoolean())
{ return response;
PresenceInfo presence = ResponseToPresenceInfo(response, userResponse);
if (presence != null)
presences.Add(presence);
}
// else
// {
// m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString());
// }
}
return presences; m_log.WarnFormat("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session data for {0}; {1}",sessionID.ToString(),response["Message"].AsString());
return null;
} }
private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt)
{ {
// Save our current location as session data // Save our current location as session data
NameValueCollection requestArgs = new NameValueCollection NameValueCollection requestArgs = new NameValueCollection
{ {
{ "RequestMethod", "UpdateSession" }, { "RequestMethod", "UpdateSession" },
{ "SessionID", sessionID.ToString() }, { "SessionID", sessionID.ToString() },
{ "SceneID", regionID.ToString() }, { "SceneID", regionID.ToString() },
{ "ScenePosition", lastPosition.ToString() }, { "ScenePosition", lastPosition.ToString() },
{ "SceneLookAt", lastLookAt.ToString() } { "SceneLookAt", lastLookAt.ToString() }
}; };
OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs);
bool success = response["Success"].AsBoolean(); bool success = response["Success"].AsBoolean();
@ -407,7 +380,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
return success; return success;
} }
private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse)
{ {
if (sessionResponse == null) if (sessionResponse == null)
return null; return null;

View File

@ -1,6 +1,8 @@
<configuration> <configuration>
<dllmap os="windows" cpu="x86" dll="BulletSim" target="lib32/BulletSim" /> <dllmap os="windows" cpu="x86" dll="BulletSim" target="lib32/BulletSim" />
<dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="lib64/BulletSim" /> <dllmap os="windows" cpu="x86-64,ia64" dll="BulletSim" target="lib64/BulletSim" />
<dllmap os="osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.dylib" />
<dllmap os="osx" cpu="x86-64,ia64" dll="BulletSim" target="lib32/libBulletSim.dylib" />
<dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.so" /> <dllmap os="!windows,osx" cpu="x86" dll="BulletSim" target="lib32/libBulletSim.so" />
<dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="lib64/libBulletSim.so" /> <dllmap os="!windows,osx" cpu="x86-64,ia64" dll="BulletSim" target="lib64/libBulletSim.so" />
</configuration> </configuration>

BIN
bin/lib32/libBulletSim.dylib Executable file

Binary file not shown.