BulletSim: Add physical 'actors' that operate on the physical object.

Add first 'actor' for locked axis.
user_profiles
Robert Adams 2013-03-31 09:12:18 -07:00
parent 9b83e53b28
commit 2c581cae2a
4 changed files with 311 additions and 74 deletions

View File

@ -0,0 +1,168 @@
/*
* 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 OMV = OpenMetaverse;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorLockAxis : BSActor
{
bool TryExperimentalLockAxisCode = false;
BSConstraint LockAxisConstraint = null;
public BSActorLockAxis(BSScene physicsScene, BSPhysObject pObj, string actorName)
: base(physicsScene, pObj,actorName)
{
LockAxisConstraint = null;
}
// BSActor.isActive
public override bool isActive
{
get { return Enabled && Prim.IsPhysicallyActive; }
}
// Release any connections and resources used by the actor.
// BSActor.Release()
public override void Release()
{
RemoveAxisLockConstraint();
}
// Called when physical parameters (properties set in Bullet) need to be re-applied.
// Called at taint-time.
// BSActor.Refresh()
public override void Refresh()
{
// If all the axis are free, we don't need to exist
if (Prim.LockedAxis == Prim.LockedAxisFree)
{
Prim.PhysicalActors.RemoveAndRelease(ActorName);
return;
}
// If the object is physically active, add the axis locking constraint
if (Enabled
&& Prim.IsPhysicallyActive
&& TryExperimentalLockAxisCode
&& Prim.LockedAxis != Prim.LockedAxisFree)
{
if (LockAxisConstraint != null)
AddAxisLockConstraint();
}
else
{
RemoveAxisLockConstraint();
}
}
// 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()
{
if (LockAxisConstraint != null)
{
// If a constraint is set up, remove it from the physical scene
RemoveAxisLockConstraint();
// Schedule a call before the next simulation step to restore the constraint.
PhysicsScene.PostTaintObject(Prim.LockedAxisActorName, Prim.LocalID, delegate()
{
Refresh();
});
}
}
private void AddAxisLockConstraint()
{
// Lock that axis by creating a 6DOF constraint that has one end in the world and
// 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(PhysicsScene.World, Prim.PhysBody,
OMV.Vector3.Zero, OMV.Quaternion.Inverse(Prim.RawOrientation),
true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
// The constraint is tied to the world and oriented to the prim.
// Free to move linearly
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float f2PI = (float)Math.PI * 2f;
OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
if (Prim.LockedAxis.X != 1f)
{
angularLow.X = 0f;
angularHigh.X = 0f;
}
if (Prim.LockedAxis.Y != 1f)
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (Prim.LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
axisConstrainer.SetAngularLimits(angularLow, angularHigh);
PhysicsScene.DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
Prim.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(Prim.RawMass);
}
private void RemoveAxisLockConstraint()
{
if (LockAxisConstraint != null)
{
PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
LockAxisConstraint = null;
PhysicsScene.DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", Prim.LocalID);
}
}
}
}

View File

@ -0,0 +1,123 @@
/*
* 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.Text;
namespace OpenSim.Region.Physics.BulletSPlugin
{
public class BSActorCollection
{
private BSScene PhysicsScene { get; set; }
private Dictionary<string, BSActor> m_actors;
public BSActorCollection(BSScene physicsScene)
{
PhysicsScene = physicsScene;
m_actors = new Dictionary<string, BSActor>();
}
public void Add(string name, BSActor actor)
{
m_actors[name] = actor;
}
public bool RemoveAndRelease(string name)
{
bool ret = false;
if (m_actors.ContainsKey(name))
{
BSActor beingRemoved = m_actors[name];
beingRemoved.Release();
m_actors.Remove(name);
ret = true;
}
return ret;
}
public void Clear()
{
Release();
m_actors.Clear();
}
public bool HasActor(string name)
{
return m_actors.ContainsKey(name);
}
public void ForEachActor(Action<BSActor> act)
{
foreach (KeyValuePair<string, BSActor> kvp in m_actors)
act(kvp.Value);
}
public void Release()
{
ForEachActor(a => a.Release());
}
public void Refresh()
{
ForEachActor(a => a.Refresh());
}
public void RemoveBodyDependencies()
{
ForEachActor(a => a.RemoveBodyDependencies());
}
}
// =============================================================================
public abstract class BSActor
{
protected BSScene PhysicsScene { get; private set; }
protected BSPhysObject Prim { get; private set; }
protected bool Enabled { get; set; }
public string ActorName { get; private set; }
public BSActor(BSScene physicsScene, BSPhysObject pObj, string actorName)
{
PhysicsScene = physicsScene;
Prim = pObj;
ActorName = actorName;
Enabled = true;
}
// Return 'true' if activily updating the prim
public virtual bool isActive
{
get { return Enabled; }
}
// Turn the actor on an off.
public virtual void Enable(bool setEnabled)
{
Enabled = setEnabled;
}
// Release any connections and resources used by the actor.
public abstract void Release();
// Called when physical parameters (properties set in Bullet) need to be re-applied.
public abstract void Refresh();
// 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.
public abstract void RemoveBodyDependencies();
}
}

View File

@ -78,6 +78,9 @@ public abstract class BSPhysObject : PhysicsActor
Name = name; // PhysicsActor also has the name of the object. Someday consolidate. Name = name; // PhysicsActor also has the name of the object. Someday consolidate.
TypeName = typeName; TypeName = typeName;
// The collection of things that push me around
PhysicalActors = new BSActorCollection(PhysicsScene);
// 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);
@ -109,6 +112,10 @@ public abstract class BSPhysObject : PhysicsActor
{ {
UnRegisterAllPreStepActions(); UnRegisterAllPreStepActions();
UnRegisterAllPostStepActions(); UnRegisterAllPostStepActions();
PhysicsScene.TaintedObject("BSPhysObject.Destroy", delegate()
{
PhysicalActors.Release();
});
} }
public BSScene PhysicsScene { get; protected set; } public BSScene PhysicsScene { get; protected set; }
@ -230,6 +237,7 @@ 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";
#region Collisions #region Collisions
@ -413,6 +421,9 @@ public abstract class BSPhysObject : PhysicsActor
#endregion // Collisions #endregion // Collisions
#region Per Simulation Step actions #region Per Simulation Step actions
public BSActorCollection PhysicalActors;
// There are some actions that must be performed for a physical object before each simulation step. // 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 // 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. // if they have anything to do, a physical object registers for an event call before the step is performed.

View File

@ -126,7 +126,7 @@ public class BSPrim : BSPhysObject
// Undo any vehicle properties // Undo any vehicle properties
this.VehicleType = (int)Vehicle.TYPE_NONE; this.VehicleType = (int)Vehicle.TYPE_NONE;
PhysicsScene.TaintedObject("BSPrim.destroy", delegate() PhysicsScene.TaintedObject("BSPrim.Destroy", delegate()
{ {
DetailLog("{0},BSPrim.Destroy,taint,", LocalID); DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
// If there are physical body and shape, release my use of same. // If there are physical body and shape, release my use of same.
@ -257,98 +257,31 @@ public class BSPrim : BSPhysObject
}); });
} }
bool TryExperimentalLockAxisCode = false;
BSConstraint LockAxisConstraint = null;
public override void LockAngularMotion(OMV.Vector3 axis) public override void LockAngularMotion(OMV.Vector3 axis)
{ {
DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis); DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
// "1" means free, "0" means locked // "1" means free, "0" means locked
OMV.Vector3 locking = new OMV.Vector3(1f, 1f, 1f); OMV.Vector3 locking = LockedAxisFree;
if (axis.X != 1) locking.X = 0f; if (axis.X != 1) locking.X = 0f;
if (axis.Y != 1) locking.Y = 0f; if (axis.Y != 1) locking.Y = 0f;
if (axis.Z != 1) locking.Z = 0f; if (axis.Z != 1) locking.Z = 0f;
LockedAxis = locking; LockedAxis = locking;
if (TryExperimentalLockAxisCode && LockedAxis != LockedAxisFree) if (LockedAxis != LockedAxisFree)
{ {
// Lock that axis by creating a 6DOF constraint that has one end in the world and
// 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
PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate() PhysicsScene.TaintedObject("BSPrim.LockAngularMotion", delegate()
{ {
CleanUpLockAxisPhysicals(true /* inTaintTime */); // If there is not already an axis locker, make one
if (!PhysicalActors.HasActor(LockedAxisActorName))
BSConstraint6Dof axisConstrainer = new BSConstraint6Dof(PhysicsScene.World, PhysBody,
OMV.Vector3.Zero, OMV.Quaternion.Inverse(RawOrientation),
true /* useLinearReferenceFrameB */, true /* disableCollisionsBetweenLinkedBodies */);
LockAxisConstraint = axisConstrainer;
PhysicsScene.Constraints.AddConstraint(LockAxisConstraint);
// The constraint is tied to the world and oriented to the prim.
// Free to move linearly
OMV.Vector3 linearLow = OMV.Vector3.Zero;
OMV.Vector3 linearHigh = PhysicsScene.TerrainManager.DefaultRegionSize;
axisConstrainer.SetLinearLimits(linearLow, linearHigh);
// Angular with some axis locked
float f2PI = (float)Math.PI * 2f;
OMV.Vector3 angularLow = new OMV.Vector3(-f2PI, -f2PI, -f2PI);
OMV.Vector3 angularHigh = new OMV.Vector3(f2PI, f2PI, f2PI);
if (LockedAxis.X != 1f)
{ {
angularLow.X = 0f; PhysicalActors.Add(LockedAxisActorName, new BSActorLockAxis(PhysicsScene, this, LockedAxisActorName));
angularHigh.X = 0f;
} }
if (LockedAxis.Y != 1f) UpdatePhysicalParameters();
{
angularLow.Y = 0f;
angularHigh.Y = 0f;
}
if (LockedAxis.Z != 1f)
{
angularLow.Z = 0f;
angularHigh.Z = 0f;
}
axisConstrainer.SetAngularLimits(angularLow, angularHigh);
DetailLog("{0},BSPrim.LockAngularMotion,create,linLow={1},linHi={2},angLow={3},angHi={4}",
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(RawMass);
}); });
} }
else
{
// Everything seems unlocked
CleanUpLockAxisPhysicals(false /* inTaintTime */);
}
return; return;
} }
// Get rid of any constraint built for LockAxis
// Most often the constraint is removed when the constraint collection is cleaned for this prim.
private void CleanUpLockAxisPhysicals(bool inTaintTime)
{
if (LockAxisConstraint != null)
{
PhysicsScene.TaintedObject(inTaintTime, "BSPrim.CleanUpLockAxisPhysicals", delegate()
{
if (LockAxisConstraint != null)
{
PhysicsScene.Constraints.RemoveAndDestroyConstraint(LockAxisConstraint);
LockAxisConstraint = null;
DetailLog("{0},BSPrim.CleanUpLockAxisPhysicals,destroyingConstraint", LocalID);
}
});
}
}
public override OMV.Vector3 RawPosition public override OMV.Vector3 RawPosition
{ {
@ -916,6 +849,7 @@ public class BSPrim : BSPhysObject
// Update vehicle specific parameters (after MakeDynamic() so can change physical parameters) // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
VehicleController.Refresh(); VehicleController.Refresh();
PhysicalActors.Refresh();
// Arrange for collision events if the simulator wants them // Arrange for collision events if the simulator wants them
EnableCollisions(SubscribedEvents()); EnableCollisions(SubscribedEvents());
@ -1753,6 +1687,7 @@ public class BSPrim : BSPhysObject
protected virtual void RemoveBodyDependencies() protected virtual void RemoveBodyDependencies()
{ {
VehicleController.RemoveBodyDependencies(this); VehicleController.RemoveBodyDependencies(this);
PhysicalActors.RemoveBodyDependencies();
} }
// The physics engine says that properties have updated. Update same and inform // The physics engine says that properties have updated. Update same and inform